< foo:mycustomfooelement text="test" abstract="true">
< property name="property" value="value">
< /foo:myCustomFooElement>
This is because the property element and abstract attribute are not defined in your xsd which describes your custom element. Following is the source of a sample application I wrote to demonstrate the use of Spring properties and attributes on custom elements. The reason I do not promote this, is because you will loose the encapsulation of implementation details which your custom element hides. So use it with care.
public class Foo {
// This property gets injected by our custom FooParser
private String text;
// This property gets set by using Spring's < property> element
private Bar bar;
// getters and setters omitted
}
We will write a custom element for the Foo class.
public class Bar {
private int count;
// getter and setters omitted
}
Bar is just a regular class that gets injected in Foo. Below is the xsd I wrote to define myCustomFooElement:
< ?xml version="1.0" encoding="UTF-8"?>
< xsd:schema xmlns="http://www.mynamespace.com/foo"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.mynamespace.com/foo"
elementFormDefault="qualified" attributeFormDefault="unqualified">
< xsd:import
schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
namespace="http://www.springframework.org/schema/beans" />
< xsd:element name="myCustomFooElement">
< xsd:complextype>
< xsd:complexcontent>
< xsd:extension base="beans:identifiedType">
<!-- Here we re-use Spring elements and attributes -->
< xsd:group ref="beans:beanElements">
< xsd:attributegroup ref="beans:beanAttributes">
< xsd:attribute name="text" type="xsd:string"
use="required" />
< /xsd:extension>
< /xsd:complexContent>
< /xsd:complexType>
< /xsd:element>
< /xsd:schema>
The XML file containing the bean definitions looks like this:
< beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:foo="http://www.mynamespace.com/foo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.mynamespace.com/foo http://www.mynamespace.com/foo/foo.xsd">
< foo:mycustomfooelement id="foo" text="test" init="true">
<!-- Here we use a Spring property element inside our custom element -->
< property name="bar">
< bean class="nl.sample.customnamespace.Bar">
< property name="count" value="100">
< /bean>
< /property>
< /foo:myCustomFooElement>
< /beans>
To parse the myCustomFooElement we must create a namespacehandler and register a beandefinition parser like this:
public class FooNameSpaceHandler extends NamespaceHandlerSupport {
private static final String NAME_CUSTOM_FOO_ELEMENT = "myCustomFooElement";
public void init() {
registerBeanDefinitionParser(NAME_CUSTOM_FOO_ELEMENT, new FooParser());
}
class FooParser extends AbstractBeanDefinitionParser {
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
// Here we parse the Spring elements such as < property>
BeanDefinitionHolder holder = parserContext.getDelegate().parseBeanDefinitionElement(element);
BeanDefinition bd = holder.getBeanDefinition();
bd.setBeanClassName(Foo.class.getName());
// Here we parse our custom attributes
String text = element.getAttribute("text");
bd.getPropertyValues().addPropertyValue("text", text);
parserContext.getRegistry().registerBeanDefinition(NAME_CUSTOM_FOO_ELEMENT, bd);
return (AbstractBeanDefinition) bd;
}
}
}
Don't forget to register the namespacehandler in a file called spring.handlers in the META-INF directory. The contents of de spring.handlers file looks like this:
http\://www.mynamespace.com/foo=nl.sample.customnamespace.FooNameSpaceHandler
Also, specify in the META-INF/spring.schemas file where Spring can find the foo.xsd:
http\://www.mynamespace.com/foo/foo.xsd=nl/sample/customnamespace/foo.xsd
Write a class to verify everything works:
public class Driver {
public static void main(String[] args) {
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("classpath:nl/sample/customnamespace/customelements.xml");
Foo foo = (Foo) appContext.getBean("foo");
System.out.println("foo.text = " + foo.getText());
System.out.println("foo.bar.count = " + foo.getBar().getCount());
}
}
Extensive documentation about extensible XML authoring can be found in the reference manual. Eriks Wiersma has also written an excellent piece on his [URL="http://erik.jteam.nl/?p=23"]blog[/URL] about implementing custom namespaces.
1 comment:
Save me a couple of days. Thanks a lot for sharing this.
Post a Comment