Fatih Enes
Fatih Enes

Reputation: 77

Java ObjectMapper.readValue turns generic type to LinkedHashMap

    @Service
public class PokemonManager implements PokemonService {

    private HttpResponse<String> getStringHttpResponseByUrl(final String url) {
        HttpClient httpClient = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .GET().header("accept", "application/json")
                .uri(URI.create(url)).build();
        HttpResponse<String> httpResponse = null;
        try {
            httpResponse = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        return httpResponse;
    }

    private <T> T getObjectResponse(T t, String url) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            t = objectMapper.readValue(getStringHttpResponseByUrl(url).body(), new TypeReference<>() {
            });
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        return t;
    }

    private List<Pokemon> getAllPokemonsAsList() {

        final String POSTS_API_URL = "https://pokeapi.co/api/v2/pokemon?limit=10000";
        PokeApiResponse pokeApiResponse = new PokeApiResponse();
        pokeApiResponse = getObjectResponse(pokeApiResponse, POSTS_API_URL);
        System.out.println(pokeApiResponse);
        return pokeApiResponse.results;
    }

    @Override
    public List<Pokemon> getAll() {
        return getAllPokemonsAsList();
    }

I have a code as above. If I do not use generics in the "getObjectResponse" method, the code works fine. However, when I use generics, the type of "t" becomes "LinkedHashMap" instead of "PokeApiResponse", and the code crashes. How can I fix this problem?

Upvotes: 2

Views: 4566

Answers (2)

udalmik
udalmik

Reputation: 7998

You are not passing enough information for ObjectMapper to parse the JSON this way. Also there is no need to pass the instance of response, you can use the Class instead. I would also extract json parsing logic to separate method:

    public static <T> T jsonToModel(String document, Class<T> type) throws IOException {
        return new ObjectMapper().readValue(document, type);
    }

    private List<Pokemon> getAllPokemonsAsList() {
        final String postsApiUrl = "https://pokeapi.co/api/v2/pokemon?limit=10000";
        final HttpResponse<String> httpResponse = getStringHttpResponseByUrl(postsApiUrl);
        final PokeApiResponse pokeApiResponse = jsonToModel(pokeApiResponse, PokeApiResponse.class);
        System.out.println(pokeApiResponse);
        return pokeApiResponse.results;
    }

Upvotes: 1

jcompetence
jcompetence

Reputation: 8383

Generally you would use it:

objectMapper.readValue("yourJSONHere", PokeApiResponse.class);

If you wanted a Generic T response perhaps this would work

private <T> T getGeneric(Class<T> clazz, String json) throws IOException {
    return  new ObjectMapper().readValue(json, clazz);
}

Example:

    Pokemon charmander = getGeneric(Pokemon.class, "{\n" +
            "  \"name\": \"charmander\"\n" +
            "}");

Upvotes: 7

Related Questions