Вместо использования JAXB RI (Metro) вы можете использовать реализацию MOXy JAXB (я технический руководитель). У него есть некоторые расширения, которые упростят сопоставление этого сценария.
jaxb.properties
Чтобы использовать MOXy в качестве реализации JAXB, вам нужно добавить файл с именем jaxb.properties в тот же пакет, что и классы вашей модели, со следующей записью:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Корень
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;
}
ЭлемА
Мы можем использовать @XmlTransformation. По своей концепции он похож на XmlAdapter, но его проще использовать для сопоставлений.
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;
}
ЭлемБ
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;
}
Трансформатор DateAttribute
Преобразователь атрибута отвечает за деупорядочение объекта 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);
}
}
}
Трансформатор DateField
Преобразователи поля отвечают за упорядочение объекта 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);
}
}
Трансформер TimeField
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);
}
}
Пример программы
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);
}
}
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>
Для показанного выше кода требуется EclipseLink 2.2, который в настоящее время находится в разработке. Ночные сборки доступны здесь:
Текущая выпущенная версия EclipseLink 2.1 поддерживает вышеуказанное, но с немного другой конфигурацией. Мы можем обсудить соответствующую настройку, если вы заинтересованы в изучении этого варианта.
person
bdoughan
schedule
25.08.2010