Wednesday, November 18, 2009

Writing Custom Namespaces in Spring

1. Application context xmls looks as below

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:test="http://www.test.xyz/schema"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.test.xyz/schema http://www.test.xyz/schema-1.0.xsd">

<test:person name="suji"/>
</beans>

Now the xsd mentioned in the schema location should map to something.

2. You shoudl have a spring.schemas file in the META-INF directory

http\://www.test.xyz/schema-1.0.xsd=com/test/test-1.0.xsd

This maps the schema to teh lcoation of teh xsd

3. Xsd looks like

<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.test.xyz/schema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">

<xsd:element name="person">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Configures all required interactions with the named Control Bus configuration
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Identifies group-name of a Control Bus this configuration defines
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>

</xsd:schema>

We have a single element person with attribute as name which is a string.

4. Now each element in the xsd should map to a resolver.

This can be mentioned in spring.handlers file which is also in the META-INF directory

http\://www.test.xyz/schema=com.test.PersonNamespaceHandler


5. Implementaion of PersonNamespaceHandler

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class PersonNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("person", new PersonParser());
}

}


6. Parser implementation

public class PersonParser extends AbstractBeanDefinitionParser {
private String beanName;

/* This method gets the parameters mentioned in the custom namespace and helps building
custom logic based on it */


@Override
protected AbstractBeanDefinition parseInternal(Element element,
ParserContext parserContext) {
BeanDefinitionBuilder rootBuilder = BeanDefinitionBuilder
.rootBeanDefinition(Person.class.getName());
beanName = element.getAttribute("name");

//Ensuring name is a compulsary attribute

Assert.hasText(beanName, "'name' must be provided");
rootBuilder.addPropertyValue("name", beanName);
return rootBuilder.getBeanDefinition();
}

protected String resolveId(Element element,
AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
return beanName;
}

}


7. Custom classes for Person

public class Person {

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


Test case for trying out this

public class PersonParserTest {

public static void main(String[] arg){
ApplicationContext ac = new ClassPathXmlApplicationContext("config.xml", PersonParserTest.class);
Person person = (Person) ac.getBean("suji");
System.out.println("Person: " + person.getName());
}
}

 
Free Domain Names @ .co.nr!