As we all know, Jackson JSON is known for its speed, convenience and agility. The previous article described the use of annotations as a way to specify how to serialize an object to JSON and how to deserialize a JSON data onto an object. But the one thing that's in the ointment is the handling of Chinese. Of course I said it was a drawback. By default, the Jackson JSON does not convert non-ASCII characters such as Chinese to \uffff in such a way as to display. That is, the default is to show {"Name": "John"} instead of {"name": "\u5f20\u4e09"}. So why is there such a demand? In the HTTP protocol, we can specify the content encoding for the header portion of the data. such as: "GBK", "UTF-8" and so on. If you set the correct, then OK, the former represents the data you can handle correctly. However, if you set an error, the Chinese characters will be garbled. Two sets of application systems docking, it is possible to use the default encoding on both sides, if one side to modify the default encoding will have unpredictable consequences for the application. Therefore, if you can develop a long-term vision, then no matter what you set the encoding method, will not make the data generated garbled. Because, here is the universal code--unicode.
Well, the question is, how do we solve it? By experimenting, Jackson JSON actually has the ability to parse Unicode-encoded JSON data with the default settings. What is missing is the lack of steps to serialize the object. Fortunately, the Jackson JSON framework allows us to customize the serialization method. So we're going to write a serialization class:
Copy Code code as follows:
Import java.io.IOException;
Import org.codehaus.jackson.JsonGenerationException;
Import Org.codehaus.jackson.JsonGenerator;
Import org.codehaus.jackson.JsonProcessingException;
Import Org.codehaus.jackson.impl.JsonWriteContext;
Import Org.codehaus.jackson.map.JsonSerializer;
Import Org.codehaus.jackson.map.SerializerProvider;
Import Org.codehaus.jackson.util.CharTypes;
public class Stringunicodeserializer extends Jsonserializer<string> {
Private final char[] Hex_chars = "0123456789ABCDEF". ToCharArray ();
Private final int[] Escape_codes = Chartypes.get7bitoutputescapes ();
private void Writeunicodeescape (Jsongenerator gen, char c) throws IOException {
Gen.writeraw (' \ \ ');
Gen.writeraw (' u ');
Gen.writeraw (hex_chars[(c >>) & 0xF]);
Gen.writeraw (hex_chars[(c >> 8) & 0xF]);
Gen.writeraw (hex_chars[(c >> 4) & 0xF]);
Gen.writeraw (Hex_chars[c & 0xF]);
}
private void Writeshortescape (Jsongenerator gen, char c) throws IOException {
Gen.writeraw (' \ \ ');
Gen.writeraw (c);
}
@Override
public void serialize (String str, Jsongenerator Gen,
Serializerprovider provider) throws IOException,
jsonprocessingexception {
int status = ((Jsonwritecontext) Gen.getoutputcontext ()). WriteValue ();
Switch (status) {
Case Jsonwritecontext.status_ok_after_colon:
Gen.writeraw (': ');
Break
Case Jsonwritecontext.status_ok_after_comma:
Gen.writeraw (', ');
Break
Case Jsonwritecontext.status_expect_name:
throw new Jsongenerationexception ("Can not write String value here");
}
Gen.writeraw (' "); writes the opening quotation mark of a string in JSON
for (char C:str.tochararray ()) {
if (c >= 0x80) {
Writeunicodeescape (Gen, C); Generate escaped Unicode characters for all non-ASCII characters
}else {
Use escaped Unicode characters for the first 128 characters in the ASCII character
int code = (c < escape_codes.length?) Escape_codes[c]: 0);
if (code = = 0) {
Gen.writeraw (c); No escaping here
}else if (Code < 0) {
Writeunicodeescape (Gen, (char) (-code-1)); Universal Escape characters
}else {
Writeshortescape (Gen, (char) code); Short escape characters (\ n \ t ...)
}
}
}
Gen.writeraw (' "); write closing quotes for strings in JSON
}
}
This serialization class will use a method to handle string types in all places where Jackson JSON is used in the application. There is no way to light, but also to register it. Let Jackson json use the method that you just defined when serializing an object:
Copy Code code as follows:
if (objectmapper== null) {
Objectmapper= new Objectmapper ();
Ignore this field when the corresponding serializer cannot be found
Objectmapper.configure (SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
Enable Jackson JSON to support Unicode encoding non-ASCII characters
Customserializerfactory serializerfactory= new Customserializerfactory ();
Serializerfactory.addspecificmapping (String.class, New Stringunicodeserializer ());
Objectmapper.setserializerfactory (serializerfactory);
End of support
}
Next we'll do a test object and validate our code:
Copy Code code as follows:
Import Java.util.Date;
Import Net.csdn.blog.chaijunkun.util.DateDeserializer;
Import Net.csdn.blog.chaijunkun.util.DateSerializer;
Import Net.csdn.blog.chaijunkun.util.DateTimeDeserializer;
Import Net.csdn.blog.chaijunkun.util.DateTimeSerializer;
Import Org.codehaus.jackson.annotate.JsonPropertyOrder;
Import org.codehaus.jackson.map.annotate.JsonDeserialize;
Import org.codehaus.jackson.map.annotate.JsonSerialize;
@JsonPropertyOrder (alphabetic= false)
public class Demoobj {
Private Integer SID;
Private String Stuname;
Private Boolean sex;
@JsonSerialize (using= dateserializer.class)
@JsonDeserialize (using= datedeserializer.class)
Private Date birthday;
@JsonSerialize (using= datetimeserializer.class)
@JsonDeserialize (using= datetimedeserializer.class)
Private Date LogTime;
Getters and Setters
}
As you can see from the code, we do not force a string-type attribute to specify which sequence and inverse sequence method to use. Then we'll construct the test case:
Copy Code code as follows:
Import Java.text.SimpleDateFormat;
Import Java.util.Calendar;
Import Java.util.Date;
Import NET.CSDN.BLOG.CHAIJUNKUN.JSON.DEMOOBJ;
Import Net.csdn.blog.chaijunkun.util.JSONUtil;
Import Org.apache.log4j.Logger;
public class Jsontest {
private static Logger logger= Logger.getlogger (jsontest.class);
private static String json= "{\ sid\": 2,\ "stuname\": \ "\u6c5f\u5357style\", \ "sex\": True,\ "birthday\": \ "2012-07-15\" , \ "logtime\": \ "2012-12-04 19:22:36\"} ";
public static void Main (string[] args) {
Demoobj objsrc= new Demoobj ();
Objsrc.setsid (1);
Objsrc.setstuname ("Uncle Bird");
Objsrc.setsex (TRUE);
Calendar calendar= calendar.getinstance ();
Calendar.set (1977, Calendar.december, 31, 0, 0, 0);
Objsrc.setbirthday (Calendar.gettime ());
Objsrc.setlogtime (New Date ());
Logger.info (String.Format ("Data converted to JSON:%s", Jsonutil.tojson (OBJSRC)));
Demoobj objdes= Jsonutil.fromjson (JSON, demoobj.class);
if (objdes==null) {
Logger.info ("deserialization failed");
}else{
Logger.info ("deserialization succeeded");
SimpleDateFormat sdf= New SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss");
Logger.info (String.Format ("ID:%d", Objdes.getsid ());
Logger.info (String.Format ("Name:%s", Objdes.getstuname ()));
Logger.info (String.Format ("Sex:%s", Objdes.getsex () ==true?) Male ":" female "));
Logger.info (String.Format ("Birthday:%s", Sdf.format (Objdes.getbirthday ()));
Logger.info (String.Format ("Login Date:%s", Sdf.format (Objdes.getlogtime ()));
}
}
}
Look at the output:
Copy Code code as follows:
Data converted to JSON: {"Sid": 1, "Stuname": "\u9e1f\u53d4", "Sex": true, "Birthday": "1977-12-31", "LogTime": "2012-12-04 19:31:57 "}
Deserialization succeeded
ID: 2
Name: Jiangnan style
Sex: Male
Birthday: 2012-07-15 00:00:00
Login Date: 2012-12-04 19:22:36
We see that the Chinese character has been successfully displayed as a Unicode-encoded data. Similarly, the Unicode-encoded data we previously constructed was successfully displayed without any modifications.
Careful friend perhaps observed that in the object definition code for the test, we specified different serialization and deserialization methods for attributes "Birthday" and "logtime" of the same date type. Let's see what's different about these two:
Copy Code code as follows:
Import java.io.IOException;
Import Java.text.SimpleDateFormat;
Import Java.util.Date;
Import Org.codehaus.jackson.JsonGenerator;
Import org.codehaus.jackson.JsonProcessingException;
Import Org.codehaus.jackson.map.JsonSerializer;
Import Org.codehaus.jackson.map.SerializerProvider;
public class Datetimeserializer extends Jsonserializer<date> {
@Override
public void serialize (date date, Jsongenerator Gen, Serializerprovider provider)
Throws IOException, Jsonprocessingexception {
SimpleDateFormat sdf=new SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss");
String formatteddate= Sdf.format (date);
Gen.writestring (formatteddate);
}
}
Copy Code code as follows:
Import java.io.IOException;
Import Java.text.SimpleDateFormat;
Import Java.util.Calendar;
Import Java.util.Date;
Import Org.codehaus.jackson.JsonParser;
Import org.codehaus.jackson.JsonProcessingException;
Import Org.codehaus.jackson.map.DeserializationContext;
Import Org.codehaus.jackson.map.JsonDeserializer;
public class Datetimedeserializer extends Jsondeserializer<date> {
@Override
Public Date Deserialize (jsonparser parser, Deserializationcontext context)
Throws IOException, Jsonprocessingexception {
String dateformat= "Yyyy-mm-dd HH:mm:ss";
SimpleDateFormat sdf= New SimpleDateFormat (DateFormat);
try{
String fielddata= Parser.gettext ();
Return Sdf.parse (Fielddata);
}catch (Exception e) {
Calendar ca= calendar.getinstance ();
Ca.set (1970, Calendar.january, 1, 0, 0, 0);
return Ca.gettime ();
}
}
}
Copy Code code as follows:
Import java.io.IOException;
Import Java.text.SimpleDateFormat;
Import Java.util.Date;
Import Org.codehaus.jackson.JsonGenerator;
Import org.codehaus.jackson.JsonProcessingException;
Import Org.codehaus.jackson.map.JsonSerializer;
Import Org.codehaus.jackson.map.SerializerProvider;
public class Dateserializer extends Jsonserializer<date> {
@Override
public void serialize (date date, Jsongenerator Gen, Serializerprovider provider)
Throws IOException, Jsonprocessingexception {
SimpleDateFormat sdf=new SimpleDateFormat ("Yyyy-mm-dd");
String formatteddate= Sdf.format (date);
Gen.writestring (formatteddate);
}
}
Copy Code code as follows:
Import java.io.IOException;
Import Java.text.SimpleDateFormat;
Import Java.util.Calendar;
Import Java.util.Date;
Import Org.codehaus.jackson.JsonParser;
Import org.codehaus.jackson.JsonProcessingException;
Import Org.codehaus.jackson.map.DeserializationContext;
Import Org.codehaus.jackson.map.JsonDeserializer;
public class Datedeserializer extends Jsondeserializer<date> {
@Override
Public Date Deserialize (jsonparser parser, Deserializationcontext context)
Throws IOException, Jsonprocessingexception {
String dateformat= "YYYY-MM-DD";
SimpleDateFormat sdf= New SimpleDateFormat (DateFormat);
try{
String fielddata= Parser.gettext ();
Return Sdf.parse (Fielddata);
}catch (Exception e) {
Calendar ca= calendar.getinstance ();
Ca.set (1970, Calendar.january, 1, 0, 0, 0);
return Ca.gettime ();
}
}
}
From the code we can see that Datetimeserializer and Datetimedeserializer are more fine-grained than Dateserializer and Datedeserializer, adding properties of specific time. This is very common in the application development, the birthday message we often know the date of the year, and the landing time often need to be more detailed. From the example we can know that even the same type, through the development of different sequences and reverse sequence methods, we can flexibly get the data form we want. The above test cases have been packaged.
Click to download
Add:
There is a recent need to modify the data when serializing and deserializing objects, and to have the generated JSON display changed to "Tourist" when the data source value is found to be empty. But I'm anyway. Specifies that the serializer and the deserialization are not valid. The program simply does not go to the specified code. And then I came to the conclusion that Jackson JSON, when deserializing the object, if the corresponding property in the JSON data is null, the custom deserialization does not go; Similarly, when you set a property value of an object to NULL, you do not go to the custom serializer when serializing it to JSON. So if you have a similar requirement, you can make a hard code decision and modify it before serializing and deserializing, and don't expect anything from the serializer to the deserialization.