Search code examples
javaxmljaxbxstreamjava.util.date

XStream marshalling unmarshalling XMLGregorianCalendar and Java.util.Date


Firstly a bit of background information an please forgive me if the format isn't correct.

I have two objects I am trying to map back and forth from via XML. One is auto-generated via wsimport so I am not able to use JAXB or XStream annotations. The other is auto-generated by the tool we are implementing.

I am in a situation where I am trying to map two objects to each other which are identical other than the Date fields on one is a Java.util.Date's and the other is a XMLGregorian Calendar.

I figured the quickest way instead of a huge manual mapping process would be to use XStream to grab XML String swap the root elements around and serialize to the other object. That's when I encountered the problem with converting dates. I have tried using a converter but again I am encountering another conversion issue. I hope someone might be able to help me with this.

I have two test entities:

import java.util.Date;

    import javax.xml.datatype.XMLGregorianCalendar;
    import com.eccles.utilities.*;

    public class SampleEntityGregorian {

        private XMLGregorianCalendar date = DateUtils.xmlGregCalFromDate(new Date());

        public XMLGregorianCalendar getGregCal() {
            return date;
        }

        public void setGregCal(XMLGregorianCalendar gregCal) {
            this.date = gregCal;
        }

    }

And

import java.util.Date;

    public class SampleEntityJavaUtil {

        private Date date = new Date();

        public Date getUtilDate() {
            return date;
        }

        public void setUtilDate(Date utilDate) {
            this.date = utilDate;
        }

    }

I have a custom converter that I am registering with Xstream to marshall/unmarshall from jav.util.date and XMLGregorianCalendar between the two.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class FromJavaUtilDateConverter implements Converter {

    public FromJavaUtilDateConverter() {
    }

    public boolean canConvert(Class clazz) {

        System.out.println("****CAN CONVERT " + clazz.getName() + "?***");
        System.out.println("Class name = " + clazz.getName());
        System.out.println(java.util.Date.class.isAssignableFrom(clazz));
        System.out.println("\n");

        return java.util.Date.class.isAssignableFrom(clazz);

    }

    public void marshal(Object value, HierarchicalStreamWriter writer,
                    MarshallingContext context) {
        System.out.println("***MARSHALLING*** \n");

        Date date = (Date) value;

        writer.setValue(date.toString());

    }

    public Object unmarshal(HierarchicalStreamReader reader,
                    UnmarshallingContext context){
        System.out.println("**UNMARSHALLING**");

        XMLGregorianCalendar result = null;

        try {

        String readerString = reader.getValue();
        System.out.println("Reader value = " + readerString + "\n");    

        GregorianCalendar gregorianCalendar;

        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");

        Date date = sdf.parse(readerString);
        System.out.println("parsed string to date = " + date.toString());

        gregorianCalendar = (GregorianCalendar)GregorianCalendar.getInstance();

        gregorianCalendar.setTime(date);
        System.out.println("Gregorian Calendar from Date = " + gregorianCalendar.getTime() + "\n");

        result = DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar);
        System.out.println("XML Gregorian Calendar = " + result.toXMLFormat() + "\n");

        //System.out.println(result.t);

        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (DatatypeConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;      
    }

}

And this is my test:

@Test
public void testSerializationToGregCalendar(){      

    SampleEntityJavaUtil entityJavaUtil = new SampleEntityJavaUtil();

    XStream xs = new XStream();
    xs.registerConverter(new FromJavaUtilDateConverter());
    xs.alias("SampleEntityGregorian.class",SampleEntityJavaUtil.class);

    String entityJavaUtilString = xs.toXML(entityJavaUtil);
    System.out.println("Entity with Java Util Date:" + "\n");
    System.out.println(entityJavaUtilString);
    System.out.println("\n");

    SampleEntityGregorian entityGregCal = new SampleEntityGregorian();

    System.out.println(xs.toXML(entityGregCal));

    try{
        entityGregCal = (SampleEntityGregorian) xs.fromXML(entityJavaUtilString);
    }
    catch(Exception e){
        System.out.println("Failed to Serialize");
        e.printStackTrace();
    }

}

And the Exception:

com.thoughtworks.xstream.converters.ConversionException: Cannot convert type com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl to type java.util.Date
---- Debugging information ----
class               : SampleEntityJavaUtil
required-type       : SampleEntityJavaUtil
converter-type      : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path                : /SampleEntityGregorian.class/date
line number         : 2
version             : 1.4.7
-------------------------------
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:430)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:257)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134)
    at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1185)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1169)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1040)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1031)
    at com.eccles.tests.ConverterTests.testSerializationToGregCalendar(ConverterTests.java:87)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Thanks in advance.

Tim


Solution

  • I'd say you're up to a pretty wild thing.

    If your only problem is the date type used, you may try to customize the JAXB part (wsimport, whatever) to use Date instead of the XMLGregorianCalender. Heres's a link about that.

    Next, you may want to consider to use something like Dozer to map between beans instead of remarshalling.

    This might be a very superficial opinion, but from what I read the approach does not seem right to me. You mention wsimport/JAXB, XStream and an own tool in one question. That does not feel right for me.