• json 相关


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

    方式一 自定义过滤器

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

    2ObjectMapper设置过滤器

    FilterProvider filterProvider = new SimpleFilterProvider();
    
    SimpleBeanPropertyFilter fieldFilter = SimpleBeanPropertyFilter().serializeAllExcept("name");
    filterProvider.addFilter("fieldFilter");
    new ObjectMapper.setFilters(filterProvider );
    
    • 1
    • 2
    • 3
    • 4
    • 5

    方式二 @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
    		        + "]";
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    /**
     * 为字段添加@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());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    结果 
    
    {"title":"title","content":"content"}
    ArticleIgnore [title=title, summary=null, content=content, author=null]
    
    • 1
    • 2
    • 3
    • 4

    方式三 @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 + "]";
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    @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());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    结果
    
    {"title":"title","content":"content"}
    ArticleIgnoreProperties [title=title, summary=null, content=content, author=null]
    
    • 1
    • 2
    • 3
    • 4

    方式四 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 + "]";
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    @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());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    结果
    
    {"name":"sam","date":1601726994454}
    AnimalIgnoreType [name=sam, date=Sat Oct 03 16:40:43 CST 2020, address=null]
    
    • 1
    • 2
    • 3
    • 4

    方式五 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 + "]";
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    定义一个空的类,并添加JsonIgnoreType注解。

    @JsonIgnoreType
    public class IgnoreType {}
    
    • 1
    • 2

    在序列化时,调用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));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    结果
    
    {"name":"sam"}
    
    • 1
    • 2
    • 3

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

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

    方式一 @JsonIgnoreProperties 注解

    使用@JsonIgnoreProperties注解忽略参考上面方式三

    @JsonIgnoreProperties(ignoreUnknown = true)
    
    • 1

    方式二 全局配置

    // 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);
    
    • 1
    • 2
    • 3
    • 4

    @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"));
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这段代码应该都能读懂,就是传进来一个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"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    由于服务端传过来的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;
      ....
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    Json反序列化过程中,key需要和你定义的实体类的属性对应,但是大家都知道,实体类属性的命名规范,关于首字母和特殊字符的问题是很严格的。以上json数据中出现了,这样的key如:

    @odata.context 、MaterialID
    
    • 1

    这样是无法直接用实体类接收的。这时候需要用到@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;
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    开篇的代码接收到的是一个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;
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    未扁平化之前

    {
        "location": {
            "provinceName":"湖北",
            "countyName":"武汉"
        },
        "personInfo": {
            "userName": "coder1234",
            "fullName": "shaungkou"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用@JsonUnwrapped 扁平对象之后

    @Getter
    @Setter
    @ToString
    public class Account {
        @JsonUnwrapped
        private Location location;
        @JsonUnwrapped
        private PersonInfo personInfo;
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    {
      "provinceName":"湖北",
      "countyName":"武汉",
      "userName": "coder1234",
      "fullName": "shaungkou"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    京东面试题:ElasticSearch 深度分页解决方案
    教你快速认识Java中的继承和多态
    Windows系统上使用CLion远程开发Linux程序
    渗透测试靶场环境搭建
    准备HarmonyOS开发环境
    百家CMS代码审计
    springboot+社区疫苗管理系统 毕业设计-附源码191705
    gson的工具类JsonUtils
    RTL8380M管理型交换机系统软件操作指南一:端口配置
    Cesium展示——wkt 数据绘制
  • 原文地址:https://blog.csdn.net/qq_40813329/article/details/126382122