Some problems and comparison between fastjson and gson

Serialize

json serialization and deserialization, which are more used in daily life, and there are many tools now, but the common one is fastjson, which is fast after all. This is mainly about the problems and comparison between fastjson and Gson

fastjson

  • serialize

    Note that if there is a field in the serialized object that does not have a corresponding Get method, the field will not be serialized. See the source code for specific reasons.

    //JSONSerialize
    public final void write(Object object) {
            if (object == null) {
                out.writeNull();
                return;
            }
            Class<?> clazz = object.getClass();
        	//Breakpoint can't break in. I don't know why. It feels like it will generate an asmserializer 
            ObjectSerializer writer = getObjectWriter(clazz);
            try {
                writer.write(this, object, null, null, 0);
            } catch (IOException e) {
                throw new JSONException(e.getMessage(), e);
            }
        }
    

    So if we don't need to serialize some fields, what should we do? In fact, we need to add the transient keyword in front of the fields

  • De serialization

    I often encounter this problem, that is, when deserializing, the object field is inconsistent with that when serializing.

    1: When deserializing, if a field lacks a corresponding set method, it cannot be deserialized.

    2: If the fields are inconsistent during deserialization and serialization, it can be successfully deserialized. Only the assignment of the fields and the assignment of the fields will be missing, but the fields will be missing.

  • How to customize complex serialization and deserialization

    Let's go straight to the code here. We need to use the Java reflection Type

     private static final TypeReference<Map<Integer,Info>> integerToInfo = new TypeReference<Map<Integer,Info>>(){};
    
      private static String data1 = "{1:{\"id\":1,\"map\":{1111:\"abc\"},\"name\":\"aaa\"}}";
    
     Map<Integer, Info> map = JSON.parseObject(data1, integerToInfo.getType());
    
    

    This is a simple application. You can see the interface source code in Json. It's still many and complex, but you can take a look at it a little bit

    com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializer(java.lang.Class<?>)
    

    There is a buildBeanInfo method in this method. The default value of fieldBased is false. The last field to be called for assignment is

    computeGetters() method, the specific thing to do in this is to get all the methods starting with get according to the reflection (of course, some of the methods in it also need to be filtered) and then remove get. The lowercase value is used as the key, and the get() value is used as the value, which is spliced into the json string. So it is also explained here that fastjson is serialized and deserialized according to get and set methods.

    But I don't know why, the breakpoint can't break into the method written above?

    GSON

    Google's Gson is the most fully functional Json parsing artifact at present, but it seems that its performance is worse than that of fastJson.

    1: For anonymous inner classes, there may be problems with gson

    For example, when initializing a map, sometimes the code can be elegant in this way, especially for the use of lamda expressions in Java 8 (the problem of dead loops in concurrent HashMap)

    private static Gson gson = new Gson();
    
    Map<String, String> map = new HashMap<String, String>() {
        {
    		put("abc", "abc");
        }
    };
    System.out.println(gson.toJson(map));
    

    There will be a strange problem here. The printed value is null. Look at the source code, com.google.gson.internal.Excluder

    create(), in the method, it will judge whether it is an anonymous inner class, as it seems, but the method excludeclasschecks (rawtype) - > isanonymousorlocal (clazz) will return true. When initializing the map above, an anonymous inner class will be created. That's probably why.

    2: Looking directly at code problems

    private static Gson gson = new Gson();
    
    Map<String, String> map = new HashMap<>();
    map.put("abc","abc");
    Set<Map.Entry<String, String>> entries = map.entrySet();
    System.out.println(gson.toJson(entries));
    

    The output result here is [{}], that is, it was not successfully deserialized as a json string, and the field value was not printed out. Why? It can only be seen from the source code. It is likely that the field value has not been assigned. What is that.

    com.google.gson.internal.bind.ReflectiveTypeAdapterFactory#getBoundFields
    //In fact, this is the binding field
    
    Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
    if (raw.isInterface()) {//raw is the type of "set element", which is java.util.Map.Entry. It is an interface!
        return result;
    }
    

    So when using it, we should pay attention to the following problem: do not use interface types for generics in the collection, or serialization will fail.

    There is no problem with fastjson.

    compare

    The set method and field name of the added attribute are inconsistent. What happens to them

    When serializing

    		//In info, the field name is firstName. The method is setName();
    		Info info = Info.valueOf(); 
            String str = JSON.toJSONString(info);
            System.err.println("fastJson result: " + str);
    
            str = gson.toJson(info);
            System.err.println("gson result: " + str);
    

    Look at the output:

    fastJson result: {"id":1,"map":{1111:"abc"},"name":"aaa"}
    gson result: {"id":1,"firstName":"aaa","map":{"1111":"abc"}}

    Why is that?

    When serializing and deserializing, fastJson is converted according to the names of get and set methods, while gson is converted according to the names of properties.

    So this kind of problem may occur. For fastJson, if the field name is unchanged and the get method and set method name of a field are modified before and after serialization, it will cause problems. And gson won't. Have you ever encountered such a problem

    Can the corresponding deserialization succeed? Just write a test

     String fastJson = "{\"id\":1,\"map\":{1111:\"abc\"},\"name\":\"aaa\"}";
     String gsonStr = "{\"id\":1,\"firstName\":\"aaa\",\"map\":{\"1111\":\"abc\"}}";
    
     Info info = JSON.parseObject(fastJson, Info.class);
     System.err.println(info.toString());
     info = gson.fromJson(gsonStr, Info.class);
     System.err.println(info.toString());
    

    Output results:

    Info{id=1, firstName='aaa', map={1111=abc}, other='null'}
    Info{id=1, firstName='aaa', map={1111=abc}, other='null'}

    It can be seen that the data can be deserialized successfully or corresponding.

Reference resources

Published 18 original articles, won praise 4, visited 4226
Private letter follow

Tags: JSON Java Google Attribute

Posted on Tue, 17 Mar 2020 06:42:13 -0400 by pranesh