XmlJavaTypeAdapter not being detected

前端 未结 2 553
半阙折子戏
半阙折子戏 2020-12-06 02:27

Hopefully an easy one for JAXB experts:

I am trying to marshal an immutable class that does not define a default no-arg constructor. I have defined an

相关标签:
2条回答
  • 2020-12-06 03:02

    The following should help:

    FOO AS ROOT OBJECT

    When @XmlJavaTypeAdapter is specified at the type level it only applies to fields/properties referencing that class, and not when an instance of that class is a root object in your XML tree. This means that you will have to convert Foo to AdaptedFoo yourself, and create the JAXBContext on AdaptedFoo and not Foo.

    Marshal

    package forum11966714;
    
    import javax.xml.bind.*;
    
    public class Marshal {
        public static void main(String[] args) {
          Foo foo = new Foo("Adam", 34);
    
          try {
            JAXBContext jaxbContext = JAXBContext.newInstance(AdaptedFoo.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
    
            // output pretty printed
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    
            jaxbMarshaller.marshal(new AdaptedFoo(foo), System.out);              
          } catch (JAXBException e) {
            e.printStackTrace();
          }   
        }
      }
    

    AdaptedFoo

    You will need to add an @XmlRootElement annotation to the AdaptedFoo class. You can remove the same annotation from the Foo class.

    package forum11966714;
    
    import javax.xml.bind.annotation.*;
    
    @XmlRootElement
    class AdaptedFoo {
        private String name;
        private int age;
    
        public AdaptedFoo() {
        }
    
        public AdaptedFoo(Foo foo) {
            this.name = foo.getName();
            this.age = foo.getAge();
        }
    
        @XmlAttribute
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @XmlAttribute
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    

    FOO AS NESTED OBJECT

    When Foo isn't the root object everything works the way you have it mapped. I have extended your model to demonstrate how this would work.

    Bar

    package forum11966714;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement
    public class Bar {
    
        private Foo foo;
    
        public Foo getFoo() {
            return foo;
        }
    
        public void setFoo(Foo foo) {
            this.foo = foo;
        }
    
    }
    

    Demo

    Note that the JAXB reference implementation will not let you specify the Foo class when bootstrapping the JAXBContext.

    package forum11966714;
    
    import java.io.File;
    
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBException;
    import javax.xml.bind.Marshaller;
    import javax.xml.bind.Unmarshaller;
    
    public class Demo {
        public static void main(String[] args) {
            try {
                JAXBContext jaxbContext = JAXBContext.newInstance(Bar.class);
    
                Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
                File xml = new File("src/forum11966714/input.xml");
                Bar bar = (Bar) jaxbUnmarshaller.unmarshal(xml);
    
                Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
                jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                jaxbMarshaller.marshal(bar, System.out);
            } catch (JAXBException e) {
                e.printStackTrace();
            }
        }
    }
    

    input.xml/Output

    <?xml version="1.0" encoding="UTF-8"?>
    <bar>
        <foo name="Jane Doe" age="35"/>
    </bar>
    
    0 讨论(0)
  • 2020-12-06 03:11

    I know that this is not the case, but if you have such an error when you put @XmlJavaTypeAdapter for the field - check that you specified the namespace. You may need it.

    In my case this didn't work:

    @XmlElement(name = "Expiration")
    @XmlJavaTypeAdapter(DateAdapter.class)
    private Date expiration;
    

    until a namespace has been specified:

    @XmlElement(name = "Expiration", namespace="http://site/your.namespace")
    @XmlJavaTypeAdapter(DateAdapter.class)
    private Date expiration;
    
    0 讨论(0)
提交回复
热议问题