【问题标题】:JAXB Unmarsharller: XMLAttributes are mapped, but its XmlElements are notJAXB Unmarsharller:已映射 XMLAttributes,但未映射其 XmlElements
【发布时间】:2021-10-20 16:39:55
【问题描述】:

TL;DR:当我从 XML 解组到 POJO 时,我只有 XmlAttributes 映射良好,但是所有 XmlElement 都是空的。

你好!

我有以下问题。这个类是用 JAXB 生成的

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "activity"
})
@XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
public class ActivityDetails {

    @XmlElement(required = true)
    protected Activity activity;
    @XmlAttribute(name = "schemaVersion", required = true)
    protected float schemaVersion;
    @XmlAttribute(name = "actionType")
    protected ActionTypes actionType;
    @XmlSchemaType(name = "dateTime")
    protected XMLGregorianCalendar timestamp;

这是一个示例 XML

<activityDetails 
    actionType="CREATE" 
    schemaVersion="2.0" 
    timestamp="2020-01-02T15:31:50.549Z" 
    xmlns="http://lorem.ipsum.com/">
    <activity>
        <activityId>
            <start>2020-01-01T03:00:00Z</start>
            <end>2020-01-02T02:59:00Z</end>
        </activityId>
    </activity>
</activityDetails>

但是,当这段代码被执行时(请不要评判我,它是遗留代码):

    Object xmlClass = Class.forName("com.lorem.ipsum." + className).getConstructor().newInstance();
    final JAXBContext jaxbContext = JAXBContext.newInstance(xmlClass.getClass());
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    Object object = unmarshaller.unmarshal(new StringReader(element));

结果“对象”的所有 XmlAttribute 都映射得很好,但没有一个 XmlElement

PS:生成的类中的命名空间是手动添加的,如果我不这样做我有这个异常:

javax.xml.bind.UnmarshalException: unexpected element (uri:"http://lorem.ipsum.com/", local:"activityDetails"). Expected elements are <{}activityDetails>

提前致谢。

更新:如果我设置所有 @XmlElement 命名空间属性,我最终会映射元素,但我必须干预所有类。有没有另一种方法可以在不必修改所有类的所有字段的情况下实现这一点?

【问题讨论】:

    标签: java xml xsd jaxb


    【解决方案1】:

    我想我能够找出问题所在。发生这种情况是因为您没有为 XML 中的命名空间提供任何前缀。以下代码适用于您提供的示例 XML:

    XML:

    <activityDetails
            actionType="CREATE"
            schemaVersion="2.0"
            timestamp="2020-01-02T15:31:50.549Z"
            xmlns:ns0="http://lorem.ipsum.com/">
        <activity>
            <activityId>
                <start>2020-01-01T03:00:00Z</start>
                <end>2020-01-02T02:59:00Z</end>
            </activityId>
        </activity>
    </activityDetails>
    

    ActivityDetails.class:

    @XmlAccessorType(XmlAccessType.FIELD)
    @Data
    @XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
    public class ActivityDetails {
        private Activity activity;
    
        @XmlAttribute
        private float schemaVersion;
    
        @XmlAttribute
        private String actionType;
    
        @XmlAttribute
        private String timestamp;
    }
    
    
    

    Activity.class:

    @Data
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Activity {
        private ActivityID activityId;
    }
    
    

    ActivityID.class:

    @Data
    @XmlAccessorType(XmlAccessType.FIELD)
    public class ActivityID {
        private String start;
        private String end;
    }
    

    主类:

    public class Main {
        public static void main(String[] args) throws JAXBException, XMLStreamException {
            final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("activity.xml");
            final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
            final Unmarshaller unmarshaller = JAXBContext.newInstance(ActivityDetails.class).createUnmarshaller();
            final ActivityDetails activityDetails = unmarshaller.unmarshal(xmlStreamReader, ActivityDetails.class).getValue();
            System.out.println(activityDetails.toString());
    
            Marshaller marshaller = JAXBContext.newInstance(ActivityDetails.class).createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            marshaller.marshal(activityDetails, System.out);
        }
    }
    
    

    以下是您的输出:

    ActivityDetails(activity=Activity(activityId=ActivityID(start=2020-01-01T03:00:00Z, end=2020-01-02T02:59:00Z)), schemaVersion=2.0, actionType=CREATE, timestamp=2020-01-02T15:31:50.549Z)
    <ns0:activityDetails xmlns:ns0="http://lorem.ipsum.com/" schemaVersion="2.0" actionType="CREATE" timestamp="2020-01-02T15:31:50.549Z">
       <activity>
          <activityId>
             <start>2020-01-01T03:00:00Z</start>
             <end>2020-01-02T02:59:00Z</end>
          </activityId>
       </activity>
    </ns0:activityDetails>
    
    

    【讨论】:

    • 谢谢...蝙蝠侠?呵呵。问题是我无法修改 XML(此代码是 Apache Beam 数据流的一部分)所以我必须处理没有前缀的 XML :(
    【解决方案2】:

    最后我找到了这个解决方案:我没有将命名空间放在每个 XMLElements 中,而是将以下 package-info.java 放在生成的类的包中。

    @XmlSchema(
        elementFormDefault=XmlNsForm.QUALIFIED,
        namespace="http://lorem.ipsum.com/",
        xmlns={@XmlNs(prefix="", namespaceURI="http://lorem.ipsum.com/")})
    package com.lorem.ipsum.generated;
    
    import javax.xml.bind.annotation.XmlNs;
    import javax.xml.bind.annotation.XmlNsForm;
    import javax.xml.bind.annotation.XmlSchema;
    

    【讨论】:

    • 嗨,我遇到了类似的问题,但是对于默认命名空间,我得到了一个额外的命名空间。例如:XML 文件有 作为根标记,它存在于 xmlns 命名空间中。通过包信息修改,我希望它在解组和编组为 后出现。但我得到 registar.com">.. 一个额外的命名空间。我在 package-info 中的前缀似乎没有影响
    • 有什么建议吗?
    猜你喜欢
    • 2012-09-12
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 1970-01-01
    • 2012-01-04
    • 2011-03-27
    • 2011-10-12
    相关资源
    最近更新 更多