GVKun编程网logo

使用Jackson来实现Java对象与JSON的相互转换的教程(jackson的json和java的转换)

13

最近很多小伙伴都在问使用Jackson来实现Java对象与JSON的相互转换的教程和jackson的json和java的转换这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展Fast

最近很多小伙伴都在问使用Jackson来实现Java对象与JSON的相互转换的教程jackson的json和java的转换这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展FastJson、Jackson、Gson进行Java对象转换Json的细节处理、GSON实现Java对象与JSON格式对象相互转换的完全教程、Gson案例:Java对象与JSON字符串相互转换、Gson详解:Java对象与JSON相互转换的利器等相关知识,下面开始了哦!

本文目录一览:

使用Jackson来实现Java对象与JSON的相互转换的教程(jackson的json和java的转换)

使用Jackson来实现Java对象与JSON的相互转换的教程(jackson的json和java的转换)

一、入门
Jackson中有个ObjectMapper类很是实用,用于Java对象与JSON的互换。
1.JAVA对象转JSON[JSON序列化]

import java.io.IOException; 
import java.text.ParseException; 
import java.text.SimpleDateFormat; 
 
import com.fasterxml.jackson.databind.ObjectMapper; 
 
public class JacksonDemo { 
  public static void main(String[] args) throws ParseException,IOException { 
    User user = new User(); 
    user.setName("小民");  
    user.setEmail("xiaomin@sina.com"); 
    user.setAge(20); 
     
    SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd"); 
    user.setBirthday(dateformat.parse("1996-10-01"));     
     
    /** 
     * ObjectMapper是JSON操作的核心,Jackson的所有JSON操作都是在ObjectMapper中实现。 
     * ObjectMapper有多个JSON序列化的方法,可以把JSON字符串保存File、OutputStream等不同的介质中。 
     * writeValue(File arg0,Object arg1)把arg1转成json序列,并保存到arg0文件中。 
     * writeValue(OutputStream arg0,Object arg1)把arg1转成json序列,并保存到arg0输出流中。 
     * writeValueAsBytes(Object arg0)把arg0转成json序列,并把结果输出成字节数组。 
     * writeValueAsstring(Object arg0)把arg0转成json序列,并把结果输出成字符串。 
     */ 
    ObjectMapper mapper = new ObjectMapper(); 
     
    //User类转JSON 
    //输出结果:{"name":"小民","age":20,"birthday":844099200000,"email":"xiaomin@sina.com"} 
    String json = mapper.writeValueAsstring(user); 
    System.out.println(json); 
     
    //Java集合转JSON 
    //输出结果:[{"name":"小民","email":"xiaomin@sina.com"}] 
    List<User> users = new ArrayList<User>(); 
    users.add(user); 
    String jsonlist = mapper.writeValueAsstring(users); 
    System.out.println(jsonlist); 
  } 
} 

2.JSON转java类[JSON反序列化]

import java.io.IOException; 
import java.text.ParseException; 
import com.fasterxml.jackson.databind.ObjectMapper; 
 
public class JacksonDemo { 
  public static void main(String[] args) throws ParseException,IOException { 
    String json = "{\"name\":\"小民\",\"age\":20,\"birthday\":844099200000,\"email\":\"xiaomin@sina.com\"}"; 
     
    /** 
     * ObjectMapper支持从byte[]、File、InputStream、字符串等数据的JSON反序列化。 
     */ 
    ObjectMapper mapper = new ObjectMapper(); 
    User user = mapper.readValue(json,User.class); 
    System.out.println(user); 
  } 
} 

 
二、Jackson支持3种使用方式:
1、Data Binding:最方便使用.
(1)Full Data Binding:

private static final String MODEL_BINDING = "{\"name\":\"name1\",\"type\":1}"; 
  public void fullDataBinding() throws Exception{ 
    ObjectMapper mapper = new ObjectMapper(); 
    Model user = mapper.readValue(MODEL_BINDING,Model.class);//readValue到一个实体类中. 
    System.out.println(user.getName()); 
    System.out.println(user.getType()); 
  } 

Model类:

private static class Model{ 
    private String name; 
    private int type; 
     
    public String getName() { 
      return name; 
    } 
    public void setName(String name) { 
      this.name = name; 
    } 
    public int getType() { 
      return type; 
    } 
    public void setType(int type) { 
      this.type = type; 
    } 
  } 

(2)Raw Data Binding:

/** 
  Concrete Java types that Jackson will use for simple data binding are: 
  JSON Type    Java Type 
  object     LinkedHashMap<String,Object> 
  array      ArrayList<Object> 
  string     String 
  number(no fraction) Integer,Long or BigInteger (smallest applicable) 
  number(fraction)  Double(configurable to use BigDecimal) 
  true|false   Boolean 
  null      null 
  */ 
  public void rawDataBinding() throws Exception{ 
    ObjectMapper mapper = new ObjectMapper(); 
    HashMap map = mapper.readValue(MODEL_BINDING,HashMap.class);//readValue到一个原始数据类型. 
    System.out.println(map.get("name")); 
    System.out.println(map.get("type")); 
  } 

 (3)generic Data Binding:

private static final String GENERIC_BINDING = "{\"key1\":{\"name\":\"name2\",\"type\":2},\"key2\":{\"name\":\"name3\",\"type\":3}}"; 
  public void genericDataBinding() throws Exception{ 
    ObjectMapper mapper = new ObjectMapper(); 
    HashMap<String,Model> modelMap = mapper.readValue(GENERIC_BINDING,new TypeReference<HashMap<String,Model>>(){});//readValue到一个范型数据中. 
    Model model = modelMap.get("key2"); 
    System.out.println(model.getName()); 
    System.out.println(model.getType()); 
  } 

