How to read JSON in list of generic

北城以北 提交于 2021-02-11 17:51:07

问题


I have a helper class calling a REST web service. This helper class receives the information from the web service within a class defined as a generic "R". I can easily use GSON to read my JSON in a POJO, but I can't figure out how to give it a List and read it properly.

So far I have tried to extract the type of R in a variable and pass it to the List without success. I have tried using Jackson with its TypeFactory, also without success, it won't take R as its parameter.

What I want to do is something like this :

resource = new GsonBuilder().create().fromJson(response,List<R>)

or with Jackson

resource = mapper.readValue(response, List<R>);

"response" being my JSON string and resource the instance of List I want to return.

I can use either GSON or Jackson. I have been trying with both since some things looked more possible with one or the other.

I was able to make it work with a non generic, but all I get with a generic is a list of list of Map of the JSON fields. It's basically ignoring the type of R.

Also, R is extended from a class called BaseResource, so I know R will always be a child of BaseResource, but the fields I need are in the child.

Bonus: my true end goal is to have my generic R be a list of a specific object. So if I could instead have :

resource = new GsonBuilder().create().fromJson(response,R)

and R can be either a BaseResource or a List. I already made it work for BaseResource, but I need it to make it work for List somehow either by my duplicating most of it and explicitely states it's a List or passing List to R.

Our current workaround is to have a wrapper that contains a list:

private class Result{
    private List<BaseResource> result;
}

but we want the web service to return lists instead of wrappers like that.


回答1:


With GSON you have to implement your own serializer see: Type Information within serialized JSON using GSON

If you were to use Jackson you can solve this using @JsonTypeInfo annotation polymorphic types: https://www.logicbig.com/tutorials/misc/jackson/jackson-json-type-info-annotation.html




回答2:


did not read if you use any framework, well if you use spring you can use restTemplate and Jackson, here is an example of a generic class to call a rest service

private <Q, R> R callGeneric(String url, Q query, Class<R> responseClass) {
    R response = null;
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    HttpEntity<Q> req = new HttpEntity<Q>(query, headers);
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    ResponseEntity<R> callResult = null;
    try{
        callResult = restTemplate.exchange(url, HttpMethod.POST, req, responseClass);
    }catch(HttpClientErrorException e){
        logger.error(e.getStatusCode());
        logger.error(e.getResponseBodyAsString());
        throw e;
    }
    if (callResult == null) {
        logger.error("callGeneric: No response (void) of the rest service");
        return null;
    }
    response = callResult.getBody();
    if (response == null) {
        logger.error("callGeneric: empty response) ");
        return null;
    }
    return response;
}

public ObjectResponse setCustCommunicationSetup(objectRequest request) {
    String url = restCommunicationHostServer + custCommunicationContext + custCommunicationServiceSetCommunicationSetup;
    logger.debug("callGeneric: "+url);
    return callGeneric(url, request, ObjectResponse.class);
}



回答3:


a similar problem is described hear maybe it will still help you

You must create correctly Type if you want deserialize List of generic

public static <T> List<T> deserialize(String json, Class<T> clazz) {
    Type type = TypeToken.getParameterized(List.class,clazz).getType();
    return new Gson().fromJson(json, type);
}

OR

Type myType = new TypeToken<List<DTO1>>() {}.getType();
List<DTO1> deserialize = new Gson().fromJson(json, myType);

OR

Yours workaround -- for me is good


problem is T because Java does not know what i kind and generate Type of T

public static <T> List<T> sec(String json, Class<T> clazz) {
    Type type1 = new TypeToken<List<T>>() {}.getType();
    Type type2 = new TypeToken<List<DTO1>>() {}.getType();
    Type type = TypeToken.getParameterized(List.class, clazz).getType();

    System.out.println(type1);   //==>....*List<T>
    System.out.println(type2);   //==>....*List<....DTO1> --> this declaration In Java
    System.out.println(type);    //==>....*List<....DTO1>
    return new Gson().fromJson(json, type);
}

Testing

this is test for more example to correct run

package pl.jac.litsofgeneriric;

import java.lang.reflect.Type;
import java.util.List;
import java.util.UUID;
import org.junit.Assert;
import org.junit.Test;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

public class DeserializeListGenericTest {

    @Test
    public void deserializeDTO1() {
        //given
        String json = "[{\"id\":1,\"name\":\"test1\"},{\"id\":2,\"name\":\"test2\"}]";
        //when
        List<DTO1> deserialize = DeserializeListGeneric.deserialize(json, DTO1.class);
        //then
        Assert.assertEquals("test1", deserialize.get(0).name);
    }

    @Test
    public void deserializeDTO2() {
        //given
        String json = "[{\"uuid\":\"97e98a6d-aae8-42cb-8731-013c207ea384\",\"name\":\"testUUID1\"},{\"uuid\":\"36c60080-7bb2-4c71-b4d8-c5a0a5fa47a2\",\"name\":\"testUUID1\"}]";
        //when
        List<DTO2> deserialize = DeserializeListGeneric.deserialize(json, DTO2.class);
        //then
        Assert.assertEquals("testUUID1", deserialize.get(0).name);
    }

    @Test
    public void deserializeMyType() {
        //given
        String json = "[{\"id\":1,\"name\":\"test1\"},{\"id\":2,\"name\":\"test2\"}]";
        //when
        Type myType = new TypeToken<List<DTO1>>() {
        }.getType();
        List<DTO1> deserialize = new Gson().fromJson(json, myType);
        //then
        Assert.assertEquals("test1", deserialize.get(0).name);
    }

    @Test
    public void deserializeGsonBuilder() {
        //given
        String json = "[{\"id\":1,\"name\":\"test1\"},{\"id\":2,\"name\":\"test2\"}]";
        //when

        Type myType = new TypeToken<List<DTO1>>() {
        }.getType();
        List<DTO1> deserialize = new GsonBuilder().create().fromJson(json, myType);
        //then
        Assert.assertEquals("test1", deserialize.get(0).name);
    }
    @Test
    public void useSystemOut() {
        //given
        String json = "[{\"id\":1,\"name\":\"test1\"},{\"id\":2,\"name\":\"test2\"}]";
        //when
        List<DTO1> deserialize = sec(json, DTO1.class);
        //then
        Assert.assertEquals("test1", deserialize.get(0).name);
    }

    public static <T> List<T> sec(String json, Class<T> clazz) {
        Type type1 = new TypeToken<List<T>>() {}.getType();
        Type type2 = new TypeToken<List<DTO1>>() {}.getType();
        Type type = TypeToken.getParameterized(List.class, clazz).getType();

        System.out.println(type1);   //==>....*List<T>
        System.out.println(type2);   //==>....*List<....DTO1> --> this declaration In Java
        System.out.println(type);    //==>....*List<....DTO1>
        return new Gson().fromJson(json, type);
    }

    public static class DTO1 {

        public Long id;
        public String name;
    }

    public static class DTO2 {
        public UUID uuid;
        public String name;
    }
}

and class DeserializeListGeneric

package pl.jac.litsofgeneriric;

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

public class DeserializeListGeneric {


    public static <T> List<T> deserialize(String json, Class<T> clazz) {
        Type type = TypeToken.getParameterized(List.class,clazz).getType();
        return new Gson().fromJson(json, type);
    }
}


来源:https://stackoverflow.com/questions/57676552/how-to-read-json-in-list-of-generic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!