Jackson vs Gson – Jackson对格森

最后修改: 2016年 8月 12日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this article, we’ll compare the Gson and Jackson APIs for serializing and deserializing JSON data to Java objects and vice-versa.

在本文中,我们将比较GsonJackson API,以便将JSON数据序列化和反序列化为Java对象,反之亦然。

Gson and Jackson are complete libraries offering JSON data-binding support for Java. Each are actively developed open-source projects which offer to handle of complex data types and support for Java Generics.

Gson和Jackson是为Java提供JSON数据绑定支持的完整库。它们都是积极开发的开源项目,提供了对复杂数据类型的处理和对Java Generics的支持。

And in most cases, both libraries can deserialize to an entity without modifying an entity class, which is important in cases where a developer doesn’t have access to the entity source code.

而且在大多数情况下,这两个库都可以在不修改实体类的情况下反序列化为实体,这在开发者无法访问实体源代码的情况下非常重要。

2. Gson Maven Dependency

2.Gson Maven的依赖性

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>${gson.version}</version>
</dependency>

You can get the latest version of Gson here.

你可以从这里获得Gson的最新版本。

3. Gson Serialization

3.Gson的序列化

Serialization converts Java objects to JSON output. Consider the following entities:

串行化将Java对象转换为JSON输出。请考虑以下实体。

public class ActorGson {
    private String imdbId;
    private Date dateOfBirth;
    private List<String> filmography;
    
    // getters and setters, default constructor and field constructor omitted
}

public class Movie {
    private String imdbId;
    private String director;
    private List<ActorGson> actors;
    
    // getters and setters, default constructor and field constructor omitted
}

3.1. Simple Serialization

3.1.简单的序列化

Let’s start with an example of Java to JSON serialization:

让我们从一个Java到JSON序列化的例子开始。

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

ActorGson rudyYoungblood = new ActorGson(
  "nm2199632",
  sdf.parse("21-09-1982"), 
  Arrays.asList("Apocalypto",
  "Beatdown", "Wind Walkers")
);
Movie movie = new Movie(
  "tt0472043", 
  "Mel Gibson",
  Arrays.asList(rudyYoungblood));

String serializedMovie = new Gson().toJson(movie);

This will result in:

这将导致。

{
    "imdbId": "tt0472043",
    "director": "Mel Gibson",
    "actors": [{
        "imdbId": "nm2199632",
        "dateOfBirth": "Sep 21, 1982 12:00:00 AM",
        "filmography": ["Apocalypto", "Beatdown", "Wind Walkers"]
    }]
}

By default:

在默认情况下。

  • All properties are serialized because they have no null values
  • dateOfBirth field was translated with the default Gson date pattern
  • Output is not formatted and JSON property names correspond to the Java entities

3.2. Custom Serialization

3.2.自定义序列化

Using a custom serializer allows us to modify the standard behavior. We can introduce an output formatter with HTML, handle null values, exclude properties from output, or add a new output.

使用自定义的序列化器允许我们修改标准行为。我们可以引入一个带有HTML的输出格式,处理null值,从输出中排除属性,或者添加一个新的输出。

ActorGsonSerializer modifies generation of JSON code for the ActorGson element:

ActorGsonSerializer修改了ActorGson元素的JSON代码的生成。

public class ActorGsonSerializer implements JsonSerializer<ActorGson> {
    private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
     
    @Override
    public JsonElement serialize(ActorGson actor, Type type,
        JsonSerializationContext jsonSerializationContext) {
        
        JsonObject actorJsonObj = new JsonObject();
        
        actorJsonObj.addProperty("<strong>IMDB Code>", actor.getImdbId());
        
        actorJsonObj.addProperty("<strong>Date Of Birth>", 
          actor.getDateOfBirth() != null ? 
          sdf.format(actor.getDateOfBirth()) : null);
        
        actorJsonObj.addProperty("<strong>N° Film:> ",  
          actor.getFilmography()  != null ?  
          actor.getFilmography().size() : null);
       
        actorJsonObj.addProperty("filmography", actor.getFilmography() != null ? 
          convertFilmography(actor.getFilmography()) : null);
        
        return actorJsonObj;
    }
 
