Migrate reference guide to well-formed docbook XML
Convert all docbook XML files to well-formed docbook 5 syntax: - Include xsi:schemaLocation element for tools support - Convert all id elements to xml:id - Convert all ulink elements to link - Simplify <lineannotation> mark-up - Fix misplaced </section> tags - Fix <interface> tags to <interfacename> - Cleanup trailing whitespace and tabs Issue: SPR-10032
This commit is contained in:
@@ -1,24 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
<appendix xml:id="extensible-xml"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="extensible-xml">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Extensible XML authoring</title>
|
||||
<section id="extensible-xml-introduction">
|
||||
<section xml:id="extensible-xml-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>Since version 2.0, Spring has featured a mechanism for schema-based extensions
|
||||
to the basic Spring XML format for defining and configuring beans. This section is
|
||||
devoted to detailing how you would go about writing your own custom XML bean definition
|
||||
parsers and integrating such parsers into the Spring IoC container.</para>
|
||||
<para>To facilitate the authoring of configuration files using a schema-aware XML editor,
|
||||
Spring's extensible XML configuration mechanism is based on XML Schema. If you are
|
||||
not familiar with Spring's current XML configuration extensions that come with the
|
||||
standard Spring distribution, please first read the appendix entitled
|
||||
<xref linkend="xsd-config"/>.</para>
|
||||
<para>Creating new XML configuration extensions can be done by following these (relatively)
|
||||
simple steps:</para>
|
||||
<para>
|
||||
<orderedlist numeration="arabic">
|
||||
<para>To facilitate the authoring of configuration files using a schema-aware XML editor,
|
||||
Spring's extensible XML configuration mechanism is based on XML Schema. If you are
|
||||
not familiar with Spring's current XML configuration extensions that come with the
|
||||
standard Spring distribution, please first read the appendix entitled
|
||||
<xref linkend="xsd-config"/>.</para>
|
||||
<para>Creating new XML configuration extensions can be done by following these (relatively)
|
||||
simple steps:</para>
|
||||
<para>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-schema">Authoring</link> an XML schema to describe your custom element(s).</para>
|
||||
</listitem>
|
||||
@@ -33,14 +37,14 @@
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-registration">Registering</link> the above artifacts with Spring (this too is an easy step).</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>What follows is a description of each of these steps. For the example, we will create
|
||||
an XML extension (a custom XML element) that allows us to configure objects of the type
|
||||
<classname>SimpleDateFormat</classname> (from the <literal>java.text</literal> package)
|
||||
in an easy manner. When we are done, we will be able to define bean definitions of type
|
||||
<classname>SimpleDateFormat</classname> like this:</para>
|
||||
<programlisting language="xml"><![CDATA[<myns:dateformat id="dateFormat"
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>What follows is a description of each of these steps. For the example, we will create
|
||||
an XML extension (a custom XML element) that allows us to configure objects of the type
|
||||
<classname>SimpleDateFormat</classname> (from the <literal>java.text</literal> package)
|
||||
in an easy manner. When we are done, we will be able to define bean definitions of type
|
||||
<classname>SimpleDateFormat</classname> like this:</para>
|
||||
<programlisting language="xml"><![CDATA[<myns:dateformat id="dateFormat"
|
||||
pattern="yyyy-MM-dd HH:mm"
|
||||
lenient="true"/>
|
||||
]]></programlisting>
|
||||
@@ -48,13 +52,13 @@
|
||||
detailed examples follow afterwards. The intent in this first simple example is to walk
|
||||
you through the basic steps involved.)</emphasis></para>
|
||||
</section>
|
||||
<section id="extensible-xml-schema">
|
||||
<title>Authoring the schema</title>
|
||||
<para>Creating an XML configuration extension for use with Spring's IoC container
|
||||
starts with authoring an XML Schema to describe the extension. What follows
|
||||
is the schema we'll use to configure <classname>SimpleDateFormat</classname>
|
||||
objects.</para>
|
||||
<programlisting language="xml"><lineannotation><!-- myns.xsd (inside package org/springframework/samples/xml) --></lineannotation><![CDATA[
|
||||
<section xml:id="extensible-xml-schema">
|
||||
<title>Authoring the schema</title>
|
||||
<para>Creating an XML configuration extension for use with Spring's IoC container
|
||||
starts with authoring an XML Schema to describe the extension. What follows
|
||||
is the schema we'll use to configure <classname>SimpleDateFormat</classname>
|
||||
objects.</para>
|
||||
<programlisting language="xml"><lineannotation><!-- myns.xsd (inside package org/springframework/samples/xml) --></lineannotation><![CDATA[
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://www.mycompany.com/schema/myns"
|
||||
@@ -79,80 +83,80 @@
|
||||
|
||||
</xsd:schema>]]></programlisting>
|
||||
<para>(The emphasized line contains an extension base for all tags that
|
||||
will be identifiable (meaning they have an <literal>id</literal> attribute
|
||||
that will be used as the bean identifier in the container). We are able to use this
|
||||
attribute because we imported the Spring-provided <literal>'beans'</literal>
|
||||
namespace.)</para>
|
||||
<para>The above schema will be used to configure <classname>SimpleDateFormat</classname>
|
||||
objects, directly in an XML application context file using the
|
||||
<literal><myns:dateformat/></literal> element.</para>
|
||||
<programlisting language="xml"><![CDATA[<myns:dateformat id="dateFormat"
|
||||
will be identifiable (meaning they have an <literal>id</literal> attribute
|
||||
that will be used as the bean identifier in the container). We are able to use this
|
||||
attribute because we imported the Spring-provided <literal>'beans'</literal>
|
||||
namespace.)</para>
|
||||
<para>The above schema will be used to configure <classname>SimpleDateFormat</classname>
|
||||
objects, directly in an XML application context file using the
|
||||
<literal><myns:dateformat/></literal> element.</para>
|
||||
<programlisting language="xml"><![CDATA[<myns:dateformat id="dateFormat"
|
||||
pattern="yyyy-MM-dd HH:mm"
|
||||
lenient="true"/>
|
||||
]]></programlisting>
|
||||
<para>Note that after we've created the infrastructure classes, the above snippet of XML
|
||||
will essentially be exactly the same as the following XML snippet. In other words,
|
||||
we're just creating a bean in the container, identified by the name
|
||||
<literal>'dateFormat'</literal> of type <classname>SimpleDateFormat</classname>, with a
|
||||
couple of properties set.</para>
|
||||
<programlisting language="xml"><![CDATA[<bean id="dateFormat" class="java.text.SimpleDateFormat">
|
||||
<para>Note that after we've created the infrastructure classes, the above snippet of XML
|
||||
will essentially be exactly the same as the following XML snippet. In other words,
|
||||
we're just creating a bean in the container, identified by the name
|
||||
<literal>'dateFormat'</literal> of type <classname>SimpleDateFormat</classname>, with a
|
||||
couple of properties set.</para>
|
||||
<programlisting language="xml"><![CDATA[<bean id="dateFormat" class="java.text.SimpleDateFormat">
|
||||
<constructor-arg value="yyyy-HH-dd HH:mm"/>
|
||||
<property name="lenient" value="true"/>
|
||||
</bean>]]></programlisting>
|
||||
<note>
|
||||
<para>The schema-based approach to creating configuration format allows for
|
||||
tight integration with an IDE that has a schema-aware XML editor. Using a properly
|
||||
authored schema, you can use autocompletion to have a user choose between several
|
||||
configuration options defined in the enumeration.</para>
|
||||
</note>
|
||||
</section>
|
||||
<section id="extensible-xml-namespacehandler">
|
||||
<title>Coding a <interfacename>NamespaceHandler</interfacename></title>
|
||||
<para>In addition to the schema, we need a <interfacename>NamespaceHandler</interfacename>
|
||||
that will parse all elements of this specific namespace Spring encounters
|
||||
while parsing configuration files. The <interfacename>NamespaceHandler</interfacename>
|
||||
should in our case take care of the parsing of the <literal>myns:dateformat</literal>
|
||||
element.</para>
|
||||
<para>The <interfacename>NamespaceHandler</interfacename> interface is pretty simple in that
|
||||
it features just three methods:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><methodname>init()</methodname> - allows for initialization of
|
||||
the <interfacename>NamespaceHandler</interfacename> and will be called by Spring
|
||||
before the handler is used</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>BeanDefinition parse(Element, ParserContext)</methodname> -
|
||||
called when Spring encounters a top-level element (not nested inside a bean definition
|
||||
or a different namespace). This method can register bean definitions itself and/or
|
||||
return a bean definition.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)</methodname> -
|
||||
called when Spring encounters an attribute or nested element of a different namespace.
|
||||
The decoration of one or more bean definitions is used for example with the
|
||||
<link linkend="beans-factory-scopes">out-of-the-box scopes Spring 2.0 supports</link>.
|
||||
We'll start by highlighting a simple example, without using decoration, after which
|
||||
we will show decoration in a somewhat more advanced example.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>Although it is perfectly possible to code your own
|
||||
<interfacename>NamespaceHandler</interfacename> for the entire namespace
|
||||
(and hence provide code that parses each and every element in the namespace),
|
||||
it is often the case that each top-level XML element in a Spring XML
|
||||
configuration file results in a single bean definition (as in our
|
||||
case, where a single <literal><myns:dateformat/></literal> element
|
||||
results in a single <classname>SimpleDateFormat</classname> bean definition).
|
||||
Spring features a number of convenience classes that support this scenario.
|
||||
In this example, we'll make use the <classname>NamespaceHandlerSupport</classname> class:</para>
|
||||
<programlisting language="java"><![CDATA[package org.springframework.samples.xml;
|
||||
<note>
|
||||
<para>The schema-based approach to creating configuration format allows for
|
||||
tight integration with an IDE that has a schema-aware XML editor. Using a properly
|
||||
authored schema, you can use autocompletion to have a user choose between several
|
||||
configuration options defined in the enumeration.</para>
|
||||
</note>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-namespacehandler">
|
||||
<title>Coding a <interfacename>NamespaceHandler</interfacename></title>
|
||||
<para>In addition to the schema, we need a <interfacename>NamespaceHandler</interfacename>
|
||||
that will parse all elements of this specific namespace Spring encounters
|
||||
while parsing configuration files. The <interfacename>NamespaceHandler</interfacename>
|
||||
should in our case take care of the parsing of the <literal>myns:dateformat</literal>
|
||||
element.</para>
|
||||
<para>The <interfacename>NamespaceHandler</interfacename> interface is pretty simple in that
|
||||
it features just three methods:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><methodname>init()</methodname> - allows for initialization of
|
||||
the <interfacename>NamespaceHandler</interfacename> and will be called by Spring
|
||||
before the handler is used</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>BeanDefinition parse(Element, ParserContext)</methodname> -
|
||||
called when Spring encounters a top-level element (not nested inside a bean definition
|
||||
or a different namespace). This method can register bean definitions itself and/or
|
||||
return a bean definition.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)</methodname> -
|
||||
called when Spring encounters an attribute or nested element of a different namespace.
|
||||
The decoration of one or more bean definitions is used for example with the
|
||||
<link linkend="beans-factory-scopes">out-of-the-box scopes Spring 2.0 supports</link>.
|
||||
We'll start by highlighting a simple example, without using decoration, after which
|
||||
we will show decoration in a somewhat more advanced example.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>Although it is perfectly possible to code your own
|
||||
<interfacename>NamespaceHandler</interfacename> for the entire namespace
|
||||
(and hence provide code that parses each and every element in the namespace),
|
||||
it is often the case that each top-level XML element in a Spring XML
|
||||
configuration file results in a single bean definition (as in our
|
||||
case, where a single <literal><myns:dateformat/></literal> element
|
||||
results in a single <classname>SimpleDateFormat</classname> bean definition).
|
||||
Spring features a number of convenience classes that support this scenario.
|
||||
In this example, we'll make use the <classname>NamespaceHandlerSupport</classname> class:</para>
|
||||
<programlisting language="java"><![CDATA[package org.springframework.samples.xml;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
public class MyNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
|
||||
public void init() {]]><emphasis role="bold"><![CDATA[
|
||||
registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
|
||||
]]></emphasis>}
|
||||
}</programlisting>
|
||||
<para>The observant reader will notice that there isn't actually a whole lot of
|
||||
@@ -165,17 +169,17 @@ public class MyNamespaceHandler extends NamespaceHandlerSupport {
|
||||
while delegating to <literal>BeanDefinitionParsers</literal> to do the grunt work of the
|
||||
XML parsing; this means that each <interfacename>BeanDefinitionParser</interfacename> will
|
||||
contain just the logic for parsing a single custom element, as we can see in the next step</para>
|
||||
</section>
|
||||
<section id="extensible-xml-parser">
|
||||
<title>Coding a <interfacename>BeanDefinitionParser</interfacename></title>
|
||||
<para>A <interfacename>BeanDefinitionParser</interfacename> will be used if the
|
||||
<interfacename>NamespaceHandler</interfacename> encounters an XML element of the type
|
||||
that has been mapped to the specific bean definition parser (which is <literal>'dateformat'</literal>
|
||||
in this case). In other words, the <interfacename>BeanDefinitionParser</interfacename> is
|
||||
responsible for parsing <emphasis>one</emphasis> distinct top-level XML element defined in the
|
||||
schema. In the parser, we'll have access to the XML element (and thus its subelements too)
|
||||
so that we can parse our custom XML content, as can be seen in the following example:</para>
|
||||
<programlisting language="java"><![CDATA[package org.springframework.samples.xml;
|
||||
</section>
|
||||
<section xml:id="extensible-xml-parser">
|
||||
<title>Coding a <interfacename>BeanDefinitionParser</interfacename></title>
|
||||
<para>A <interfacename>BeanDefinitionParser</interfacename> will be used if the
|
||||
<interfacename>NamespaceHandler</interfacename> encounters an XML element of the type
|
||||
that has been mapped to the specific bean definition parser (which is <literal>'dateformat'</literal>
|
||||
in this case). In other words, the <interfacename>BeanDefinitionParser</interfacename> is
|
||||
responsible for parsing <emphasis>one</emphasis> distinct top-level XML element defined in the
|
||||
schema. In the parser, we'll have access to the XML element (and thus its subelements too)
|
||||
so that we can parse our custom XML content, as can be seen in the following example:</para>
|
||||
<programlisting language="java"><![CDATA[package org.springframework.samples.xml;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
@@ -184,10 +188,10 @@ import org.w3c.dom.Element;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { ]]><co id="extensible-xml-parser-simpledateformat-co-1"/><![CDATA[
|
||||
public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { ]]><co xml:id="extensible-xml-parser-simpledateformat-co-1"/><![CDATA[
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return SimpleDateFormat.class; ]]><co id="extensible-xml-parser-simpledateformat-co-2"/><![CDATA[
|
||||
return SimpleDateFormat.class; ]]><co xml:id="extensible-xml-parser-simpledateformat-co-2"/><![CDATA[
|
||||
}
|
||||
|
||||
protected void doParse(Element element, BeanDefinitionBuilder bean) {
|
||||
@@ -202,66 +206,66 @@ public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefi
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
<calloutlist>
|
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-1">
|
||||
<para>We use the Spring-provided <classname>AbstractSingleBeanDefinitionParser</classname>
|
||||
to handle a lot of the basic grunt work of creating a <emphasis>single</emphasis>
|
||||
<interfacename>BeanDefinition</interfacename>.</para>
|
||||
</callout>
|
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-2">
|
||||
<para>We supply the <classname>AbstractSingleBeanDefinitionParser</classname> superclass
|
||||
with the type that our single <interfacename>BeanDefinition</interfacename> will represent.</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
<para>In this simple case, this is all that we need to do. The creation of our single
|
||||
<interfacename>BeanDefinition</interfacename> is handled by the <classname>AbstractSingleBeanDefinitionParser</classname>
|
||||
superclass, as is the extraction and setting of the bean definition's unique identifier.</para>
|
||||
</section>
|
||||
<section id="extensible-xml-registration">
|
||||
<title>Registering the handler and the schema</title>
|
||||
<para>The coding is finished! All that remains to be done is to somehow make the Spring XML
|
||||
parsing infrastructure aware of our custom element; we do this by registering our custom
|
||||
<interfacename>namespaceHandler</interfacename> and custom XSD file in two special purpose
|
||||
properties files. These properties files are both placed in a
|
||||
<filename class="directory">'META-INF'</filename> directory in your application, and can, for
|
||||
example, be distributed alongside your binary classes in a JAR file. The Spring XML parsing
|
||||
infrastructure will automatically pick up your new extension by consuming these special
|
||||
properties files, the formats of which are detailed below.</para>
|
||||
<section id="extensible-xml-registration-spring-handlers">
|
||||
<title><filename>'META-INF/spring.handlers'</filename></title>
|
||||
<para>The properties file called <filename>'spring.handlers'</filename> contains a mapping
|
||||
of XML Schema URIs to namespace handler classes. So for our example, we need to write the
|
||||
following:</para>
|
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler]]></programlisting>
|
||||
<para><emphasis>(The <literal>':'</literal> character is a valid delimiter in the Java properties format,
|
||||
and so the <literal>':'</literal> character in the URI needs to be escaped with a backslash.)</emphasis></para>
|
||||
<para>The first part (the key) of the key-value pair is the URI associated with your custom namespace
|
||||
extension, and needs to <emphasis>match exactly</emphasis> the value of the
|
||||
<literal>'targetNamespace'</literal> attribute as specified in your custom XSD schema.</para>
|
||||
</section>
|
||||
<section id="extensible-xml-registration-spring-schemas">
|
||||
<title><filename>'META-INF/spring.schemas'</filename></title>
|
||||
<para>The properties file called <filename>'spring.schemas'</filename> contains a mapping
|
||||
of XML Schema locations (referred to along with the schema declaration in XML files
|
||||
that use the schema as part of the <literal>'xsi:schemaLocation'</literal> attribute)
|
||||
to <emphasis>classpath</emphasis> resources. This file is needed to prevent Spring from
|
||||
absolutely having to use a default <interfacename>EntityResolver</interfacename> that requires
|
||||
Internet access to retrieve the schema file. If you specify the mapping in this properties file,
|
||||
Spring will search for the schema on the classpath (in this case <literal>'myns.xsd'</literal>
|
||||
in the <literal>'org.springframework.samples.xml'</literal> package):</para>
|
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd]]></programlisting>
|
||||
<para>The upshot of this is that you are encouraged to deploy your XSD file(s) right alongside
|
||||
the <interfacename>NamespaceHandler</interfacename> and <interfacename>BeanDefinitionParser</interfacename>
|
||||
classes on the classpath.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="extensible-xml-using">
|
||||
<title>Using a custom extension in your Spring XML configuration</title>
|
||||
<para>Using a custom extension that you yourself have implemented is no different from
|
||||
using one of the 'custom' extensions that Spring provides straight out of the box. Find below
|
||||
an example of using the custom <literal><dateformat/></literal> element developed in the
|
||||
previous steps in a Spring XML configuration file.</para>
|
||||
<programlisting language="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
<calloutlist>
|
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-1">
|
||||
<para>We use the Spring-provided <classname>AbstractSingleBeanDefinitionParser</classname>
|
||||
to handle a lot of the basic grunt work of creating a <emphasis>single</emphasis>
|
||||
<interfacename>BeanDefinition</interfacename>.</para>
|
||||
</callout>
|
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-2">
|
||||
<para>We supply the <classname>AbstractSingleBeanDefinitionParser</classname> superclass
|
||||
with the type that our single <interfacename>BeanDefinition</interfacename> will represent.</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
<para>In this simple case, this is all that we need to do. The creation of our single
|
||||
<interfacename>BeanDefinition</interfacename> is handled by the <classname>AbstractSingleBeanDefinitionParser</classname>
|
||||
superclass, as is the extraction and setting of the bean definition's unique identifier.</para>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-registration">
|
||||
<title>Registering the handler and the schema</title>
|
||||
<para>The coding is finished! All that remains to be done is to somehow make the Spring XML
|
||||
parsing infrastructure aware of our custom element; we do this by registering our custom
|
||||
<interfacename>namespaceHandler</interfacename> and custom XSD file in two special purpose
|
||||
properties files. These properties files are both placed in a
|
||||
<filename class="directory">'META-INF'</filename> directory in your application, and can, for
|
||||
example, be distributed alongside your binary classes in a JAR file. The Spring XML parsing
|
||||
infrastructure will automatically pick up your new extension by consuming these special
|
||||
properties files, the formats of which are detailed below.</para>
|
||||
<section xml:id="extensible-xml-registration-spring-handlers">
|
||||
<title><filename>'META-INF/spring.handlers'</filename></title>
|
||||
<para>The properties file called <filename>'spring.handlers'</filename> contains a mapping
|
||||
of XML Schema URIs to namespace handler classes. So for our example, we need to write the
|
||||
following:</para>
|
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler]]></programlisting>
|
||||
<para><emphasis>(The <literal>':'</literal> character is a valid delimiter in the Java properties format,
|
||||
and so the <literal>':'</literal> character in the URI needs to be escaped with a backslash.)</emphasis></para>
|
||||
<para>The first part (the key) of the key-value pair is the URI associated with your custom namespace
|
||||
extension, and needs to <emphasis>match exactly</emphasis> the value of the
|
||||
<literal>'targetNamespace'</literal> attribute as specified in your custom XSD schema.</para>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-registration-spring-schemas">
|
||||
<title><filename>'META-INF/spring.schemas'</filename></title>
|
||||
<para>The properties file called <filename>'spring.schemas'</filename> contains a mapping
|
||||
of XML Schema locations (referred to along with the schema declaration in XML files
|
||||
that use the schema as part of the <literal>'xsi:schemaLocation'</literal> attribute)
|
||||
to <emphasis>classpath</emphasis> resources. This file is needed to prevent Spring from
|
||||
absolutely having to use a default <interfacename>EntityResolver</interfacename> that requires
|
||||
Internet access to retrieve the schema file. If you specify the mapping in this properties file,
|
||||
Spring will search for the schema on the classpath (in this case <literal>'myns.xsd'</literal>
|
||||
in the <literal>'org.springframework.samples.xml'</literal> package):</para>
|
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd]]></programlisting>
|
||||
<para>The upshot of this is that you are encouraged to deploy your XSD file(s) right alongside
|
||||
the <interfacename>NamespaceHandler</interfacename> and <interfacename>BeanDefinitionParser</interfacename>
|
||||
classes on the classpath.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-using">
|
||||
<title>Using a custom extension in your Spring XML configuration</title>
|
||||
<para>Using a custom extension that you yourself have implemented is no different from
|
||||
using one of the 'custom' extensions that Spring provides straight out of the box. Find below
|
||||
an example of using the custom <literal><dateformat/></literal> element developed in the
|
||||
previous steps in a Spring XML configuration file.</para>
|
||||
<programlisting language="xml"><![CDATA[<?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"
|
||||
@@ -280,15 +284,15 @@ http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.x
|
||||
</bean>
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
<section id="extensible-xml-meat">
|
||||
<title>Meatier examples</title>
|
||||
<para>Find below some much meatier examples of custom XML extensions.</para>
|
||||
<section id="extensible-xml-custom-nested">
|
||||
<title>Nesting custom tags within custom tags</title>
|
||||
<para>This example illustrates how you might go about writing the various artifacts
|
||||
required to satisfy a target of the following configuration:</para>
|
||||
<programlisting language="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-meat">
|
||||
<title>Meatier examples</title>
|
||||
<para>Find below some much meatier examples of custom XML extensions.</para>
|
||||
<section xml:id="extensible-xml-custom-nested">
|
||||
<title>Nesting custom tags within custom tags</title>
|
||||
<para>This example illustrates how you might go about writing the various artifacts
|
||||
required to satisfy a target of the following configuration:</para>
|
||||
<programlisting language="xml"><![CDATA[<?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:foo="http://www.foo.com/schema/component"
|
||||
@@ -322,7 +326,7 @@ public class Component {
|
||||
private String name;
|
||||
private List<Component> components = new ArrayList<Component> ();
|
||||
|
||||
]]><lineannotation>// mmm, there is no setter method for the <literal>'components'</literal></lineannotation><![CDATA[
|
||||
]]><lineannotation>// mmm, there is no setter method for the 'components'</lineannotation><![CDATA[
|
||||
public void addComponent(Component component) {
|
||||
this.components.add(component);
|
||||
}
|
||||
@@ -434,11 +438,11 @@ public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
return parseComponentElement(element);
|
||||
}
|
||||
|
||||
|
||||
private static AbstractBeanDefinition parseComponentElement(Element element) {
|
||||
BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ComponentFactoryBean.class);
|
||||
factory.addPropertyValue("parent", parseComponent(element));
|
||||
|
||||
|
||||
List<Element> childElements = DomUtils.getChildElementsByTagName(element, "component");
|
||||
if (childElements != null && childElements.size() > 0) {
|
||||
parseChildComponents(childElements, factory);
|
||||
@@ -452,36 +456,36 @@ public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser
|
||||
component.addPropertyValue("name", element.getAttribute("name"));
|
||||
return component.getBeanDefinition();
|
||||
}
|
||||
|
||||
|
||||
private static void parseChildComponents(List<Element> childElements, BeanDefinitionBuilder factory) {
|
||||
ManagedList<BeanDefinition> children = new ManagedList<BeanDefinition>(childElements.size());
|
||||
|
||||
|
||||
for (Element element : childElements) {
|
||||
children.add(parseComponentElement(element));
|
||||
}
|
||||
|
||||
|
||||
factory.addPropertyValue("children", children);
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Lastly, the various artifacts need to be registered with the Spring XML infrastructure.</para>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.handlers'</filename></lineannotation><![CDATA[
|
||||
<programlisting><lineannotation># in 'META-INF/spring.handlers'</lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler]]></programlisting>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.schemas'</filename></lineannotation><![CDATA[
|
||||
<programlisting><lineannotation># in 'META-INF/spring.schemas'</lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd]]></programlisting>
|
||||
</section>
|
||||
<section id="extensible-xml-custom-just-attributes">
|
||||
<title>Custom attributes on 'normal' elements</title>
|
||||
<para>Writing your own custom parser and the associated artifacts isn't hard, but sometimes it
|
||||
is not the right thing to do. Consider the scenario where you need to add metadata to already
|
||||
existing bean definitions. In this case you certainly don't want to have to go off and write
|
||||
your own entire custom extension; rather you just want to add an additional attribute
|
||||
to the existing bean definition element.</para>
|
||||
<para>By way of another example, let's say that the service class that you are defining a bean
|
||||
definition for a service object that will (unknown to it) be accessing a clustered
|
||||
<ulink url="http://jcp.org/en/jsr/detail?id=107">JCache</ulink>, and you want to ensure that
|
||||
the named JCache instance is eagerly started within the surrounding cluster:</para>
|
||||
<programlisting language="xml"><![CDATA[<bean id="checkingAccountService" class="com.foo.DefaultCheckingAccountService"
|
||||
]]><lineannotation><emphasis role="bold">jcache:cache-name="checking.account"></emphasis></lineannotation><![CDATA[
|
||||
</section>
|
||||
<section xml:id="extensible-xml-custom-just-attributes">
|
||||
<title>Custom attributes on 'normal' elements</title>
|
||||
<para>Writing your own custom parser and the associated artifacts isn't hard, but sometimes it
|
||||
is not the right thing to do. Consider the scenario where you need to add metadata to already
|
||||
existing bean definitions. In this case you certainly don't want to have to go off and write
|
||||
your own entire custom extension; rather you just want to add an additional attribute
|
||||
to the existing bean definition element.</para>
|
||||
<para>By way of another example, let's say that the service class that you are defining a bean
|
||||
definition for a service object that will (unknown to it) be accessing a clustered
|
||||
<link xl:href="http://jcp.org/en/jsr/detail?id=107">JCache</link>, and you want to ensure that
|
||||
the named JCache instance is eagerly started within the surrounding cluster:</para>
|
||||
<programlisting language="xml"><![CDATA[<bean id="checkingAccountService" class="com.foo.DefaultCheckingAccountService"
|
||||
]]><lineannotation>jcache:cache-name="checking.account"></lineannotation><![CDATA[
|
||||
]]><lineannotation><!-- other dependencies here... --></lineannotation><![CDATA[
|
||||
</bean>]]></programlisting>
|
||||
<para>What we are going to do here is create another <interfacename>BeanDefinition</interfacename>
|
||||
@@ -548,7 +552,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class JCacheInitializingBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
|
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
|
||||
public BeanDefinitionHolder decorate(
|
||||
@@ -584,23 +588,23 @@ public class JCacheInitializingBeanDefinitionDecorator implements BeanDefinition
|
||||
}
|
||||
]]></programlisting>
|
||||
<para>Lastly, the various artifacts need to be registered with the Spring XML infrastructure.</para>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.handlers'</filename></lineannotation><![CDATA[
|
||||
<programlisting><lineannotation># in 'META-INF/spring.handlers'</lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler]]></programlisting>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.schemas'</filename></lineannotation><![CDATA[
|
||||
<programlisting><lineannotation># in 'META-INF/spring.schemas'</lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
<section id="extensible-xml-resources">
|
||||
<title>Further Resources</title>
|
||||
<para>Find below links to further resources concerning XML Schema and the extensible XML support
|
||||
described in this chapter.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/">XML Schema Part 1: Structures Second Edition</ulink></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/">XML Schema Part 2: Datatypes Second Edition</ulink></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-resources">
|
||||
<title>Further Resources</title>
|
||||
<para>Find below links to further resources concerning XML Schema and the extensible XML support
|
||||
described in this chapter.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>The <link xl:href="http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/">XML Schema Part 1: Structures Second Edition</link></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <link xl:href="http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/">XML Schema Part 2: Datatypes Second Edition</link></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</appendix>
|
||||
|
||||
Reference in New Issue
Block a user