如何使用错误的父/子模型解组 xml 消息

发布于 2024-11-08 11:51:34 字数 1431 浏览 0 评论 0原文

我正在尝试将第 3 方 XML 有效负载解组到一个类中。问题是有效负载具有父/子关系,并且根节点、父节点和子节点都具有相同的元素名称。这是有效负载的示例。

<?xml version="1.0" encoding="UTF-8"?>
<Directory>
    <id>2</id>
    <name>Media</name>
    <Directory>
        <id>5</id>
        <name>Default_Content</name>
        <Directory>
            <id>9</id>
            <name>Images</name>
        </Directory>
        <Directory>
            <id>8</id>
            <name>Icons</name>
        </Directory>
        <Directory>
            <id>6</id>
            <name>Additional_Content</name>
        </Directory>
    </Directory>
    <Directory>
        <id>12</id>
        <name>IC</name>
    </Directory>
</Directory>

所以我试图注释一个类,以便 JAXB/JAX-RS 可以将其解组为有用的东西。

我已经尝试过类似的方法

@XmlRootElement(name="Directory")
public class Directory {
    private int id;
    private String name;

    @XmlElement(name="Directory");
    private List<Directory> directories = new ArrayList<Directory>();
}

,但是,可以预见的是,它会抛出一个 IllegalAnnotationException 因为有两个同名的属性。

关于如何使用 JAXB/JAX-RS 干净地处理这个混乱的问题,或者我应该自己解析它,有什么想法吗?

I am trying to unmarshal a 3rd party XML payload into a class. The problem is that the payload has a parent/child relationship and the root node, the parent and the children all have the same element name. Here is a sample of the payload.

<?xml version="1.0" encoding="UTF-8"?>
<Directory>
    <id>2</id>
    <name>Media</name>
    <Directory>
        <id>5</id>
        <name>Default_Content</name>
        <Directory>
            <id>9</id>
            <name>Images</name>
        </Directory>
        <Directory>
            <id>8</id>
            <name>Icons</name>
        </Directory>
        <Directory>
            <id>6</id>
            <name>Additional_Content</name>
        </Directory>
    </Directory>
    <Directory>
        <id>12</id>
        <name>IC</name>
    </Directory>
</Directory>

So I am trying to annotate a class so JAXB/JAX-RS can unmarshal this into something useful.

I've tried something like this

@XmlRootElement(name="Directory")
public class Directory {
    private int id;
    private String name;

    @XmlElement(name="Directory");
    private List<Directory> directories = new ArrayList<Directory>();
}

But, predictably, it throws an IllegalAnnotationException because of having 2 properties with the same name.

Any ideas as to how I can use JAXB/JAX-RS to cleanly handle this mess or should I just parse it on my own?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

清欢 2024-11-15 11:51:34

简短回答

异常是由于字段/属性冲突造成的。您可以注释属性(获取方法)或在您的类型上设置以下注释:

@XmlAccessorType(XmlAccessType.FIELD)
public class Directory {
  ...
}

长答案

JAXB 的默认访问类型是 PUBLIC_MEMBER 这意味着 JAXB 将映射所有公共字段(实例变量)和属性(获取/设置方法)。

public class Foo {

    private String bar;

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

}

如果您注释一个字段:

public class Foo {

    @XmlAttribute
    private String bar;

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

}

那么 JAXB 会认为它映射了两个 bar 属性并抛出异常:

Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "bar"
    this problem is related to the following location:
        at public java.lang.String example.Foo.getBar()
        at example.Foo
    this problem is related to the following location:
        at private java.lang.String example.Foo.bar
        at example.Foo

解决方案是注释该属性并将 XmlAccessType 类型设置为 FIELD

@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {

    @XmlAttribute
    private String bar;

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

}

< strong>您的模型

目录

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="Directory")
@XmlAccessorType(XmlAccessType.FIELD)
public class Directory {
    private int id;
    private String name;

    @XmlElement(name="Directory")
    private List<Directory> directories = new ArrayList<Directory>();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Directory> getDirectories() {
        return directories;
    }

    public void setDirectories(List<Directory> directories) {
        this.directories = directories;
    }

}

演示

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(Directory.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Directory directory = (Directory) unmarshaller.unmarshal(new File("input.xml"));

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(directory, System.out);
    }

}

Short Answer

The exception is due to a field/property collision. You can either annotate the properties (get methods) or set the following annotation on your type:

@XmlAccessorType(XmlAccessType.FIELD)
public class Directory {
  ...
}

Long Answer

JAXB's default access type is PUBLIC_MEMBER this means that JAXB will map all public fields (instance variables) and properties (get/set methods).

public class Foo {

    private String bar;

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

}

If you annotate a field:

public class Foo {

    @XmlAttribute
    private String bar;

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

}

Then JAXB will think it has two bar properties mapped and thrown an exception:

Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "bar"
    this problem is related to the following location:
        at public java.lang.String example.Foo.getBar()
        at example.Foo
    this problem is related to the following location:
        at private java.lang.String example.Foo.bar
        at example.Foo

The solution is to annotate the property and set the XmlAccessType type to FIELD

@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {

    @XmlAttribute
    private String bar;

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

}

Your Model

Directory

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="Directory")
@XmlAccessorType(XmlAccessType.FIELD)
public class Directory {
    private int id;
    private String name;

    @XmlElement(name="Directory")
    private List<Directory> directories = new ArrayList<Directory>();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Directory> getDirectories() {
        return directories;
    }

    public void setDirectories(List<Directory> directories) {
        this.directories = directories;
    }

}

Demo

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(Directory.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Directory directory = (Directory) unmarshaller.unmarshal(new File("input.xml"));

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(directory, System.out);
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文