一、依赖
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;
}
}
}