    private String convertFilmography(List<String> filmography) {
        return filmography.stream()
          .collect(Collectors.joining("-"));
    }
}

In order to exclude the director property, the @Expose annotation is used for properties we want to consider:

为了排除director属性,@Expose注解被用于我们要考虑的属性。

public class MovieWithNullValue {
    
    @Expose
    private String imdbId;
    private String director;
    
    @Expose
    private List<ActorGson> actors;
}

Now we can proceed with Gson object creation using the GsonBuilder class:

现在我们可以使用GsonBuilder类继续创建Gson对象。

Gson gson = new GsonBuilder()
  .setPrettyPrinting()
  .excludeFieldsWithoutExposeAnnotation()
  .serializeNulls()
  .disableHtmlEscaping()
  .registerTypeAdapter(ActorGson.class, new ActorGsonSerializer())
  .create();
 
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
 
ActorGson rudyYoungblood = new ActorGson("nm2199632",
  sdf.parse("21-09-1982"), Arrays.asList("Apocalypto","Beatdown", "Wind Walkers"));

MovieWithNullValue movieWithNullValue = new MovieWithNullValue(null,
  "Mel Gibson", Arrays.asList(rudyYoungblood));
 
String serializedMovie = gson.toJson(movieWithNullValue);

The result is the following:

其结果如下。

{
  "imdbId": null,
  "actors": [
    {
      "<strong>IMDB Code>": "nm2199632",
      "<strong>Date Of Birth>": "21-09-1982",
      "<strong>N° Film:> ": 3,
      "filmography": "Apocalypto-Beatdown-Wind Walkers"
    }
  ]
}

Notice that:

注意到这一点。

  • the output is formatted
  • some property names are changed and contain HTML
  • null values are included, and the director field is omitted
  • Date is now in the dd-MM-yyyy format
  • a new property is present – N° Film
  • filmography is a formatted property, not the default JSON list

4. Gson Deserialization

4.Gson反序列化

4.1. Simple Deserialization

4.1.简单的反序列化

Deserialization converts JSON input into Java objects. To illustrate the output, we implement the toString() method in both entity classes:

反序列化将JSON输入转换为Java对象。为了说明输出,我们在两个实体类中都实现了toString()方法。

public class Movie {
    @Override
    public String toString() {
      return "Movie [imdbId=" + imdbId + ", director=" + director + ",actors=" + actors + "]";
    }
    ...
}

public class ActorGson {
    @Override
    public String toString() {
        return "ActorGson [imdbId=" + imdbId + ", dateOfBirth=" + dateOfBirth +
          ",filmography=" + filmography + "]";
    }
    ...
}

Then we utilize the serialized JSON and run it through standard Gson deserialization:

然后我们利用序列化的JSON,通过标准的Gson反序列化来运行它。

String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\":" +
  "[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\"," +
  "\"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}";
        
Movie outputMovie = new Gson().fromJson(jsonInput, Movie.class);
outputMovie.toString();

The output is us our entities, populated with the data from our JSON input:

输出是我们的实体,用我们的JSON输入的数据进行填充。

Movie [imdbId=tt0472043, director=null, actors=[ActorGson 
  [imdbId=nm2199632, dateOfBirth=Tue Sep 21 04:00:00 PDT 1982, 
  filmography=[Apocalypto, Beatdown, Wind Walkers]]]]

As was the case with the simple serializer:

正如简单的序列化器的情况一样。

  • the JSON input names must correspond with the Java entity names, or they are set to null.
  • dateOfBirth field was translated with the default Gson date pattern, ignoring the time zone.

4.2. Custom Deserialization

