Xstream's jodatime Local Date display
I'm using xstrem to serialise a jodatime local date into xml. However when output the generated xml 开发者_开发百科the LocalDate is not in an easily readable format. See below:
<date>
<iLocalMillis>1316563200000</iLocalMillis>
<iChronology class="org.joda.time.chrono.ISOChronology" reference="../../tradeDate/iChronology"/>
Any ideas how I can get xstream to display the date in a format that won't drive me up the wall?
Here's what I have used successfully. I believe I used the info at the link mentioned in the first post.
import java.lang.reflect.Constructor;
import org.joda.time.DateTime;
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 final class JodaTimeConverter implements Converter {
@Override
@SuppressWarnings("unchecked")
public boolean canConvert(final Class type) {
return (type != null) && DateTime.class.getPackage().equals(type.getPackage());
}
@Override
public void marshal(final Object source, final HierarchicalStreamWriter writer,
final MarshallingContext context) {
writer.setValue(source.toString());
}
@Override
@SuppressWarnings("unchecked")
public Object unmarshal(final HierarchicalStreamReader reader,
final UnmarshallingContext context) {
try {
final Class requiredType = context.getRequiredType();
final Constructor constructor = requiredType.getConstructor(Object.class);
return constructor.newInstance(reader.getValue());
} catch (final Exception e) {
throw new RuntimeException(String.format(
"Exception while deserializing a Joda Time object: %s", context.getRequiredType().getSimpleName()), e);
}
}
}
You can register it like:
XStream xstream = new XStream(new StaxDriver());
xstream.registerConverter(new JodaTimeConverter());
The version from @Ben Carlson has an issue if your object tree contains other classes from the same package as DateTime.
A more robust version for converting DateTime to XML and back that does not require reflection as well:
public static class JodaTimeConverter implements Converter
{
@Override
@SuppressWarnings("unchecked")
public boolean canConvert( final Class type )
{
return DateTime.class.isAssignableFrom( type );
}
@Override
public void marshal( Object source, HierarchicalStreamWriter writer, MarshallingContext context )
{
writer.setValue( source.toString() );
}
@Override
@SuppressWarnings("unchecked")
public Object unmarshal( HierarchicalStreamReader reader,
UnmarshallingContext context )
{
return new DateTime( reader.getValue() );
}
}
Register the converter with XStream to use it:
XStream xstream = new XStream();
xstream.registerConverter(new JodaTimeConverter());
We needed a to convert a Joda DateTime to / from an XML attribute. For that, converters need to implement interface SingleValueConverter. Our final implementation:
package com.squins.xstream.joda;
import org.joda.time.DateTime;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;
public final class JodaDateTimeConverter extends AbstractSingleValueConverter
{
@Override
public boolean canConvert(final Class type)
{
return DateTime.class.equals(type);
}
@Override
public Object fromString(String str)
{
try
{
return new DateTime(str);
}
catch (final Exception e)
{
throw new ConversionException("Cannot parse date " + str);
}
}
}
You have to implement (or find) a custom converter for xstream, which will handle JodaTime object in a way you find appropriate.
Here is a small example of such converter: http://x-stream.github.io/converter-tutorial.html
I've used the one that it is here. Pasting it for simplicity:
public class JodaTimeConverter implements Converter
{
@Override
public boolean canConvert(Class type) {
return type != null && DateTime.class.getPackage().equals(type.getPackage());
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
writer.setValue(source.toString());
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
try {
Constructor constructor = context.getRequiredType().getConstructor(Object.class);
return constructor.newInstance(reader.getValue());
} catch (Exception e) { // NOSONAR
throw new SerializationException(String.format(
"An exception occurred while deserializing a Joda Time object: %s",
context.getRequiredType().getSimpleName()), e);
}
}
}
The other samples didn't work. Cheers!
精彩评论