2、Tree Model:最灵活。

private static final String TREE_MODEL_BINDING = "{\"treekey1\":\"treevalue1\",\"treekey2\":\"treevalue2\",\"children\":[{\"childkey1\":\"childkey1\"}]}"; 
  public void treeModelBinding() throws Exception{ 
    ObjectMapper mapper = new ObjectMapper(); 
    JsonNode rootNode = mapper.readTree(TREE_MODEL_BINDING); 
    //path与get作用相同,但是当找不到该节点的时候,返回missing node而不是Null. 
    String treekey2value = rootNode.path("treekey2").getTextValue();// 
    System.out.println("treekey2value:" + treekey2value); 
    JsonNode childrenNode = rootNode.path("children"); 
    String childkey1Value = childrenNode.get(0).path("childkey1").getTextValue(); 
    System.out.println("childkey1Value:"+childkey1Value); 
     
    //创建根节点 
    ObjectNode root = mapper.createObjectNode(); 
    //创建子节点1 
    ObjectNode node1 = mapper.createObjectNode(); 
    node1.put("nodekey1",1); 
    node1.put("nodekey2",2); 
    //绑定子节点1 
    root.put("child",node1); 
    //数组节点 
    ArrayNode arrayNode = mapper.createArrayNode(); 
    arrayNode.add(node1); 
    arrayNode.add(1); 
    //绑定数组节点 
    root.put("arraynode",arrayNode); 
    //JSON读到树节点 
    JsonNode valuetoTreeNode = mapper.valuetoTree(TREE_MODEL_BINDING); 
    //绑定JSON节点 
    root.put("valuetotreenode",valuetoTreeNode); 
    //JSON绑定到JSON节点对象 
    JsonNode bindJsonNode = mapper.readValue(GENERIC_BINDING,JsonNode.class);//绑定JSON到JSON节点对象. 
    //绑定JSON节点 
    root.put("bindJsonNode",bindJsonNode); 
    System.out.println(mapper.writeValueAsstring(root)); 
  } 

3、Streaming API:最佳性能。
 
对于性能要求高的程序,推荐使用流API,否则使用其他方法
不管是创建JsonGenerator还是JsonParser,都是使用JsonFactory。

package com.jingshou.jackson; 
 
import java.io.File; 
import java.io.IOException; 
 
import com.fasterxml.jackson.core.JsonEncoding; 
import com.fasterxml.jackson.core.JsonFactory; 
import com.fasterxml.jackson.core.JsonGenerator; 
import com.fasterxml.jackson.core.JsonParser; 
import com.fasterxml.jackson.core.JsonToken; 
 
public class JacksonTest6 { 
 
  public static void main(String[] args) throws IOException { 
    JsonFactory jfactory = new JsonFactory(); 
      
    /*** write to file ***/ 
    JsonGenerator jGenerator = jfactory.createGenerator(new File( 
        "c:\\user.json"),JsonEncoding.UTF8); 
    jGenerator.writeStartObject(); // { 
    
    jGenerator.writeStringField("name","mkyong"); // "name" : "mkyong" 
    jGenerator.writeNumberField("age",29); // "age" : 29 
    
    jGenerator.writeFieldName("messages"); // "messages" : 
    jGenerator.writeStartArray(); // [ 
    
    jGenerator.writeString("msg 1"); // "msg 1" 
    jGenerator.writeString("msg 2"); // "msg 2" 
    jGenerator.writeString("msg 3"); // "msg 3" 
    
    jGenerator.writeEndarray(); // ] 
    
    jGenerator.writeEndobject(); // } 
    jGenerator.close(); 
     
    /*** read from file ***/ 
    JsonParser jParser = jfactory.createParser(new File("c:\\user.json")); 
    // loop until token equal to "}" 
    while (jParser.nextToken() != JsonToken.END_OBJECT) { 
    
      String fieldname = jParser.getCurrentName(); 
      if ("name".equals(fieldname)) { 
    
       // current token is "name",// move to next,which is "name"'s value 
       jParser.nextToken(); 
       System.out.println(jParser.getText()); // display mkyong 
    
      } 
    
      if ("age".equals(fieldname)) { 
    
       // current token is "age",which is "name"'s value 
       jParser.nextToken(); 
       System.out.println(jParser.getIntValue()); // display 29 
    
      } 
    
      if ("messages".equals(fieldname)) { 
    
       jParser.nextToken(); // current token is "[",move next 
    
       // messages is array,loop until token equal to "]" 
       while (jParser.nextToken() != JsonToken.END_ARRAY) { 
    
             // display msg1,msg2,msg3 
         System.out.println(jParser.getText());  
    
       } 
    
      } 
    
     } 
     jParser.close(); 
 
  } 
 
} 

FastJson、Jackson、Gson进行Java对象转换Json的细节处理

FastJson、Jackson、Gson进行Java对象转换Json的细节处理

转 https://blog.csdn.net/moneyshi/article/details/51830329

Java对象转换Json的细节处理

前言

Java对象在转json的时候,如果对象里面有属性值为null的话,那么在json序列化的时候要不要序列出来呢?对比以下json转换方式

一、fastJson

1、fastJson在转换java对象为json的时候,默认是不序列化null值对应的key的

也就是说当对象里面的属性为空的时候,在转换成json时,不序列化那些为null值的属性
 
具体案例如下:
AutopartsSearchRequest 有以下属性:

分享图片

 
  1. public static void main(String[] args) {
  2. AutopartsSearchRequest request = new AutopartsSearchRequest();
  3. request.setKeywords( "123");
  4. request.setSortingField( "234242");
  5. String str = JSONObject.toJSONString(request); //fastjson默认转换是不序列化null值对应的key的
  6. System.out.println(str);
  7. }

