一 JACKSON 序列化相关
1 JACKSON序列化问题解决
最近使用了jackson json来格式化数据输出,但是反序列化生成对象的时候碰到点麻烦,jackson把数据默认解析成了Map对象,
经查询文档,问题解决,在ObjectMapper的readvalue方法中按Object所使用的类型声明即可,代码如下:
Map<Integer, RbtCounter> srcMap = new LinkedHashMap();
Map<Integer, RbtCounter> destMap;
String jsonData = mapper.writeValueAsString(srcMap);
正确:
destMap = mapper.readValue(jsonData, new TypeReference<Map<Integer, RbtCounter>>(){}); // 反序列化
TypeReference -- 让Jackson Json在List/Map中识别自己的Object
错误
destMap = mapper.readValue(jsonData, LinkedHashMap.class); List中的自定义Object同理解决。
2 未知属性异常
在使用的过程中,很有可能会遇到json反序列化的问题。当你对象中有get***()的地方,它就当做它是一个属性,所以当你序列化json之后,在反序列化的时候,很有可能会出现异常的情况,因为在你的model中没有这个***的定义。
那该如何处理和解决呢?
jackson给出了它自己的解决方案(JacksonHowToIgnoreUnknow):
1. 在class上添加忽略未知属性的声明:@JsonIgnoreProperties(ignoreUnknown=true)
2. 在反序列化中添加忽略未知属性解析,如下:
1 /** 2 * json deserialize 3 * @param json 4 * @param mapClazz 5 * @return 6 */ 7 public static Object jsonDeserialize(final String json, final Class<?> mapClazz) { 8 ObjectMapper om = new ObjectMapper(); 9 try { 10 // 忽略未知属性 11 om.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); 12 return om.readValue(json, mapClazz); 13 } catch (Exception ex) { 14 return null; 15 } 16 }
3. 添加"Any setter"来处理未知属性
1 // note: name does not matter; never auto-detected, need to annotate 2 // (also note that formal argument type #1 must be "String"; second one is usually 3 // "Object", but can be something else -- as long as JSON can be bound to that type) 4 @JsonAnySetter 5 public void handleUnknown(String key, Object value) { 6 // do something: put to a Map; log a warning, whatever 7 }
4. 注册问题处理句柄
注册一个DeserializationProblemHandler句柄,来调用ObjectMapper.addHandler()。当添加的时候,句柄的handleUnknownProperty方法可以在每一个未知属性上调用一次。
这个方法在你想要添加一个未知属性处理日志的时候非常有用:当属性不确定的时候,不会引起一个绑定属性的错误
demo 1
第一种:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class JsonToJavaBean { public static void main(String[] args) { String str= "{\"student\":[{\"name\":\"leilei\",\"age\":23},{\"name\":\"leilei02\",\"age\":23}]}" ; Student stu = null ; List<Student> list = null ; try { ObjectMapper objectMapper= new ObjectMapper(); StudentList studentList=objectMapper.readValue(str, StudentList. class ); list=studentList.getStudent(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } for (Student s:list){ System.out.println(s.getName()+ " " +s.getAge()); } }} |
第二种:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public static void main(String[] args) { ArrayList<Student> list= new ArrayList<Student>(); Student s1= new Student(); s1.setName( "leilei" ); s1.setAge( 23 ); Student s2= new Student(); s2.setName( "leilei02" ); s2.setAge( 23 ); list.add(s1); list.add(s2); StringWriter str= new StringWriter(); ObjectMapper objectMapper= new ObjectMapper(); try { objectMapper.writeValue(str, list); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(str); } |
demo 2
student的这list包含了若干对象,每个对象都有各自的属性值的。 应该是你说的提出来的意思吧2 基于protostuff的序列化
- 传统方式
按照传统的开发流程,都是如下:
1.先编写proto文件格式,例如
- message Person {
- required int32 id = 1;
- required string name = 2;
- optional string email = 3;
- }
2.运行编译程序,生成实体类Person.java
protoc --java_out=./src ./person.proto
3.在程序中可以直接使用Person类的相关函数进行序列化和反序列化
- //序列化
- Person person = builder.build();
- byte[] buf = person.toByteArray();
- //反序列化
- Person person2 = PersonProbuf.Person.parseFrom(buf);
实际上我们只是包含了3个变量而已,可读性大大降低了。其次,开发过程每次都得借助外部的编译工具来生成代码。
于是我们可能就有了一个简单的思路。自己编写Person的类,然后通过外部的api,直接对这个类进行序列化和反序列化。
直接抛弃了protoc工具。
这个思路,已经有人实现出来了,最早是在c#语言版本的protobuf-net实现了。它利用c#的Attribute(类似Java的Annotation注解)+反射来实现普通实体类的Protobuf序列化和
反序列化。
本想自己把protobuf-net的c#代码转换成Java代码。后来在OverStack中翻到有人介绍 Protostuff ,正是基于这种思路的。
- 改进版
- public class Person{
- public int id;
- public String name;
- public String email;
- }
2.测试序列化和反序列化
- public static void main(String[] args) throws IOException {
- // //类的模式设置为Person类
- Schema<Person> schema = RuntimeSchema.getSchema(Person.class);
- Person person1 = new Person();
- person1.id = 10086;
- person1.name = "ken";
- person1.email = "ken@iamcoding.com";
- // 缓存buff
- LinkedBuffer buffer = LinkedBuffer.allocate(1024);
- // 序列化成protobuf的二进制数据
- byte[] data = ProtobufIOUtil.toByteArray(person1, schema, buffer);
- // 反序列化
- Person person2 = new Person();
- ProtobufIOUtil.mergeFrom(data, person2, schema);
- System.out.println(person2.id);
- }
更多的功能可以去详细阅读相关的手册吧。比如,指定实体类字段的序列化顺序,忽略某些字段不被序列化等等。
- 性能考虑
具体的测试数据可以去查阅网上相关的数据,在此省略了。
- 总结
Protostuff的优势是将开发流程简化,让我们可以更高效,更专注地开发。
参考:http://blog.csdn.net/janeky/article/details/17151465
