1 在需要忽略某些字段的bean
上添加@JsonFilter("fieldFilter")
2ObjectMapper设置过滤器
FilterProvider filterProvider = new SimpleFilterProvider();
SimpleBeanPropertyFilter fieldFilter = SimpleBeanPropertyFilter().serializeAllExcept("name");
filterProvider.addFilter("fieldFilter");
new ObjectMapper.setFilters(filterProvider );
在需要忽略的字段上标注注解@JsonIgnore
,在序列化时即可忽略该字段
public class ArticleIgnore {
private String title;
@JsonIgnore
private String summary;
private String content;
@JsonIgnore
private String author;
// 省略setter、getter方法
@Override
public String toString() {
return "ArticleIgnore [title=" + title + ", summary=" + summary + ", content=" + content + ", author=" + author
+ "]";
}
}
/**
* 为字段添加@JsonIgnore注解,可以忽略该字段的序列化和反序列化。
*
* @throws JsonProcessingException
*/
@Test
public void jsonIgnore() throws JsonProcessingException {
ArticleIgnore article = new ArticleIgnore();
article.setTitle("title");
article.setSummary("summary");
article.setContent("content");
article.setAuthor("author");
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(article));
String str = "{\"title\":\"title\",\"summary\":\"summary\",\"content\":\"content\",\"author\":\"author\"}";
ArticleIgnore newArticle = mapper.readValue(str, ArticleIgnore.class);
System.out.println(newArticle.toString());
}
结果
{"title":"title","content":"content"}
ArticleIgnore [title=title, summary=null, content=content, author=null]
JsonIgnore作用于单个字段
,JsonIgnoreProperties作用于类的多个字段
,两者都是用来忽略指定的字段。
@JsonIgnoreProperties(ignoreUnknown = true),
将这个注解写在类上之后,就会忽略类中不存在的字段
@JsonIgnoreProperties({ "summary", "author" })
public class ArticleIgnoreProperties {
private String title;
private String summary;
private String content;
private String author;
// 省略getter、setter方法
@Override
public String toString() {
return "ArticleIgnoreProperties [title=" + title + ", summary=" + summary + ", content=" + content + ", author="
+ author + "]";
}
}
@Test
public void jsonIgnoreProperties() throws JsonProcessingException {
ArticleIgnoreProperties article = new ArticleIgnoreProperties();
article.setTitle("title");
article.setSummary("summary");
article.setContent("content");
article.setAuthor("author");
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(article));
String str = "{\"title\":\"title\",\"summary\":\"summary\",\"content\":\"content\",\"author\":\"author\"}";
ArticleIgnoreProperties newArticle = mapper.readValue(str, ArticleIgnoreProperties.class);
System.out.println(newArticle.toString());
}
结果
{"title":"title","content":"content"}
ArticleIgnoreProperties [title=title, summary=null, content=content, author=null]
public class AnimalIgnoreType {
private String name;
private Date date;
private Address address;
@JsonIgnoreType
public static class Address {
private String city;
// 忽略getter、setter方法
@Override
public String toString() {
return "Address [city=" + city + "]";
}
}
// 忽略getter、setter方法
@Override
public String toString() {
return "AnimalIgnoreType [name=" + name + ", date=" + date + ", address=" + address + "]";
}
}
@Test
public void ignoreType() throws JsonProcessingException {
AnimalIgnoreType animal = new AnimalIgnoreType();
animal.setName("sam");
animal.setDate(new Date());
AnimalIgnoreType.Address address = new AnimalIgnoreType.Address();
address.setCity("gz");
animal.setAddress(address);
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(animal));
String jsonString = "{\"name\":\"sam\",\"date\":1601714443779,\"address\":{\"city\":\"gz\"}}";
AnimalIgnoreType newAnimal = mapper.readValue(jsonString, AnimalIgnoreType.class);
System.out.println(newAnimal.toString());
}
结果
{"name":"sam","date":1601726994454}
AnimalIgnoreType [name=sam, date=Sat Oct 03 16:40:43 CST 2020, address=null]
在 bean 上加注解,作用于全局,但是有的时候,我们可能不需要在所有情况下都忽略这个对象的这些字段,下面这种方式可以支持定制过滤方式。
前面使用JsonIgnoreType注解,忽略的类型是固定的
。
利用ObjectMapper的addMixIn方法
,可以动态的将JsonIgnoreType注解应用于其他数据类型
。
public class AnimalIgnoreType {
private String name;
private Date date;
private Address address;
public static class Address {
private String city;
// 省略getter、setter方法
@Override
public String toString() {
return "Address [city=" + city + "]";
}
}
// 省略getter、setter方法
@Override
public String toString() {
return "AnimalIgnoreType [name=" + name + ", date=" + date + ", address=" + address + "]";
}
}
定义一个空的类,并添加JsonIgnoreType注解。
@JsonIgnoreType
public class IgnoreType {}
在序列化时,调用ObjectMapper的addMixIn方法,将JsonIgnoreType注解应用于目标类。
下面的例子,会将IgnoreType类的注解,添加到Date和Address上,因此序列化时这两个类对应的字段会被忽略
/**
* 调用ObjectMapper的addMixIn方法,将@JsonIgnoreType注解应用于任意目标类.
*
* @throws JsonProcessingException
*/
@Test
public void mixIn() throws JsonProcessingException {
AnimalIgnoreType animal = new AnimalIgnoreType();
animal.setName("sam");
animal.setDate(new Date());
AnimalIgnoreType.Address address = new AnimalIgnoreType.Address();
address.setCity("gz");
animal.setAddress(address);
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(Date.class, IgnoreType.class);
mapper.addMixIn(Address.class, IgnoreType.class);
System.out.println(mapper.writeValueAsString(animal));
}
结果
{"name":"sam"}
JSON字符串中含有我们并不需要的字段
,那么当对应的实体类中不含有该字段时,会抛出一个异常
,告诉你有些字段没有在实体类中找到,目的是不让他抛出异常
使用@JsonIgnoreProperties注解忽略
,参考上面方式三
@JsonIgnoreProperties(ignoreUnknown = true)
// jackson 1.9版本之前(包括1.9)
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// jackson 2.x
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
前情摘要
先来一点故事补充,话说小明的领导给小明安排了一个任务,很简单就是调用别人的API,我们作为Client接收数据并进行相应的处理,领导说由于各种原因,目前不知道对方接口的返回数据格式,所以你先做数据解析吧,先写XML格式的,于是小明开始着手工作了,经过编码,调试,并且领导也review通过了。但是,领导接到消息说数据格式好像是JSON格式的,小明只好重新开始工作了。解析XML格式的代码请点击访问以下链接:
小明一听解析JSON格式,那不是手到擒来么,以前经常这么干,如以下代码所示
JSONObject jsonObject = new JSONObject(assetJson);
JSONArray jsonArray = jsonObject.getJSONArray("value");
for(int i=0;i<jsonArray.length();i++) {
JSONObject jsonObj = jsonArray.getJSONObject(i);
if(jsonObj.has("AssetNumber") && !jsonObj.isNull("AssetNumber")) {
asset.setAssetNumber(jsonObj.getLong("AssetNumber"));
}
这段代码应该都能读懂,就是传进来一个Json字符串
,然后用一个实体类
接收,为了防止异常保证代码健壮性,很多人都会像小明一样加上jsonObject.has(key
)和jsonObject.isNull(key)
。这时候小明正在为自己的小聪明得意,但是殊不知,这个json对象中有60多个key,意思就是得为这个小聪明多写120行重复
的代码。然后再仔细一看,对方的API返回的数据,字段都是超级多,很显然,这么多重复代码无论你是放在Service层处理还是直接裸在Controller里都不是很友好。然后你是不是以为我要提高代码的可重用性,哈哈,这样的代码如果按这个思路来的话是没有办法简化的。那怎么办,换一个思路咯。(有点小啰嗦,请见谅)
json数据例子如下:
{"@odata.context": "/$metadata#Materials",
"value": [{
"@odata.type": "#Nlyte.Model.StandardNetworkMaterial",
"MaterialID": 1
},
{
"@odata.type": "#Nlyte.Model.StandardServerMaterial",
"MaterialID": 96
},
{
"@odata.type": "#Nlyte.Model.BladeServerMaterial",
"MaterialID": 101
}],
"@odata.nextLink": "Materials?$skip=200"
}
由于服务端传过来的json数据格式问题,小明写了如下实体类
public class JsonResultForMaterial {
@JsonProperty(value="@odata.context")
private String odatacontext;
private List<Material> value;
@JsonProperty(value="@odata.nextLink")
private String odatanextLink;
....
}
public class Material {
@JsonProperty(value = "@odata.type")
private String odataType;
@JsonProperty(value = "MaterialID")
private int materialID;
....
}
在Json反序列化过程中,key需要和你定义的实体类的属性对应
,但是大家都知道,实体类属性的命名规范
,关于首字母和特殊字符的问题是很严格的。以上json数据中出现了,这样的key如:
@odata.context 、MaterialID
这样是无法直接用实体类接收的
。这时候需要用到@JsonProperty(),来修饰具体属性
,这样就可以解决无法映射的问题
这样我们就获得了一个json结果对象,里面有我们需要操作的属性。这里不用考虑,开篇的那个问题,比如key是否存在,key的值是否为空。然后代码可以改成如下:
public List<Asset> getAssetsFromNlyte(List<NlyteAsset> nlyteAssets) {
List<Asset> assetsFromNlyte = new ArrayList<Asset>();
Asset asset;
for(NlyteAsset nlyteAsset:nlyteAssets) {
asset = new Asset();
asset.setAssetNumber(nlyteAsset.getAssetNumber());
asset.setTag(nlyteAsset.getTag());
assetsFromNlyte.add(asset);
}
return assetsFromNlyte;
}
开篇的代码接收到的是一个json字符串,需要使用JSONObject和JSONArray等进行处理,还需要判断key等等,最后再进行数据的封装。这里的代码直接接收到一个list,然后直接进行遍历,封装数据。这里就解决了,要写很多has(key)和isNull(key)判断的问题。
@Getter
@Setter
@ToString
public class Account {
private Location location;
private PersonInfo personInfo;
@Getter
@Setter
@ToString
public static class Location {
private String provinceName;
private String countyName;
}
@Getter
@Setter
@ToString
public static class PersonInfo {
private String userName;
private String fullName;
}
}
未扁平化之前
{
"location": {
"provinceName":"湖北",
"countyName":"武汉"
},
"personInfo": {
"userName": "coder1234",
"fullName": "shaungkou"
}
}
使用@JsonUnwrapped 扁平对象之后
@Getter
@Setter
@ToString
public class Account {
@JsonUnwrapped
private Location location;
@JsonUnwrapped
private PersonInfo personInfo;
......
}
{
"provinceName":"湖北",
"countyName":"武汉",
"userName": "coder1234",
"fullName": "shaungkou"
}