【问题标题】:How to handle java.util.Date with MOXy bindings file如何使用 MOXy 绑定文件处理 java.util.Date
【发布时间】:2012-01-05 15:46:43
【问题描述】:

我是 MOXy 和 JaxB 的新手,我遇到了 java.util.Date 转换的问题。

我正在使用映射文件将 XML 文件(我无法控制)解组为对象(我既不能手动注释现有类也不能更改它们)。

我的 XML 映射文件如下所示:

<?xml version="1.0"?>
<xml-bindings 
        xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
        version="2.1">
    <java-types>
        <java-type name="Observation">
            <xml-type prop-order="date theoricalTime ci ch cr type" />
            <java-attributes>
                <xml-element java-attribute="date" xml-path="Date/text()" />
                <xml-element java-attribute="theoricalTime" xml-path="TheoricalTime/text()" />
                <xml-element java-attribute="ci" xml-path="CIPR/text()" />
                <xml-element java-attribute="ch" xml-path="CHPR/text()" />
                <xml-element java-attribute="cr" xml-path="CRPR/text()" />
                <xml-element java-attribute="type" xml-path="Type/text()" />
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

在我要编组的类中,属性“date”和“theoricalTime”的类型为 java.util.Date。

我正在编组的 xml 中的值是具有这种格式的字符串:“dd/MM/yyyy HH:mm:ss”(“05/01/2012 16:36:24”)。我也有一些只有时间值“HH:mm:ss”(“14:17:33”)的字段。

这是我在解组文件时得到的堆栈跟踪:

Exception in thread "main" Local Exception Stack: 
Exception [EclipseLink-3002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [22/01/2009 20:56:29], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[date-->Date/text()]] with descriptor [XMLDescriptor(Observation --> [DatabaseTable(Observation)])], could not be converted to [class java.util.Calendar].
    at org.eclipse.persistence.exceptions.ConversionException.incorrectDateTimeFormat(ConversionException.java:127)
    at org.eclipse.persistence.exceptions.ConversionException.incorrectDateTimeFormat(ConversionException.java:133)
    at org.eclipse.persistence.internal.oxm.XMLConversionManager.convertStringToXMLGregorianCalendar(XMLConversionManager.java:703)
    at org.eclipse.persistence.internal.oxm.XMLConversionManager.convertStringToDate(XMLConversionManager.java:1111)
    at org.eclipse.persistence.internal.oxm.XMLConversionManager.convertObjectToUtilDate(XMLConversionManager.java:804)
    at org.eclipse.persistence.internal.oxm.XMLConversionManager.convertObject(XMLConversionManager.java:165)
    at org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform.convertObject(DatasourcePlatform.java:160)
    at org.eclipse.persistence.oxm.mappings.XMLDirectMapping.getAttributeValue(XMLDirectMapping.java:293)
    at org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue.endElement(XMLDirectMappingNodeValue.java:182)
    at org.eclipse.persistence.oxm.record.UnmarshalRecord.endElement(UnmarshalRecord.java:823)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:601)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1774)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2930)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:807)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:107)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
    at org.eclipse.persistence.internal.oxm.record.XMLReader.parse(XMLReader.java:157)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:753)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:333)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:320)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:280)
    at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:306)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:115)
    at Main.Test(Main.java:97)
    at Main.main(Main.java:35)

我的问题是:是否可以使用 MOXy 的外部元数据在映射文件中指定类型转换?如何使用上面指定的格式处理日期时间和时间并将它们映射到日期字段?

(我暗暗希望 Blaise Doughan 正在阅读这篇文章。)

提前感谢您的帮助!