输出结果:{"keywords":"123","sortingField":"234242"}  , 没有序列化那些值为null的属性
 

2、但是如果想把null对应的key序列化出来呢? 

那就要仔细看看fastjson转换java对象为json的时候的入参了:也就是这个方法:
 
JSONObject.toJSONString(Object object,SerializerFeature... features)

Fastjson的SerializerFeature序列化属性:


 
  1. QuoteFieldNames———-输出key时是否使用双引号,默认为 true
  2. WriteMapNullValue——–是否输出值为 null的字段,默认为false
  3. WriteNullNumberAsZero—-数值字段如果为 null,输出为0,而非null
  4. WriteNullListAsEmpty—–List字段如果为 null,输出为[],而非null
  5. WriteNullStringAsEmpty—字符类型字段如果为 null,输出为”“,而非null
  6. WriteNullBooleanAsFalse– Boolean字段如果为null,输出为false,而非null
 
结合上面,SerializerFeature... features是个数组,那么我们可以传入我们想要的参数,比如想序列化null,案例如下:
  1. public static void main(String[] args) {
  2. AutopartsSearchRequest request = new AutopartsSearchRequest();
  3. request.setKeywords( "123");
  4. request.setSortingField( "234242");
  5. String str = JSONObject.toJSONString(request,SerializerFeature.WriteMapNullValue);
  6. System.out.println(str);
  7. }

输出结果如下:
 

分享图片

 

3、想字符类型字段如果为null,转换输出为”“,而非null ,需要多加一个参数:WriteNullStringAsEmpty, 案例如下:

 
  1. public static void main(String[] args) {
  2. AutopartsSearchRequest request = new AutopartsSearchRequest();
  3. request.setKeywords( "123");
  4. request.setSortingField( "234242");
  5. String str = JSONObject.toJSONString(request,SerializerFeature.WriteMapNullValue,
  6. SerializerFeature.WriteNullStringAsEmpty);
  7. System.out.println(str);
  8. }

输出结果如下:
 
 

分享图片

 
 
 
 

二、Jackson

 

1、jackson默认是序列化null对应的key的,也就是说不管你对象属性有没有值,在转换json的时候都会被序列化出来

  1. public static void main(String[] args) throws JsonGenerationException,JsonMappingException,IOException {
  2. AutopartsSearchRequest request = new AutopartsSearchRequest();
  3. request.setKeywords( "123");
  4. request.setSortingField( "234242");
  5. ObjectMapper mapper = new ObjectMapper();
  6. String str = mapper.writeValueAsstring(request);
  7. System.out.println(str);
  8. //输出结果(此处就不格式化了):{"sortingField":"234242","partsClassifyId":null,"partsSubClassifyId":null,"sortingDirection":null:......
  9. }

 

2、同理,想要不序列化null也是可以的,具体如下:

  1. 1.实体上
  2.  
  3. @JsonInclude(Include.NON_NULL)
  4.  
  5. //将该标记放在属性上,如果该属性为NULL则不参与序列化
  6. //如果放在类上边,那对这个类的全部属性起作用
  7. //Include.Include.ALWAYS 默认
  8. //Include.NON_DEFAULT 属性为默认值不序列化
  9. //Include.NON_EMPTY 属性为 空(“”) 或者为 NULL 都不序列化
  10. //Include.NON_NULL 属性为NULL 不序列化
  11.  
  12.  
  13. 2.代码上
  14. ObjectMapper mapper = new ObjectMapper();
  15.  
  16. mapper.setSerializationInclusion(Include.NON_NULL);
  17.  
  18. //通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
  19. //Include.Include.ALWAYS 默认
  20. //Include.NON_DEFAULT 属性为默认值不序列化
  21. //Include.NON_EMPTY 属性为 空(“”) 或者为 NULL 都不序列化
  22. //Include.NON_NULL 属性为NULL 不序列化


注意:只对VO起作用,Map List不起作用,另外jackson还能过滤掉你设置的属性,具体的就各位自己去研究源码了

或者参照: jackson详解

 
 

三、Gson


1、gson和fastjson一样,默认是不序列化null值对应的key的,具体案例如下:

 
  1. public static void main(String[] args) throws JsonGenerationException,IOException {
  2. AutopartsSearchRequest request = new AutopartsSearchRequest();
  3. request.setKeywords( "123");
  4. request.setSortingField( "234242");
  5. Gson g = new GsonBuilder().create();
  6. String str = g.toJson(request);
  7. System.out.println(str);
  8. //输出结果:{"sortingField":"234242","keywords":"123"}
  9. }


2、若是想序列化null值对应的key,只需要将以上创建代码改成以下代码就行:

Gson g = new GsonBuilder().serializeNulls().create();
 
案例就不写了

 

3、若是想转行null为空字符串"",则需要手动处理了

 
具体参考: gson转换null为空字符串

GSON实现Java对象与JSON格式对象相互转换的完全教程

GSON实现Java对象与JSON格式对象相互转换的完全教程

Gson是一个Java库,用来实现Json和Java对象之间的相互转换。Gson是一个托管在https://github.com/google/gson的开源项目。

Gson中主要的类是Gson,也可以使用类GsonBuilder在创建Gson对象的同时设置一些选项。
Gson对象在处理Json时不会保存任何状态,所以使用者能够很轻松的对同一个Gson对象进行多次序列化、反序列化等操作。

示例:基本使用

