Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

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')
 
(11 intermediate revisions by 2 users not shown)
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/javax/xml/bind/annotation/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 XmlWriteTransformer]
+
}}
+
=Transformation Mapping=
+
 
+
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 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>
+
 
+
 
+
==XML Read Transformer==
+
 
+
Use an XML ''read transformer'' to construct the object value from XML, as shown here:
+
 
+
<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>
+
 
+
 
+
==XML Write Transformer(s)==
+
 
+
Use an XML ''write transformer'' to construct an XML value from the object.
+
 
+
Each transformation mapping may have multiple write transformers. In this example, you will need two:
+
 
+
* The first XML 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 XML 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

Back to the top