14

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.

Mark Korzhov
  • 2,109
  • 11
  • 31
  • 63
  • @Dici I want to pass a generic class to the method as an argument and call TypeReference something like this: `new TypeReference>()` – Mark Korzhov Jan 03 '16 at 16:45
  • Your question is more or less the same as [this](http://stackoverflow.com/questions/20773850/gson-typetoken-with-dynamic-arraylist-item-type) except for Jackson rather than Gson. The answer remains the same, you just need to adapt the library APIs. – Sotirios Delimanolis Jan 03 '16 at 19:29

4 Answers4

11

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.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • 1
    Yes, this. In short: Type Erasure makes it impossible to do this in Java. However you can in Kotlin as I have found out. See also: https://github.com/FasterXML/jackson-module-kotlin/issues/412#issuecomment-769877247 – Stefan Hendriks Jan 29 '21 at 15:59
5

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.

Marcel Baumann
  • 181
  • 1
  • 6
0

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;
    }
...
Artanis Zeratul
  • 963
  • 2
  • 14
  • 40
0

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;
}

}
Mohammed Mukhtar
  • 1,731
  • 20
  • 18