解组JAXB时动态标记值为空(基于http://stackoverflow.com/a/26328873/383861)

时间:2014-10-14 20:27:39

标签: java xml jaxb

package dogs;

@XmlRootElement(name = "dog")
public class Dog extends JAXBElement<String>{

    public static final QName NAME = new QName("dog");

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private String dogName;
    private String sound;

    public Dog(String name) {
        super(NAME, String.class, name);
    }

    public Dog(String dogName, String sound) {
        super(NAME, String.class, sound);
        this.dogName = dogName;
    }

    @Override
    public QName getName() {
        final String name = getDogName();
        if(name != null) {
            return new QName(name);
        }

        return NAME;
    }

    public String getDogName() {
        return dogName;
    }

    public void setDogName(String dogName) {
        this.dogName = dogName;
    }

    public String getSound() {
        return sound;
    }

    public void setSound(String sound) {
        this.sound = sound;
    }

    @Override
    public String toString() {
        return "Dog [dogName=" + dogName + ", sound=" + sound + "]";
    }
}


package dogs;


@XmlRootElement(name = "listOfDogs")
public class Dogs {

    private List<Object> dogs;

    @XmlMixed
    @XmlAnyElement
    @XmlElementWrapper(name = "dogs")
    public List<Object> getDogs() {
        return this.dogs;
    }

    public void setDogs(List<Object> dogs) {
        this.dogs = dogs;
    }

    public static void main(String[] args) throws JAXBException, FileNotFoundException, XMLStreamException {

        JAXBContext context = JAXBContext.newInstance(Dogs.class);

        XMLInputFactory xif = XMLInputFactory.newInstance();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("dogs2.xml"));
        xsr = new MyStreamReaderDelegate(xsr);

        Unmarshaller unmarshaller = context.createUnmarshaller();
        Dogs dogs = (Dogs) unmarshaller.unmarshal(xsr);
        System.out.println(dogs.getDogs());
    }

    private static class MyStreamReaderDelegate extends StreamReaderDelegate {

        public MyStreamReaderDelegate(XMLStreamReader xsr) {
            super(xsr);
        }

        @Override
        public String getAttributeLocalName(int index) {
            return super.getAttributeLocalName(index);
        }

        @Override
        public String getLocalName() {
            if(super.getLocalName().equals("dog")) {
                try {
                    super.nextTag();
                } catch (XMLStreamException e) {
                    e.printStackTrace();
                }
            }
            return super.getLocalName();
        }
    }

    @Override
    public String toString() {
        return "Dogs [dogs=" + dogs + "]";
    }
}

dogs2.xml文件是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<listOfDogs>
    <dogs>
        <dog>
            <name>Henry</name>
            <sound>Bark</sound>
        </dog>
    </dogs>
</listOfDogs>

上述代码的结果是:

[[name: null], [sound: null]]

但它应该是:

[Dog [dogName=Henry, sound=Bark]]

如您所见,不会调用类Dog的toString()方法。我尝试从JAXBElement重写getValue()以返回类Dog中的声音但没有结果,因为它没有被调用。在解组时,没有任何来自Dog类的东西被调用。而不是List狗,我宁愿有List狗,所以我可以从某个索引获取所有狗并调用getDogName()和getSound(); 我已经阅读了很多关于这个主题的帖子,但我找不到帮助我的东西。

我在哪里做错了?有其他选择吗?

2 个答案:

答案 0 :(得分:0)

这不是一个答案,而是一个我无法使其发挥作用的声明。无论如何,我会报告,因为我认为这可能是一个有价值的意见。

我的想法是每个狗名实施一个ObjectFactory方法:

@XmlRegistry
public class ObjectFactory {

    public Dogs createDogs() {
        return new Dogs();
    }

    @XmlElementDecl(name = "dog")
    public Dog createDog(DogType value) {
        return new Dog(value);
    }

    @XmlElementDecl(name = "fido", substitutionHeadName = "dog", substitutionHeadNamespace = "")
    public Dog createFido(DogType value) {
        return new Dog("fido", value);
    }

    @XmlElementDecl(name = "barks", substitutionHeadName = "dog", substitutionHeadNamespace = "")
    public Dog createBarks(DogType value) {
        return new Dog("barks", value);
    }
}

我实际上预计在解组时会调用这些createBarkscreateFido方法。这将在DogType实例中设置狗名称。说实话,我很惊讶这些方法没有被调用。

但是,在解组时不会调用这些方法,因此我无法获得真正的标记名称。

我的想法没有用。如果有人想要试验,请点击我的代码herehere

在我的测试中,名字未设置:

    @Test
    public void unmarshallsDogs() throws JAXBException {
        final JAXBContext context = JAXBContext
                .newInstance(ObjectFactory.class);
        final Dogs dogs = (Dogs) context.createUnmarshaller().unmarshal(
                getClass().getResource("dogs.xml"));
        Assert.assertEquals(3, dogs.getDogs().size());
        // Does not work
//      Assert.assertEquals("henry", dogs.getDogs().get(0).getValue()
//              .getName());
        Assert.assertEquals("bark", dogs.getDogs().get(0).getValue().getSound());
        // Does not work
//      Assert.assertEquals("fido", dogs.getDogs().get(1).getValue()
//              .getName());
        Assert.assertEquals("woof", dogs.getDogs().get(1).getValue().getSound());
        // Does not work
//      Assert.assertEquals("barks", dogs.getDogs().get(2).getValue()
//              .getName());
        Assert.assertEquals("miau", dogs.getDogs().get(2).getValue().getSound());
    }

请参阅Blaise Doughan的this answer获取基于XmlAdapter的解决方案。

答案 1 :(得分:0)

解决方案1 ​​ - 根据您的xml文件

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<listOfDogs>
    <dogs>
        <dog>
            <name>Henry</name>
            <sound>Bark</sound>
        </dog>
    </dogs>
</listOfDogs>

@XMLRootElement(name="listOfDogs")
class ListOfDogs {

    private Dogs dogs;
    //Getters and Setters

    @Override
    public String toString(){
        return dogs + "";
    }

}

@XMLRootElement(name="dogs")
class Dogs {

    List<Dog> dogs;

    @XMLElement(name="dog")
    public List<Dog> getDogs() {
        return dogs;
    }
    //Setters

   @Override
   public String toString() {
       return dogs + "";
   }
}

@XmlRootElement(name = "dog")
public class Dog {

    private String dogName;
    private String sound;

    @XmlElement(name = "name")
    public String getDogName() {
        return dogName;
    }

    public void setDogName(String dogName) {
        this.dogName = dogName;
    }

    public String getSound() {
        return sound;
    }

    public void setSound(String sound) {
        this.sound = sound;
    }

    @Override
     public String toString() {
        return "Dog[" + "dogName=" + dogName + ", sound=" + sound + ']';
     }

}

解决方案2:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dogs>
    <dog>
        <name>Henry</name>
        <sound>Bark</sound>
    </dog>
</dogs>

使用此解决方案,ListOfDogs类不再是utile.you可以删除它。