[Coldbox 7] Exploring the Object Populator's TrustedSetter Argument

I’ve been using Wirebox’s object populator for years, and I have never really considered what the optional argument trustedSetter actually does, until now.

The argument description reads like this:
“If set to true, the setter method will be called even if it does not exist in the bean”

By default trustedSetter is set to “false”. What this means, is that, when the populator is looping through keys in the source memento struct, it will only call setter methods (i.e. setFirstName( value ) ) that exist in the object.

If it’s set to true, it tries to call setters (i.e. setFirstName( value ) ) for every key in the memento, even if the setter doesn’t exist.

Remember, if your CFC component has the attribute accessors="true`` CFML will create setters for you. You can define an object property with the attribute setter=“false”` to NOT dynamically create an individual setter.

component accessors="true" {
    
    property name="topSecret" setter="false"; // no dynamic setter

}

So, if there’s no setter, and trustedSetter is set to “false”, the object populator won’t attempt to set that property. This is really cool behavior because you can protect properties that shouldn’t be set by external means.

So what happens if you force trustedSetter to “true” and then attempt to populate a property that doesn’t have a setter?

rc.topSecret = "I should not be set";

populate(
    model = prc.user,
    memento = rc,
    trustedSetter = true
);

You will get an exception: “Error populating bean models.app.BondApp with argument…”

Another way you can protect properties is to exclude them using the populator’s exclude argument, which accepts a list of properties to ignore. So you could also do this:

rc.topSecret = "I should not be set";

populate(
    model = prc.user,
    memento = rc,
    exclude = "topSecret" // don't try and set the 'topSecret' property if it exists in 'rc' 
);

Now if you’re anything like me, your next question is, “What about component properties that have the ‘inject’ attribute?” We use “inject” to tell Wirebox to automatically inject something into our components when instantiated.

component accessors="true" {
    
    property name="topSecret" inject="coldbox:setting:topSecret"; // Wirebox will inject the value here

}

If you populate the object, and trustedSetter is set to false (the default), you could override this property!

rc.topSecret = "I should not be set";

populate(
    model = prc.user,
    memento = rc,
);

writeDump( prc.user.getTopSecret() ); // value will be: I should not be set

So, the safest thing, if you do not want to accidentally override an injected property is to ensure no setter is created by adding “setter=false” like this:

component accessors="true" {
    
    property name="topSecret" inject="coldbox:setting:topSecret" setter="false"; // Wirebox can inject, but no setter is created

}

Anyway, I thought this was pretty interesting and hopefully it will help someone else who is curious what the trustedSetter argument does and how they can further protect object properties from accidental overwriting.

2 Likes

Just to add to this, you can also control what’s set/not set in the target model using this.population:

1 Like

Nice! I didn’t know about that one. Thank you!

Wow, nice writeup! I’ve come across this setting once or twice before, but it helps to see a full use case and explanation of what it does. Thanks!