一、依赖
jackson依赖3个包,由于jackson-databind依赖于jackson-annotations,jackson-core,所以实际引用jackson-databind即可以。
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.8.1</version> </dependency>
二、常用注解
1、@JsonAnyGetter, @JsonAnySetter:用于将字符串中未映射到属性的值放在一个map;
@Data public class DatasetDynamic { private String album_id; private String album_title;
@J private Map<String , Object> otherProperties = new HashMap<String , Object>(); @JsonCreator public DatasetDynamic(@JsonProperty("album_id") String album_id, @JsonProperty("album_title") String album_title) { this.album_id = album_id; this.album_title = album_title; } public Object get(String name) { return otherProperties.get(name); }
@JsonAnyGetter public Map<String , Object> any() { return otherProperties; }
@JsonAnySetter public void set(String name, Object value) { otherProperties.put(name, value); } }
{ "album_id":"123", "album_title":"haha", "test1":"heihei", "test2":222 }
输出:DatasetDynamic(album_id=123, album_title=haha, otherProperties={test2=222, test1=heihei})
2、@JsonIgnoreProperties和@JsonIgnore:
用于标记属性,在json与java之间相互转化时,将忽略被此注解标记的属性。@JsonIgnoreProperties是类级别注解,可以忽略多个属性,@JsonIgnore用来标注单个属性。
@JsonIgnoreProperties({ "album_title" }) public class DatasetFilter { @JsonIgnore private String album_id; private String album_title; private Map<String , Object> otherProperties = new HashMap<String , Object>(); private String album_comments; }
3、@JsonRawValue: 直接显示属性值,对字符串,即是去掉双引号。
public class PersonRawValue { public long personId = 0; //@JsonRawValue public String address = "$#"; }
不加注解显示:{"personId":0,"address":"$#"} 加注解显示:{"personId":0,"address":$#}
4、@JsonPropertyOrder:指对象属性序列化的顺序,指定顺序的先显示,没有指定的按照默认顺序在后面,@JsonFormat:时间格式化
@JsonPropertyOrder({"id","time","name"}) public class User { private Long id; private String name; private BigDecimal age; @JsonFormat(pattern = "yyyy-MM-dd") private Date date; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Timestamp time; public User(Long id, String name, Date date) { this.id = id; this.name = name; this.date = date; } }
输出结果:
{ "id" : 2, "time" : null, "name" : "theUser", "age" : null, "date" : "2018-07-23" }
5、@JsonInclude:控制序列化时的显示,将该标记放在属性上,如果该属性为NULL则不参与序列化 。如果放在类上边,那对这个类的全部属性起作用
Include.Include.ALWAYS 默认
Include.NON_DEFAULT 属性为默认值不序列化
Include.NON_EMPTY 属性为空(“”)或者为 NULL 都不序列化
Include.NON_NULL 属性为NULL 不序列化
@JsonInclude(JsonInclude.Include.NON_EMPTY) public class User { private Long id; }
6、@JsonSerialize,@JsonDeserialize: 自定义序列化
// 自定义反序列化 public class ItemDeserializer extends JsonDeserializer<Item> { @Override public Item deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { JsonNode jsonNode = jsonParser.readValueAsTree(); int id = jsonNode.path("id").intValue(); String itemName = jsonNode.get("itemName").asText(); Long userId = jsonNode.get("owner").asLong(); return new Item(id, itemName, new User(userId, "")); } } // 自定义序列化 public class ItemSerializer extends JsonSerializer<Item> { @Override public void serialize(Item item, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); jsonGenerator.writeNumberField("id", item.id); jsonGenerator.writeStringField("itemName", item.itemName); jsonGenerator.writeNumberField("owner", item.getOwner().getId()); //jsonGenerator.writeObjectField("owner", item.owner); jsonGenerator.writeEndObject(); } }
应用方法有2种:
(1)注解方式:
@Data @AllArgsConstructor @NoArgsConstructor @JsonSerialize(using = ItemSerializer.class) @JsonDeserialize(using = ItemDeserializer.class) public class Item { public int id; public String itemName; public User owner; }
(2)代码方式:
SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(Item.class, new ItemSerializer()); simpleModule.addDeserializer(Item.class, new ItemDeserializer()); ObjectMapper mapper = JacksonUtil.getNewDefaultMapper(); mapper.registerModule(simpleModule);
//...
7、@JsonCreator :解决多态性问题,通过注解,可以在序列化时,保存具体的类型信息到json中,当json反序列到java对象时,就可以根据具体类型信息创建正确的java对象。
当str -> bean时会调用@JsonCreator注解的构造函数,如果没有此注解,则默认调用无参构造函数
@Data public class Lion extends Animal { private String name; @JsonCreator public Lion(@JsonProperty("name") String name) { this.name = name; } } public static void main(String[] args) throws IOException { Lion lion = new Lion("jack"); log.info(JacksonUtil.toJson(lion)); log.info(JacksonUtil.jsonToBean(JacksonUtil.toJson(lion), Lion.class)); }
输出:
"@class" : "vo.Lion", "name" : "jack", "sound" : null, "type" : null, "endangered" : null } [2018-08-26 21:03:47] main INFO test.annotation.Test1.main(Test1.java:26) Lion(name=jack)
修改类:
@Data @NoArgsConstructor public class Lion extends Animal { private String name; public Lion(String name) { this.name = name; } } // 输出结果: "@class" : "vo.Lion", "name" : "jack", "sound" : null, "type" : null, "endangered" : null } [2018-08-26 21:08:46] main INFO test.annotation.Test1.main(Test1.java:26) Lion(name=jack)
8、@JsonTypeInfo、@JsonSubTypes:解决多态性问题,通过注解,可以在序列化时,保存具体的类型信息到json中,当json反序列到java对象时,就可以根据具体类型信息创建正确的java对象
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") @JsonSubTypes({ @Type(value = Lion.class, name = "lion"), @Type(value = Elephant.class, name = "elephant") }) @Data public abstract class Animal { @JsonProperty("name") String name; @JsonProperty("sound") String sound; @JsonProperty("type") String type; @JsonProperty("endangered") Boolean endangered; } @Data public class Zoo { public String name; public String city; public List<Animal> animals = new ArrayList<Animal>(); @JsonCreator public Zoo(@JsonProperty("name") String name,@JsonProperty("city") String city) { this.name = name; this.city = city; } public List<Animal> addAnimal(Animal animal) { animals.add(animal); return animals; } } @Data @NoArgsConstructor public class Lion extends Animal { private String name; @JsonCreator public Lion(@JsonProperty("name") String name) { this.name = name; } } @Data @NoArgsConstructor public class Elephant extends Animal { @JsonProperty private String name; @JsonCreator public Elephant(@JsonProperty("name") String name) { this.name = name; } } public static void main(String[] args) throws IOException { Zoo zoo = new Zoo("London zoo", "London"); Lion lion = new Lion("Simba"); Elephant elephant = new Elephant("Manny"); zoo.addAnimal(lion).add(elephant); String jsonStr = JacksonUtil.toJson(zoo); log.info(jsonStr); log.info(JacksonUtil.jsonToBean(jsonStr, Zoo.class)); }
输出:
[2018-08-26 21:18:24] main INFO test.annotation.Test1.main(Test1.java:26) { "name" : "London zoo", "city" : "London", "animals" : [ { "@class" : "vo.Lion", "name" : "Simba", "sound" : null, "type" : null, "endangered" : null }, { "@class" : "vo.Elephant", "name" : "Manny", "sound" : null, "type" : null, "endangered" : null } ] } [2018-08-26 21:18:24] main INFO test.annotation.Test1.main(Test1.java:27) Zoo(name=London zoo, city=London, animals=[Lion(name=Simba), Elephant(name=Manny)])
这里面有个问题,Jackson是如何识别具体的实现类?有2个问题解答:(1)区分实现类的标识?(2)标识如何写入?
注解:@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") //使用类限定名区分,标识作为数据的史弟属性定入
具体参数:
use:定义使用哪一种类型识别码,它有下面几个可选值:
1、JsonTypeInfo.Id.CLASS:使用完全限定类名做识别
2、JsonTypeInfo.Id.MINIMAL_CLASS:若基类和子类在同一包类,使用类名(忽略包名)作为识别码
3、JsonTypeInfo.Id.NAME:一个合乎逻辑的指定名称
4、JsonTypeInfo.Id.CUSTOM:自定义识别码,
5、JsonTypeInfo.Id.NONE:不使用识别码
include(可选):指定识别码是如何被包含进去的,它有下面几个可选值:
1、JsonTypeInfo.As.PROPERTY:作为数据的兄弟属性
2、JsonTypeInfo.As.EXISTING_PROPERTY:作为POJO中已经存在的属性
3、JsonTypeInfo.As.EXTERNAL_PROPERTY:作为扩展属性
4、JsonTypeInfo.As.WRAPPER_OBJECT:作为一个包装的对象
5、JsonTypeInfo.As.WRAPPER_ARRAY:作为一个包装的数组
三、ObjectMapper常用配置:
private static ObjectMapper mapper = new ObjectMapper(); static { mapper.enable(SerializationFeature.INDENT_OUTPUT); //化化输出 mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //序列化空的POPJ mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); //不将date转化成timestamp mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //忽略未知属性 mapper.disable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); //不将空转化为null mapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); //允许没有引号的字段名(非标准) mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); }
四、Jackson模型:【待补充】
附1:封装类
/** * 例1:String str = JacksonUtil.toJson(userList); * 例2:User u = JacksonUtil.jsonToBean(str, User.class); * 例3:List<User> userList = JacksonUtil.jsonTo(str, new TypeReference<List<User>>(){}); * 例4:Map<String, User> map = JacksonUtil.jsonTo(str, new TypeReference<Map<String, User>(){}); */ @Log4j2 public class JacksonUtil { private static ObjectMapper mapper = new ObjectMapper(); static { mapper.enable(SerializationFeature.INDENT_OUTPUT); //化化输出 mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //序列化空的POPJ mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); //不将date转化成timestamp mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //忽略未知属性 mapper.disable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); //不将空转化为null mapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); //允许没有引号的字段名(非标准) mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); } public JacksonUtil() { } public static ObjectMapper getNewMapper() { return new ObjectMapper(); } public static ObjectMapper getNewDefaultMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //序列化空的POPJ mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); //不将date转化成timestamp mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //忽略未知属性 mapper.disable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); //不将空转化为null mapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); //允许没有引号的字段名(非标准) mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); return mapper; } public static <T> String toJson(T t) { return toJson(t, null); } public static <T> T jsonTo(String json, TypeReference<T> typeReference) { return jsonTo(json, typeReference, null); } public static <T> T jsonToBean(String json, Class<T> clazz) { return jsonToBean(json, clazz, null); } public static <T> T fileToBean(File file, Class<T> clazz) { return fileToBean(file, clazz, null); } public static <T> String toJson(T t, ObjectMapper objectMapper) { if (Objects.isNull(t)) return null; try { return objectMapper == null ? mapper.writeValueAsString(t) : objectMapper.writeValueAsString(t); } catch (JsonProcessingException e) { log.error("to json error:" + t, e); return null; } } public static <T> T jsonToBean(String json, Class<T> clazz, ObjectMapper objectMapper) { if (StringUtils.isBlank(json)) return null; try { return objectMapper == null ? mapper.readValue(json, clazz) : objectMapper.readValue(json, clazz); } catch (IOException e) { log.error("json to bean error:" + json, e); return null; } } public static <T> T fileToBean(File file, Class<T> clazz, ObjectMapper objectMapper) { if (!file.exists()) return null; try { return objectMapper == null ? mapper.readValue(file, clazz) : objectMapper.readValue(file, clazz); } catch (IOException e) { log.error("file to bean error:" + file.getName(), e); return null; } } public static <T> T jsonTo(String json, TypeReference<T> typeReference, ObjectMapper objectMapper) { if (StringUtils.isBlank(json)) return null; try { return objectMapper == null ? mapper.readValue(json, typeReference) : objectMapper.readValue(json, typeReference); } catch (Exception e) { log.error("json to map error:" + json, e); return null; } } public static <T> T jsonTo(String json, Class<T> clazz, ObjectMapper objectMapper) { if (StringUtils.isBlank(json)) return null; try { return mapper.readValue(json, new TypeReference<T>(){}); } catch (Exception e) { log.error("json to map error:" + json, e); return null; } } }