Почему Gson.toJson сериализует универсальное поле в пустой объект JSON? - PullRequest
7 голосов
/ 04 сентября 2011

У меня есть универсальный класс, содержащий поле типа T, Gson сериализует это поле как пустой объект.Я включил код ниже, чтобы продемонстрировать проблему.Обратное чтение JSON кажется нормальным (если вы указали токен правильного типа).

import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

public class GsonIssue {
    static class AbstractThing {
        private String fieldA = "valueA";

        public String getFieldA() {
            return fieldA;
        }

        public void setFieldA(String fieldA) {
            this.fieldA = fieldA;
        }

        @Override
        public String toString() {
            return "AbstractThing [fieldA=" + fieldA + "]";
        }
    }

    static class Thing extends AbstractThing {
        private String fieldB = "valueB";

        @Override
        public String toString() {
            return "Thing [fieldB=" + fieldB + ", fieldA=" + getFieldA() + "]";
        }
    }

    static class Wrapper<T extends AbstractThing> {
        private T abstractThing;
        private String standardField = "standard value";

        public Wrapper(T abstractThing) {
            this.abstractThing = abstractThing;
        }

        @Override
        public String toString() {
            return "Wrapper [abstractThing=" + abstractThing + ", standardField=" + standardField + "]";
        }
    }

    public static void main(String[] args) {
        Wrapper<Thing> wrapper = new Wrapper<Thing>(new Thing());

        Gson gson = new Gson();
        String json = gson.toJson(wrapper);
        System.out.println(json);
        // prints : {"abstractThing":{},"standardField":"standard value"}
        // so standardField is correctly serialized but not abstractThing.

        // but if we manually construct the expected json string, and parse it back, we get the expected object structure
        json = "{\"standardField\": \"some text\", " +
                "\"abstractThing\":{\"fieldB\" : \"arb value\", \"fieldA\" : \"another arb value\"}}";

        Type type = new TypeToken<Wrapper<Thing>>() {}.getType();
        Object fromJson = gson.fromJson(json, type);
        System.out.println(fromJson);
        // prints : Wrapper [abstractThing=Thing [fieldB=arb value, fieldA=another arb value], standardField=some text]
        // which is as expected
    }
}

1 Ответ

9 голосов
/ 04 сентября 2011

Из своих документов:

Когда вы вызываете toJson (obj), Gson вызывает obj.getClass () для получения информации о полях для сериализации. Аналогично, вы обычно можете передать объект MyClass.class в методе fromJson (json, MyClass.class). Это прекрасно работает, если объект не является универсальным типом. Однако, если объект имеет универсальный тип, информация об универсальном типе теряется из-за стирания типа Java

Вы можете решить эту проблему, указав правильный параметризованный тип для вашего универсального типа. Вы можете сделать это с помощью класса TypeToken.

Они приводят следующий пример для List<T>:

Type listType = new TypeToken<List<String>>() {}.getType();
gson.toJson(myStrings, listType);

Так что для вашего кода вам понадобится ...

Type myType = new TypeToken<Wrapper<Thing>>() {}.getType();
String json = gson.toJson(wrapper, myType);

https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...