4.2.自定义反序列化

Using a custom deserializer allows us to modify the standard deserializer behavior. In this case, we want the date to reflect the correct time zone for dateOfBirth. We use a custom ActorGsonDeserializer on the ActorGson entity to achieve this:

使用一个自定义的反序列化器允许我们修改标准的反序列化器行为。在这种情况下,我们希望日期能够反映dateOfBirth的正确时区。我们在ActorGson实体上使用一个自定义的ActorGsonDeserializer来实现这个目的。

public class ActorGsonDeserializer implements JsonDeserializer<ActorGson> {

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

    @Override
    public ActorGson deserialize(JsonElement json, Type type,
      JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        
        JsonObject jsonObject = json.getAsJsonObject();

        JsonElement jsonImdbId = jsonObject.get("imdbId");
        JsonElement jsonDateOfBirth = jsonObject.get("dateOfBirth");
        JsonArray jsonFilmography = jsonObject.getAsJsonArray("filmography");

        ArrayList<String> filmList = new ArrayList<String>();
        if (jsonFilmography != null) {
            for (int i = 0; i < jsonFilmography.size(); i++) {
                filmList.add(jsonFilmography.get(i).getAsString());
            }
        }

    ActorGson actorGson = new ActorGson(jsonImdbId.getAsString(),
      sdf.parse(jsonDateOfBirth.getAsString()), filmList);
        return actorGson;
    }
}

We employed a SimpleDateFormat parser to parse the input date, accounting for the time zone.

我们采用了一个SimpleDateFormat解析器来解析输入的日期,并考虑到时区。

Note that we could have decided to simply write a custom deserializer for only the Date, but the ActorGsonDeserializer offers a more detailed view of the deserialization process.

请注意,我们可以决定只为Date写一个自定义的反序列化器,但是ActorGsonDeserializer提供了一个更详细的反序列化过程的视图。

Also note that the Gson approach does not require modifying the ActorGson entity, which is ideal as we may not always have access to the input entity. We use the custom deserializer here:

还要注意的是,Gson方法不需要修改ActorGson实体,这很理想,因为我们可能并不总是能接触到输入实体。我们在这里使用自定义的反序列化器。

String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\":"
  + "[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\",
  + \"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}";

Gson gson = new GsonBuilder()
  .registerTypeAdapter(ActorGson.class,new ActorGsonDeserializer())
  .create();

Movie outputMovie = gson.fromJson(jsonInput, Movie.class);
outputMovie.toString();

The output is similar to the simple deserializer result, except the date uses correct time zone:

输出与简单的反序列化器结果类似,只是日期使用了正确的时区。

Movie [imdbId=tt0472043, director=null, actors=[ActorGson
  [imdbId=nm2199632, dateOfBirth=Tue Sep 21 12:00:00 PDT 1982, 
  filmography=[Apocalypto, Beatdown, Wind Walkers]]]]

5. Jackson Maven Dependency

5.Jackson的Maven依赖性

<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-databind</artifactId>   
    <version>${jackson.version}</version> 
</dependency>

You can get the latest version of Jackson here.

你可以在这里获得最新版本的杰克逊

6. Jackson Serialization

6.Jackson的序列化

6.1. Simple Serialization

6.1.简单的序列化

Here we will use Jackson to obtain the same serialized content we had with Gson using the following entities. Note that the entity’s getters/setters must be public:

在这里,我们将使用Jackson来获得与Gson相同的序列化内容,使用的实体如下。注意,实体的getters/setters必须是公共的。

public class ActorJackson {
    private String imdbId;
    private Date dateOfBirth;
    private List<String> filmography;
    
    // required getters and setters, default constructor 
    // and field constructor details omitted
}

public class Movie {
    private String imdbId;
    private String director;
    private List<ActorJackson> actors;
    