//Serialization
Gson gson = new Gson();
gson.toJson(1);   //==> prints 1
gson.toJson("abcd");  //==> prints "abcd"
gson.toJson(new Long(10)); //==> prints 10
int[] values = { 1 };
gson.toJson(values);  //==> prints [1]

//Deserialization
int one = gson.fromJson("1",int.class);
Integer one = gson.fromJson("1",Integer.class);
Long one = gson.fromJson("1",Long.class);
Boolean f = gson.fromJson("false",Boolean.class);
String str = gson.fromJson("\"abc\"",String.class);
String anotherStr = gson.fromJson("[\"abc\"]",String.class);

//Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj); 
//==> json is {"value1":1,"value2":"abc"}

示例:对象与Json之间转换

定义BagOfPrimitives类:

class BagOfPrimitives {
 private int value1 = 1;
 private String value2 = "abc";
 private transient int value3 = 3;
 BagOfPrimitives() {
 // no-args constructor
 }
}

序列化为Json:

//Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj); 
//==> json is {"value1":1,"value2":"abc"}

不要序列化含有循环引用的对象,否则会造成无限的递归。

反序列化:

//Deserialization
BagOfPrimitives obj2 = gson.fromJson(json,BagOfPrimitives.class); 
//==> obj2 is just like obj

处理对象时的一些细节:

  • 推荐使用私有字段(译者:可以通过反射获取私有字段的名称和值)
  • 没有必要使用标注指明哪些字段该被序列化或者反序列化。在当前类(也包括其父类)中的所有字段都默认会被序列化/反序列化。
  • 如果某字段在声明时使用了关键字transient,默认情况下不会被序列化/反序列化。
  • Gson如下处理null字段:
  • 序列化时候null字段会被跳过
  • 反序列化时,类中有但Json中没有的字段将设值为null。
  • synthetic字段不会被序列化/反序列化。
  • 在外部类(outer classes)中的内部类(inner classes)、匿名类(anonymous classes)和局部类(local classes)中的字段不会被序列化/反序列化。

嵌套类(包括内部类)的处理

Gson可以很轻松地序列化嵌套类,且能够反序列化静态的嵌套类。Gson无法自动地反序列化纯粹的内部类,是因为内部类的无参构造函数需要引用包含它的对象(即外部类的实例)。要反序列化静态类,可以将内部类静态化或者提供一个自定义的实例创造器(instance creator)。下面是一个示例:

public class A {
 public String a;

 class B {

 public String b;

 public B() {
  // No args constructor for B
 }
 }
}

上面的类B无法被Gson序列化。由于类B是一个(非静态的)内部类,Gson也无法反序列化{"b":"abc"}到类B的实例中。如果B被声明为static class B,那么Gson就能对这个字符串反序列化了。

另外一个解决方法是为B写一个实例创建器:

public class InstanceCreatorForB implements InstanceCreator<A.B> {
 private final A a;
 public InstanceCreatorForB(A a) {
 this.a = a;
 }
 public A.B createInstance(Type type) {
 return a.new B();
 }
}

这种方法是可行的,但是不推荐。(译者表示没看懂这个实例创建器,不知道该怎么用)

示例:数组

Gson gson = new Gson();
int[] ints = {1,2,3,4,5};
String[] strings = {"abc","def","ghi"};

//Serialization
gson.toJson(ints);  ==> prints [1,5]
gson.toJson(strings); ==> prints ["abc","ghi"]

//Deserialization
int[] ints2 = gson.fromJson("[1,5]",int[].class);
==> ints2 will be same as ints

Gson也支持具有复杂数据类型的多维数组。

示例:集合(Collection)

Gson gson = new Gson();
Collection<Integer> ints = Lists.immutableList(1,5);

//Serialization
String json = gson.toJson(ints); //==> json is [1,5]

//Deserialization
Type collectionType = new Typetoken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json,collectionType);
//ints2 is same as ints

处理集合(Collection)时的限制:

  • 可以序列化任意对象的集合,反序列化就不行了。
  • 反序列化时,集合必须是指定的泛型。

序列化/反序列化泛型

当使用toJson(obj)时,Gson调用obj.getClass()获取字段信息以在序列化中使用。类似的,也可以将对象MyClass.class作为参数传递给fromJson(json,MyClass.class)方法,这可以在在对象不是泛型的时候使用。不过,当对象是一个泛型类型的对象,由于Java中类型擦除(Type Erasure)这一机制,泛型类型信息会丢失。下面的例子将说明这一点:

class Foo<T> {
 T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly

gson.fromJson(json,foo.getClass()); // Fails to deserialize foo.value as Bar

上面的代码将value解释为Bar类型,这是因为Gson调用foo.getClass()获取类的信息,但是这种那个方法返回的是一个原始的类,即Foo.class。这意味着Gson无法知道这是一个Foo<Bar>类型的对象。

要解决这个问题,可以是为你的泛型指定正确的参数化的类型。可以使用Typetoken类做到:

Type fooType = new Typetoken<Foo<Bar>>() {}.getType();
gson.toJson(foo,fooType);
gson.fromJson(json,fooType);

fooType实际上定义了一个匿名的内部类,这个内部类含有一个可以返回全部参数化类型的gettype()方法。

序列化/反序列化含有任意类型的对象的集合

有时候处理的JSON包含了混合的类型,例如:

['hello',5,{name:'GREETINGS',source:'guest'}]

对应的集合应该是:

Collection collection = new ArrayList();
collection.add("hello");
collection.add(5);
collection.add(new Event("GREETINGS","guest"));

其中的Event类如下定义:

class Event {
 private String name;
 private String source;
 private Event(String name,String source) {
 this.name = name;
 this.source = source;
 }
}

通过Gson,你不需要做任何特殊的事情就可以序列化集合:toJson(collection)会输出令人满意的结果。

然而,通过fromJson(json,Collection.class)反序列化是不行的,这是因为Gson无法将json中的的内容与类型对应起来。Gson需要你在fromJson中提供一个通用版本的集合类型。你有三个选择:

方案1:使用Gson解析器的API(低级的流解析器或者DOM解析器JsonParser)去解析数组元素,然后使用Gson.fromJson()处理每一个数组元素。这是首选的方案。
方案2:为Collection.class注册一类型适配器将数组中的元素映射到合适的对象。这种方法的缺点是会使你在处理其他的集合类型时候产生不便。
方案3:为MyCollectionMemberType注册一个类型适配器,在fromJson中使用Collection<MyCollectionMemberType>。只有当数组看起来像一个高级的元素或者你能够将字段类型改成Collection<MyCollectionMemberType>,这种方法才比较可行。
内置的序列化/反序列化器

Gson为常用的但是默认表示可能并不合适的类提供了序列化/反序列化器。
下面是这些类的一个列表:

