JAXB:将单独的日期和时间元素映射到一个属性

Jör*_*ann 4 java calendar jaxb

我正在使用如下所示的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>
Run Code Online (Sandbox Code Playgroud)

我想将日期和时间映射到我的bean中的单个DateCalendar属性.这可能是使用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
Run Code Online (Sandbox Code Playgroud)

问题(除了附加代码)是我不能总是保证日期在时间值之前设置,但我想不出一个具体的例子,这可能会给出结果.

可以理解基于注释的解决方案的任何示例或上述代码的改进/反例.

编辑:我接受了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);
    }
}
Run Code Online (Sandbox Code Playgroud)

bdo*_*han 5

XmlAdapter是正确的方法:

具有Date属性的类

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

改编的Date对象

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

示例程序

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

XML文档

<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
    <ELEM>
        <DATE>20100825</DATE>
        <TIME>141500</TIME>
    </ELEM>
</ROOT> 
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