    // required getters and setters, default constructor 
    // and field constructor details omitted
}
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); 
ActorJackson rudyYoungblood = new ActorJackson("nm2199632",sdf.parse("21-09-1982"),
  Arrays.asList("Apocalypto","Beatdown","Wind Walkers") ); 
Movie movie = new Movie("tt0472043","Mel Gibson", Arrays.asList(rudyYoungblood)); 
ObjectMapper mapper = new ObjectMapper(); 
String jsonResult = mapper.writeValueAsString(movie);

The output is as follows:

输出结果如下。

{"imdbId":"tt0472043","director":"Mel Gibson","actors":
[{"imdbId":"nm2199632","dateOfBirth":401439600000,
"filmography":["Apocalypto","Beatdown","Wind Walkers"]}]}

Some notes of interest:

一些有意义的说明。

  • ObjectMapper is our Jackson serializer/deserializer
  • The output JSON is not formatted
  • By default, Java Date is translated to long value

6.2. Custom Serialization

6.2.自定义序列化

We can create a Jackson serializer for ActorJackson element generation by extending StdSerializer for our entity. Again note that the entity getters/setters must be public:

我们可以通过为我们的实体扩展StdSerializer,为ActorJackson元素的生成创建一个Jackson序列器。再次注意,实体的getters/setters必须是公共的。

public class ActorJacksonSerializer extends StdSerializer<ActorJackson> {

    private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

    public ActorJacksonSerializer(Class t) {
        super(t);
    }

    @Override
    public void serialize(ActorJackson actor, JsonGenerator jsonGenerator,
      SerializerProvider serializerProvider) throws IOException {

        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("imdbId", actor.getImdbId());
        jsonGenerator.writeObjectField("dateOfBirth",
          actor.getDateOfBirth() != null ?
          sdf.format(actor.getDateOfBirth()) : null);
    
        jsonGenerator.writeNumberField("N° Film: ", 
          actor.getFilmography() != null ? actor.getFilmography().size() : null);
    jsonGenerator.writeStringField("filmography", actor.getFilmography()
          .stream().collect(Collectors.joining("-")));

        jsonGenerator.writeEndObject();
    }
}

We create a Movie entity to allow ignoring of the director field:

我们创建一个电影实体,允许忽略导演字段。

public class MovieWithNullValue {
    
    private String imdbId;
    
    @JsonIgnore
    private String director;
    
    private List<ActorJackson> actors;
    
    // required getters and setters, default constructor
    // and field constructor details omitted
}

Now we can proceed with a custom ObjectMapper creation and setup:

现在我们可以继续进行自定义ObjectMapper的创建和设置。

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

ActorJackson rudyYoungblood = new ActorJackson(
  "nm2199632", 
  sdf.parse("21-09-1982"), 
  Arrays.asList("Apocalypto", "Beatdown","Wind Walkers"));
MovieWithNullValue movieWithNullValue = 
  new MovieWithNullValue(null,"Mel Gibson", Arrays.asList(rudyYoungblood));

SimpleModule module = new SimpleModule();
module.addSerializer(new ActorJacksonSerializer(ActorJackson.class));
ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.registerModule(module)
  .writer(new DefaultPrettyPrinter())
  .writeValueAsString(movieWithNullValue);

The output is formatted JSON that handles null values, formats the date, excludes the director field and shows new output of :

输出是格式化的JSON,处理null值,格式化日期,排除director字段,显示的新输出。

{
  "actors" : [ {
    "imdbId" : "nm2199632",
    "dateOfBirth" : "21-09-1982",
    "N° Film: " : 3,
    "filmography" : "Apocalypto-Beatdown-Wind Walkers"
  } ],
  "imdbID" : null
}

7. Jackson Deserialization

7.Jackson的反序列化

7.1. Simple Deserialization

7.1.简单的反序列化

To illustrate the output, we implement the toString() method in both Jackson entity classes:

为了说明输出,我们在Jackson的两个实体类中实现了toString()方法。