  • java.net.URL,例如会序列化为字符串 http://code.google.com/p/google-gson/
  • java.net.URI,例如会序列化为字符串/p/google-gson/

自定义序列化/反序列化

有时候,Gson的默认实现并不是你想要的,这在处理一些类库时(例如DateTime)时比较常见。

Gson允许你注册自定义的序列化/反序列化器。要这样做的话,你需要实现以下几个部分:

Json序列化器:需要为一个对象自定义序列化
Json反序列化器:需要为一个类型自定义反序列化
类创建器:如果存在无参构造函数或者已经注册了一个反序列化器,就不需要了。

GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(MyType2.class,new MyTypeAdapter());
gson.registerTypeAdapter(MyType.class,new MySerializer());
gson.registerTypeAdapter(MyType.class,new MyDeserializer());
gson.registerTypeAdapter(MyType.class,new MyInstanceCreator());

registerTypeAdapter会检查类型适配器是否实现了多个接口,并为这些接口注册类型适配器。

写一个序列化器

下面是一个为DateTime自定义序列化器的示例:

private class DateTimeSerializer implements JsonSerializer<DateTime> {
 public JsonElement serialize(DateTime src,Type typeOfSrc,JsonSerializationContext context) {
 return new JsonPrimitive(src.toString());
 }
}

Gson在序列化DateTime实例时会调用toJson()。

写一个反序列化器

下面的示例是讲如何写一个DateTime类的反序列化器:

private class DateTimeDeserializer implements JsonDeserializer<DateTime> {
 public DateTime deserialize(JsonElement json,Type typeOfT,JsonDeserializationContext context)
  throws JsonParseException {
 return new DateTime(json.getAsJsonPrimitive().getAsstring());
 }
}

当Gson需要将一个JSON字符串发反序列化为DateTime对象时,会调用 fromJson()。

对于序列化器/反序列化器,应注意:

  • 很多情况下,你想要注册一个处理程序将泛型与一个原始类型对应起来,
  • 例如,假如你有一个叫做Id的类来表示和转换Id
  • Id<T>类型中,所有的泛型拥有相同的序列化器,这个序列化器就是输出id的值
  • 反序列化器很像,但并不会完全一样。例如要返回一个Id<T>对象,需要调用new Id(Class<T>,String)。
  • Gson支持注册一个处理程序,你也可以为指定的泛型注册指定的处理程序。toJson和fromJson的Type参数包含了泛型信息以帮助你写出一个可以将所有的泛型与同一个原始类型对应起来的处理程序。

写一个实例创建器

在反序列化一个对象时,Gson需要创建一个类的实例。在序列化/反序列化时具有良好表现的类是指这个类拥有一个无参构造函数。通常,当处理一个类库中没有无参构造函数的类时,需要使用实例创建器。

实例创建器示例:

private class MoneyInstanceCreator implements InstanceCreator<Money> {
 public Money createInstance(Type type) {
 return new Money("1000000",CurrencyCode.USD);
 }
}

参数化类型的实例创建器

有时候要实例化的类型会是一个参数化类型。总的来说,由于真正的实例是一个原始类型,所以这不是什么问题。下面是一个示例:

class MyList<T> extends ArrayList<T> {
}

class MyListInstanceCreator implements InstanceCreator<MyList<?>> {
 @SuppressWarnings("unchecked")
 public MyList<?> createInstance(Type type) {
 // No need to use a parameterized list since the actual instance will have the raw type anyway.
 return new MyList();
 }
}

不过,有时你需要基于真正的参数化类型来创建实例。在这种情况下,你可以将类型参数传递给createInstance方法。下面是一个例子:

public class Id<T> {
 private final Class<T> classOfId;
 private final long value;
 public Id(Class<T> classOfId,long value) {
 this.classOfId = classOfId;
 this.value = value;
 }
}

class IdInstanceCreator implements InstanceCreator<Id<?>> {
 public Id<?> createInstance(Type type) {
 Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments();
 Type idType = typeParameters[0]; // Id has only one parameterized type T
 return Id.get((Class)idType,0L);
 }
}

在上面的示例中,如果没有将真正的类型传递给参数化类型,Id类的实例是无法创建的。通过给方法传递参数type,我们才得以解决这个问题。这里,type对象可以看做是Id<Foo>的Java参数化类型的表示,相应的实例应该被绑定到Id<Foo>。由于类Id只有一个参数化类型的参数T,我们使用getActualTypeArgument()返回的类型数组的第0个元素,在这个例子中就是Foo.class。

紧凑的输出 VS 优美的输出

Gson中Json默认的输出是紧凑的JSON格式。也就是说在JSON中没有多余的空白符。所以在JSON的输出中字段名和字段值之间、字段之间、数组元素之间是没有空白的。另外,null字段不会被输出(注意:在集合和数组对象中null会被保留的)。

如果要输出的优美些,你需要使用GsonBuilder对Gson的实例进行配置。JsonFormatter不存在于公有API中,所以客户端无法配置默认的输出设置。现在我们只提供了JsonPrintFormatter,其默认情况下每行80个字符,缩进使用2个字符,右边距是4个字符。

下面的示例展示了如何让Gson实例使用JsonPrintFormatter,而不是使用默认的JsonCompactFormatter。

Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(someObject);

空对象

在Gson的默认实现中,null对象是被忽略的。这可以让输出格式(既可以认为是序列化的结果)更加紧密;不过客户端必须为其定义一个默认的值,以使得JSON能够正常的反序列化。

如果要让Gson实例可以序列化null,可以:

Gson gson = new GsonBuilder().serializeNulls().create();

注意,当序列化null的时,会在JsonElement结构中添加一个JsonNull元素。因此,我们可以可以在自定义的序列化器/反序列化器中使用这个对象(gson)。

下面是一个例子:

public class Foo {
 private final String s;
 private final int i;

