No, you can not use type variables like T this way with TypeReference: you must pass actual parameterization. This is because there is no runtime information whatsoever associated with T here: it is just a placeholder. So it is effectively treated as java.lang.Object.
But you can build structured types programmatically using TypeFactory (instance of which is available via ObjetMapper.getTypeFactory()). You will still need Class instances that represent key and value types, but with this information it is possible to construct JavaType values that contain full type information that you need.
No, you can not use type variables like T this way with TypeReference: you must pass actual parameterization. This is because there is no runtime information whatsoever associated with T here: it is just a placeholder. So it is effectively treated as java.lang.Object.
But you can build structured types programmatically using TypeFactory (instance of which is available via ObjetMapper.getTypeFactory()). You will still need Class instances that represent key and value types, but with this information it is possible to construct JavaType values that contain full type information that you need.
you can do like this
public T fromMap(S map, TypeReference<T> typeReference) {
ObjectMapper objectMapper = new ObjectMapper();
T obj = objectMapper.convertValue(map, typeReference);
return obj;
}
[Update Sept 2020] Although my original answer here, from many years ago, seems to be helpful and is still getting upvotes, I now use the GSON library from Google, which I find to be more intuitive.
I've got the following code:
public void testJackson() throws IOException {
ObjectMapper mapper = new ObjectMapper();
File from = new File("albumnList.txt");
TypeReference<HashMap<String,Object>> typeRef
= new TypeReference<HashMap<String,Object>>() {};
HashMap<String,Object> o = mapper.readValue(from, typeRef);
System.out.println("Got " + o);
}
It's reading from a file, but mapper.readValue() will also accept an InputStream and you can obtain an InputStream from a string by using the following:
new ByteArrayInputStream(astring.getBytes("UTF-8"));
There's a bit more explanation about the mapper on my blog.
Try TypeFactory. Here's the code for Jackson JSON (2.8.4).
Map<String, String> result;
ObjectMapper mapper;
TypeFactory factory;
MapType type;
factory = TypeFactory.defaultInstance();
type = factory.constructMapType(HashMap.class, String.class, String.class);
mapper = new ObjectMapper();
result = mapper.readValue(data, type);
Here's the code for an older version of Jackson JSON.
Map<String, String> result = new ObjectMapper().readValue(
data, TypeFactory.mapType(HashMap.class, String.class, String.class));
It is already reported as an issue, but was labeled as 3.x.
There's a comment by the author of the library that explains why this hasn't been corrected yet:
Looks like
ObjectMapperAPI (and perhapsObjectReadertoo) omits type-variable matching withTypeReference. This would make sense to change, but is likely to cause some source-compatibility issues (not binary), so perhaps do this in 3.0 and not earlier.
TypeReference abstract class is not meant to be used directly as a container for generic information. This is from the javadoc:
This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to ResolvedType implementation (implemented by JavaType from "databind" bundle) to be used.
Even if ObjectMapper accepted a parameterized TypeReference ,it wouldn't do the job since all generic specification like this new TypeReference<List<Long>> { } is completely erased at run time.
To pass generic information to Jackson's ObjectMapper, you need to create a JavaType instance:
JavaType type = mapper.getTypeFactory().constructCollectionType(List.class, Long.class);
and then
List<Long> list = mapper.readValue(..., type);