【问题讨论】:

    标签: date jaxb eclipselink moxy


    【解决方案1】:

    以下演示了如何将XmlAdapter 与 MOXy 的外部映射文档一起使用,以实现您正在寻找的结果:

    日期适配器

    由于您的日期/时间数据采用以下格式dd/MM/yyyy HH:mm:ss,您需要使用XmlAdapter,如下所示:

    package forum8745305;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import javax.xml.bind.annotation.adapters.XmlAdapter;
    
    public class DateAdapter extends XmlAdapter<String, Date> {
    
        private SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    
        @Override
        public String marshal(Date v) throws Exception {
            return dateFormat.format(v);
        }
    
        @Override
        public Date unmarshal(String v) throws Exception {
            return dateFormat.parse(v);
        }
    
    }
    

    oxm.xml

    这通常在您的域模型上使用@XmlJavaTypeAdapter 注释指定,​​但由于您使用的是 MOXy 的外部元数据文档,您可以按如下方式指定它。我已在包级别指定它,以便它将应用于属于该包中域类的java.util.Date 类型的所有字段/属性:

    <?xml version="1.0"?>
    <xml-bindings 
            xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
            version="2.1"
            package-name="forum8745305">
        <xml-java-type-adapters>
            <xml-java-type-adapter value="forum8745305.DateAdapter" type="java.util.Date"/>
        </xml-java-type-adapters>
        <java-types>
            <java-type name="Observation">
                <xml-type prop-order="date theoricalTime ci ch cr type" />
                <xml-root-element/>
                <java-attributes>
                    <xml-element java-attribute="date" xml-path="Date/text()"/>
                    <xml-element java-attribute="theoricalTime" xml-path="TheoricalTime/text()" />
                    <xml-element java-attribute="numeroTrain" xml-path="NumeroTrain/text()" />
                    <xml-element java-attribute="ci" xml-path="CIPR/text()" />
                    <xml-element java-attribute="ch" xml-path="CHPR/text()" />
                    <xml-element java-attribute="cr" xml-path="CRPR/text()" />
                    <xml-element java-attribute="type" xml-path="Type/text()" />
                </java-attributes>
            </java-type>
        </java-types>
    </xml-bindings>
    

    观察

    根据您的问题,您的域类可能如下所示:

    package forum8745305;
    
    import java.util.Date;
    
    public class Observation {
    
        private Date date;
        private Date theoricalTime;
        private String numeroTrain;
        private String ci;
        private String ch;
        private String cr;
        private String type;
    
        public Date getDate() {
            return date;
        }
    
        public void setDate(Date date) {
            this.date = date;
        }
    
        public Date getTheoricalTime() {
            return theoricalTime;
        }
    
        public void setTheoricalTime(Date theoricalTime) {
            this.theoricalTime = theoricalTime;
        }
    
        public String getNumeroTrain() {
            return numeroTrain;
        }
    
        public void setNumeroTrain(String numeroTrain) {
            this.numeroTrain = numeroTrain;
        }
    
        public String getCi() {
            return ci;
        }
    
        public void setCi(String ci) {
            this.ci = ci;
        }
    
        public String getCh() {
            return ch;
        }
    
        public void setCh(String ch) {
            this.ch = ch;
        }
    
        public String getCr() {
            return cr;
        }
    
        public void setCr(String cr) {
            this.cr = cr;
        }
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
    }
    

    演示

    以下代码可用于运行示例:

    package forum8745305;
    
    import java.io.File;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.Marshaller;
    import javax.xml.bind.Unmarshaller;
    
    import org.eclipse.persistence.jaxb.JAXBContextFactory;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            Map<String, Object> properties = new HashMap<String, Object>(1);
            properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum8745305/oxm.xml");
            JAXBContext jc = JAXBContext.newInstance(new Class[] {Observation.class}, properties);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            File xml = new File("src/forum8745305/input.xml");
            Observation observation = (Observation) unmarshaller.unmarshal(xml);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(observation, System.out);
        }
    
    }
    

    输入/输出

    <?xml version="1.0" encoding="UTF-8"?>
    <observation>
        <Date>05/01/2012 16:36:24</Date>
        <TheoricalTime>01/02/2012 12:34:45</TheoricalTime>
    </observation>
    

    更多信息

    更新

    您还可以在属性级别指定XmlAdapters。这意味着如果您愿意,您可以为每个 Date 属性设置不同的 XmlAdapter

    <?xml version="1.0"?>
    <xml-bindings 
            xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
            version="2.1"
            package-name="forum8745305">
        <java-types>
            <java-type name="Observation">
                <xml-type prop-order="date theoricalTime ci ch cr type" />
                <xml-root-element/>
                <java-attributes>
                    <xml-element java-attribute="date" xml-path="Date/text()">
                        <xml-java-type-adapter value="forum8745305.DateAdapter"/>
                    </xml-element>
                    <xml-element java-attribute="theoricalTime" xml-path="TheoricalTime/text()">
                        <xml-java-type-adapter value="forum8745305.DateAdapter"/>
                    </xml-element>
                    <xml-element java-attribute="numeroTrain" xml-path="NumeroTrain/text()" />
                    <xml-element java-attribute="ci" xml-path="CIPR/text()" />
                    <xml-element java-attribute="ch" xml-path="CHPR/text()" />
                    <xml-element java-attribute="cr" xml-path="CRPR/text()" />
                    <xml-element java-attribute="type" xml-path="Type/text()" />
                </java-attributes>
            </java-type>
        </java-types>
    </xml-bindings>
    

    【讨论】:

    • 它适用于所有日期时间字段(包含“01/02/2012 18:02:34”的字段),但我仍然对如何映射仅包含时间或日期的字段感到困惑(“14 :01:34" 和 "dd/MM/yyyy") 哪些应该映射到日期字段?我是否应该为每种格式(“dd/MM/yyyy HH:mm:ss”、“dd/MM/yyyy”和“HH:mm:ss”)创建 3 个 SimpleDateFormat 并测试字符串的内容以了解应该是哪个 SimpleDateFormat用过的 ?或者有没有办法为每个属性指定一个特定的方法?
    • @user1121108 - 如果您在属性级别指定 XmlAdapter,我已经用 XML 元数据的外观更新了我的答案。根据您的评论,您需要为每种所需格式提供单独的 XmlAdapters
    • @user1121108:如果你有不同格式的字符串,你应该有一个XmlAdapter,但尝试几种解析模式(从最长开始)。不幸的是,您将无法从Date 正确转换回StringDate 中没有未设置字段的概念。考虑从Joda Time 映射到Partial
    • 感谢您的回答,这非常有帮助,有没有地方可以找到关于 MOXy 外部元数据映射的不同可能性的一些文档?
    • @user1121108 - MOXy 用户指南 (wiki.eclipse.org/EclipseLink/UserGuide/MOXy) 是您最好的资源。每个部分都描述了如何使用注释和 XML 进行相关映射。
    猜你喜欢
    • 1970-01-01
    • 2019-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多