...
A Factory Bean is required if the plugin you have implemented takes a parameter (via a bean setter or a constructor) which is not a String or an Object which Spring can convert into from a String. The IdP String infrastructure has a reasonably wide set of functions to convert from Strings to other types:
Booleans
Integers
Durations (
@Duration long)
Predicates
If your code requires more than this then you need a Factory Bean. To put another way, if the object passed to builder.addConstructorArgValue()
or builder.addParameterValue()
is not a String, then you should have used a Factory Bean.
...
Consider two beans. One represents rational numbers
The Rational bean
Code Block | ||||
---|---|---|---|---|
| ||||
public class Rational { private int denominator; private int numerator; public void setDenominator(int what) { denominator = what; } public void setNumerator(int what) { numerator = what; } public float approxValue() { return numerator/denominator; } } |
and the other contains an instance of it.
The Containing Bean
Code Block | ||||
---|---|---|---|---|
| ||||
public class Parent extends AbstractIdentifiableInitializableComponent { private Rational rational; public void setRational(Rational what) { rational = what; } } |
...
Code Block | ||
---|---|---|
| ||
<plugin:Parent numerator="22" denominator="7" name="pi"/> |
You might intially initially write parsing code like this
Broken parsing
Code Block | ||||
---|---|---|---|---|
| ||||
final String id = StringSupport.trimOrNull(child.getAttributeNS(null, "name")); builder.addPropertyValue("id", id); final String num = StringSupport.trimOrNull(child.getAttributeNS(null, "numerator")); final String denom = StringSupport.trimOrNull(child.getAttributeNS(null, "denominator")); final Rational rational = new Rational(); rational.setDenominator(Integer.decode(denom)); rational.setNumerator(Integer.decode(num)); builder.addPropertyValue("rational", rational); |
...
The idea here is to hold the parameters inside the bean and then create the subsidiary bean in the doInitialize()
method. Again using the same example the Parent bean would become
The Containing Bean
Code Block | ||||
---|---|---|---|---|
| ||||
public class Parent extends AbstractIdentifiableInitializableComponent { private Rational rational; private int denominator; private int numerator; public void setDenominator(int what) { denominator = what; } public void setNumerator(int what) { numerator = what; } @Override public void doInitialize() throws ComponentInitializationException { super.doInitialize(); final Rational rational = new Rational(); rational.setNumerator(numerator); rational.setDenominator(denominator); setRational(rational); } } |
...
In our example, the FactoryBean might look like this:
A Factory Bean
Code Block | ||||
---|---|---|---|---|
| ||||
public class ParentFactoryBean extends AbstractComponentAwareFactoryBean<Parent> { private int denominator; private int numerator; public void setDenominator(int what) { denominator = what; } public void setNumerator(int what) { numerator = what; } @Override public Class<?> getObjectType() { return Parent.class; } @Override protected Parent doCreateInstance() throws Exception { final Rational rational = new Rational(); rational.setNumerator(numerator); rational.setDenominator(denominator); Parent parent = new Parent(); parent.setRational(rational); return parent; } } |