 public Foo() {
 this(null,5);
 }

 public Foo(String s,int i) {
 this.s = s;
 this.i = i;
 }
}

Gson gson = new GsonBuilder().serializeNulls().create();
Foo foo = new Foo();
String json = gson.toJson(foo);
System.out.println(json);

json = gson.toJson(null);
System.out.println(json);

输出:

{"s":null,"i":5}
null

版本支持

可以使用@Since标注来维护同一个对象的多个版本。这个标注可以用在类和字段上,将来也会支持用在方法上。为了使用这个特性,你需要配置Gson实例,让其忽略大于某个版本号的字段和对象。如果没有在Gson对象中设置版本,序列化/反序列化时会使用所有的字段和类。

public class VersionedClass {
 @Since(1.1) private final String newerField;
 @Since(1.0) private final String newField;
 private final String field;

 public VersionedClass() {
 this.newerField = "newer";
 this.newField = "new";
 this.field = "old";
 }
}

VersionedClass versionedobject = new VersionedClass();
Gson gson = new GsonBuilder().setVersion(1.0).create();
String jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);
System.out.println();

gson = new Gson();
jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);

输出:

{"newField":"new","field":"old"}

{"newerField":"newer","newField":"new","field":"old"}

从序列化/反序列化中排除字段

Gson支持使用很多方法来去除类、字段、字段类型。如果下面的方法无法满足你的需求,可以使用自定义序列化/反序列化器的方法。

1.Java Modifier Exclusion

默认情况下,如果将一个字段声明为transient,这个字段就会被排除。另外,如果一个字段被声明为static,默认情况下这个字段也会被排除。如果要包含某些声明为transient的字段,你可以这样做:

import java.lang.reflect.Modifier;

Gson gson = new GsonBuilder()
 .excludeFieldsWithModifiers(Modifier.STATIC)
 .create();

注意,在excludeFieldsWithModifiers方法中,你可以使用任意数量的Modifier常量。例如:

Gson gson = new GsonBuilder()
 .excludeFieldsWithModifiers(Modifier.STATIC,Modifier.TRANSIENT,Modifier.VOLATILE)
 .create();

2.使用@Expose字段排除

这个特性允许你在类中标记特定的字段使其在序列化/反序列化中不被排除/被排除。要使用这个标注,你应该使用new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()创建Gson。Gson实例会排除类中所有没被@Expose标注的字段。

3.用户定义排除策略

如果上面的排除方法无法满足需求,你也可以自定义自己的排除策略。更多内容,可以参考ExclusionStrategy JavaDoc。

下面的例子展示了如何排除使用了@Foo标注的字段,排除String类的顶级类型或者声明的字段类型:

 

@Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.FIELD})
 public @interface Foo {
 // Field tag only annotation
 }

 public class SampleObjectForTest {
 @Foo private final int annotatedField;
 private final String stringField;
 private final long longField;
 private final Class<?> clazzField;

 public SampleObjectFortest() {
  annotatedField = 5;
  stringField = "someDefaultValue";
  longField = 1234;
 }
 }

 public class MyExclusionStrategy implements ExclusionStrategy {
 private final Class<?> typetoSkip;

 private MyExclusionStrategy(Class<?> typetoSkip) {
  this.typetoSkip = typetoSkip;
 }

 public boolean shouldSkipClass(Class<?> clazz) {
  return (clazz == typetoSkip);
 }

 public boolean shouldSkipField(FieldAttributes f) {
  return f.getAnnotation(Foo.class) != null;
 }
 }

 public static void main(String[] args) {
 Gson gson = new GsonBuilder()
  .setExclusionStrategies(new MyExclusionStrategy(String.class))
  .serializeNulls()
  .create();
 SampleObjectForTest src = new SampleObjectFortest();
 String json = gson.toJson(src);
 System.out.println(json);
 }

输出:

{"longField":1234}

JSON字段命名的支持

Gson的一些预定义的字段命名策略,可以将标准的Java字段名称(也就是驼峰命名法,例如sampleFieldNameInJava)转换成一个Json的字段名(也就是sample_field_name_in_java或者SampleFieldNameInJava)。更多信息,可以参考FieldNamingPolicy。

Gson也有一个基于标注的策略让客户端自定义字段的名称。这个策略下,如果提供了一个非法的字段名作为标注的值,会使Gson抛出Runtime异常。

下面的示例展示了如何使用这两种Gson命名策略:

