Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics and Super Type Tokens

I am trying to make the three following methods into one generic solution, I tried some ideas which compile but don't do well at runtime.

public static List<User> parseToUsers(HttpResponse response) {
  ObjectMapper mapper = new ObjectMapper();
  String results = parseToString(response);
  return mapper.readValue(results, new TypeReference<List<User>>() {});
}

public static List<Record> parseToRecords(HttpResponse response) {
  ObjectMapper mapper = new ObjectMapper();
  String results = parseToString(response);
  return mapper.readValue(results, new TypeReference<List<Record>>() {});
}

public static Record parseToRecord(HttpResponse response) {
  ObjectMapper mapper = new ObjectMapper();
  String results = parseToString(response);
  return mapper.readValue(results, new TypeReference<Record>() {});;
}

I have also tried to understand this blog post about Super Type Tokens.

EDIT:

This is what I came up with so far:

public static <T> T parseJsonResponse(TypeReference<T> type, HttpResponse response) throws DroidException {
    ObjectMapper mapper = new ObjectMapper();
    String results = parseResponseToString(response);
    return readValue = mapper.readValue(results, type);
}

Then I call it like this.

parseJsonResponseToList(new TypeReference<List<Record>>() {}, response)

Not really satisfieng.Is there a better solution?


1 Answers

So what exactly is the problem? In what way do you not like it?

Jackson has other ways for constructing generic types; so perhaps what are looking for is along lines of:

public List<T> listOf(String json, Class<T> elementType) {
   ObjectMapper mapper = new ObjectMapper(); // should (re)use static instance for perf!
   JavaType listType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, elementType);
   return mapper.readValue(json, listType);
}

TypeFactory can be used to programmatically construct types that use generics -- return type is JavaType, because basic Java Class is type-erased. TypeFactory is actually used to convert TypeReference to JavaType internally as well.

EDIT

As to regular, non-Collection/Map types, it's really quite simple:

public T parseSingle(Class<T> cls, InputStream src) throws IOException {
  return mapper.readValue(src, cls);
}

(you also do NOT want to read contents as String -- not only is it slow, but it's easy to mess up character encodings, so if possible, feed InputStream or byte[] instead)

like image 96
StaxMan Avatar answered Jul 20 '26 20:07

StaxMan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!