简体   繁体   中英

jaxb unmarshal to object by type

I want to parse out different types based on xml, when header=1 then User, header=2 then Order etc. for example:

<entity>
  <header>1</header>
  <body>
    <userId>1</userId>
    <userName>jonh</userName>
    ...
  <body>
</entity>
<entity>
  <header>2</header>
  <body>
    <orderId>1</orderId>
    <orderNo>20200101</orderNo>
    ...
  <body>
</entity>

How to implement this function?

Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object object = unmarshaller.unmarshal(xml);

I would try this: provide the type when unmarshalling. So maybe do something like this: create a transient facade object:

public class XmlEntityFacade {

   private int header;
   private Object body;

   //getters and setters...

}

And then cast this type while unmarshalling:

...
XmlEntityFacade facade = (XmlEntityFacade) unmarshaller.unmarshal(xml);

Then you can access the value of the by calling .getHeader() and body with .getBody() (getters that you have provided XmlEntityFacade class). And then depending on the value cast the required type to the Object.

public class TwiceUnmarshalTest {

    @Data
    @ToString
    public static abstract class HeaderResponse {
        private String header;
    }

    @XmlRootElement(name = "entity")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class XmlHeaderResponse extends HeaderResponse {
    }

    private final String xml = "<entity>" +
            "  <header>2</header>" +
            "  <body>" +
            "    <orderId>1</orderId>" +
            "    <orderNo>2020</orderNo>" +
            "  </body>" +
            "</entity>";

    @SuppressWarnings("unchecked")
    public static <T> T unmarshal(Reader reader, Class<T> typeClass) throws Exception {
        JAXBContext jaxbContext = JAXBContext.newInstance(typeClass);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        return (T) unmarshaller.unmarshal(reader);
    }

    @Test
    public void headerResponse() throws Exception {
        HeaderResponse response = unmarshal(new StringReader(xml), XmlHeaderResponse.class);
        System.out.println(response);
    }

    @ToString(callSuper = true)
    public static abstract class Response<T> extends HeaderResponse {
        @XmlAnyElement(lax = true)
        public T body;
    }

    @Data
    @XmlRootElement(name = "body")
    public static class Order {
        private String orderId;
        private String orderNo;

    }

    @XmlRootElement(name = "entity")
    @XmlSeeAlso({Order.class})
    public static class OrderResponse extends Response<Order> {
    }

    @Test
    public void response() throws Exception {
        XmlHeaderResponse response = unmarshal(new StringReader(xml), XmlHeaderResponse.class);
        System.out.println(response);
        //TwiceUnmarshalTest.HeaderResponse(header=2)
        if (response.getHeader().equals("2")) {
            OrderResponse orderResponse = unmarshal(new StringReader(xml), OrderResponse.class);
            System.out.println(orderResponse);
  //TwiceUnmarshalTest.Response(super=TwiceUnmarshalTest.HeaderResponse(header=2), body=TwiceUnmarshalTest.Order(orderId=1, orderNo=2020))
        }
    }
}

unmarshal twice, just get the header first, then get the entity. Not very good but can be used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM