json 相关

Jackson序列化时忽略字段的方式

方式一 自定义过滤器

1 在需要忽略某些字段的bean上添加@JsonFilter("fieldFilter")

2ObjectMapper设置过滤器

FilterProvider filterProvider = new SimpleFilterProvider();

SimpleBeanPropertyFilter fieldFilter = SimpleBeanPropertyFilter().serializeAllExcept("name");
filterProvider.addFilter("fieldFilter");
new ObjectMapper.setFilters(filterProvider );

方式二 @JsonIgnore

需要忽略的字段上标注注解@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]

方式三 @JsonIgnoreProperties注解忽略 不存在的字段 、多个字段

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]

方式四 JsonIgnoreType注解忽略指定类型的字段

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]

方式五 addMixIn() 方法 定制过滤方式

在 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"}

解决 jackson默认序列化实体类的所有属性,不存在则报错

JSON字符串中含有我们并不需要的字段,那么当对应的实体类中不含有该字段时,会抛出一个异常,告诉你有些字段没有在实体类中找到,目的是不让他抛出异常

方式一 @JsonIgnoreProperties 注解

使用@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);

@JsonProperty使用

前情摘要
先来一点故事补充,话说小明的领导给小明安排了一个任务,很简单就是调用别人的API,我们作为Client接收数据并进行相应的处理,领导说由于各种原因,目前不知道对方接口的返回数据格式,所以你先做数据解析吧,先写XML格式的,于是小明开始着手工作了,经过编码,调试,并且领导也review通过了。但是,领导接到消息说数据格式好像是JSON格式的,小明只好重新开始工作了。解析XML格式的代码请点击访问以下链接:

解析XML格式代码

代码编写之JSONObject解决一切

小明一听解析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反序列化

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)判断的问题。

json 扁平化

@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"
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值