| <?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <document xmlns="http://maven.apache.org/XDOC/2.0" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd"> |
| <properties> |
| <title>Download Commons Digester</title> |
| <author email="dev@commons.apache.org">Commons Documentation Team</author> |
| </properties> |
| <body> |
| <section name="Annotations"> |
| <p>The <code>annotations</code> package provides for Java5 Annotations |
| meta-data based definition of rules for <code>Digester</code>. |
| This improves maintainability of both Java code and XML documents, as |
| rules are now defined in POJOs and generating <code>Digester</code> |
| parsers at run-time, avoiding manual updates.</p> |
| |
| <subsection name="Introduction"> |
| <p>This is a brief overview of the digester-rules-in-Java5 Annotations |
| feature. Inspired by the basic idea behind the JPA, BeanValidation and |
| JAXB's specifications, this feature lets you define Digester rules |
| directly in target POJOs, instead of creating and initializing the Rules |
| objects programmatically, which can become tedious.</p> |
| </subsection> |
| |
| <subsection name="Annotation Rules"> |
| <p>A digester rule on a POJO is expressed through one or more annotations. |
| An annotation is considered a digester rule definition if its retention |
| policy contains RUNTIME and if the annotation itself is annotated with |
| <code>org.apache.commons.digester.annotations.DigesterRule</code>.</p> |
| |
| <p>The <code>DigesterRule</code> is defined by the combination of:</p> |
| <ul> |
| <li>the reflected <code>Class<? extends org.apache.commons.digester.Rule></code> |
| by the annotation;</li> |
| <li>the <code>org.apache.commons.digester.annotations.DigesterLoaderHandler</code> |
| class that has to be invoked during the target class traversal |
| (if not specifyied, the annotation processor will supply the |
| <code>org.apache.commons.digester.annotations.handlers.DefaultLoaderHandler</code>);</li> |
| <li>the <code>org.apache.commons.digester.annotations.AnnotationRuleProvider</code> |
| provider that produces the <code>pattern, rule</code> pair.</li> |
| </ul> |
| |
| <p>Digester annotations can target any of the following <code>ElementType</code>s:</p> |
| <ul> |
| <li><code>FIELD</code> for Digester rules concerning attributes;</li> |
| <li><code>METHOD</code> for Digester rules concerning methods calls;</li> |
| <li><code>PARAMETER</code> for Digester rules concerning methods parameters setting;</li> |
| <li><code>TYPE</code> for Digester rules concerning types creation.</li> |
| </ul> |
| <p>While other <code>ElementType</code>s are not forbidden, the Digester |
| annotations processor does not have to recognize and process annotation |
| rules placed on such types.</p> |
| |
| <p>Every Digester rule annotation <b>must</b> define a <i>pattern</i> |
| element of type <code>String</code> that represents the element matching |
| path pattern.</p> |
| |
| <source>@Documented |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target(ElementType.TYPE) |
| @CreationRule |
| @DigesterRule( |
| reflectsRule = ObjectCreateRule.class, |
| providedBy = ObjectCreateRuleProvider.class |
| ) |
| public @interface ObjectCreate { |
| |
| String pattern(); |
| |
| }</source> |
| </subsection> |
| |
| <subsection name="Applying multiple annotation rule of the same type"> |
| <p>It is often useful to declare the same annotation rule more than once |
| to the same target, with different properties. To support this requirement, |
| the Digester annotation processor treats annotations annotated by |
| <code>@org.apache.commons.digester.annotations.DigesterRuleList</code> |
| whose <code>value</code> element has a return type of an array of rule |
| annotations in a special way. Each element in the value array are processed |
| by the Digester annotation processor as regular annotation rule annotations. |
| This means that each Digester rule specified in the <code>value</code> |
| element is applied to the target. The annotation must have retention |
| <code>RUNTIME</code> and can be applied on a type, field, method or |
| method parameter. It is recommended to use the same set of targets as |
| the initial Digester annotation rule.</p> |
| |
| <p>Note to designers: each Digester annotation rule should be coupled |
| with its corresponding multi-valued annotation. |
| It is recommended, though not mandated, the definition of |
| an inner annotation named <code>List</code>.</p> |
| |
| <source>@Documented |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target(ElementType.TYPE) |
| @CreationRule |
| @DigesterRule( |
| reflectsRule = ObjectCreateRule.class, |
| providedBy = ObjectCreateRuleProvider.class |
| ) |
| public @interface ObjectCreate { |
| |
| String pattern(); |
| |
| @Documented |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target(ElementType.TYPE) |
| @DigesterRuleList |
| @interface List { |
| ObjectCreate[] value(); |
| } |
| |
| }</source> |
| </subsection> |
| |
| <subsection name="Rule provider implementation"> |
| <p>A Digester rule provider implementation performs the rule creation |
| of a given annotation for a given annotated element. The implementation |
| classes are specified by the <code>providedBy</code> element of the |
| <code>@DigesterRule</code> annotation that decorates the rule annotation |
| definition. The rule provider implementation implements the |
| <code>org.apache.commons.digester.annotations.AnnotationRuleProvider<A extends Annotation, E extends AnnotatedElement, R extends Rule></code> |
| interface.</p> |
| |
| <source>class ObjectCreateRuleProvider implements AnnotationRuleProvider<ObjectCreate, Class<?>, ObjectCreateRule> { |
| |
| private Class<?> clazz; |
| |
| public void init(ObjectCreate annotation, Class<?> element) { |
| this.clazz = element; |
| } |
| |
| public ObjectCreateRule get() { |
| return new ObjectCreateRule(this.clazz); |
| } |
| |
| }</source> |
| |
| <h5>Notes</h5> |
| <p>A new instance of the provider will be created each time the Digester |
| annotations processor will meet the relative rule that requests it.</p> |
| <p>To supply the missing <code>AnnotatedElement</code> for methods |
| <code>PARAMETER</code>s, the Digester annotation processor come with the |
| <code>org.apache.commons.digester.annotations.reflect.MethodArgument</code> |
| class.</p> |
| </subsection> |
| |
| <subsection name="Digester loader handler implementation"> |
| <p>The Digester loader handler is an <code>AnnotatedElement</code> |
| interceptor invoked when meeting a particular Digester rule annotation |
| while analyzing the target class.</p> |
| |
| <p>By default, the Digester annotations processor, when meeting a |
| Digester annotation rule, extracts the rule pattern and the relative |
| rule provider to store it in the |
| <code>org.apache.commons.digester.annotations.FromAnnotationsRuleSet</code>, |
| an <code>org.apache.commons.digester.RuleSet</code> implementation.</p> |
| |
| <p>If designers have the need of a more elaborate annottaion processing, |
| they can specify the <code>handledBy</code> element of the |
| <code>@DigesterRule</code> annotation that decorates the rule annotation |
| definition. The Digester loader handler implementation implements the |
| <code>DigesterLoaderHandler<A extends Annotation, E extends AnnotatedElement></code> |
| interface. Follows below an example:</p> |
| |
| <source>class SetPropertiesLoaderHandler implements DigesterLoaderHandler<SetProperty, Field> { |
| |
| public void handle(SetProperty annotation, Field element, FromAnnotationsRuleSet ruleSet) { |
| SetPropertiesRuleProvider ruleProvider = ruleSet.getProvider(annotation.pattern(), SetPropertiesRuleProvider.class); |
| |
| if (ruleProvider == null) { |
| ruleProvider = new SetPropertiesRuleProvider(); |
| ruleSet.addRuleProvider(annotation.pattern(), ruleProvider); |
| } |
| |
| ruleProvider.addAlias(annotation, element); |
| } |
| |
| }</source> |
| </subsection> |
| |
| <subsection name="Built-in Rules"> |
| <p>All built-in annotation rules are in the package |
| <code>org.apache.commons.digester.annotations.rules</code>. |
| Here is the list of annotations and their usage.</p> |
| |
| <h4><code>TYPE</code> annotations</h4> |
| <table> |
| <thead> |
| <tr><th>Annotation</th><th>Reflect rule</th></tr> |
| </thead> |
| <tbody> |
| <tr><td>@ObjectCreate</td><td>org.apache.commons.digester.ObjectCreateRule</td></tr> |
| <tr><td>@FactoryCreate</td><td>org.apache.commons.digester.FactoryCreateRule</td></tr> |
| </tbody> |
| </table> |
| |
| <h4><code>FIELD</code> annotations</h4> |
| <table> |
| <thead> |
| <tr><th>Annotation</th><th>Reflect rule</th></tr> |
| </thead> |
| <tbody> |
| <tr><td>@BeanPropertySetter</td><td>org.apache.commons.digester.BeanPropertySetterRule</td></tr> |
| <tr><td>@SetProperty</td><td>org.apache.commons.digester.SetPropertiesRule</td></tr> |
| </tbody> |
| </table> |
| |
| <h4><code>METHOD</code> annotations</h4> |
| <table> |
| <thead> |
| <tr><th>Annotation</th><th>Reflect rule</th></tr> |
| </thead> |
| <tbody> |
| <tr><td>@CallMethod</td><td>org.apache.commons.digester.CallMethodRule</td></tr> |
| <tr><td>@SetNext</td><td>org.apache.commons.digester.SetNextRule</td></tr> |
| <tr><td>@SetRoot</td><td>org.apache.commons.digester.SetRootRule</td></tr> |
| <tr><td>@SetTop</td><td>org.apache.commons.digester.SetTopRule</td></tr> |
| </tbody> |
| </table> |
| |
| <h4><code>PARAMETER</code> annotations</h4> |
| <table> |
| <thead> |
| <tr><th>Annotation</th><th>Reflect rule</th></tr> |
| </thead> |
| <tbody> |
| <tr><td>@AttributeCallParam</td><td>org.apache.commons.digester.Digester#addCallParam(String, int, String)</td></tr> |
| <tr><td>@CallParam</td><td>org.apache.commons.digester.Digester#addCallParam(String, int)</td></tr> |
| <tr><td>@PathCallParam</td><td>org.apache.commons.digester.Digester#addCallParamPath(String, int)</td></tr> |
| <tr><td>@StackCallParam</td><td>org.apache.commons.digester.Digester#addCallParam(String, int, int)</td></tr> |
| </tbody> |
| </table> |
| </subsection> |
| |
| <subsection name="Bootstrapping"> |
| <p>The core of Digester annotations rules processor is the |
| <code>org.apache.commons.digester.annotations.DigesterLoader</code> class.</p> |
| |
| <p>A <code>org.apache.commons.digester.annotations.DigesterLoader</code> |
| instance is able to analyze <code>Class<?></code> graphs and builds |
| the relative <code>org.apache.commons.digester.RuleSet</code> to create |
| <code>org.apache.commons.digester.Digester</code> instances.</p> |
| |
| <p>The bootstrap sequence has been designed to be as simple as possible, |
| all that's needed is creating a new |
| <code>org.apache.commons.digester.annotations.DigesterLoaderBuilder</code> |
| instance, plugging the desired |
| <code>org.apache.commons.digester.annotations.spi.AnnotationRuleProviderFactory</code> and |
| <code>org.apache.commons.digester.annotations.spi.DigesterLoaderHandlerFactory</code>. |
| using a chaining builders pattern.</p> |
| |
| <p>An <code>org.apache.commons.digester.annotations.spi.AnnotationRuleProviderFactory</code> |
| implementation performs the creation of |
| <code>org.apache.commons.digester.annotations.AnnotationRuleProvider<A extends Annotation, E extends AnnotatedElement, R extends Rule></code> |
| instances; the default implementation is limited to create the provider |
| by invoking the default empty constructor of the required class, but |
| users are free to give their implementation if they need a more complex |
| factory, i.e. providers requires components that could be injected from a |
| context, etc. etc.</p> |
| |
| <h5>Note</h5> |
| <p>It is strongly descouraged caching <code>AnnotationRuleProvider</code> |
| instances!!!</p> |
| |
| <p>Same thing for the <code>org.apache.commons.digester.annotations.spi.DigesterLoaderHandlerFactory</code>, |
| which implementation performs the creation of |
| <code>DigesterLoaderHandler<A extends Annotation, E extends AnnotatedElement></code> |
| instances; the default implementation is limited to create the handler |
| by invoking the default empty constructor of the required class, but |
| users are free to give their implementation if they need a more complex |
| factory, i.e. providers requires components that could be injected from a |
| context, etc. etc.</p> |
| |
| <p>Said that, to obtain a fresh new |
| <code>org.apache.commons.digester.annotations.DigesterLoader</code> instance |
| with default factories, it is enough invoking the default empty constructor:</p> |
| |
| <source>DigesterLoader digesterLoader = new DigesterLoaderBuilder() |
| .useDefaultAnnotationRuleProviderFactory() |
| .useDefaultDigesterLoaderHandlerFactory();</source> |
| |
| <p>Otherwise, if users need specify theyr custom factories:</p> |
| |
| <source>DigesterLoader digesterLoader = new DigesterLoaderBuilder() |
| .useAnnotationRuleProviderFactory(new MyAnnotationRuleProviderFactory()) |
| .useDigesterLoaderHandlerFactory(new MyDigesterLoaderHandlerFactory());</source> |
| </subsection> |
| |
| <subsection name="Example: a simple RSS parser"> |
| <p>Let's assume there is the need to parse the following (simplified) |
| XML/RSS feed:</p> |
| |
| <source><rss version="2.0"> |
| <channel> |
| |
| <title>Apache</title> |
| <link>http://www.apache.org</link> |
| <description>The Apache Software Foundation</description> |
| <language>en-US</language> |
| <rating>(PICS-1.1 "http://www.rsac.org/ratingsv01.html" |
| 2 gen true comment "RSACi North America Server" |
| for "http://www.rsac.org" on "1996.04.16T08:15-0500" |
| r (n 0 s 0 v 0 l 0))</rating> |
| |
| <image> |
| <title>Apache</title> |
| <url>http://jakarta.apache.org/images/jakarta-logo.gif</url> |
| <link>http://jakarta.apache.org</link> |
| <width>505</width> |
| <height>480</height> |
| <description>The Jakarta project. Open source, serverside java.</description> |
| </image> |
| |
| <item> |
| <title>Commons Attributes 2.1 Released</title> |
| <link>http://jakarta.apache.org/site/news/news-2004-2ndHalf.html#20040815.1</link> |
| <description>The Apache Commons team is happy to announce the release of Commons Attributes 2.1. |
| This is the first release of the new Commons-Attributes code.</description> |
| </item> |
| |
| <item> |
| <title>Cloudscape Becomes Apache Derby</title> |
| <link>http://jakarta.apache.org/site/news/elsewhere-2004-2ndHalf.html#20040803.1</link> |
| <description>IBM has submitted a proposal to the Apache DB project for a Java-based package to be called 'Derby'.</description> |
| </item> |
| |
| <item> |
| <title>Commons BeanUtils 1.7 Released</title> |
| <link>http://jakarta.apache.org/site/news/news-2004-2ndHalf.html#20040802.1</link> |
| <description/> |
| </item> |
| |
| <item> |
| <title>Commons JXPath 1.2 Released</title> |
| <link>http://jakarta.apache.org/site/news/news-2004-2ndHalf.html#20040801.2</link> |
| <description/> |
| </item> |
| </channel> |
| </rss></source> |
| |
| <p>So, let's define the Java entities and annotate them; first the <code>Channel</code> entity:</p> |
| |
| <source>@ObjectCreate(pattern = "rss/channel") |
| class Channel { |
| |
| private final List<Item> items = new ArrayList<Item>(); |
| |
| @BeanPropertySetter(pattern = "rss/channel/title") |
| private String title; |
| |
| @BeanPropertySetter(pattern = "rss/channel/link") |
| private String link; |
| |
| @BeanPropertySetter(pattern = "rss/channel/description") |
| private String description; |
| |
| @BeanPropertySetter(pattern = "rss/channel/language") |
| private String language; |
| |
| private Image image; |
| |
| // getters and setters |
| |
| @SetNext |
| public void setImage(Image image) { |
| this.image = image; |
| } |
| |
| @SetNext |
| public void addItem(Item item) { |
| this.items.add(item); |
| } |
| |
| }</source> |
| |
| <p>Then the <code>Image</code> entity:</p> |
| |
| <source>@ObjectCreate(pattern = "rss/channel/image") |
| class Image { |
| |
| @BeanPropertySetter(pattern = "rss/channel/image/description") |
| private String description; |
| |
| @BeanPropertySetter(pattern = "rss/channel/image/width") |
| private int width; |
| |
| @BeanPropertySetter(pattern = "rss/channel/image/height") |
| private int height; |
| |
| @BeanPropertySetter(pattern = "rss/channel/image/link") |
| private String link; |
| |
| @BeanPropertySetter(pattern = "rss/channel/image/title") |
| private String title; |
| |
| @BeanPropertySetter(pattern = "rss/channel/image/url") |
| private String url; |
| |
| // getters and setters |
| |
| }</source> |
| |
| <p>and finally the <code>Item</code> entity:</p> |
| |
| <source>@ObjectCreate(pattern = "rss/channel/item") |
| class Item { |
| |
| @BeanPropertySetter(pattern = "rss/channel/item/description") |
| private String description; |
| |
| @BeanPropertySetter(pattern = "rss/channel/item/link") |
| private String link; |
| |
| @BeanPropertySetter(pattern = "rss/channel/item/title") |
| private String title; |
| |
| // getters and setters |
| |
| }</source> |
| |
| <p>It is now possible to create the <code>Digester</code> instance and parse the XML:</p> |
| |
| <source>DigesterLoader digesterLoader = new DigesterLoaderBuilder() |
| .useDefaultAnnotationRuleProviderFactory() |
| .useDefaultDigesterLoaderHandlerFactory(); |
| ... |
| Digester digester = digesterLoader.createDigester(Channel.class); |
| try { |
| Channel channel = (Channel) digester.parse(new URL("http://www.myfeedprovider.com/rss.xml").openStream()); |
| } catch (Exception e) { |
| // do something |
| } |
| </source> |
| |
| <h5>Notes</h5> |
| <p>If asking to the <code>DigesterLoader</code> instance more then twice the |
| <code>Digester</code> for the same <code>Class<?></code>, the |
| <code>DigesterLoader</code> won't analize the target class for each request, |
| but rather will reuse cached results.</p> |
| |
| <p>The same <code>DigesterLoader</code> instance can be reused to create |
| other <code>Digester</code> instances.</p> |
| </subsection> |
| </section> |
| </body> |
| </document> |