Reputation: 2159
For json mapping I use the following method:
public static <T> T mapJsonToObject(String json, T dtoClass) throws Exception {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(json, new TypeReference<RestResponse<UserDto>>() {
});
}
And UserDto looks like this:
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserDto {
@JsonProperty("items")
private List<User> userList;
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
}
I want to improve this method of mapping without being attached to a UserDto class, and replacing it with a generic.
Is it possible? And How?
Thanks.
Upvotes: 15
Views: 24130
Reputation: 1741
This is an example of parsing simple List based generics with Jackson, with a simple Java annotation!
package innovate.tamergroup.lastmiledelivery.loader.otm.models;
import java.util.List;
import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"hasMore",
"limit",
"count",
"offset",
"items",
"links"
})
@Generated("jsonschema2pojo")
public class OTMListWrapper<T> {
@JsonProperty("hasMore")
private Boolean hasMore;
@JsonProperty("limit")
private Long limit;
@JsonProperty("count")
private Long count;
@JsonProperty("offset")
private Long offset;
@JsonTypeInfo(use=JsonTypeInfo.Id.NONE, include=JsonTypeInfo.As.PROPERTY, property="items")
private List<T> items = null;
@JsonProperty("links")
private List<OTMLink> links = null;
@JsonProperty("hasMore")
public Boolean getHasMore() {
return hasMore;
}
@JsonProperty("hasMore")
public void setHasMore(Boolean hasMore) {
this.hasMore = hasMore;
}
public OTMListWrapper<T> withHasMore(Boolean hasMore) {
this.hasMore = hasMore;
return this;
}
@JsonProperty("limit")
public Long getLimit() {
return limit;
}
@JsonProperty("limit")
public void setLimit(Long limit) {
this.limit = limit;
}
public OTMListWrapper<T> withLimit(Long limit) {
this.limit = limit;
return this;
}
@JsonProperty("count")
public Long getCount() {
return count;
}
@JsonProperty("count")
public void setCount(Long count) {
this.count = count;
}
public OTMListWrapper<T> withCount(Long count) {
this.count = count;
return this;
}
@JsonProperty("offset")
public Long getOffset() {
return offset;
}
@JsonProperty("offset")
public void setOffset(Long offset) {
this.offset = offset;
}
public OTMListWrapper<T> withOffset(Long offset) {
this.offset = offset;
return this;
}
@JsonProperty("items")
public List<T> getItems() {
return items;
}
@JsonProperty("items")
public void setItems(List<T> items) {
this.items = items;
}
public OTMListWrapper<T> withItems(List<T> items) {
this.items = items;
return this;
}
@JsonProperty("links")
public List<OTMLink> getLinks() {
return links;
}
@JsonProperty("links")
public void setLinks(List<OTMLink> links) {
this.links = links;
}
public OTMListWrapper<T> withLinks(List<OTMLink> links) {
this.links = links;
return this;
}
}
Upvotes: 0
Reputation: 1003
Try this:
import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Array;
import java.util.Arrays;
...
public static <TargetType> List<TargetType> convertToList(String jsonString, Class<TargetType> targetTypeClass) {
List<TargetType> listOfTargetObjects = null;
ObjectMapper objectMapper = new ObjectMapper();
TargetType[] arrayOfTargetType = (TargetType[]) Array.newInstance(targetTypeClass, 0);
try {
listOfTargetObjects = (List<TargetType>) Arrays.asList(objectMapper.readValue(jsonString, arrayOfTargetType.getClass()));
} catch (JsonMappingException jsonMappingException) {
listOfTargetObjects = null;
} catch (JsonProcessingException jsonProcessingException) {
listOfTargetObjects = null;
} catch (Exception exception) {
listOfTargetObjects = null;
}
return listOfTargetObjects;
}
...
Upvotes: 0
Reputation: 181
One approach will be to define a Jackson JavaType representing a list of items of type clazz. You still need to have access to the class of the generic parameter at runtime. The usual approach is something like
<T> class XX { XX(Class<T> clazz, ...) ... }
to pass the class of the generic parameter into the generic class at construction.
Upon access to the Class clazz variable you can construct a Jackson JavaType representing, for example, a list of items of class clazz with the following statement.
JavaType itemType = mapper.getTypeFactory().constructCollectionType(List.class, clazz);
I hope it helped. I am using this approach in my own code.
Upvotes: 5
Reputation: 116630
TypeReference
requires you to specify parameters statically, not dynamically, so it does not work if you need to further parameterize types.
What I think you need is JavaType
: you can build instances dynamically by using TypeFactory
. You get an instance of TypeFactory
via ObjectMapper.getTypeFactory()
. You can also construct JavaType
instances from simple Class
as well as TypeReference
.
Upvotes: 11