我正在使用如下所示的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>
我想将日期和时间映射到我的bean中的单个Date
或Calendar
属性。这可能是使用jaxb注释吗?类javax.xml.bind.annotation.adapters.XmlAdapter
似乎可以做到这一点,但我必须承认我并不完全理解它的javadoc。
解决方法是为日期和时间字符串创建其他setter,以便在Calendar
属性中设置相应的值,如下所示:
private Calendar calendar;
public void setDate(String date) {
if (calendar == null) {
calendar = new GregorianCalendar();
}
calendar.set(YEAR, Integer.parseIn(date.substring(0, 4)));
calendar.set(MONTH, Integer.parseIn(date.substring(4, 6))-1);
calendar.set(DAY_OF_MONTH, Integer.parseIn(date.substring(6, 8)));
}
// Similar code for setTime
问题(除了附加代码)是我不能总是保证在时间值之前设置日期,但我想不出一个具体的例子,这可能会给出结果。
我们赞赏基于注释的解决方案的任何示例或上述代码的改进/反例。
编辑:我选择了Blaise Doughan给出的第二个答案,但修改了他的DateAttributeTransformer更灵活,并且不希望字段名称包含字符串“DATE”。字段名称取自字段上的XmlWriterTransformer注释:
@Override
public Object buildAttributeValue(Record record, Object instance, Session session) {
try {
String dateString = null;
String timeString = null;
String dateFieldName = null;
String timeFieldName = null;
// TODO: Proper Exception handling
try {
XmlWriteTransformers wts = instance.getClass().getDeclaredField(mapping.getAttributeName()).getAnnotation(XmlWriteTransformers.class);
for (XmlWriteTransformer wt : wts.value()) {
String fieldName = wt.xpath();
if (wt.transformerClass() == DateFieldTransformer.class) {
dateFieldName = fieldName;
} else {
timeFieldName = fieldName;
}
}
} catch (NoSuchFieldException ex) {
throw new RuntimeException(ex);
} catch (SecurityException ex) {
throw new RuntimeException(ex);
}
for(DatabaseField field : mapping.getFields()) {
XMLField xfield = (XMLField)field;
if(xfield.getXPath().equals(dateFieldName)) {
dateString = (String) record.get(field);
} else {
timeString = (String) record.get(field);
}
}
return yyyyMMddHHmmss.parseObject(dateString + timeString);
} catch(ParseException e) {
throw new RuntimeException(e);
}
}
答案 0 :(得分:5)
XmlAdapter是正确的方法:
具有日期属性的类
import java.util.Date;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement(name="ROOT")
public class Root {
private Date date;
@XmlElement(name="ELEM")
@XmlJavaTypeAdapter(DateAdapter.class)
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
XmlAdapter的实施
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class DateAdapter extends XmlAdapter<AdaptedDate, Date> {
private SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyyMMdd");
private SimpleDateFormat HHmmss = new SimpleDateFormat("HHmmss");
private SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
@Override
public Date unmarshal(AdaptedDate v) throws Exception {
String dateString = v.getDate() + v.getTime();
return yyyyMMddHHmmss.parse(dateString);
}
@Override
public AdaptedDate marshal(Date v) throws Exception {
AdaptedDate adaptedDate = new AdaptedDate();
adaptedDate.setDate(yyyyMMdd.format(v));
adaptedDate.setTime(HHmmss.format(v));
return adaptedDate;
}
}
改编的日期对象
import javax.xml.bind.annotation.XmlElement;
public class AdaptedDate {
private String date;
private String time;
@XmlElement(name="DATE")
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
@XmlElement(name="TIME")
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
示例程序
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);
File xml = new File("input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
XML文档
<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
<ELEM>
<DATE>20100825</DATE>
<TIME>141500</TIME>
</ELEM>
</ROOT>
有关详细信息,请参阅:
答案 1 :(得分:2)
您可以使用MOXy JAXB实现(我是技术主管),而不是使用JAXB RI(Metro)。它有一些扩展,可以很容易地映射这个场景。
<强> 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;
}
<强> ElemA 强>
我们可以提升@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;
}
<强> 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 强>
属性转换器负责解组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 强>
字段转换器负责编组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);
}
}
示例程序
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版本支持上述版本,但配置略有不同。如果您有兴趣探索此选项,我们可以讨论适当的设置。