Brenno Leal Brenno Leal - 4 days ago 3
Java Question

return generic list type according the parameter

Im getting a data from web service. I would like to create a generic method to make the request, and cast the output depending of the type I pass as parameter. Lets see the code:

public <T> Class getAPI(URL url, Class <T> clazz)
{
// GET
ObjectMapper mapper = new ObjectMapper();
List<clazz> objs = mapper.readValue(url, new TypeReference<List<clazz>>(){});
return objs;
}


No sucess yet...

Is it possible?

Edit

This is how i call the method:

URL url = new URL("http://localhost:8080/...");
Util u = new Util();
List<className> objs = u.getAPI(url, className.class);
System.out.println(className.get(0).getId());


Stacktrace of the ClassCastException

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to pkg.className
at GetTest.test(GetTest.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Answer

Finally. did a bit of research, now it works as we needed (sorry, this one got very personal to me [insert angry emoji here])

And here is the magic:

public <T> List<T> getAPI(URL url, Class <T> clazz) throws JsonParseException, JsonMappingException, IOException {   
        // GET 
        ObjectMapper mapper = new ObjectMapper();        
        List<T> objs = mapper.readValue(url, TypeFactory.defaultInstance().constructParametrizedType(ArrayList.class, List.class, clazz));
        return objs;
    }

Here the full Code (TestData still the same):

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;

public class Util {

    // Just as posted by prior post:
    public <T> List<T> getAPI(URL url, Class <T> clazz) throws JsonParseException, JsonMappingException, IOException {   
        // GET 
        ObjectMapper mapper = new ObjectMapper();        
        List<T> objs = mapper.readValue(url, TypeFactory.defaultInstance().constructParametrizedType(ArrayList.class, List.class, clazz));
        return objs;
    }

    // Test all together
    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
        URL url = new URL("https://jsonplaceholder.typicode.com/comments");
        Util u = new Util();
        List<TestData> objs = u.getAPI(url, TestData.class);
        System.out.println(objs.get(0).getId());
    }
}

--- not sooo original post ---

Well, guess i failed one more time... in fact, the generics work fine, but Jackson doesn't like our generics, as pointed out here: https://stackoverflow.com/a/6078477/2355392

The second method could be a good point to start, but as i was trying this out, i didn't have a TypeFactory.genericType() in my classpath, maybe wrong jackson-version...

The screenshot below is ok, until you let the SysOut run, it crashes with your ClassCastException you mentioned above (how embarrassing...)

--- original post---

So here you go:

import java.io.IOException;
import java.net.URL;
import java.util.List;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Util {

    // exactly like posted in my prior answer (despite exceptionhandling):
    public <T> List<T> getAPI(URL url, Class <T> clazz) throws JsonParseException, JsonMappingException, IOException {   
        // GET 
        ObjectMapper mapper = new ObjectMapper();        
        List<T> objs = mapper.readValue(url, new TypeReference<List<T>>(){});
        return objs;
    }

    // Test all together
    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
        // thanks for this URL!
        URL url = new URL("https://jsonplaceholder.typicode.com/comments");
        Util u = new Util();
        List<TestData> objs = u.getAPI(url, TestData.class);
        System.out.println(objs.get(0).getId());
    }
}

The TestData PoJo i used:

public class TestData {

    private String name, email, body;
    private int postId, id;

    // generated by IDE, i'm lazy AF
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getBody() {
        return body;
    }
    public void setBody(String body) {
        this.body = body;
    }
    public int getPostId() {
        return postId;
    }
    public void setPostId(int postId) {
        this.postId = postId;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }       
}

Result ((edit: NOT!!)good enough, i guess): Breakpoint on SysOut, returned ArrayList