Jackson学习
文档:http://tutorials.jenkov.com/java-json/index.html
https://github.com/FasterXML/jackson/wiki
转载:https://www.cnblogs.com/yangchongxing/p/9153150.html
目录
=================================================================================
0、配置
3、反序列化列表对象List<CompanyLoopPicture>
4、Unrecognized field、反序列化时json中包含bean对象中没有的字段,也就是json中的字段比bean中的多
=================================================================================
0、配置
spring: # jackson 配置 jackson: # 日期格式化 date-format: yyyy-MM-dd HH:mm:ss # 时区 time-zone: GMT+8 # 序列化 serialization: # 格式化输出,true格式化了有利于人看 indent-output: false # 忽略无法转换的对象 fail-on-empty-beans: false # 反序列化 deserialization: # 允许对象忽略json中不存在的属性 fail-on-ignored-properties: false # 设置空如何序列化 default-property-inclusion: non_null # 转化 parser: # 允许出现特殊字符和转义符 allow-unquoted-control-chars: true # 允许出现单引号 allow-single-quotes: true
# 日期格式化 spring.jackson.date-format = yyyy-MM-dd HH:mm:ss # 时区 spring.jackson.time-zone = GMT+8 # 序列化 # 格式化输出,true格式化了有利于人看 spring.jackson.serialization.indent-output = false # 忽略无法转换的对象 spring.jackson.serialization.fail-on-empty-beans = false # 反序列化 # 允许对象忽略json中不存在的属性 spring.jackson.deserialization.fail-on-ignored-properties = false # 设置空如何序列化 spring.jackson.default-property-inclusion = non_null # 允许出现特殊字符和转义符 spring.jackson.parser.allow-unquoted-control-chars = true # 允许出现单引号 spring.jackson.parser.allow-single-quotes = true
Java 工具对象
static ObjectMapper objectMapper = new ObjectMapper(); static { // 如果json中有实体类中不存在的字段不报错 objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); }
package com.qq.weixin.mp.result; import com.fasterxml.jackson.databind.ObjectMapper; public class AccessTokenResult { private String accessToken; private long expiresIn; public String getAccessToken() { return accessToken; } public void setAccessToken(String accessToken) { this.accessToken = accessToken; } public long getExpiresIn() { return expiresIn; } public void setExpiresIn(long expiresIn) { this.expiresIn = expiresIn; } @Override public String toString() { return "AccessTokenResult [accessToken=" + accessToken + ", expiresIn=" + expiresIn + "]"; } public static void main(String[] args) { AccessTokenResult bean = new AccessTokenResult(); bean.setAccessToken("2r5fx9eiyapFxEGgHq"); bean.setExpiresIn(7200); try { ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(bean);//序列化 System.out.println(json); AccessTokenResult object = mapper.readValue(json, AccessTokenResult.class);//反序列化 System.out.println(object); } catch (Exception e) { e.printStackTrace(); } } }
结果
{"accessToken":"2r5fx9eiyapFxEGgHq","expiresIn":7200}
AccessTokenResult [accessToken=2r5fx9eiyapFxEGgHq, expiresIn=7200]
@JsonProperty(value="access_token") 也可以指定在属性字段上,这样就不用分别指定 get 和 set 方法了
package com.qq.weixin.mp.result; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; public class AccessTokenResult { private String accessToken; private long expiresIn; @JsonProperty(value="access_token") public String getAccessToken() { return accessToken; } @JsonProperty(value="access_token") public void setAccessToken(String accessToken) { this.accessToken = accessToken; } @JsonProperty(value="expires_in") public long getExpiresIn() { return expiresIn; } @JsonProperty(value="expires_in") public void setExpiresIn(long expiresIn) { this.expiresIn = expiresIn; } @Override public String toString() { return "AccessTokenResult [accessToken=" + accessToken + ", expiresIn=" + expiresIn + "]"; } public static void main(String[] args) { AccessTokenResult bean = new AccessTokenResult(); bean.setAccessToken("2r5fx9eiyapFxEGgHq"); bean.setExpiresIn(7200); try { ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(bean);//序列化 System.out.println(json); AccessTokenResult object = mapper.readValue(json, AccessTokenResult.class);//反序列化 System.out.println(object); } catch (Exception e) { e.printStackTrace(); } } }
结果
{"access_token":"2r5fx9eiyapFxEGgHq","expires_in":7200}
AccessTokenResult [accessToken=2r5fx9eiyapFxEGgHq, expiresIn=7200]
@JsonProperty注解,作用在get方法将属性名序列化为指定的名称,作用在set方法将指定名称反序列化到属性
3、反序列化列表对象List<CompanyLoopPicture>
public static void main(String[] args) { try { List<CompanyLoopPicture> list = new ArrayList<CompanyLoopPicture>(); CompanyLoopPicture clp = new CompanyLoopPicture(); clp.setId(1); clp.setCompanyId(100); clp.setTitle("google"); clp.setPicture("/upload/images/1.jpg"); clp.setLink("http://www.google.com"); clp.setFlag("modify"); list.add(clp); clp = new CompanyLoopPicture(); clp.setId(2); clp.setCompanyId(200); clp.setTitle("intel"); clp.setPicture("/upload/images/2.jpg"); clp.setLink("http://www.intel.com"); clp.setFlag("delete"); list.add(clp); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(list); System.out.println(json); JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, CompanyLoopPicture.class); List<CompanyLoopPicture> newList = mapper.readValue(json, javaType);
或者
List<CompanyLoopPicture> newList = mapper.readValue(json, new TypeReference<List<CompanyLoopPicture>>(){}); System.out.println(newList); } catch (Exception e) { e.printStackTrace(); } }
使用public <T> T readValue(String content, JavaType valueType)
JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, CompanyLoopPicture.class); 指定集合类型以及泛型类型
4、Unrecognized field、反序列化时json中包含bean对象中没有的字段,也就是json中的字段比bean中的多
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
或者 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
并且给Bean类的顶部追加@JsonIgnoreProperties(ignoreUnknown=true),忽略未知就可解决。
@JsonIgnore注解用来忽略某些字段,可以用在Field或者Getter方法上,用在Setter方法时,和Filed效果一样。这个注解只能用在POJO存在的字段要忽略的情况。
@JsonIgnoreProperties(ignoreUnknown = true),将这个注解写在类上之后,就会忽略类中不存在的字段,。这个注解还可以指定要忽略的字段。使用方法如下:
@JsonIgnoreProperties({ "internalId", "secretKey" })指定的字段不会被序列化和反序列化。
package com.yuanxingyuan.weixin.test; /** * 测试用对象 * @author 杨崇兴 * */ public class Person { private String name; private String postAddress; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPostAddress() { return postAddress; } public void setPostAddress(String postAddress) { this.postAddress = postAddress; } }
定义过滤器接口
package com.yuanxingyuan.weixin.test; import com.fasterxml.jackson.annotation.JsonFilter; @JsonFilter("MyJacksonFilter") public interface MyJacksonFilter { }
实现
package com.yuanxingyuan.weixin.test; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.databind.ser.PropertyWriter; import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import com.yuanxingyuan.weixin.param.AddNewsArticleParam; import com.yuanxingyuan.weixin.param.AddNewsParam; import com.yuanxingyuan.weixin.util.JacksonUtil; public class MaterialServiceTest { public static void main(String[] args) throws JsonProcessingException { Person person = new Person(); person.setName("杨崇兴"); person.setPostAddress("陕西省 西安市"); person.setAge(18); // 方式一:定义Filter SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.serializeAllExcept("age"); // 方式二:或重写 SimpleBeanPropertyFilter的 serializeAsField 方法 SimpleBeanPropertyFilter filter2 = new SimpleBeanPropertyFilter() { @Override public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception { if (!writer.getName().equals("age")) { writer.serializeAsField(pojo, jgen, provider); } } }; // 定义Provider FilterProvider filterProvider = new SimpleFilterProvider().addFilter("MyJacksonFilter", filter);// 或者用filter2 // 数据绑定 ObjectMapper mapper = new ObjectMapper(); mapper.addMixIn(Person.class, MyJacksonFilter.class); mapper.setFilterProvider(filterProvider); String json = mapper.writeValueAsString(person); System.out.println(json); } }
结果
{"name":"杨崇兴","postAddress":"陕西省 西安市"}
mapper.addMixIn(Person.class, MyJacksonFilter.class);很关键
addMixIn 方法签名如下:
public ObjectMapper addMixIn(Class<?> target, Class<?> mixinSource);
addMixIn 方法的作用是用 mixinSource 接口或类的注解会重写 target 或 target 的子类型的注解
测试Bean
package com.yuanxingyuan.weixin.param; import java.util.List; public class AddNewsParam { /** * 文章 */ private List<AddNewsArticleParam> articles; public List<AddNewsArticleParam> getArticles() { return articles; } public void setArticles(List<AddNewsArticleParam> articles) { this.articles = articles; } } package com.yuanxingyuan.weixin.param; public class AddNewsArticleParam { /** * 标题 */ private String title; /** * 图文消息的封面图片素材id(必须是永久mediaID) */ private String thumbMediaId; /** * 作者 * 【非必须】 */ private String author; /** * 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空。如果本字段为没有填写,则默认抓取正文前64个字。 * 【非必须】 */ private String digest; /** * 是否显示封面,0为false,即不显示,1为true,即显示 */ private boolean showCoverPic; /** * 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M, * 且此处会去除JS,涉及图片url必须来源 "上传图文消息内的图片获取URL"接口获取。 * 外部图片url将被过滤。 */ private String content; /** * 图文消息的原文地址,即点击“阅读原文”后的URL */ private String contentSourceUrl; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getThumbMediaId() { return thumbMediaId; } public void setThumbMediaId(String thumbMediaId) { this.thumbMediaId = thumbMediaId; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getDigest() { return digest; } public void setDigest(String digest) { this.digest = digest; } public boolean getShowCoverPic() { return showCoverPic; } public void setShowCoverPic(boolean showCoverPic) { this.showCoverPic = showCoverPic; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getContentSourceUrl() { return contentSourceUrl; } public void setContentSourceUrl(String contentSourceUrl) { this.contentSourceUrl = contentSourceUrl; } }
过滤对象AddNewsArticleParam中的非必需字段,author,digest
package com.yuanxingyuan.weixin.test; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.databind.ser.PropertyWriter; import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import com.yuanxingyuan.weixin.param.AddNewsArticleParam; import com.yuanxingyuan.weixin.param.AddNewsParam; import com.yuanxingyuan.weixin.util.JacksonUtil; public class MaterialServiceTest { public static void main(String[] args) throws JsonProcessingException { AddNewsArticleParam article = new AddNewsArticleParam(); article.setTitle("Title"); article.setThumbMediaId("MediaId"); article.setShowCoverPic(true); article.setContent("content"); article.setContentSourceUrl("url"); article.setAuthor("Author"); article.setDigest("Digest"); List<AddNewsArticleParam> articles = new ArrayList<AddNewsArticleParam>(); articles.add(article); AddNewsParam news = new AddNewsParam(); news.setArticles(articles); String json1 = JacksonUtil.toJson(AddNewsArticleParam.class, news, new String[]{"author","digest"}); System.out.println(json1); }
/** * 序列化(自定义过滤器) * @param clazz * @param value * @param filterFields * @return */ public static String toJson(Class<?> clazz, Object value, String[] filterFields) { try { SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.serializeAllExcept(filterFields); FilterProvider filterProvider = new SimpleFilterProvider().addFilter("MyJacksonFilter", filter); ObjectMapper mapper = new ObjectMapper(); mapper.addMixIn(clazz, MyJacksonFilter.class); mapper.setFilterProvider(filterProvider); return mapper.writeValueAsString(value); } catch (Exception e) { e.printStackTrace(); return ""; } }
特别注意:addMixIn中的class是List中对象的class
方式一、使用@JsonInclude注解
放在属性上仅对该属性起作用,放在类上对整个类的属性起作用包含继承来的属性
@JsonInclude(Include.NON_NULL) ,属性为NULL时不参与序列化
方式二、使用代码
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);
可设置的值:
Include.Include.ALWAYS (默认)属性都序列化
Include.NON_DEFAULT 属性为默认值不序列化
Include.NON_EMPTY 属性为空或者为NULL不序列化
Include.NON_NULL 属性为NULL不序列化
Company c = new Company(); c.setName("apple"); c.setPostalCode("100000"); ObjectMapper mapper = new ObjectMapper(); mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE); try { String json = mapper.writeValueAsString(c);// 序列化 System.out.println(json); Company company = mapper.readValue(json, Company.class);//反序列化 System.out.println(company.toString()); } catch (Exception e) { e.printStackTrace(); }
PropertyNamingStrategy 的常量值
命名策略 | 序列化结果 |
SNAKE_CASE | {"name":"apple","postal_code":"100000"} |
UPPER_CAMEL_CASE | {"Name":"apple","PostalCode":"100000"} |
LOWER_CAMEL_CASE | {"name":"apple","postalCode":"100000"} |
LOWER_CASE | "name":"apple","postalcode":"100000"} |
KEBAB_CASE | {"name":"apple","postal-code":"100000"} |
name 设置为空 postalCode 设置为null
Company c = new Company(); c.setName(""); c.setPostalCode(null); ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); try { String json = mapper.writeValueAsString(c);// 序列化 System.out.println(json); Company company = mapper.readValue(json, Company.class);//反序列化 System.out.println(company.toString()); } catch (Exception e) { e.printStackTrace(); }
JsonInclude.Include
序列化包含 | 序列化结果 |
ALWAYS | {"name":"","postalCode":null} 不管是空还是null都包含在序列化结果中 |
NON_NULL | {"name":""} 不包含值为null的属性 |
NON_DEFAULT | {} |
NON_EMPTY | {} 不包含值为空或null的属性 |
NON_ABSENT | {"name":""} 不包含值为null或absent like Java 8 `Optional`, or {link java.utl.concurrent.atomic.AtomicReference}的属性 |
USE_DEFAULTS | {"name":"","postalCode":null} |
CUSTOM | 被 JsonInclude#valueFilter 和 JsonInclude#contentFilter 指定的 |
import com.fasterxml.jackson.annotation.JsonFormat; import org.springframework.format.annotation.DateTimeFormat; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") @TableField("time_") private String time;