XBean > Home > Features > Editing Custom XML

XBean supports custom XML languages for different libraries of Java code. This page details some guidelines.

References

To refer to another POJO inside XBean you can use the # character to refer to another bean in the same file. This is similar to the <property name="foo" ref="bar"/> style in Spring.

e.g. consider this example

<beans xmlns:p="http://xbean.apache.org/schemas/pizza">

  <bean id="topping" class="java.lang.String">
    <constructor-arg>
      <value>Salami</value>
    </constructor-arg>
  </bean>

  <p:pizza id="pizzaService" myTopping="#topping" cheese="##Edam" size="17"/>
  
</beans>

The topping bean is configured using the regular Spring way; the pizza bean is configured using XBean XML; however notice that the pizza bean is configured via the reference #topping. If you really do want to configure a property with a string which starts with # then escape it as ## as we are doing with the cheese property in this example. i.e. the cheese property will be set to the string "#Edam"

PropertyEditor Support

Sometimes you want to have property that takes a value that is more human friendly to set. For example, the ammount of beer remainaing in a keg. Folks tend to think in different units of measurment, but you POJO probably just want a an ammount in a specific unit. Since XBean 2.6, it supports a per property PropertyEditor. You can conifigure a PropertyEditor that should be used for a specific property when it is converting the user configured text property value to the actual value that will be set on the property. This gives you an oppertunity to let the user use values like "1000 ml" or "25 l" or "300 pints", and the PropertyEditor would take care of converting all those values into ml units.

Here's an example of what the user would configure:

<beans xmlns:x="http://xbean.apache.org/schemas/pizza">

  <x:keg id="ml1000" remaining="1000 ml"/>
  <x:keg id="pints5" remaining="5 pints"/>
  <x:keg id="liter20" remaining="20 liter"/>
  <x:keg id="empty" remaining="0"/>

</beans>

Here's how the bean developer would setup the PropertyEditor for the "remaining" property:

/**
 * @org.apache.xbean.XBean element="keg" 
 * 
 * Used to verify that property PropertyEditors work correctly.
 * 
 * @author chirino
 */
public class KegService {
	
    private long remaining;

	/**
	 * Gets the amount of beer remaining in the keg (in ml)
	 * 
	 * @param remaining
	 */
	public long getRemaining() {
		return remaining;
	}

	/**
	 * Sets the amount of beer remaining in the keg (in ml)
	 * 
     * @org.apache.xbean.Property propertyEditor="org.apache.xbean.spring.example.MilliLittersPropertyEditor"
	 * @param remaining
	 */
	public void setRemaining(long remaining) {
		this.remaining = remaining;
	}
	
	public long dispense( long amount ) {
		this.remaining -= amount;
		return this.remaining;
	}

}

And here is how the PropertyEditor was implemented:

/**
 * 
 * Used to verify that per property PropertyEditors work correctly.
 * 
 * @author chirino
 */
public class MilliLittersPropertyEditor extends PropertyEditorSupport {

	public void setAsText(String text) throws IllegalArgumentException {

		Pattern p = Pattern.compile("^(\\d+)\\s*(l(iter)?)?$", Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(text);
		if( m.matches() ) {
			setValue(new Long(Long.parseLong(m.group(1))*1000));
			return;
		}
		
		p = Pattern.compile("^(\\d+)\\s*(ml)?$", Pattern.CASE_INSENSITIVE);
		m = p.matcher(text);
		if( m.matches() ) {
			setValue(new Long(Long.parseLong(m.group(1))));
			return;
		}

		p = Pattern.compile("^(\\d+)\\s*pints?$", Pattern.CASE_INSENSITIVE);
	    m = p.matcher(text);
		if( m.matches() ) {
			long pints = Long.parseLong(m.group(1));
			setValue(new Long( (long)(pints * 1750) ));
			return;
		}
		
		throw new IllegalArgumentException("Could convert not to long (in ml) for "+ text);		
	}

	public String getAsText() {
		Long value = (Long) getValue();
		return (value != null ? value.toString() : "");
	}
}