private class SomeObject {
 @Serializedname("custom_naming") private final String someField;
 private final String someOtherField;

 public SomeObject(String a,String b) {
 this.someField = a;
 this.someOtherField = b;
 }
}

SomeObject someObject = new SomeObject("first","second");
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
String jsonRepresentation = gson.toJson(someObject);
System.out.println(jsonRepresentation);

输出:

{"custom_naming":"first","SomeOtherField":"second"}

如果要自定义名称,可以使用@Serializedname标注。

在序列化器和反序列化器之间共享状态

有时你会需要在序列化器和反序列化器之间共享状态,你可以使用下面的三个方法达到目的:

  • 在一个静态字段中存储共享状态
  • 将序列化/反序列化器声明为一个父类型的内部类,然后使用父类型的实例的字段存储共享状态
  • 使用Java中的ThreadLocal

前两种方法不是线程安全的,第三种是。


GSON解析null出错解决办法
GSON有一个缺点就是无法设置null替换,
我们只能手动的批量替换服务器返回的null了,正常的接口定义的时候是绝对不允许服务器返回null的,后台结果却总会出现null!
如果搜索的话有一个常见的答案,

Gson gson = new GsonBuilder().serializeNulls().create();

但是这个却无法解决反序列问题,怎么解决呢?
解决办法如下:

Gson gson = new GsonBuilder().registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory()).create();
//然后用上面一行写的gson来序列化和反序列化实体类type
gson.fromJson(json,type);
gson.toJson(type);
//NullStringToEmptyAdapterFactory的代码

public class NullStringToEmptyAdapterFactory<T> implements TypeAdapterFactory {
 @SuppressWarnings("unchecked")
 public <T> TypeAdapter<T> create(Gson gson,Typetoken<T> type) {
  Class<T> rawType = (Class<T>) type.getRawType();
  if (rawType != String.class) {
   return null;
  }
  return (TypeAdapter<T>) new StringNullAdapter();
 }
}
// StringNullAdapter代码

public class StringNullAdapter extends TypeAdapter<String> {
 @Override
 public String read(JsonReader reader) throws IOException {
  // Todo Auto-generated method stub
  if (reader.peek() == JsonToken.NULL) {
   reader.nextNull();
   return "";
  }
  return reader.nextString();
 }
 @Override
 public void write(JsonWriter writer,String value) throws IOException {
  // Todo Auto-generated method stub
  if (value == null) {
   writer.nullValue();
   return;
  }
  writer.value(value);
 }
}

Gson案例:Java对象与JSON字符串相互转换

Gson案例:Java对象与JSON字符串相互转换

Gson案例:Java对象与JSON字符串相互转换

一、Gson概述

Gson是一个Java类库,可将Java对象转换为相应的JSON形式,也可以将JSON字符串转换为对应的Java对象。Gson是一个开源库,其地址为:http://code.google.com/p/google-gson。Gson可以使用任意Java对象,包括哪些预先存在的、不在你的源代码中的对象(因此,你并不知道对象的属性)。

二、案例演示

1、创建Java项目GsonDemo

2、创建lib目录,在里面添加gson的jar包

3、在src里创建net.hw.bean包,在里面创建User实体类

4、在src里创建net.hw.gson包,在里面创建Bean2Json类</

本文同步分享在 博客“howard2005”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

Gson详解:Java对象与JSON相互转换的利器

Gson详解:Java对象与JSON相互转换的利器

1. Gson是什么(What is Gson)

Gson是一个开源的Java库,用于任意Java对象与JSON之间的相互转换,由Google开发维护。

Gson的优势:

  • 简单易用:以toJsonfromJson两个方法为核心
  • 不需要annotations的支持,可以在缺少源代码或不方便修改源代码的情况下使用
  • 支持泛型和集合

github: https://github.com/google/gson
API Spec: http://google.github.io/gson/apidocs/

2. 将Gson引入项目

  • 在Maven中加入依赖
<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.5</version>
</dependency>
  • 将jar直接加入项目的lib文件夹

为了图省事,我把相应jar放在我的百度云。(其实是把maven下载的版本打包而已)

3. 示例(How to use)

3.1 --自定义测试类--

public class Person implements Serializable, Comparable<Person>{

	private static final long serialVersionUID = 2373954257153196535L;
	private String name;
	private int age;
	private String gender;
	//实现Comparable只是为了测试Set的序列化/反序列化,并无其他意思
	public int compareTo(Person o) {
		if(o == null) return -1;
		if(this == o) return 0;
		if(this.getName().equals(o.getName()) && this.getAge() == o.getAge() && this.getGender() == o.getGender()) return 0;
		return -1;
	}
	// a series of setter/getter
}

3.2 序列化

Java对象 → JSON:toJson(Object)

Person p1 = new Person("David", 26, "male");
Person p2 = new Person("Annie", 23, "female");
Person p3 = new Person("琼恩", 29, "男");
Gson gson = new Gson();//也可以通过new GsonBuilder().create();来实例化

//单个对象
String json = gson.toJson(p1);//{"name":"David","age":26,"gender":"male"}

//List
List<Person> list = Arrays.asList(p1, p2, p3);
String jsonList = gson.toJson(list);

//Set
Set<Person> set = new HashSet<Person>();
set.add(p1);
set.add(p2);
set.add(p1);
String jsonSet = gson.toJson(set);

//数组:先转换成List
Person[] arr = {p1, p2, p3};
List<Person> jsonArrList = Arrays.asList(arr);
String jsonArr = gson.toJson(jsonArrList);

