简体   繁体   中英

Fields not deserialized when instance creator is registered with gson

I'm using gson to deserialize objects, and I'm telling gson the interface class rather than the implementation class of the object I want. I register an InstanceCreator that constructs an instance of the implementation class.

This test demonstrates the problem that I encounter:

public class UnexpectedGsonBehaviorTest {

    public static interface Fruits {
        List<String> getFruitList();
    }

    public static class FruitsImpl implements Fruits {

        private List<String> fruitList;

        public List<String> getFruitList() {
            return fruitList;
        }

        public String toString() {
            return "FruitsImpl{" + "fruitList=" + fruitList + '}';
        }

    }

    @Test
    public void testUseCustomFruitsInstanceCreator() {
        Gson gson = new GsonBuilder()
          .registerTypeAdapter(Fruits.class, new InstanceCreator<Fruits>(){
            public Fruits createInstance(Type type) {
                return new FruitsImpl();
            }
        }).create();
        String fruitsJson = "{\"fruitList\": [\"apples\", \"pears\", \"bananas\"]}";
        System.out.println("input: " + fruitsJson);
        Fruits fruits = gson.fromJson(fruitsJson, Fruits.class);
        System.out.println("output: " + fruits);
        assertNotNull("expect non-null fruit list", fruits.getFruitList());
    }

}

I expect the list member of the FruitsImpl object to be deserialized, but it is not. The output is

input: {"fruitList": ["apples", "pears", "bananas"]}
output: FruitsImpl{fruitList=null} 

and the assertion fails.

If I just use a default gson instance and gson.fromJson(fruitsJson, FruitsImpl.class) , the list field is correctly deserialized. Am I using gson wrong, or is there some other issue?

If you debug it and put a breakpoint inside createInstance and step into the gson code you should see the problem.

After instantiation gson tries to populate all the bound fields in the ReflectiveTypeAdapterFactory . The bound fields map is empty in your case. This is because it can't inspect your interface for fields.

From getBoundFields in ReflectiveTypeAdapterFactory

Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
if (raw.isInterface()) {
  return result;
}

So the instance creator is more suitable if the type you told gson to deserialize has no zero arg constructor for gson to call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM