Search code examples
javajaxbunmarshallingjaxb2

How to map single tag to multiple fields in JAXB


Is it possible to acheive below in JAXB

 msg.txt

<Message> 
 <abc>Hello World</abc>
 <cdf>Dummy</cdf>
</Message>

  @XmlRootElement(name="message")
  class Message{

     public String abc;
     public String cdf;
   }

   class Test{
      public static void main(String args[]){
         JAXBContext jc = JAXBContext.newInstance();
         Unmarshaller u = jc.createUnmarshaller();
         Message m = (Message) u.unmarshal(new File("C:/msg.txt"));
       }
   }

Now, I want to have Message object populated with abc = 'Hello World' and cdf = 'Hello'.That is, substring of abc field.

I tried using XMLJavaAdapter for cdf field but in unmarshal method of Adapter class I can only get string dummy as ValueType, ie, value of cdf field.

Can this be possible in JAXB?


Solution

  • You can map abc and then mark cdf as @XmlTransient (to prevent it from being populated as part of the unmarshal.

    @XmlRootElement(name="message")
    class Message{
    
         public String abc;
    
         @XmlTransient
         public String cdf;
    }
    

    Then you can leverage an unmarshal event to populate the cdf field after the unmarshalling is done. Below are links to 2 different approachs for doing this:

    1. http://docs.oracle.com/javase/7/docs/api/javax/xml/bind/Unmarshaller.Listener.html
    2. http://docs.oracle.com/javase/7/docs/api/javax/xml/bind/Unmarshaller.html#unmarshalEventCallback

    Corrections to Your Demo Code

    You need to include the Message class when creatig the JAXBContext:

     JAXBContext jc = JAXBContext.newInstance(Message.class);
    

    Also you need to make sure the name you specify in the @XmlRootElement annotation matches the root element name in your XML document. Currently you have a mismatch the case used for these.