Au lieu d'utiliser le JAXB RI (Metro), vous pouvez utiliser la mise en œuvre Moxy JAXB (je suis le chef de file de la technologie). Il a quelques extensions qui rendront la cartographie de ce scénario assez facile.
jaxb.properties
Pour que votre Moxy utilisent la mise en œuvre de JAXB vous devez ajouter un fichier nommé JAXB.propriétés dans le même package que vos classes de modèle avec l'entrée suivante:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
racine
import javax.xml.bind.annotation.*;
@XmlRootElement(name="ROOT")
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlElement(name="ELEM_A")
private ElemA elemA;
@XmlElement(name="ELEM_B")
private ElemB elemB;
}
Elema
Nous pouvons Leverate @XmlTransformation. Il est similaire dans le concept à XmlAdapter, mais plus facile à partager parmi les mappages.
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import org.eclipse.persistence.oxm.annotations.XmlReadTransformer;
import org.eclipse.persistence.oxm.annotations.XmlTransformation;
import org.eclipse.persistence.oxm.annotations.XmlWriteTransformer;
import org.eclipse.persistence.oxm.annotations.XmlWriteTransformers;
@XmlAccessorType(XmlAccessType.FIELD)
public class ElemA {
@XmlTransformation
@XmlReadTransformer(transformerClass=DateAttributeTransformer.class)
@XmlWriteTransformers({
@XmlWriteTransformer(xpath="A_DATE/text()", transformerClass=DateFieldTransformer.class),
@XmlWriteTransformer(xpath="A_TIME/text()", transformerClass=TimeFieldTransformer.class),
})
public Date aDate;
@XmlElement(name="STRING")
private String string;
}
ElemB
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import org.eclipse.persistence.oxm.annotations.XmlReadTransformer;
import org.eclipse.persistence.oxm.annotations.XmlTransformation;
import org.eclipse.persistence.oxm.annotations.XmlWriteTransformer;
import org.eclipse.persistence.oxm.annotations.XmlWriteTransformers;
@XmlAccessorType(XmlAccessType.FIELD)
public class ElemB {
@XmlTransformation
@XmlReadTransformer(transformerClass=DateAttributeTransformer.class)
@XmlWriteTransformers({
@XmlWriteTransformer(xpath="B_DATE/text()", transformerClass=DateFieldTransformer.class),
@XmlWriteTransformer(xpath="B_TIME/text()", transformerClass=TimeFieldTransformer.class),
})
private Date bDate;
@XmlElement(name="NUM")
private int num;
@XmlTransformation
@XmlReadTransformer(transformerClass=DateAttributeTransformer.class)
@XmlWriteTransformers({
@XmlWriteTransformer(xpath="C_DATE/text()", transformerClass=DateFieldTransformer.class),
@XmlWriteTransformer(xpath="C_TIME/text()", transformerClass=TimeFieldTransformer.class),
})
private Date cDate;
}
DateAttributeTransformer
Le transformateur d'attribut est responsable de unmarshalling l'objet Date.
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);
}
}
}
DateFieldTransformer
Les transformateurs de terrain sont responsables de l'objet de triage date.
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);
}
}
TimeFieldTransformer
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);
}
}
Exemple de programme
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
System.out.println(jc);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum41/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
document XML
<ROOT>
<ELEM_A>
<A_DATE>20100825</A_DATE>
<A_TIME>141500</A_TIME>
<!-- other elements, maybe also other or date/time combinations -->
<STRING>ABC</STRING>
</ELEM_A>
<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>
</ROOT>
Le code indiqué ci-dessus nécessite EclipseLink 2.2 en cours de développement. Un nightly builds sont disponibles ici:
La version publiée actuelle de EclipseLink 2.1 prend en charge ce qui précède, mais avec une configuration légèrement différente. Nous pouvons discuter de la configuration appropriée si vous souhaitez explorer cette option.
Merci encore pour la réponse complète, je vais essayer EclipseLink MOXy. –
Quelques détails supplémentaires sont disponibles sur mon blog: http://bdoughan.blogspot.com/2010/08/xmltransformation-going-beyond.html –
J'ai trouvé du temps pour essayer ça et ça marche très bien dans mes tests.J'ai fait quelques modifications à DateAttributeTransformer pour remplacer le contrôle 'contains' avec quelque chose d'aussi hacky mais plus flexible. Je vais ajouter la source modifiée à la question. –