Create a custom json string deserializer in java
Tech-Today

Create a custom json string deserializer in java


On normal cases we really have a lot of ways in doing so, we can use jaxb, jackson and more.

But in some cases we really need to improvised, for example in the project I'm working right now I have a date string from a .net application in this format: "2014-04-08T07:08:48.1344874Z". As you can see it has 7 characters in the millisecond section, while java normally use 3. Of course you'll say just use a simpleDateFormat that will parse the 7 characters, I've thought of that and here's the result

SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSX");
Date d1 = df1.parse("2014-04-07T15:20:40.7439627Z");
System.out.println("D1: " + d1); // produces "Mon Apr 07 19:24:39 CEST 2014"

//as I said it works on 3 character millies
SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
Date d2 = df2.parse("2014-04-07T15:20:40.743Z");
System.out.println("D2: " + d2); // produces "Mon Apr 07 17:20:40 CEST 2014"

Note that I'm using UTC+2.

I found a solution that is worth mentioning, although it didn't really work 100% for me. Normally when you generate classes from xsd using xjc, it will use an XmlGregorianCalendar object. So the first problem is how will I convert it to a Date object?

1.) Create a xs:dateTime binding, xs:dateTime is what you'll see in your xsd.
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<globalBindings>
<javaType name="java.util.Date" xmlType="xs:dateTime"
parseMethod="org.czetsuya.xsd.converter.XsdDateTimeConverter.unmarshal"
printMethod="org.czetsuya.xsd.converter.XsdDateTimeConverter.marshalDateTime" />
<javaType name="java.util.Date" xmlType="xs:date"
parseMethod="org.czetsuya.xsd.converter.XsdDateTimeConverter.unmarshal"
printMethod="org.czetsuya.xsd.converter.XsdDateTimeConverter.marshalDate" />
</globalBindings>

</bindings>

2.) Generate the java class from xsd, I normally do it via eclipse using the jaxb converter from jaxb schema to java class.

What it does is create a JavaType adapter and replace XmlGregorianCalendar with a date object. The xs:dateTime fields will be annotated like this:
@XmlJavaTypeAdapter(Adapter1 .class)
@XmlSchemaType(name = "dateTime")
protected Date myDate;

And it will work, and so I thought but it did not :-) Same problem I describe earlier. Btw, I'm using jackson ObjectMapper to parse a json string into an object like this:
ObjectMapper mapper = ObjectMapperFactory.createObjectMapper();
messageWrapper = mapper.readValue(message, MyClass.class);

That code successfully parsed my json string but the date values are still totally wrong no matter the data type.

And so the final part of the solution. Customizing a Json de-serializer for object of type Date. See our XmlGregorianCalendar to Date comes into place.

So our converter:
package org.czetsuya.xsd.converter;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.xml.bind.DatatypeConverter;

import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;

/**
* @author Edward P. Legaspi
**/
public class XsdDateTimeConverter extends JsonDeserializer {

protected static Logger log = Logger.getLogger(XsdDateTimeConverter.class);

public static Date unmarshal(String dateTime) {
return DatatypeConverter.parseDate(dateTime).getTime();
}

public static String marshalDate(Date date) {
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date);
return DatatypeConverter.printDate(calendar);
}

public static String marshalDateTime(Date dateTime) {
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(dateTime);
return DatatypeConverter.printDateTime(calendar);
}

@Override
public Date deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
// format: 2014-04-08T07:08:48.1344874Z
String date = jp.getText();
if (date == null || date.length() != 28) {
log.debug("Null or invalid date=" + date);
return null;
}

// remove extra 4 milliseconds
date = date.substring(0, date.length() - 5)
+ date.charAt(date.length() - 1);

SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
try {
return sf.parse(date);
} catch (ParseException e) {
log.error("Error parsing date=" + date);
return null;
}
}
}

Well you can disregard the first 3 methods as it really not use. The most important part is in the deserialize method. It removes the last 4 millisecond characters so java can understand and parse it to a Date object. But how will the mapper know about this converter, of course you have to tell it :-)
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule("czetsuya", Version.unknownVersion());
module.addDeserializer(Date.class, new XsdDateTimeConverter());
mapper.registerModule(module);

And that's it when you call the reader from the mapper it should now parse the correct value of date string.

References:
http://stackoverflow.com/questions/6553051/setting-up-json-custom-deserializer
http://stackoverflow.com/questions/5106987/jax-ws-and-joda-time
http://www.baeldung.com/jackson-deserialization
http://stackoverflow.com/questions/21706415/jackson-objectmapper-using-custom-serializers-and-deserializers
http://blog.palominolabs.com/2012/06/05/writing-a-custom-jackson-serializer-and-deserializer/




- How To Read And Write Csv Using Jackson Library
The sample code below demonstrates how we can read a csv file into an array of objects. Also it writes an array of objects into csv. To use don't forget to include in your pom.xml <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId>...

- How To Display A Date With Textfield Click With Swift
Displaying Date with TextField Click with Swift First you must have a textfield connected to storyboard. @IBOutlet weak var txtField_helloDatePicker: UITextField! Next you should have a constant of UIDatePicker type. let datePicker...

- How To Encode And Decode A Json Encrypted String In Java
This tutorial requires the use of apache commons and jackson libraries. For example I have a highly confidential string and I want to send it over the net, of course normally I want to encrypt it. And one of the method we can send this encrypted string...

- Mssql Get The Date From Datetime
...

- C# Converting A Date To Timestamp And How To Create An Md5 Function
A always use these 2 methods so I'm gonna paste them here. I don't remember if I change some lines in these code but I'm sure I got them from Microsoft hmmm already forget about it. DateTime -> TimeStamp /// /// method for converting a System.DateTime...



Tech-Today








.