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.