Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
EclipseLink/Development/2.1/AnnoxSupportForJAXB/311570
Overview
JAXB makes use of Annotations on Java Classes to customize it's mapping of those classes to XML. However in some cases, when dealing with existing Java classes, it's preferable to be able to specify that annotation data externally. EclipseLink already supports this through it's externalized meta-data: http://wiki.eclipse.org/EclipseLink/DesignDocs/293925/MOXyExtensions
Annox (http://confluence.highsource.org/display/ANX/Home) is an open source project that allows a user to specify java annotation meta-data in an external document. In the case that a user wanted to be able to make use of Annox to specify their Annotations, EclipseLink's JAXB can be quickly extended to support this.
Annox makes use of one .xml file/class to specify the annotation data. The file needs to be in the same package as the class and uses the .ann.xml extension. For example, to add annotations to an Employee class, a file called Employee.ann.xml would be created and added into Employees package.
Sample Employee.ann.xml:
<class xmlns="http://annox.dev.java.net" xmlns:g="http://annox.dev.java.net/javax.xml.bind.annotation"> <g:XmlRootElement name="employee-root" namespace="myns"/> <field name="id"> <g:XmlAttribute/> </field> <field name="name"> <g:XmlElement name="employee-name"/> </field> <field name="transientThing"> <g:XmlTransient/> </field> </class>
AnnotationHelper
By introducing the AnnotationHelper, EclipseLink can make an easy extension point available that would allow for a user to get their annotation data in any arbitrary way, including Annox, at runtime. AnnotationHelper is a class in the org.eclipse.persistence.javamodel.reflection package.
package org.eclipse.persistence.jaxb.javamodel.reflection; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; /** * <p><b>Purpose:</b>Provide a class which is responsible for returning Annotations * from AnnotatedElements. This class can be extended in the case that the annotation * data is being provided from an external source. * * @author mmacivor * */ public class AnnotationHelper { /** * Get an annotation of type annotationClass if it's present on the AnnotatedElement * elem. */ public Annotation getAnnotation(AnnotatedElement elem, Class annotationClass) { return elem.getAnnotation(annotationClass); } /** * Get all annotations that exist on the AnnotatedElement elem */ public Annotation[] getAnnotations(AnnotatedElement elem) { return elem.getAnnotations(); } /** * Return true if the annotation annotationClass exists on the annotatedElement elem. */ public boolean isAnnotationPresent(AnnotatedElement elem, Class annotationClass) { return elem.isAnnotationPresent(annotationClass); } }
All calls to obtain Annotations by EclipseLink during JAXBContext creation will go through the AnnotationHelper. A user can specify that they want to use a custom AnnotationHelper by setting an instance of AnnotationHelper as a property passed into the JAXBContext creation method:
MyAnnotationHelper helper = new MyAnnotationHelper(); Map<String, Object> properties = new HashMap<String, Object>(); properties.put(JAXBContextFactory.ANNOTATION_HELPER_KEY, helper); JAXBContext ctx = JAXBContextFactory.createContext(new Class[] {Employee.class}, properties, Thread.currentThread().getContextClassLoader());
Using Annox
If a user wanted to make use of Annox to obtain their annotation data, they could create a custom AnnotationHelper that makes use of the Annox APIs.
import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import org.eclipse.persistence.jaxb.javamodel.reflection.AnnotationHelper; import org.jvnet.annox.reflect.AnnotatedElementFactory; public class AnnoxAnnotationHelper extends AnnotationHelper { AnnotatedElementFactory factory; public AnnoxAnnotationHelper(AnnotatedElementFactory factory) { this.factory = factory; } @Override public boolean isAnnotationPresent(AnnotatedElement elem, Class annotationClass) { try { return factory.getAnnotatedElement(elem).isAnnotationPresent(annotationClass); } catch(Exception ex) { throw new RuntimeException(ex); } } @Override public Annotation getAnnotation(AnnotatedElement elem, Class annotationClass) { try { return factory.getAnnotatedElement(elem).getAnnotation(annotationClass); } catch(Exception ex) { throw new RuntimeException(ex); } } @Override public Annotation[] getAnnotations(AnnotatedElement elem) { try { return factory.getAnnotatedElement(elem).getAnnotations(); } catch(Exception ex) { throw new RuntimeException(ex); } } }