Search code examples
javaxmlmarshallingunmarshallingpojo

Unmarshalling dates using JAXB but getting nullpointer exception


I am trying to convert XML to java object. In my xml, there is field which looks like:

<pickDisplayTs>2021-09-24T18:03:06.603 +0000</pickDisplayTs>

My Java object looks like the following:

@XmlElement(name = "pickDisplayTs" )
@XmlJavaTypeAdapter(DateAdapter.class)
public Date pickDisplayTs;

My DataAdapter class is the following:

    import javax.xml.bind.annotation.adapters.XmlAdapter;
    import java.text.SimpleDateFormat;
    import java.util.Date;

   public class DateAdapter extends XmlAdapter<String, Date> {

   private static final String CUSTOM_FORMAT_STRING = "yyyy-MM- 
   dd'T'HH:mm:ss.SSS'Z'";


    @Override
    public Date unmarshal(String v) throws Exception {
    return new SimpleDateFormat(CUSTOM_FORMAT_STRING).parse(v);
   }

@Override
public String marshal(Date v) throws Exception {
    return new SimpleDateFormat(CUSTOM_FORMAT_STRING).format(v);
}

}

Code reference: https://github.com/eugenp/tutorials/blob/950bbadc353bdca114befc98cf4a18476352220e/jaxb/src/main/java/com/baeldung/jaxb/dateunmarshalling/DateAdapter.java

This is the method for unmarshalling the xml file:

  String filepath = "xml/PickComplete.xml";
  String xmlPickComplete = readFromResources(filepath);
  PickComp pickCompleteMq = Xml.xmlToObject(xmlPickComplete, PickingSubSystemOrderCompleteMessage.class);

The entire pickCompleteMq is coming to be null but if I am declaring the pickDisplayTs as string, its all good, not sure where I am going wrong. But I need the field to be in Date.

Any help will be appreciated. Thank you.


Solution

  • The problem is with the input. XML extract you have provided doesn't follow the DateAdapter you are using. If you marshal a pojo that contain Date the expected xml tag should be

    <pickDisplayTs>2022-02-16T14:02:13.010Z</pickDisplayTs>
    

    Trying to parse the given input gives ParseException. Code snippet:

    Date parse = new SimpleDateFormat(CUSTOM_FORMAT_STRING).parse("2021-09-24T18:03:06.603 +0000");
    System.out.println(parse);
    

    Output

    java.text.ParseException: Unparseable date: "2021-09-24T18:03:06.603 +0000"
    at java.text.DateFormat.parse(DateFormat.java:366)

    Solution proposal:

        private static final String CUSTOM_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss.SSS Z";
        public static void main(String[] args) throws ParseException {
            String dateStr = "2021-09-24T18:03:06.603 +0000";
            Date marshaledDate = new SimpleDateFormat(CUSTOM_FORMAT_STRING).parse(dateStr);
    
            SimpleDateFormat format = new SimpleDateFormat(CUSTOM_FORMAT_STRING);
            format.setTimeZone(TimeZone.getTimeZone("UTC"));
    
            String unmarshalledDate = format.format(marshaledDate);
            System.out.println(unmarshalledDate);
        }
    

    You can use the above logic in your DataAdapter class as follows:

    public class DateAdapter extends XmlAdapter<String, Date> {
            private static final String CUSTOM_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss.SSS Z";
    
            @Override
            public Date unmarshal(String v) throws Exception {
                return new SimpleDateFormat(CUSTOM_FORMAT_STRING).parse(v);
            }
    
            @Override
            public String marshal(Date v) throws Exception {
                SimpleDateFormat sdf = new SimpleDateFormat(CUSTOM_FORMAT_STRING);
                sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
                return sdf.format(v);
            }
        }