Jackson反序列化集合元素为LinkedHashMap,如何转为指定DTO类型?
解决Jackson反序列化泛型集合为LinkedHashMap的问题
这个问题我之前也碰到过,是Jackson处理泛型多态集合时因为类型擦除导致的典型问题——Java编译时会擦除泛型信息,运行时Jackson不知道List<? extends MovieInfoDTO>里的元素该对应哪个具体子类,所以默认用LinkedHashMap来存储JSON键值对,最终导致强转报错。下面给你几个可行的解决办法:
方法一:给父类添加多态类型注解(推荐,支持多子类场景)
在父类MovieInfoDTO上添加Jackson的多态识别注解,明确告诉Jackson如何区分不同的子类类型:
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type" // 这个字段用来标识子类类型,需要在JSON请求中携带 ) @JsonSubTypes({ @JsonSubTypes.Type(value = BoxOffice.class, name = "boxOffice"), // 如果还有其他MovieInfoDTO的子类,比如MovieRating,继续添加 @JsonSubTypes.Type(value = MovieRating.class, name = "movieRating") }) public abstract class MovieInfoDTO { // 父类的字段、方法定义 }
之后你的JSON请求里只要包含"type":"boxOffice"字段,Jackson就会自动把对应的元素反序列化成BoxOffice对象,而不是LinkedHashMap。
方法二:在Builder的集合字段指定具体元素类型(适合单一子类场景)
如果你的elementsToAdd集合只会包含BoxOffice一种子类,可以直接在Builder的集合字段上用@JsonDeserialize的contentAs属性指定元素类型:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; public class ContributionNewRequest { private List<? extends MovieInfoDTO> elementsToAdd; private ContributionNewRequest(Builder builder) { this.elementsToAdd = builder.elementsToAdd; } @JsonDeserialize(builder = Builder.class) public static class Builder { // 明确指定集合元素的具体类型为BoxOffice @JsonDeserialize(contentAs = BoxOffice.class) private List<? extends MovieInfoDTO> elementsToAdd; public Builder elementsToAdd(List<? extends MovieInfoDTO> elementsToAdd) { this.elementsToAdd = elementsToAdd; return this; } public ContributionNewRequest build() { return new ContributionNewRequest(this); } } }
注意这个方法只适合集合中只有一种子类的场景,如果有多种子类,还是方法一更灵活。
方法三:手动反序列化时使用TypeReference(适合手动调用Jackson的场景)
如果你是手动用ObjectMapper反序列化JSON字符串,而不是框架自动处理,可以通过TypeReference来保留泛型信息:
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; ObjectMapper mapper = new ObjectMapper(); ContributionNewRequest request = mapper.readValue( jsonRequestString, new TypeReference<ContributionNewRequest>() {} );
不过看你的场景应该是Spring MVC这类框架自动处理请求,所以前两种方法更贴合你的需求。
内容的提问来源于stack exchange,提问作者JONKI
相关产品推荐
相关产品推荐

