2

Problem Statement

I am trying to pass an instance of an Apex type from LWC into an AuraEnabled method. However, all of the attributes are coming through as null.


MVR

Back End

public with sharing class MyController
{
    @AuraEnabled(cacheable=true)
    public static void doStuff(Model instance)
    {
        system.debug(JSON.serialize(instance));
        // { "sampleAttribute": null }
    }
    public class Model
    {
        @AuraEnabled
        public String sampleAttribute;
    }
}

Front End

import doStuff from "@salesforce/apex/MyController.doStuff"

export default class MyComponent extends LightningElement {
    ...
    const instance = {
        sampleAttribute: "I am populated"
    };
    console.debug(instance);
    // { sampleAttribute: "I am populated" }

    doStuff({ instance })
        .then(result => { ... })
        .catch(error => { ... });
}

Question

Why are my attributes all cleared out by the time they arrive at the back end? They are clearly populated right before I send them. I even tried specifying each attribute via string key just to be sure that wasn't contributing to the problem, but it did not resolve the issue.


Workaround

For now I am using serialization to get the call to work.

Back End

@AuraEnabled(cacheable=true)
public static void doStuff(String payload)
{
    doStuffWithModel((Model)JSON.deserialize(payload, Model.class));
}
public static void doStuffWithModel(Model instance)
{
    // implementation
}

Front End

const instance = {
    sampleAttribute: "I am populated"
};
doStuff({ instance })
    .then(result => { ... })
    .catch(error => { ... });

Expose Apex Methods to Lightning Web Components To expose an Apex method to a Lightning web component, the method must be static and either global or public. Annotate the method with @AuraEnabled.

...

These types are supported for input and output.

  • Primitive—Boolean, Date, DateTime, Decimal, Double, Integer, Long, and String.
  • sObject—standard and custom sObjects are both supported.
  • Apex—an instance of an Apex class. (Most often a custom class.)
  • Collection—a collection of any of the other types.

But the documentation clearly indicates use of Apex types is supported. Using JSON should not be necessary.

  • I think NULL is actually expected behavior here. We are venturing into the "pass by reference by value" behavior of Apex (i.e. Java bytecode). developer.salesforce.com/blogs/developer-relations/2012/05/… – krigi May 28 at 18:16
  • 1
    That article doesn't mention pass-by-reference between front-end and back-end. That sounds infeasible at best. I do not think it has any bearing on the observed behavior. – Adrian Larson May 28 at 18:21
  • 2
    This should work. Oddly, trying to repro this issue gives me an internal server error. – sfdcfox May 28 at 19:11
3

This fails because the Model class is an inner class. It is probably a bug, but we hit this a while back and found:

  • instances of inner classes can be returned to the client but cannot be passed to the server
  • instances of top level classes can be passed both ways

As per sfdcfox's comment, we most often saw an internal server error when trying to pass an instance of an inner class to an aura enabled method.

The documentation does say:

Custom classes used for component attributes shouldn’t be inner classes or use inheritance. While these Apex language features might work in some situations, there are known issues, and their use is unsupported in all cases.

Whilst this appears to be for Aura code, the LWC documentation indicates LWC has the same behaviour (see the link for "Apex" in the section entitled "Expose Apex Methods to Lightning Web Components"). So whilst it is probably a bug, they have documented to say things can go wrong if you try to use inner classes.

Something else that can cause issues is the use of @AuraEnabled public attributes in your data object, which can be remedied by switching to public properties. Thus changing your inner Model class to a top level one like the following should resolve any issues:

public class Model {
    @AuraEnabled
    public String someAttribute { get; set; }
}
| improve this answer | |
  • I found the same with your first bullet. Man that's kind of mind blowing. I would agree that's got to be a bug. – Adrian Larson May 28 at 20:55
  • 1
    Quite bizarre and very annoying. – Phil W May 28 at 20:56
  • I mean that sounds like a relic from Visualforce days...I remember the same constraint for parameters on a component (not page)... – Adrian Larson May 28 at 20:59
  • We hoisted our classes to be top-level where necessary, but your solution of JSON serialize/deserialize does at least allow for a less cluttered source tree. Maybe we should have done that :D – Phil W May 28 at 21:01
  • I prefer avoiding it. Maybe I'll regret that decision in a year. ¯\_(ツ)_/¯ – Adrian Larson May 28 at 21:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.