简介
之前我们都会使用 @JsonDeserialize
与 @JsonSerialize
来指定序列化与反序列化时使用的实际类型,但是现在这里有另外一种情况:
一个父类,多个子类,序列化时要求序列化所有属性,反序列化时要求使用实际类型,显然普通的序列化中没有包含子类类型信息,导致反序列化时无法确定使用多个子类中的哪一个,所以我们借助 Jackson 的 @JsonSubTypes
来实现多态解析。
举例
假如有以下两种格式json:
[
{
"id":1,
"type":"GITHUB",
"name":"Github代码库",
"path":"XuxuGood/jackjson",
"description":"JackJson多态解析"
},
{
"id":2,
"type":"GITLAB",
"name":"Gitlab代码库",
"path":"XuxuGood/jackjson",
"description":"JackJson多态解析"
}
]
{
"id":1,
"type":"GITHUB",
"name":"Github代码库",
"path":"XuxuGood/jackjson",
"description":"JackJson多态解析"
}
特点:
- 有公共字段,这里是
id
和type
type
用来确定是哪个子类
实现方式一
定义实体类
import com.example.jackson.common.RepoType;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;
/**
* @author xiaoxuxuy
*/
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = GithubRepo.class, name = "GITHUB"),
@JsonSubTypes.Type(value = GitlabRepo.class, name = "GITLAB")
})
public class BaseCodeRepo {
private Long id;
private RepoType type;
}
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author xiaoxuxuy
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class GithubRepo extends BaseCodeRepo {
private String name;
private String path;
private String description;
}
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author xiaoxuxuy
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class GitlabRepo extends BaseCodeRepo {
private String name;
private String path;
private String description;
}
解析
多个(GithubRepo和GitlabRepo数组)解析:
@Test
public void version1Json1Test() {
String jsonString = JsonConst.JSON1;
log.info("Json1字符串为: {}", jsonString);
ObjectMapper objectMapper = new ObjectMapper();
try {
List<BaseCodeRepo> baseCodeRepos = objectMapper.readValue(jsonString, new TypeReference<List<BaseCodeRepo>>() {
});
baseCodeRepos.forEach(item -> log.info(item.getType() + "对象信息为: {}", JSONObject.toJSONString(item)));
} catch (IOException e) {
e.printStackTrace();
}
}
单个 GithubRepo 解析:
@Test
public void version1Json2Test() {
String jsonString = JsonConst.JSON2;
log.info("Json2字符串为: {}", jsonString);
ObjectMapper mapper = new ObjectMapper();
try {
GithubRepo githubRepo = (GithubRepo) mapper.readValue(jsonString, BaseCodeRepo.class);
log.info("GITHUB对象信息为: {}", JSONObject.toJSONString(githubRepo));
} catch (IOException e) {
e.printStackTrace();
}
}
实现方式二
JsonTypeInfo 借助 @JsonSubTypes
注解来感知抽象类的有哪些实现类,并且知道是如何匹配的。在大型工程中抽象类的子类很多(接口的实现很多),那么 @JsonSubTypes
注解就显得十分臃肿,所以借助以下方式将 @JsonSubTypes
剔除掉。
定义实体类
import com.example.jackson.common.RepoType;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;
/**
* @author xiaoxuxuy
*/
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true)
public class BaseCodeRepo {
private Long id;
private RepoType type;
}
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* @author xiaoxuxuy
*/
@Data
@JsonTypeName(value = "GITHUB")
@EqualsAndHashCode(callSuper = true)
public class GithubRepo extends BaseCodeRepo {
private String name;
private String path;
private String description;
}
import com.fasterxml.jackson.annotation.JsonTypeName;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* @author xiaoxuxuy
*/
@Data
@JsonTypeName(value = "GITLAB")
@EqualsAndHashCode(callSuper = true)
public class GitlabRepo extends BaseCodeRepo {
private String name;
private String path;
private String description;
}
解析
多个(GithubRepo和GitlabRepo数组)解析:
@Test
public void version2Json1Test() {
ObjectMapper mapper = new ObjectMapper();
// 注入多态解析类
ClassFactory.BASE_CODE_REPOS.forEach(mapper::registerSubtypes);
String jsonString = JsonConst.JSON1;
log.info("Json1字符串为: {}", jsonString);
try {
List<BaseCodeRepo> baseCodeRepos = mapper.readValue(jsonString, new TypeReference<List<BaseCodeRepo>>() {
});
baseCodeRepos.forEach(item -> log.info(item.getType() + "对象信息为: {}", JSONObject.toJSONString(item)));
} catch (IOException e) {
e.printStackTrace();
}
}
单个 GithubRepo 解析:
@Test
public void version2Json2Test() {
ObjectMapper mapper = new ObjectMapper();
// 注入多态解析类
ClassFactory.BASE_CODE_REPOS.forEach(mapper::registerSubtypes);
String jsonString = JsonConst.JSON2;
log.info("Json2字符串为: {}", jsonString);
try {
GithubRepo githubRepo = (GithubRepo) mapper.readValue(jsonString, BaseCodeRepo.class);
log.info("GITHUB对象信息为: {}", JSONObject.toJSONString(githubRepo));
} catch (IOException e) {
e.printStackTrace();
}
}
评论区