Return-Path:
Rule implementation that sets properties on the object at the top of=
the
+ * An Action that sets properties on the object at the top of the
* stack, based on attributes with corresponding names. This rule supports custom mapping of attribute names to property nam=
es.
- * The default mapping for particular attributes can be overridden by usin=
g=20
+ * By default, any xml attribute xyz=3D'value' causes a call to propert=
y-setter
+ * method setXyz(value) on the top object on the stack. If the target meth=
od
+ * does not take a String parameter, then the BeanUtils library attempts
+ * to convert the String value of the xml attribute to the required type.<=
/p>
+ *
+ * Custom mapping of attribute names to property names can also be done.
+ * The default mapping for particular attributes can be overridden by using
* {@link #ActionSetProperties(String[] attributeNames, String[] propertyN=
ames)}.
* This allows attributes to be mapped to properties with different names.
- * Certain attributes can also be marked to be ignored.
XML Attributes that are not in the default namespace are ignored.
*/ =20 public class SetPropertiesAction extends AbstractAction { =20 - // ----------------------------------------------------------- Constru= ctors + private HashMap customMap =3D null; + + // ----------------------------------------------------------- + // Constructors + // ----------------------------------------------------------- =20 /** * Base constructor. */ public SetPropertiesAction() { - // nothing to set up=20 + // nothing to set up } - =20 - /**=20 - *Convenience constructor overrides the mapping for just one prope= rty.
+ + /** + *Constructor which allows the default attribute->property mapping= to + * be overriden.
+ * + *The keys of the map are xml attribute names, and the associated = values + * are the java property name to map that attribute to. If the value + * associated with an attribute name is null then the attibute will be + * ignored.
+ * + * The following constructs a rule that maps the class
+ * attribute to the className
property. The attribute
+ * ignore
is not mapped, and will therefore be ignored ra=
ther
+ * than be passed to a setIgnore method (the default behaviour). All o=
ther
+ * attributes are mapped as usual using exact name matching.
+ *
+ * HashMap map =3D new HashMap();
+ * map.put("class", "className");
+ * map.put("ignore", null);
+ * SetPropertiesAction(map);
+ *
See also {@link #addAlias} which allows the custom mapping to be + * modified after the SetPropertiesAction has been constructed.
+ * + * @param customMap is a map. The map is copied, so future changes to + * the map will not affect this object.=20 + */ + public SetPropertiesAction(Map customMap) { + this.customMap =3D new HashMap(customMap); + } + + /** + *Convenience constructor which overrides the default attribute->p= roperty + * mapping for just one property.
* *For details about how this works, see - * {@link #ActionSetProperties(String[] attributeNames, String[] prope= rtyNames)}.
+ * {@link #ActionSetProperties(Map customMappings)}. * - * @param attributeName map this attribute=20 - * @param propertyName to a property with this name + * @param attributeName map this attribute. Must not be null. + * @param propertyName to a property with this name. May be null. */ public SetPropertiesAction(String attributeName, String propertyName) { - attributeNames =3D new String[1]; - attributeNames[0] =3D attributeName; - propertyNames =3D new String[1]; - propertyNames[0] =3D propertyName; + customMap =3D new HashMap(1); + customMap.put(attributeName, propertyName); } - =20 - /**=20 - *Constructor allows attribute->property mapping to be overriden.<= /p> + + /** + *
Constructor which allows the default attribute->property mapping= to + * be overriden.
* - *Two arrays are passed in.=20 - * One contains the attribute names and the other the property names. - * The attribute name / property name pairs are match by position - * In order words, the first string in the attribute name list matches - * to the first string in the property name list and so on.
+ *Two arrays are passed in. One contains the attribute names and t= he + * other the property names. The attribute name / property name pairs = are + * matched by position In order words, the first string in the attribu= te + * name list maps to the first string in the property name list and so= on. + *
* *If a property name is null or the attribute name has no matching - * property name, then this indicates that the attibute should be igno= red.
- *=20 + * property name (ie the property array is shorter than the attribute = array) + * then the attibute will be ignored. + * * The following constructs a rule that maps the The following constructs a rule that maps the Add an additional attribute name to property name mapping.
+ * This is particularly useful for the xmlrules optional module. See {@link #SetPropertiesAction(Map customMap)}.
+ */
+ public void addAlias(String attributeName, String propertyName) {
+ if (customMap =3D=3D null) {
+ customMap =3D new HashMap();
+ }
+ customMap.put(attributeName, propertyName);
+ }
=20
- // --------------------------------------------------------- Public Me=
thods
+ // ---------------------------------------------------------
+ // Action Methods
+ // ---------------------------------------------------------
=20
/**
* Process the beginning of this element.
*
- * @param attributes The attribute list of this element
+ * @param context The object on which all parsing state is stored.
+ * @param namespace The xml namespace the current element is in.
+ * @param name The local name of the current element.
+ * @param attributes The attribute list of the current element
*/
public void begin(
- Context context, String namespace, String elementName, Attributes attr=
ibutes)=20
+ Context context,
+ String namespace, String elementName,
+ Attributes attributes)
throws ParseException {
- =20
+
Log log =3D context.getLogger();
=20
- // Build a set of attribute names and corresponding values
+ // Build a set of property names and corresponding values
HashMap values =3D new HashMap();
- =20
- // set up variables for custom names mappings
- int attNamesLength =3D 0;
- if (attributeNames !=3D null) {
- attNamesLength =3D attributeNames.length;
- }
- int propNamesLength =3D 0;
- if (propertyNames !=3D null) {
- propNamesLength =3D propertyNames.length;
- }
- =20
+
+ // for each xml attribute
for (int i =3D 0; i < attributes.getLength(); i++) {
- String name =3D attributes.getLocalName(i);
- if ("".equals(name)) {
- name =3D attributes.getQName(i);
- }
- String value =3D attributes.getValue(i);
- =20
- // we'll now check for custom mappings
- for (int n =3D 0; n Add an additional attribute name to property name mapping.
- * This is intended to be used from the xml rules.
+ * This method is intended to convert xml hypenated names
+ * into javabean names. Traditionally, xml element and attribute names that are=20
+ * formed from multiple words use hyphens to separate the words,
+ * for example a-long-attribute-name. However the Java tradition
+ * is to use camel-case, eg aLongAttributeName. This method
+ * converts from the xml to the java convention. If src contains no hyphens then a reference to the same object
+ * is returned. If src ends in a hyphen, then it is stripped.alt-city
* attribute to the
city
property and the alt-state=
- * to the state
property.=20
+ * to the state
property.
* All other attributes are mapped as usual using exact name matching.
*
*
*
- * SetPropertiesRule(
- * new String[] {"alt-city", "alt-state"},=20
+ * SetPropertiesAction(
+ * new String[] {"alt-city", "alt-state"},
* new String[] {"city", "state"});
*
Example Two
* class
- * attribute to the className
property.
- * The attribute ignore-me
is not mapped.
- * All other attributes are mapped as usual using exact name matching.
+ * attribute to the className
property. The attribute
+ * ignore
is not mapped, and will therefore be ignored ra=
ther
+ * than be passed to a setIgnore method (the default behaviour). All o=
ther
+ * attributes are mapped as usual using exact name matching.
*
*
@@ -106,105 +151,117 @@
* @param propertyNames names of properties mapped to
*/
public SetPropertiesAction(String[] attributeNames, String[] propertyN=
ames) {
- // create local copies
- this.attributeNames =3D new String[attributeNames.length];
- for (int i=3D0, size=3DattributeNames.length; i
- * SetPropertiesRule(
- * new String[] {"class", "ignore-me"},=20
+ * SetPropertiesAction(
+ * new String[] {"class", "ignore"},
* new String[] {"className"});
*