Как распаковать xml-сообщение с плохой родительской / дочерней моделью - PullRequest
6 голосов
/ 19 мая 2011

Я пытаюсь разархивировать полезную нагрузку 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 мог преобразовать это во что-то полезное.

Я пробовал что-то вродеthis

@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 дляаккуратно справиться с этой неразберихой или мне нужно разобрать ее самостоятельно?

1 Ответ

13 голосов
/ 19 мая 2011

Краткий ответ

Исключение связано с конфликтом полей / свойств.Вы можете либо аннотировать свойства (методы get), либо установить следующую аннотацию для вашего типа:

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

Длинный ответ

Тип доступа JAXB по умолчанию PUBLIC_MEMBERэто означает, что JAXB отобразит все открытые поля (переменные экземпляра) и свойства (методы get / set).

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

}

Ваша модель

Каталог

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

}
...