public class Movie {
    @Override
    public String toString() {
        return "Movie [imdbId=" + imdbId + ", director=" + director
          + ", actors=" + actors + "]";
    }
    ...
}

public class ActorJackson {
    @Override
    public String toString() {
        return "ActorJackson [imdbId=" + imdbId + ", dateOfBirth=" + dateOfBirth
          + ", filmography=" + filmography + "]";
    }
    ...
}

Then we utilize the serialized JSON and run it through Jackson deserialization:

然后我们利用序列化的JSON,通过Jackson反序列化运行。

String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\":
  [{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\",
  \"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}";
ObjectMapper mapper = new ObjectMapper();
Movie movie = mapper.readValue(jsonInput, Movie.class);

The output is us our entities, populated with the data from our JSON input:

输出是我们的实体,用我们的JSON输入的数据进行填充。

Movie [imdbId=tt0472043, director=null, actors=[ActorJackson 
  [imdbId=nm2199632, dateOfBirth=Tue Sep 21 04:00:00 PDT 1982, 
  filmography=[Apocalypto, Beatdown, Wind Walkers]]]]

As was the case with the simple serializer:

正如简单的序列化器的情况一样。

  • the JSON input names must correspond with the Java entity names, or they are set to null,
  • dateOfBirth field was translated with the default Jackson date pattern, ignoring the time zone.

7.2. Custom Deserialization

7.2.自定义反序列化

Using a custom deserializer allows us to modify the standard deserializer behavior.

使用一个自定义的反序列化器,我们可以修改标准的反序列化器行为。

In this case, we want the date to reflect the correct time zone for dateOfBirth, so we add a DateFormatter to our Jackson ObjectMapper:

在这种情况下,我们想让日期反映出dateOfBirth的正确时区,所以我们在Jackson的ObjectMapper中添加一个DateFormatter。

String jsonInput = "{\"imdbId\":\"tt0472043\",\"director\":\"Mel Gibson\",
  \"actors\":[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\",
  \"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}";

ObjectMapper mapper = new ObjectMapper();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
mapper.setDateFormat(df);
        
Movie movie = mapper.readValue(jsonInput, Movie.class);
movie.toString();

The output reflects the correct time zone with the date:

输出反映了正确的时区与日期。

Movie [imdbId=tt0472043, director=Mel Gibson, actors=[ActorJackson 
  [imdbId=nm2199632, dateOfBirth=Tue Sep 21 12:00:00 PDT 1982, 
  filmography=[Apocalypto, Beatdown, Wind Walkers]]]]

This solution is clean and simple.

这个解决方案是干净和简单的。

Alternatively, we could have created a custom deserializer for the ActorJackson class, registered this module with our ObjectMapper, and deserialized the date using the @JsonDeserialize annotation on the ActorJackson entity.

另外,我们可以为ActorJackson类创建一个自定义的反序列化器,在我们的ObjectMapper中注册这个模块,并使用@JsonDeserialize注释对ActorJackson实体进行反序列化。

The disadvantage of that approach is the need to modify the entity, which may not be ideal for cases when we don’t have access to the input entity classes.

这种方法的缺点是需要修改实体,这对于我们无法接触到输入实体类的情况来说可能不是很理想。

8. Conclusion

8.结论

Both Gson and Jackson are good options for serializing/deserializing JSON data, simple to use and well documented.

Gson和Jackson都是序列化/反序列化JSON数据的好选择,使用简单,文档齐全。

Advantages of Gson:

Gson的优势。

  • Simplicity of toJson/fromJson in the simple cases
  • For deserialization, do not need access to the Java entities

Advantages of Jackson:

杰克逊的优势。

  • Built into all JAX-RS (Jersey, Apache CXF, RESTEasy, Restlet), and Spring framework
  • Extensive annotation support

You can find the code for Gson and Jackson on GitHub.

你可以在GitHub上找到GsonJackson的代码。