jackson允许配置多态类型处理,当进行反序列话时,JSON数据匹配的对象可能有多个子类型,为了正确的读取对象的类型,我们需要添加一些类型信息。可以通过下面几个注解来实现:
@JsonTypeInfo
作用于类/接口,被用来开启多态类型处理,对基类/接口和子类/实现类都有效
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property = “name”)
这个注解有一些属性:
use:定义使用哪一种类型识别码,它有下面几个可选值:
JsonTypeInfo.Id.CLASS:使用完全限定类名做识别
JsonTypeInfo.Id.MINIMAL_CLASS:若基类和子类在同一包类,使用类名(忽略包名)作为识别码
JsonTypeInfo.Id.NAME:一个合乎逻辑的指定名称
JsonTypeInfo.Id.CUSTOM:自定义识别码,由@JsonTypeIdResolver对应,稍后解释
JsonTypeInfo.Id.NONE:不使用识别码
include(可选):指定识别码是如何被包含进去的,它有下面几个可选值:
JsonTypeInfo.As.PROPERTY:作为数据的兄弟属性
JsonTypeInfo.As.EXISTING_PROPERTY:作为POJO中已经存在的属性
JsonTypeInfo.As.EXTERNAL_PROPERTY:作为扩展属性
JsonTypeInfo.As.WRAPPER_OBJECT:作为一个包装的对象
JsonTypeInfo.As.WRAPPER_ARRAY:作为一个包装的数组
property(可选):制定识别码的属性名称
此属性只有当:
use为JsonTypeInfo.Id.CLASS(若不指定property则默认为@class)、JsonTypeInfo.Id.MINIMAL_CLASS(若不指定property则默认为@c)、JsonTypeInfo.Id.NAME(若不指定property默认为@type),
include为JsonTypeInfo.As.PROPERTY、JsonTypeInfo.As.EXISTING_PROPERTY、JsonTypeInfo.As.EXTERNAL_PROPERTY时才有效
defaultImpl(可选):如果类型识别码不存在或者无效,可以使用该属性来制定反序列化时使用的默认类型
visible(可选,默认为false):是否可见
属性定义了类型标识符的值是否会通过JSON流成为反序列化器的一部分,默认为fale,也就是说,jackson会从JSON内容中处理和删除类型标识符再传递给JsonDeserializer。
@JsonSubTypes
作用于类/接口,用来列出给定类的子类,只有当子类类型无法被检测到时才会使用它,一般是配合@JsonTypeInfo在基类上使用,比如:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property = “typeName”)
@JsonSubTypes({@JsonSubTypes.Type(value=Sub1.class,name = “sub1”),@JsonSubTypes.Type(value=Sub2.class,name = “sub2”)})
@JsonSubTypes的值是一个@JsonSubTypes.Type[]数组,里面枚举了多态类型(value对应子类)和类型的标识符值(name对应@JsonTypeInfo中的property标识名称的值,此为可选值,若不制定需由@JsonTypeName在子类上制定)
@JsonTypeName
作用于子类,用来为多态子类指定类型标识符的值
比如:
@JsonTypeName(value = “sub1”)
示例
基类:
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value= Test.RoleUser.class,name = "role"),@JsonSubTypes.Type(value= Test.TokenUser.class,name = "token")})
public abstract class AbstractBaseEntity {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public AbstractBaseEntity setUserName(String userName) {
this.userName = userName;
return this;
}
public String getPassword() {
return password;
}
public AbstractBaseEntity setPassword(String password) {
this.password = password;
return this;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("AbstractBaseEntity{");
sb.append("userName='").append(userName).append('\'');
sb.append(", password='").append(password).append('\'');
sb.append('}');
return sb.toString();
}
}
测试类
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @author micocube
* projectName: utils4j
* packageName: jackson
* email: ldscube@gmail.com
* createTime: 2019-07-05 11:23
* version: 0.1
* description:
*/
public class Test {
# 子类
public static class TokenUser extends AbstractBaseEntity {
private String token;
public String getToken() {
return token;
}
public TokenUser setToken(String token) {
this.token = token;
return this;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("TokenUser{");
sb.append("token='").append(token).append('\'');
sb.append('}');
sb.append(super.toString());
return sb.toString();
}
}
# 子类
public static class RoleUser extends AbstractBaseEntity {
private String roleName;
public String getRoleName() {
return roleName;
}
public RoleUser setRoleName(String roleName) {
this.roleName = roleName;
return this;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("RoleUser{");
sb.append("roleName='").append(roleName).append('\'');
sb.append('}');
sb.append(super.toString());
return sb.toString();
}
}
public static void main(String[] args) throws Exception{
ObjectMapper objectMapper = new ObjectMapper();
RoleUser roleUser = new RoleUser();
roleUser.setRoleName("role");
roleUser.setPassword("rolePwd");
roleUser.setUserName("roleUserName");
TokenUser tokenUser = new TokenUser();
tokenUser.setToken("token");
tokenUser.setPassword("tokenPassword");
tokenUser.setUserName("tokenUserName");
String roleStr = objectMapper.writeValueAsString(roleUser);
String tokenStr = objectMapper.writeValueAsString(tokenUser);
System.out.println(roleStr);
System.out.println(tokenStr);
AbstractBaseEntity roleEntity = objectMapper.readValue(roleStr, AbstractBaseEntity.class);
AbstractBaseEntity tokenEntity = objectMapper.readValue(tokenStr, AbstractBaseEntity.class);
System.out.println(roleEntity);
System.out.println(tokenEntity);
}
}
程序输出
{"type":"jackson.Test$RoleUser","userName":"roleUserName","password":"rolePwd","roleName":"role"}
{"type":"jackson.Test$TokenUser","userName":"tokenUserName","password":"tokenPassword","token":"token"}
RoleUser{roleName='role'}AbstractBaseEntity{userName='roleUserName', password='rolePwd'}
TokenUser{token='token'}AbstractBaseEntity{userName='tokenUserName', password='tokenPassword'}
因为基类中use = JsonTypeInfo.Id.CLASS,property = “type”,序列化时(输出的第一行和第二行type值为class限定名),若改为use = JsonTypeInfo.Id.NAME,property = “type”,那么输出如下,use是Name,取值为JsonSubTypes的name,属性名为type
{"type":"role","userName":"roleUserName","password":"rolePwd","roleName":"role"}
{"type":"token","userName":"tokenUserName","password":"tokenPassword","token":"token"}
RoleUser{roleName='role'}AbstractBaseEntity{userName='roleUserName', password='rolePwd'}
TokenUser{token='token'}AbstractBaseEntity{userName='tokenUserName', password='tokenPassword'}