/*
 * 关于Java关键字:transient
 * 
 * transient声明的field(成员变量)在对象序列化时会被忽略,
 * 常用于声明password之类比较敏感的变量。
 * transient不能用于声明方法。(反正方法既不会也没必要被序列化)
 * 
 * 由于gson.toJson(obj)涉及序列化,transient在此也会生效,
 * 即transient声明的变量不会出现在生成的json(String)中。(亲测)
 */

3.3 反序列化

JSON → Java对象:fromJson(String, Type)

  • 反序列化时,必须提供反序列化的类型java.lang.reflect.Type
  • 对于普通的引用类型(Object子类),可使用java.lang.Class对象(实现了Type接口)
Type t1 = Person.class;
Type t2 = p1.getClass();
boolean flag = (t1 == t2);//true

Person person = gson.fromJson(json, t1);
System.out.println(person.getName());//David
  • 对于参数化类型(即泛型),可通过com.google.gson.reflect.TypeToken获取其类型
Type setType = new TypeToken<Set<Person>>(){}.getType();//TypeToken<T>的Constructor(构造器/构造方法)为protected, 使用匿名内部类的方式进行实例化

Set<Person> people = gson.fromJson(jsonSet, setType);
Iterator<Person> ps = people.iterator();
while(ps.hasNext()){
	System.out.println(ps.next().getName());
}

3.4 重定向数据来源/输出

默认情况下,toJson(Object)将生成的JSON数据保存在一个StringWriter中;fromJson(String, Type)则是从String中读取。可传入相应WriterReader改变数据的去处或来源。

File f = new File("/Users/Lawrence/Documents/out.txt");
Writer out = new FileWriter(f);
gson.toJson(set, out);//将生成的JSON数据保存在文件中,而不是默认的String
out.close();

Reader reader = new FileReader(f);
Set<Person> setFromFile = gson.fromJson(reader, setType);//从文件中读取数据,而不是默认的String
System.out.println(setFromFile.size());//2
reader.close();

/* 
 * 改变数据输出,需要java.lang.Appendable
 * 事实上Writer就实现了Appendable,所以其子类都满足这个条件
 */

3.5 --修改自定义测试类--

Person类增加两个变量:

  • geo:长度为2的double数组用于表示地理位置,即经纬度
  • Account
public class Person implements Serializable, Comparable<Person>{
	private static final long serialVersionUID = 2373954257153196535L;
	private String name;
	private int age;
	private String gender;
	
	private double[] geo = new double[2];
	private Account account;
	/* a series of setter/getter */
}

Account.java:

public class Account {
	private String id;
	private String email;	
	private Date dateOfRegister = new Date();
	/* setter/getter */
}

3.6 自定义输出格式

通过修改GsonBuilder的属性,自定义输出的结果:

Person p1 = new Person("David", 26, "male");
Account ac = new Account("id", "<h1>test1@test1.com</h1>");
p1.setAccount(ac);

Person p2 = new Person("Rose", 23, "女");
Account ac2 = new Account("id2", "<p>test2@test2.com</p>");
p2.setAccount(ac2);

Person p3 = new Person();
p3.setName("Hello");

List<Person> list = Arrays.asList(p1, p2, p3);

Gson gson = new GsonBuilder()
		.setPrettyPrinting()//自动换行和添加缩进
		.serializeNulls()//保留null的变量并将值设为null
		.disableHtmlEscaping()//不会对用于表示HTML标签的"<"和">"编码
		.setDateFormat("yyyy-MM-dd")//为所有java.util.Date定义输出格式
		.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES)
		//定义变量名的显示方式,如此处将Account的dateOfRegister定义输出为"Date Of Register"
		.create();

System.out.println(gson.toJson(list));

以上输出为

[
  {
    "Name": "David",
    "Age": 26,
    "Gender": "male",
    "Geo": [
      0.0,
      0.0
    ],
    "Account": {
      "Id": "id",
      "Email": "<h1>test1@test1.com</h1>",
      "Date Of Register": "2015-12-16"
    }
  },
  {
    "Name": "Rose",
    "Age": 23,
    "Gender": "女",
    "Geo": [
      0.0,
      0.0
    ],
    "Account": {
      "Id": "id2",
      "Email": "<p>test2@test2.com</p>",
      "Date Of Register": "2015-12-16"
    }
  },
  {
    "Name": "Hello",
    "Age": 0,
    "Gender": null,
    "Geo": [
      0.0,
      0.0
    ],
    "Account": null
  }
]

3.7 操作JSON树

将3.6中添加的由3个Person对象组成的list为例:

JsonElement root = gson.toJsonTree(list);//3个Person对象

if(root.isJsonArray()){
	JsonArray arr = (JsonArray) root;
	Iterator<JsonElement> iter = arr.iterator();
	JsonElement target = null;
	while(iter.hasNext()){
		JsonObject element = (JsonObject) iter.next();
		String name = element.get("Name").getAsString();
		if("Hello".equals(name)){
//			arr.remove(element);//不能调用ArrayList的remove(), 因为会抛出java.util.ConcurrentModificationException
			iter.remove();//需要调用的是Iterator的remove();

		}
	}
}
System.out.println(gson.toJson(root));

4. 说明

以上内容均参考官方文档,如有错误,还望指正。

  • github: https://github.com/google/gson
  • API Spec: http://google.github.io/gson/apidocs/

关于使用Jackson来实现Java对象与JSON的相互转换的教程jackson的json和java的转换的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于FastJson、Jackson、Gson进行Java对象转换Json的细节处理、GSON实现Java对象与JSON格式对象相互转换的完全教程、Gson案例:Java对象与JSON字符串相互转换、Gson详解:Java对象与JSON相互转换的利器等相关内容,可以在本站寻找。

本文标签: