Jump to: navigation, search

Difference between revisions of "EclipseLink/UserGuide/MOXy/Mapping the Unmappable/XML Transformations"

(Replacing page with 'See http://www.eclipse.org/eclipselink/documentation/2.4/moxy/advanced_concepts007.htm')
 
Line 1: Line 1:
{{EclipseLink_UserGuide
+
See http://www.eclipse.org/eclipselink/documentation/2.4/moxy/advanced_concepts007.htm
|info=y
+
|toc=y
+
|eclipselink=y
+
|eclipselinktype=MOXy
+
|api=y
+
|apis= * [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/oxm/annotations/XmlTransformation.html XmlTransformation]
+
* [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/oxm/annotations/XmlReadTransformer.html XmlReadTransformer]
+
* [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/oxm/annotations/XmlWriteTransformer.html XmlWriteTransformer]
+
* [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/mappings/transformers/AttributeTransformer.html AttributeTransformer]
+
* [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/mappings/transformers/FieldTransformer.html FieldTransformer]
+
}}
+
=XML Transformations=
+
 
+
In many cases, you can use MOXy's '''@XmlTransformation''' annotation to give you considerably more control over the marshalling and unmarshalling of your objects.  '''@XmlTransformation''' can be used to create a custom mapping where one or more XML nodes can be used to create the value for the Java attribute. 
+
 
+
To handle the custom requirements at marshal (write) and unmarshall (read) time, '''@XmlTransformation''' uses instances of '''org.eclipse.persistence.mappings.transformers''' (such as '''AttributeTransformer''' and '''FieldTransformer'''), providing a non-intrusive solution that avoids the need for domain objects to implement any 'special' interfaces.
+
 
+
For example, if you wanted to map the following XML to objects and combine the values of '''DATE''' and '''TIME''' into a single '''java.util.Date''' object, you can use an '''@XmlTransformation''':
+
 
+
<source lang="xml">
+
<ELEM_B>
+
  <B_DATE>20100825</B_DATE>
+
  <B_TIME>153000</B_TIME>
+
  <NUM>123</NUM>
+
  <C_DATE>20100825</C_DATE>
+
  <C_TIME>154500</C_TIME>
+
</ELEM_B>
+
</source>
+
 
+
'''Note:''' Ordinarily, you would use '''@XmlAdapter'''. However:
+
* Although the '''DATE/TIME''' pairings are repeated throughout the document, the element name changes ''each time'' (such as '''B_DATE/B_TIME''', '''C_DATE/C_TIME''', and so on).
+
* Because each pairing is missing a grouping element, you would need to adapt ''the entire'' '''ElemB''' class.
+
 
+
Because of these issues, MOXy's transformation mapping is much easier to implement:
+
 
+
==Example==
+
 
+
<source lang="Java">
+
package example;
+
 
+
import java.util.Date;
+
+
import javax.xml.bind.annotation.*;
+
import org.eclipse.persistence.oxm.annotations.*;
+
+
@XmlAccessorType(XmlAccessType.FIELD)
+
@XmlRootElement(name="ELEM_B")
+
public class ElemB {
+
+
    @XmlTransformation
+
    @XmlReadTransformer(transformerClass=DateAttributeTransformer.class)
+
    @XmlWriteTransformers({
+
        @XmlWriteTransformer(xmlPath="B_DATE/text()", transformerClass=DateFieldTransformer.class),
+
        @XmlWriteTransformer(xmlPath="B_TIME/text()", transformerClass=TimeFieldTransformer.class),
+
    })
+
    private Date bDate;
+
+
    @XmlElement(name="NUM")
+
    private int num;
+
+
    @XmlTransformation
+
    @XmlReadTransformer(transformerClass=DateAttributeTransformer.class)
+
    @XmlWriteTransformers({
+
        @XmlWriteTransformer(xmlPath="C_DATE/text()", transformerClass=DateFieldTransformer.class),
+
        @XmlWriteTransformer(xmlPath="C_TIME/text()", transformerClass=TimeFieldTransformer.class),
+
    })
+
    private Date cDate;
+
+
}
+
</source>
+
 
+
 
+
==AttributeTransformer==
+
 
+
Use an '''AttributeTransformer''' to construct the Java attribute value:
+
 
+
<source lang="java">
+
package example;
+
 
+
import java.text.ParseException;
+
import java.text.SimpleDateFormat;
+
+
import org.eclipse.persistence.internal.helper.DatabaseField;
+
import org.eclipse.persistence.mappings.foundation.AbstractTransformationMapping;
+
import org.eclipse.persistence.mappings.transformers.AttributeTransformer;
+
import org.eclipse.persistence.sessions.Record;
+
import org.eclipse.persistence.sessions.Session;
+
+
public class DateAttributeTransformer implements AttributeTransformer {
+
+
    private AbstractTransformationMapping mapping;
+
    private SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
+
+
    public void initialize(AbstractTransformationMapping mapping) {
+
        this.mapping = mapping;
+
    }
+
+
    public Object buildAttributeValue(Record record, Object instance, Session session) {
+
        try {
+
            String dateString = null;
+
            String timeString = null;
+
           
+
            for (DatabaseField field : mapping.getFields()) {
+
                if (field.getName().contains("DATE")) {
+
                    dateString = (String) record.get(field);
+
                } else {
+
                    timeString = (String) record.get(field);
+
                }
+
            }
+
            return yyyyMMddHHmmss.parseObject(dateString + timeString);
+
        } catch(ParseException e) {
+
            throw new RuntimeException(e);
+
        }
+
    }
+
 
+
}
+
</source>
+
 
+
 
+
==FieldTransformer==
+
 
+
Use an '''FieldTransformer''' to construct the XML field value from the Java object.
+
 
+
Each transformation mapping may have multiple write transformers. In this example, you will need two:
+
 
+
* The first write transformer writes the year, month, and day in '''yyMMdd''' format:
+
 
+
<source lang="java">
+
package example;
+
 
+
import java.text.SimpleDateFormat;
+
import java.util.Date;
+
+
import org.eclipse.persistence.mappings.foundation.AbstractTransformationMapping;
+
import org.eclipse.persistence.mappings.transformers.FieldTransformer;
+
import org.eclipse.persistence.sessions.Session;
+
+
public class DateFieldTransformer implements FieldTransformer {
+
+
    private AbstractTransformationMapping mapping;
+
    private SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyyMMdd");
+
+
    public void initialize(AbstractTransformationMapping mapping) {
+
        this.mapping = mapping;
+
    }
+
+
    public Object buildFieldValue(Object instance, String xPath, Session session) {
+
        Date date = (Date) mapping.getAttributeValueFromObject(instance);
+
        return yyyyMMdd.format(date);
+
    }
+
+
}
+
</source>
+
 
+
* The second write transformer writes out the hour, minutes, and seconds in '''HHmmss''' format.
+
 
+
<source lang="java">
+
package example;
+
 
+
import java.text.SimpleDateFormat;
+
import java.util.Date;
+
+
import org.eclipse.persistence.mappings.foundation.AbstractTransformationMapping;
+
import org.eclipse.persistence.mappings.transformers.FieldTransformer;
+
import org.eclipse.persistence.sessions.Session;
+
+
public class TimeFieldTransformer implements FieldTransformer {
+
+
    private AbstractTransformationMapping mapping;
+
    private SimpleDateFormat HHmmss = new SimpleDateFormat("HHmmss");
+
+
    public void initialize(AbstractTransformationMapping mapping) {
+
        this.mapping = mapping;
+
    }
+
+
    public Object buildFieldValue(Object instance, String xPath, Session session) {
+
        Date date = (Date) mapping.getAttributeValueFromObject(instance);
+
        return HHmmss.format(date);
+
    }
+
+
}
+
</source>
+

Latest revision as of 10:33, 8 November 2012

See http://www.eclipse.org/eclipselink/documentation/2.4/moxy/advanced_concepts007.htm