通用ResponseTo <T> as Json

时间:2019-08-12 11:49:53

标签: java json spring gson fasterxml

我正在努力反序列化由通用结果结构包装的JSON对象:

我来自服务器的JSON

{
  "totalsize": 5,
  "data" : [
             {"name":1},
             {"name":2}
           ]
}

我的Java对象来自结果:

public class ResponseTo<T> {

    public Long totalsize = null;
    public final List<T> data = new ArrayList<>();
}

在这种情况下(可能是另一个GET请求中的其他内容)

public class Item {
    public int name;
}

在这种情况下,TItem

如何使用以下方法将JSON有效负载反序列化为该对象结构:
GSON和/或com.fasterxml.jackson

我想要一个像这样的静态方法:

public static <T> ResponseTo<T> stringToObject(String jsonString, Class<T> clazz ) {
    final Gson gson = new Gson();
    // do some typeadapter function magic
    return gson.fromJson( jsonString, ResponseTo.class );
}

调用
ResponseTo<Item> responseTo = stringToObject( <json-string>, Item.class );

我仅收到com.google.gson.internal.LinkedTreeMap作为数据对象。

我该怎么做才能使其正常工作? -我做错了吗?

3 个答案:

答案 0 :(得分:1)

您需要使用类型令牌来处理一般情况,因为Java编译器将擦除T的类型信息,而Gson也不知道将T还原为哪种类型。

Type typeToken = new TypeToken<ResponseTo<Item>>() { }.getType();
ResponseTo<Item> responseTo = stringToObject( <json-string>, typeToken );

答案 1 :(得分:0)

Gson

您可以使用内部com.google.gson.internal.$Gson$Types类来实现此目的:

import com.google.gson.Gson;
import com.google.gson.internal.$Gson$Types;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

public class GsonApp {

    public static void main(String[] args) {
        String json = "{\n" +
                "  \"totalsize\": 5,\n" +
                "  \"data\": [\n" +
                "    {\n" +
                "      \"name\": 1\n" +
                "    },\n" +
                "    {\n" +
                "      \"name\": 2\n" +
                "    }\n" +
                "  ]\n" +
                "}\n";

        System.out.println(stringToObject(json, Item.class));
    }

    static <T> ResponseTo<T> stringToObject(String jsonString, Class<T> clazz) {
        final Gson gson = new Gson();
        // do some typeadapter function magic
        ParameterizedType parameterizedType = $Gson$Types.newParameterizedTypeWithOwner(ResponseTo.class, ResponseTo.class, clazz);
        return gson.fromJson(jsonString, parameterizedType);
    }
}

class ResponseTo<T> {

    public Long totalsize = null;
    public final List<T> data = new ArrayList<>();

    @Override
    public String toString() {
        return "ResponseTo{" +
                "totalsize=" + totalsize +
                ", data=" + data +
                '}';
    }
}

class Item {
    public int name;

    @Override
    public String toString() {
        return "Item{" +
                "name=" + name +
                '}';
    }
}

上面的代码显示:

ResponseTo{totalsize=5, data=[Item{name=1}, Item{name=2}]}

Jackson

Jackson中,您可以执行类似的方法:

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        String json = "{\n" +
                "  \"totalsize\": 5,\n" +
                "  \"data\": [\n" +
                "    {\n" +
                "      \"name\": 1\n" +
                "    },\n" +
                "    {\n" +
                "      \"name\": 2\n" +
                "    }\n" +
                "  ]\n" +
                "}\n";

        System.out.println(stringToObject(json, Item.class));
    }

    static <T> ResponseTo<T> stringToObject(String jsonString, Class<T> clazz) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        // do some typeadapter function magic
        JavaType responseType = mapper.getTypeFactory().constructParametricType(ResponseTo.class, clazz);
        return mapper.readValue(jsonString, responseType);
    }
}

答案 2 :(得分:0)

如果对象中有类型区分符(即,每个示例中的公共字段均具有唯一值),那么Jackson @JsonTypeInfo(JsonTypeInfo.As.EXISTING_PROPERTY...)将允许您定义查找位置,并且初始化可以使用以下方法预先注册所有可能的类: ObjectMapper.registerSubtypes(Item.class)。然后,杰克逊会选择正确的人。

如果要实例化类型的规则比“在字段X中查找”复杂,那么您必须编写自己的@JsonTypeResolver来实现所说的逻辑(不平凡)。