http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/extensible-xml.html

레퍼런스를 보자. 초반에 먼저 개략적인 개발 단계가 나온다.

  1. 커스텀 엘리먼트를 기술할 XML 스키마 작성
  2. NamespaceHandler 구현체 코딩(매우 간단하고 쉬움)
  3. BeanDefinitionParser 구현체 코딩(실제 작업할 부분)
  4. 위에서 만든것들 스프링에 등록하기(매우 간단하고 쉬움)

근데.. 왠지 이거 순서가 잘못된것 같다. 아니.. 파서도 안만들었는데 뭘 등록하라고 NamespaceHandler를 구현하라는건지.. @_@;; 옛날에는 이런것도 스프링 이슈트래커에 올려주면 금방금방 피드백도 주고 잘 고쳐줬었는데.. 요즘은 어떨런지 모르겠다. 귀찮네;;

1 -> 3 -> 2-> 4 순서가 맞는것 같다.

1. XML 스키마 작성

[xml]
<myns:dateformat id="dateFormat"
pattern="yyyy-MM-dd HH:mm"
lenient="true"/>
[/xml]

이런 형태의 커스텀 엘리먼트를 제공할 계획이라면 다음과 같은 스키마를 작성해야 한다.

[xml]
<!-- myns.xsd (inside package org/springframework/samples/xml) -->

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.mycompany.com/schema/myns"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.mycompany.com/schema/myns"
elementFormDefault="qualified"
attributeFormDefault="unqualified">

<xsd:import namespace="http://www.springframework.org/schema/beans"/>

<xsd:element name="dateformat">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="lenient" type="xsd:boolean"/>
<xsd:attribute name="pattern" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>

</xsd:schema>
[/xml]

2. BeanDefinitionParser 구현

[java]
package org.springframework.samples.xml;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

import java.text.SimpleDateFormat;

public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

protected Class getBeanClass(Element element) {
return SimpleDateFormat.class;
}

protected void doParse(Element element, BeanDefinitionBuilder bean) {
// this will never be null since the schema explicitly requires that a value be supplied
String pattern = element.getAttribute("pattern");
bean.addConstructorArg(pattern);

// this however is an optional property
String lenient = element.getAttribute("lenient");
if (StringUtils.hasText(lenient)) {
bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
}
}
}
[/java]

구상한 XML에서 사용할 값을 읽어와서 bean에다 설정해준다.

3. NamespaceHandler 구현

[java]
package org.springframework.samples.xml;

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

public class MyNamespaceHandler extends NamespaceHandlerSupport {

public void init() {
registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
}
}
[/java]

커스텀 엘리먼트와 그것을 처리할 파서를 매핑해준다. 커스턴 엘리먼트는 1번 과정에서 스키마 만들면서 만든거나 다름없고 파서는 2번 과정에서 만들었으니 그것을 사용해서 등록하면 된다.

4. 등록하기

코딩은 끝났고 이제 META-INF 디렉토리에 프로퍼티 파일을 만들어서 핸들러와 스키마를 설정해줘야 한다. 이걸 JAR로 묶어서 클래스패스에 두면 스프링이 자동으로 읽어서 스프링 XML 설정 파일로 사용할 수 있게 해준다. (해봐야지.)

4-1. "META-INF/spring.handlers"

[xml]
http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler
[/xml]

이때 ":" 문자를 백슬러쉬로 이스케이프 시켜줘야 한다.

4-2. "META-INF/spring.schema"

[xml]
http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd
[/xml]

5. 커스텀 XML 설정 사용하기

[xml]
<?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:myns="http://www.mycompany.com/schema/myns"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">

<!-- as a top-level bean -->
<myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/>

<bean id="jobDetailTemplate" abstract="true">
<property name="dateFormat">
<!-- as an inner bean -->
<myns:dateformat pattern="HH:mm MM-dd-yyyy"/>
</property>
</bean>

</beans>
[/xml]

아직 레퍼런스를 다 보진 못했는데 일단은 대략 어떤식으로 만드는지 파악이 됐다. 중요한건 어제 토비님 글에서 본것처럼 만들려고 구상한 커스텀 설정에 따라 파서 구현 방법이 달라진다는 것이다. 아마 레퍼런스 남은 부분에선 그것을 설명하려는 것 같다. 요건 낼 아침에 일찍 인나면 봐야지..