JacksonJson知识集锦
Jackson JSON 提供了一系列API,便于Java程序读写JSON字符串。它具有强大对数据绑定能力,可以方便的在Java对象和JSON字符串之间进行转换。
代码示例:
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 28 |
ObjectMapper mapper = new ObjectMapper(); // 启用缩进,更易读 mapper.configure(SerializationFeature.INDENT_OUTPUT, true); // 输出Map类型时,以键排序 mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); // 日期对象的默认输出格式 mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd")); /** * Java字段名/属性名到JSON字段的映射策略 */ mapper.setPropertyNamingStrategy( new PropertyNamingStrategy() { public String nameForField( MapperConfig config, AnnotatedField field, String defaultName ) { if ( field.getFullName().equals( "cc.gmem.vo.Entity#name" ) ) return "Entity-Name"; return super.nameForField( config, field, defaultName ); } public String nameForGetterMethod( MapperConfig config, AnnotatedMethod method, String defaultName ) { if ( method.getAnnotated().getDeclaringClass().equals( Entity.class ) && defaultName.equals( "no" ) ) return "Entity-No"; return super.nameForGetterMethod( config, method, defaultName ); } } ); // 忽略空属性/字段 mapper.setSerializationInclusion(Include.NON_EMPTY); // 把entity转换为JSON然后写入标准输出 mapper.writeValue(System.out, entity); |
示例代码:
1 2 3 4 5 6 7 8 9 10 11 |
// 此工厂用于创建JsonNode对象 JsonNodeFactory factory = new JsonNodeFactory( false ); // 此工厂用于创建JSON的生成器、解析器 JsonFactory jsonFactory = new JsonFactory(); // 写入到标准输出 JsonGenerator generator = jsonFactory.createGenerator( System.out ); ObjectMapper mapper = new ObjectMapper(); // 根节点 ObjectNode entity = factory.objectNode(); entity.put( "name", "entityname" ); mapper.writeTree( generator, entity ); |
这种方式很不直观,但是节约内存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
JsonFactory factory = new JsonFactory(); JsonGenerator generator = factory.createGenerator(new FileWriter(new File("entity.json"))); generator.writeStartObject(); generator.writeFieldName("name"); generator.writeString("Alex"); generator.writeFieldName("dataset"); generator.writeStartArray(); generator.writeStartObject(); generator.writeStringField("zip", "223442"); generator.writeEndObject(); generator.writeEndArray(); generator.writeEndObject(); generator.close(); |
Jackson提供了一种底层API,允许逐符号的处理JSON:
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 28 29 30 |
JsonFactory factory = new JsonFactory(); JsonParser parser = factory.createParser( "{ addresses: [ { zip: 223442 } ] }" ); // 允许非标准的JSON格式:不带引号的字段名 parser.configure( JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true ); while ( !parser.isClosed() ) { // 获取下一个解析得到的记号 JsonToken token = parser.nextToken(); // 没有下一个记号,说明解析完毕 if ( token == null ) break; // 寻找名为addresses的字段 if ( JsonToken.FIELD_NAME.equals( token ) && "addresses".equals( parser.getCurrentName() ) ) { // 期望下一个符号是数组开始 token = parser.nextToken(); if ( !JsonToken.START_ARRAY.equals( token ) ) break; // 期望下一个符号是对象开始 token = parser.nextToken(); if ( !JsonToken.START_OBJECT.equals( token ) ) break; while ( true ) { token = parser.nextToken(); if ( token == null ) break; if ( JsonToken.FIELD_NAME.equals( token ) && "zip".equals( parser.getCurrentName() ) ) { token = parser.nextToken(); System.out.println( parser.getText() ); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
ObjectMapper mapper = new ObjectMapper(); mapper.configure( JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true ) JsonNode node = mapper.readTree( "{ addresses: [ { zip: 223442 } ] }" ); Iterator<String> fieldNames = node.fieldNames(); while ( fieldNames.hasNext() ) { String fieldName = fieldNames.next(); System.out.println( fieldName ); JsonNode el = node.get( fieldName ); if ( el instanceof ArrayNode ) { ArrayNode ael = (ArrayNode) el; ael.forEach( n -> { System.out.println( n ); } ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
ObjectMapper mapper = new ObjectMapper(); // 缩进(漂亮输出pretty-printing mapper.enable(SerializationFeature.INDENT_OUTPUT); // 禁止把日期类型串行化为数字时间戳 mapper.disable( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS ); // 遇到里面没有任何可访问字段/属性的对象时怎么办,禁用后将这种对象串行化为{} mapper.disable( SerializationFeature.FAIL_ON_EMPTY_BEANS ); // 遇到不可映射的属性时,是否报错 mapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ); // 允许把空串绑定到null值 mapper.enable( DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT ); // 允许非标准的JSON格式:使用单引号 mapper.configure( JsonParser.Feature.ALLOW_SINGLE_QUOTES, true ); // 允许非标准的JSON格式:不带引号的字段名 mapper.configure( JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true ); // 允许JSON中的C/C++风格的注释 mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); // 启用非ASCI字符(默认启用) mapper.configure( JsonGenerator.Feature.ESCAPE_NON_ASCII, false ); // 绑定为特定类型 Entity entity = mapper.readValue(json, Entity.class); // 默认自动转换为Map或者List之类集合对象 Map entity = mapper.readValue(json); |
Jackson有时可以用来进行数据类型的转换,例如:
1 2 3 4 5 6 7 8 9 |
// 在包装类型和基本类型的集合之间进行转换 List<Integer> sourceList = ...; int[] ints = mapper.convertValue(sourceList, int[].class); // 在POJO和Map之间进行转换 Map<String,Object> propertyMap = mapper.convertValue(pojoValue, Map.class); PojoType pojo = mapper.convertValue(propertyMap, PojoType.class); // 将Base64转换为字节数组 String base64 = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz"; byte[] binary = mapper.convertValue(base64, byte[].class); |
JSON到Java对象的数据绑定,主要依赖于注解
注解 | 说明 | ||||||||||
@JsonProperty |
用于字段/setter/getter上,指定该字段映射到的JSON字段名 属性: |
||||||||||
@JsonIgnore | 用于字段/setter上,指定该字段不进行数据绑定 | ||||||||||
@JsonIgnoreType | 用于类上,指定哪些类型的字段都被忽略 | ||||||||||
@JsonAutoDetect | 用于类上,指定哪些类型的方法用于属性的自动发现。示例:
|
||||||||||
@JsonIgnoreProperties | 用于类上,指定哪些字段不进行数据绑定 | ||||||||||
@JsonInclude | 用于类或字段上,指定哪些“无值“(null、空)需要包含在串行化过程中 | ||||||||||
@JsonFormat | 指定如何格式化某个字段,例如:
|
||||||||||
@JsonUnwrapped | 在串行化时,展开一个嵌入式对象,在反串行化时,包装对应的几个字段为对象 | ||||||||||
@JsonView | 用于定义视图,每个POJO可以定义多个视图,这些视图包含不同的属性 | ||||||||||
@JsonNaming |
用于指定JSON与POJO转换时的名称映射策略: 示例:
|
||||||||||
反串行化注解 | |||||||||||
@JacksonInject |
指示属性通过注入得到,而不是从JSON解析到 示例:
|
||||||||||
@JsonAnySetter | 定义一个具有两个参数的方法为通配的Setter,用于绑定未成功映射的JSON属性 | ||||||||||
@JsonCreator | Jackson JSON不需要默认构造器。在公共/私有的构造器上加上此注解,则Jackson在绑定时自动调用此构造器来创建对象:
或者,你也可以注解在静态的工厂方法上:
|
||||||||||
@JsonSetter | 用于指定任意方法为Setter | ||||||||||
@JsonEnumDefaultValue | 2.8新增。反串行化未知枚举值时,给出默认值 | ||||||||||
@JsonDeserialize | 指定一个自定义的反串行化器:
|
||||||||||
串行化注解 | |||||||||||
@JsonAnyGetter | 指定一个用作通配Getter的方法,调用该方法应该获得一个Map,其中所有键会作为JSON的额外属性 | ||||||||||
@JsonGetter | 用于指定任意方法为Getter | ||||||||||
@JsonPropertyOrder | 用于指定属性的串行化顺序 | ||||||||||
@JsonRawValue |
指示一个属性的值应该原样的放置到产生的JSON中,不进行任何转义 在属性值是预先准备好的JSON格式时,使用该注解 |
||||||||||
@JsonValue | 在POJO的某个方法上标注,当此POJO被串行化时,调用此方法得到的值作为串行化结果 | ||||||||||
@JsonRootName | 给串行化后的POJO加上一个外套:
导致串行化为:
|
||||||||||
@JsonAppend | 在串行化时添加额外字段,而不需要改变类。示例:
|
||||||||||
@JsonSerialize | 指定一个自定义的串行化器:
|
||||||||||
类型处理 | |||||||||||
@JsonSubTypes |
用于类上,指示该类型的子类型,反串行化多态类时如果基于逻辑类型名称,则可以使用 示例一:
串行化结果为:
示例二:
串行化结果为:
类似的:
|
||||||||||
@JsonTypeId | 用于类上,指示该字段的值用作类型标识 | ||||||||||
@JsonTypeName | 用于类上,定义一个逻辑类名。示例:
|
||||||||||
对象引用和标识符 | |||||||||||
@JsonManagedReference @JsonBackReference |
这一对注解用于指示、处理父子关系。可以用来处理对象循环引用 示例:
|
||||||||||
@JsonIdentityInfo |
类/属性注解,用于指定对象标识符,这样,指向单个POJO的多个引用可以被正确的反串行化。可以用于处理对象循环引用 示例:
|
报错信息:Unrecognized field "***" (Class ***), not marked as ignorable
报错原因:JSON中包含对象没有的属性
解决办法:
1 2 3 4 5 6 7 8 9 |
#方法一 @Entity @Table ( name = "T_USER" ) @JsonIgnoreProperties ( ignoreUnknown = true ) public class User implements java.io.Serializable #方法二 ObjectMapper objectMapper = getObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
报错信息:存在循环引用
解决办法:设置@JsonIgnore。JacksonJson 2.x版本中有专门处理循环引用的注解
Leave a Reply