Jackson
简介
依赖
- jackson-core
- jackson- annotations
- jackson-databind
其中 jackson-databind 内部依赖了 jackson-annotations 与 jackson-core,所以 Maven 应用时,只要导入 databind 一个,则同时也导入了 annotations 与 core 依赖。
核心模块
Streaming(jackson-core):低阶API库,提供流式解析工具JsonParser,流式生成工具JsonGenerator;
Annotations(jackson-annotations):jackson注解;
Databind (jackson-databind):基于java对象的序列化、反序列化能力,需要前面两个模块的支持才能实现;
Jackson常用的类
- JsonFactory:这个类是Jackson主要的工厂方法,主要用于配置和构建解析器(JsonParser)和生成器(如JsonGenerator),这个工厂实例是线程安全的,如果有配置的话,可以重复使用。
- JsonGenerator:这个类主要是用来生成Json格式的内容的,我们可以使用JsonFactory 的方法生成一个实例。
- JsonParser:这个主要是用来读取Json格式的内容,并且完成解析操作的,我们可以使用JsonFactory的方法生成一个实例。
- ObjectMapper:这个类提供了Java对象和Json之间的转化,主要通过JsonParser和JsonGenerator实例来完成实际的对Json数据的读写操作。
Jackson-core
- jackson-core为一个低阶API库,提供流式解析工具JsonParser,流式生成工具JsonGenerator
- 在日常的序列化和反序列化处理中,最常用的是jackson-annotations和jackson-databind,而jackson-core由于它提供的API过于基础,我们大多数情况下是用不上的;
- 尽管jackson-databind负责序列化和反序列化处理,但它的底层实现是调用了jackson-core的API;
JsonGenerator是定义公共API编写的Json内容的基类,使用JsonFactory实例的工厂方法创建实例。
JsonGenerator的使用案例如下所示:
package test;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.PrintWriter;import org.codehaus.jackson.JsonGenerationException;import org.codehaus.jackson.JsonGenerator;import org.codehaus.jackson.map.ObjectMapper;public class JsonGeneratorTest {public static void main(String[] args) throws JsonGenerationException, IOException {String ret = "";ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectMapper mapper = new ObjectMapper();JsonGenerator jg = mapper.getJsonFactory().createJsonGenerator(new PrintWriter(bos));jg.writeStartObject();jg.writeStringField("name", "zhaokaiqiang");jg.writeNumberField("age", 22);jg.writeObjectField("sex", "man");jg.writeArrayFieldStart("likes");jg.writeString("apple");jg.writeString("banner");jg.writeStartObject();jg.writeNumberField("index",1);jg.writeStringField("color","red");jg.writeEndObject();jg.writeStartObject();jg.writeNumberField("index",2);jg.writeStringField("color","green");jg.writeEndObject();jg.writeEndArray();jg.writeEndObject();jg.flush();jg.close();ret = bos.toString();bos.close();System.out.println(ret);}}
ObjectMapper
一)、从JSON中获取Java对象
1.简单示例:
从Json字符串中解析数据并封装到实体类当中
readValue绑定实体类和json字符串,用于进行读取解析封装,返回一个实体类
public class Car {private String brand = null;private int doors = 0;public String getBrand() { return this.brand; }public void setBrand(String brand){ this.brand = brand;}public int getDoors() { return this.doors; }public void setDoors (int doors) { this.doors = doors; }}
public class testObjectMapper {@Testpublic void test1(){ObjectMapper objectMapper= new ObjectMapper();String carJson="{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";Car car;{try {car = objectMapper.readValue(carJson,Car.class);System.out.println("car brand"+ car.getBrand());System.out.println("car doors"+ car.getDoors());} catch (IOException e) {e.printStackTrace();}}}
{"brand":"Mercedes","doors":"5"}
2.ObjectMapper如何匹配JSON对象的字段和Java对象的属性
默认情况下,Jackson通过将JSON字段的名称与Java对象中的getter和setter方法进行匹配,将JSON对象的字段映射到Java对象中的属性。 Jackson删除了getter和setter方法名称的“ get”和“ set”部分,并将其余名称的第一个字符转换为小写。
3.Json字符串->Java对象
从JSON字符串读取Java对象非常容易。 上面已经有了一个示例——JSON字符串作为第一个参数传递给ObjectMapper的readValue()方法。 这是另一个简单的示例:
ObjectMapper objectMapper = new ObjectMapper();String carJson ="{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";Car car = objectMapper.readValue(carJson, Car.class);
3.Json字符输入流->Java对象
通过Reader实例加载的JSON中读取对象
ObjectMapper objectMapper = new ObjectMapper();String carJson ="{ \"brand\" : \"Mercedes\", \"doors\" : 4 }";Reader reader = new StringReader(carJson);Car car = objectMapper.readValue(reader, Car.class);
4.JSON文件->Java对象
从文件读取JSON当然可以通过FileReader(而不是StringReader)来完成,也可以通过File对象来完成。
@Testpublic void testFile(){ObjectMapper objectMapper=new ObjectMapper();File file=new File("D:\\learn_software\\program_file\\IDEAProgject\\jackson\\src\\main\\java\\com\\fischer\\data\\car.json");try {Car car = objectMapper.readValue(file, Car.class);System.out.println(car);} catch (IOException e) {e.printStackTrace();}}
Car{brand='Mercedes', doors=5}//输出结果
5.JSON via URL -> Java对象
ObjectMapper objectMapper = new ObjectMapper();URL url = new URL("file:data/car.json");Car car = objectMapper.readValue(url, Car.class);
示例使用文件URL,也可以使用HTTP URL(类似于http://jenkov.com/some-data.json)。
6.JSON数组字符串->Java对象数组
Jackson ObjectMapper也可以从JSON数组字符串读取对象数组。 这是从JSON数组字符串读取对象数组的示例:
注意readValue中指定为数组类型的Car[]
@Testpublic void testArray(){String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";ObjectMapper objectMapper=new ObjectMapper();try {for (Car car : objectMapper.readValue(jsonArray, Car[].class)) {System.out.println(car);}} catch (IOException e) {e.printStackTrace();}}
7.JSON数组字符串->List
TypeReference用于在反序列化时,将数据封装成泛型对象
- 泛型中指定要封装成的对象,如TypeReference
- >,或TypeReference
不使用TperReference:
String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";ObjectMapper objectMapper=new ObjectMapper();List list = objectMapper.readValue(jsonArray, List.class);
{brand='ford', doors=0},{brand='Fiat', doors=0}
使用TypeReference(具体代码如下)
Car{brand='ford', doors=0},Car{brand='Fiat', doors=0}
@Testpublic void testList(){String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";ObjectMapper objectMapper=new ObjectMapper();try {for (Object o : (List) objectMapper.readValue(jsonArray, new TypeReference<List<Car>>() {})) {System.out.println(o);}} catch (IOException e) {e.printStackTrace();}}
8.JSON字符串->Map
与List同理,借助TypeReference
String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";ObjectMapper objectMapper = new ObjectMapper();Map<String, Object> jsonMap = objectMapper.readValue(jsonObject,new TypeReference<Map<String,Object>>(){});
9.忽略未知JSON字段
有时候,与要从JSON读取的Java对象相比,JSON中的字段更多。 默认情况下,Jackson在这种情况下会抛出异常,报不知道XYZ字段异常,因为在Java对象中找不到该字段。
但是,有时应该允许JSON中的字段多于相应的Java对象中的字段。 例如,要从REST服务解析JSON,而该REST服务包含的数据远远超出所需的。 在这种情况下,可以使用Jackson配置忽略这些额外的字段。 以下是配置Jackson ObjectMapper忽略未知字段的示例:objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- 泛型中指定要封装成的对象,如TypeReference
日后研究研究是否可以在springboot的配置文件中进行设置:
- Springboot中DeserializationFeature.XXX对应的关键词为deserialization.XXX
- 在Springboot当中,对应的操作为:
jackson:deserialization.FAIL_ON_UNKNOWN_PROPERTIES: false
10.不允许基本类型为null
如果JSON字符串包含其值设置为null的字段(对于在相应的Java对象中是基本数据类型(int,long,float,double等)的字段),Jackson ObjectMapper默认会处理基本数据类型为null的情况,如:int类型会默认赋值为0,字符串类型则为null我们可以可以将Jackson ObjectMapper默认配置为失效,这样基本数据为null就会转换失败objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
得到以下报错:@Testpublic void testNull(){String json="{ \"brand\":null, \"doors\":null }";ObjectMapper objectMapper=new ObjectMapper();objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);try {Car car = objectMapper.readValue(json, Car.class);System.out.println(car);} catch (IOException e) {e.printStackTrace();}}
11.自定义反序列化
暂时不大懂,日后用到了进一步研究
有时,可能希望以不同于Jackson ObjectMapper缺省方式的方式将JSON字符串读入Java对象。 可以将自定义反序列化器添加到ObjectMapper,可以按需要执行反序列化。
这是在Jackson的ObjectMapper中注册和使用自定义反序列化器的方式:
自定义反序列化器CarDeserializer类String json = "{ \"brand\" : \"Ford\", \"doors\" : 6 }";SimpleModule module =new SimpleModule("CarDeserializer", new Version(3, 1, 8, null, null, null));module.addDeserializer(Car.class, new CarDeserializer(Car.class));ObjectMapper mapper = new ObjectMapper();mapper.registerModule(module);Car car = mapper.readValue(json, Car.class);
public class CarDeserializer extends StdDeserializer<Car> {public CarDeserializer(Class<?> vc) {super(vc);}@Overridepublic Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException {Car car = new Car();while(!parser.isClosed()){JsonToken jsonToken = parser.nextToken();if(JsonToken.FIELD_NAME.equals(jsonToken)){String fieldName = parser.getCurrentName();System.out.println(fieldName);jsonToken = parser.nextToken();if("brand".equals(fieldName)){car.setBrand(parser.getValueAsString());} else if ("doors".equals(fieldName)){car.setDoors(parser.getValueAsInt());}}}return car;}}
二)、将对象写入JSON
1.Java对象->JSON
Jackson ObjectMapper也可以用于从对象生成JSON。 可以使用以下方法之一进行操作:
- Springboot中DeserializationFeature.XXX对应的关键词为deserialization.XXX
writeValue()
- writeValueAsString()
- writeValueAsBytes()
通过Car生成JSON:
@Testpublic void testWrite(){ObjectMapper objectMapper=new ObjectMapper();Car car=new Car();car.setBrand("Tesla");car.setDoors(4);try {objectMapper.writeValue(new FileOutputStream("output-2.json"),car);} catch (IOException e) {e.printStackTrace();}
调用ObjectMapper的writeValue()方法,该方法将Car对象转换为JSON并将其写入给定的FileOutputStream,最后写入一个文件当中
ObjectMapper的writeValueAsString()和writeValueAsBytes()都从一个对象生成JSON,并将生成的JSON作为String或字节数组返回。 示例如下:
@Testpublic void testWriteString() {ObjectMapper objectMapper = new ObjectMapper();Car car = new Car();car.setBrand("Tesla");car.setDoors(4);try {String s = objectMapper.writeValueAsString(car);System.out.println(s);} catch (IOException e) {e.printStackTrace();}}
{"brand":"Tesla","doors":4}
2.自定义序列化
有时,想要将Java对象序列化为JSON的方式与使用Jackson的默认方式不同。 例如,可能想要在JSON中使用与Java对象中不同的字段名称,或者希望完全省略某些字段。
Jackson可以在ObjectMapper上设置自定义序列化器。 该序列化器已为某个类注册,然后在每次要求ObjectMapper序列化Car对象时将调用该序列化器。
这是为Car类注册自定义序列化器的示例:
CarSerializer carSerializer = new CarSerializer(Car.class);ObjectMapper objectMapper = new ObjectMapper();SimpleModule module =new SimpleModule("CarSerializer", new Version(2, 1, 3, null, null, null));module.addSerializer(Car.class, carSerializer);objectMapper.registerModule(module);Car car = new Car();car.setBrand("Mercedes");car.setDoors(5);String carJson = objectMapper.writeValueAsString(car);
自定义序列化器CarSerializer类:
public class CarSerializer extends StdSerializer<Car> {protected CarSerializer(Class<Car> t) {super(t);}public void serialize(Car car, JsonGenerator jsonGenerator,SerializerProvider serializerProvider)throws IOException {jsonGenerator.writeStartObject();jsonGenerator.writeStringField("producer", car.getBrand());jsonGenerator.writeNumberField("doorCount", car.getDoors());jsonGenerator.writeEndObject();}}
三)、Jackson日期转化
默认情况下,Jackson会将java.util.Date对象序列化为其long型的值,该值是自1970年1月1日以来的毫秒数。但是,Jackson还支持将日期格式化为字符串。
默认的Jackson日期格式,该格式将Date序列化为自1970年1月1日以来的毫秒数(long类型)。
日期pojo:
public class Transaction {private String type = null;private Date date = null;}
@Testpublic void testDate(){Transaction transaction=new Transaction("transfer",new Date());ObjectMapper objectMapper=new ObjectMapper();try {String s = objectMapper.writeValueAsString(transaction);System.out.println(s);} catch (JsonProcessingException e) {e.printStackTrace();}}
{"type":"transfer","date":1646377981781}//结果
设置Jackson日期格式
@Testpublic void testDate(){Transaction transaction=new Transaction("transfer",new Date());ObjectMapper objectMapper=new ObjectMapper();try {SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");objectMapper.setDateFormat(dateFormat);String s = objectMapper.writeValueAsString(transaction);System.out.println(s);} catch (JsonProcessingException e) {e.printStackTrace();}}
{"type":"transfer","date":"2022-03-04"}
四)、Jackson JSON树模型
Jackson具有内置的树模型,可用于表示JSON对象。
- 如果不知道接收到的JSON的格式,或者由于某种原因而不能(或者只是不想)创建一个类来表示它,那么就要用到Jackson的树模型。
如果需要在使用或转化JSON之前对其进行操作,也需要被用到Jackson树模型。
1.快速入门
在原本传入实体类.class的位置变为传入JsonNode.class,即可将json字符串解析为JsonNode对象
@Testpublic void testquickStart(){String carJson ="{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";ObjectMapper objectMapper=new ObjectMapper();try {JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);System.out.println(jsonNode.toString());} catch (IOException e) {e.printStackTrace();}}
ObjectMapper类还具有一个特殊的readTree()方法,该方法返回JsonNode。 这是使用ObjectMapper readTree()方法将JSON解析为JsonNode的示例:
String carJson ="{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";ObjectMapper objectMapper = new ObjectMapper();try {JsonNode jsonNode = objectMapper.readTree(carJson);} catch (IOException e) {e.printStackTrace();}
2. Jackson JsonNode类
通过JsonNode类,可以以非常灵活和动态的方式将JSON作为Java对象导航。这里了解一些如何使用它的基础知识。
将JSON解析为JsonNode(或JsonNode实例树)后,就可以浏览JsonNode树模型:解析JSON字段(String,int)
- 解析数组
解析嵌套类型
{"brand":"Mercedes","doors":5,"owners":["John","Jack","Jill"],"nestedObject":{"field":"value"}}
@Testpublic void testJsonNode(){String carJson ="{ \"brand\" : \"Mercedes\", \"doors\" : 5," +" \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +" \"nestedObject\" : { \"field\" : \"value\" } }";ObjectMapper objectMapper = new ObjectMapper();try {//字符串类型字段JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);JsonNode brandNode = jsonNode.get("brand");String s = brandNode.asText();System.out.println("brand -> "+s);//int类型字段JsonNode doors = jsonNode.get("doors");int i = doors.asInt();System.out.println("doors -> "+i);//数组类型JsonNode owners = jsonNode.get("owners");for (JsonNode owner : owners) {String text = owner.asText();System.out.print(text+" ");}System.out.println("");//嵌套类型JsonNode nestedObject = jsonNode.get("nestedObject");JsonNode field = nestedObject.get("field");String asText = field.asText();System.out.println("field "+ asText);} catch (IOException e) {e.printStackTrace();}}
3.Java对象->JsonNode
ObjectMapper objectMapper = new ObjectMapper();Car car = new Car();car.brand = "Cadillac";car.doors = 4;JsonNode carJsonNode = objectMapper.valueToTree(car);
4.JsonNode-> Java对象
##ObjectMapper objectMapper = new ObjectMapper();String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";JsonNode carJsonNode = objectMapper.readTree(carJson);Car car = objectMapper.treeToValue(carJsonNode);
JsonNode
Jackson JsonNode类com.fasterxml.jackson.databind.JsonNode是Jackson的JSON树形模型(对象图模型)。 Jackson可以将JSON读取到JsonNode实例中,然后将JsonNode写入JSON。 因此,这一节将说明如何将JSON反序列化为JsonNode以及将JsonNode序列化为JSON
1.JsonNode vs ObjectNode
Jackson JsonNode类是不可变的。 这意味着,实际上不能直接构建JsonNode实例的对象图。 而是创建JsonNode子类ObjectNode的对象图。 作为JsonNode的子类,可以在可以使用JsonNode的任何地方使用ObjectNode。
暂时还不大懂,以后用到再琢磨琢磨2、JSON-> JsonNode
要使用Jackson将JSON读取到JsonNode中,首先需要创建一个Jackson ObjectMapper实例。 在ObjectMapper实例上,调用readTree()并将JSON源作为参数传递。 这是将JSON反序列化为JsonNode的示例:
@Testpublic void testJavaToJsonNode(){String json = "{ \"f1\" : \"v1\" } ";ObjectMapper objectMapper=new ObjectMapper();try {JsonNode jsonNode = objectMapper.readTree(json);System.out.println(jsonNode.toString());} catch (IOException e) {e.printStackTrace();}}
3. JsonNode->JSON
要将Jackson的JsonNode写入JSON,还需要一个Jackson ObjectMapper实例。 在ObjectMapper上,调用writeValueAsString()方法或任何适合需要的写入方法。 这是将JsonNode写入JSON的示例:
@Testpublic void testJNToNSON(){String json = "{ \"f1\" : \"v1\" } ";ObjectMapper objectMapper = new ObjectMapper();try {JsonNode jsonNode = objectMapper.readTree(json);String s=objectMapper.writeValueAsString(jsonNode);System.out.println(s);} catch (IOException e) {e.printStackTrace();}}
4.获取字段
通过get给出字段名获取
{"field1" : "value1","field2" : 999}
JsonNode jsonNode = ... //parse above JSON into a JsonNodeJsonNode field1 = jsonNode.get("field1");JsonNode field2 = jsonNode.get("field2");
通过at在路径中获取
{"identification" : {"name" : "James","ssn: "ABC123552"}}
JsonNode nameNode = jsonNode.at("/identification/name");
注意传递给at()方法的参数:字符串/ identification / name。 这是一个JSON路径表达式。 此路径表达式指定从根JsonNode到您要访问其值的字段的完整路径。 这类似于从文件系统根目录到Unix文件系统中文件的路径。
5.转换JsonNode字段
Jackson JsonNode类包含一组可以将字段值转换为另一种数据类型的方法。 例如,将String字段值转换为long或相反。 这是将JsonNode字段转换为一些更常见的数据类型的示例:
String f2Str = jsonNode.get("f2").asText();double f2Dbl = jsonNode.get("f2").asDouble();int f2Int = jsonNode.get("f2").asInt();long f2Lng = jsonNode.get("f2").asLong();
使用默认值转换: 如果JsonNode中的字段可以为null,则在尝试转换它时可以提供默认值。 这是使用默认值调用转换方法的示例:
ObjectMapper objectMapper = new ObjectMapper();String json = "{ \"f1\":\"Hello\", \"f2\":null }";JsonNode jsonNode = objectMapper.readTree(json);String f2Value = jsonNode.get("f2").asText("Default");
6. ObjectNode
如前所述,JsonNode类是不可变的。 要创建JsonNode对象图,必须能够更改图中的JsonNode实例,例如 设置属性值和子JsonNode实例等。由于是不可变的,因此无法直接使用JsonNode来实现。
创建ObjectNode
而是创建一个ObjectNode实例,该实例是JsonNode的子类。 这是一个通过Jackson ObjectMapper createObjectNode()方法创建ObjectNode的示例:ObjectMapper objectMapper = new ObjectMapper();ObjectNode objectNode = objectMapper.createObjectNode();
Set ObjectNode字段
要在Jackson ObjectNode上设置字段,可以调用其set()方法,并将字段名称String和JsonNode作为参数传递。 这是在Jackson的ObjectNode上设置字段的示例:String json = "{ \"f1\" : \"v1\" } ";ObjectMapper objectMapper=new ObjectMapper();ObjectNode objectNode = objectMapper.createObjectNode();try {JsonNode jsonNode = objectMapper.readTree(json);JsonNode brand = objectNode.set("childNode", jsonNode);System.out.println(brand.toString());} catch (IOException e) {e.printStackTrace();}
{"childNode":{"f1":"v1"}}//childNode字段
Put ObjectNode字段
ObjectNode类还具有一组方法,可以直接为字段put(设置)值。 这比尝试将原始值转换为JsonNode并使用set()进行设置要容易得多。 以下是使用put()方法为ObjectNode上的字段设置字符串值的示例:ObjectMapper objectMapper=new ObjectMapper();ObjectNode objectNode = objectMapper.createObjectNode();objectNode.put("field1", "value1");objectNode.put("field2", 123);objectNode.put("field3", 999.999);System.out.println(objectNode.toString());
{"field1":"value1","field2":123,"field3":999.999}
删除ObjectNode字段:使用remove(”fieldname”)
- 循环ObjectNode字段
JsonNode类具有一个名为fieldNames()的方法,该方法返回一个Iterator,可以迭代JsonNode的所有字段名称。 我们可以使用字段名称来获取字段值。 这是一个迭代Jackson JsonNode的所有字段名称和值的示例:Iterator<String> stringIterator = objectNode.fieldNames();while (stringIterator.hasNext()){String next = stringIterator.next();JsonNode jsonNode = objectNode.get(next);System.out.println(jsonNode.toString());}
Jackson注解
| 注解 | 用法 | | :—-: | :—- | | _@_JsonProperty | 用于属性,把属性的名称序列化时映射为为另外一个名称。示例:
@JsonProperty(“birth d ate”)
private Date birthDate; | | [@JsonFormat ](/JsonFormat ) | 用于属性或者方法,把属性的格式序列化时转换成指定的格式。示例:
[@JsonFormat(timezone ](/JsonFormat(timezone ) = “GMT+8”, pattern = “yyyy-MM-dd HH:mm”)
public Date getBirthDate() | | [@JsonPropertyOrder ](/JsonPropertyOrder ) | 用于类, 指定属性在序列化时 json 中的顺序 , 示例:
@JsonPropertyOrder({ “birth_Date”, “name” })
public class Person | | [@JsonCreator ](/JsonCreator ) | 用于构造方法,和 [@JsonProperty ](/JsonProperty ) 配合使用,适用有参数的构造方法。 示例: [@JsonCreator ](/JsonCreator )
public Person(@JsonProperty(“name”)String name) {…} | | [@JsonAnySetter ](/JsonAnySetter ) | 用于属性或者方法,设置未反序列化的属性名和值作为键值存储到 map 中
[@JsonAnySetter ](/JsonAnySetter )
public void set(String key, Object value) {
map.put(key, value);
} | | [@JsonAnyGetter ](/JsonAnyGetter ) | 用于方法 ,获取所有未序列化的属性
public Mapany() { return map; } | | [ @_JsonRootName ](/JsonRootName ) | 用于定义一个根Key,需要进行配置:
jackson:
deserialization.UNWRAP_ROOT_VALUE: true |
一)、Read+Write注解
此类注解可以进行序列化以及反序列化,成为双向注解或者Read+Write注解
1._@_JsonIgnore
Jackson注解@JsonIgnore用于告诉Jackson忽略Java对象的某个属性(字段)。 在将JSON读取到Java对象中以及将Java对象写入JSON时,都将忽略该属性
import com.fasterxml.jackson.annotation.JsonIgnore;public class PersonIgnore {@JsonIgnorepublic long personId = 0;public String name = null;}
2._@_JsonIgnoreProperties
与@JsonIgnore的作用相同,但是放在类上面,在内部指定不参与序列化和反序列化的成员变量
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;@JsonIgnoreProperties({"firstName", "lastName"})public class PersonIgnoreProperties {public long personId = 0;public String firstName = null;public String lastName = null;}
firstName与LastName均不参与序列化和反序列化
3._@_JsonIgnoreType
_@_JsonIgnoreType Jackson注解用于将整个类型(类)标记为在使用该类型的任何地方都将被忽略。
@Data@NoArgsConstructor@JsonRootName("car")public class Car {private String brand = null;private int doors = 0;@JsonIgnoreprivate String type;@JsonProperty(value = "Driver")private Driver driver;public Car(String brand,int doors,String type,Driver driver){this.brand=brand;this.doors=doors;this.type=type;this.driver=driver;}}
@Data@JsonIgnoreTypepublic class Driver {private String name;private String sex;private int age;}
加上注解后,Driver整个类都将被忽略
{"brand":"tesla","doors":5}
取消注解:
{"brand":"tesla","doors":5,"Driver":{"name":"John Wick","sex":"male","age":29}}
4._@_JsonAutoDetect
暂时没大看懂在干什么
Jackson注解@JsonAutoDetect用于告诉Jackson在读写对象时包括非public修饰的属性。
这是一个示例类,展示如何使用@JsonAutoDetect注解:
import com.fasterxml.jackson.annotation.JsonAutoDetect;@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )public class PersonAutoDetect {private long personId = 123;public String name = null;}
JsonAutoDetect.Visibility类包含与Java中的可见性级别匹配的常量,表示ANY,DEFAULT,NON_PRIVATE,NONE,PROTECTED_AND_PRIVATE和PUBLIC_ONLY。
5._@_JsonRootName
对于只有id和name两个字段的POJO来说,正常的序列化结果如下:
{"id" : 1,"name" : "book"}
jackson在序列化时,可以在上述json外面再包裹一层,官方叫做WRAP_ROOT_VALUE,本文中叫做root对象,如下所示,整个json的只有一个键值对,key是aaabbbccc,value内部才是POJO实例的id和name字段的值:
{"aaabbbccc" : {"id" : 2,"name" : "food"}}
配置:
在使用ObjectMapper时,使用以下方法使root生效:
objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
在Springboot项目中,可以通过配置文件的方法使其生效:
jackson:serialization.UNWRAP_ROOT_VALUE: true
默认值:如果不使用@JsonRootName注解,则root字段默认为实体类的名称,@JsonRootName可以用于指定root的名称
在SSM项目当中,序列化的工作交给了ResponseEntity,可以将toString的字符数据转化为json的数据格式,因此序列化的工作不需要自己来完成,自己只需要关注反序列化的工作即可
下面来讨论反序列化的工作
配置反序列化,若不进行配置,jackson依旧无法识别root这个key,得到的值全为null同样需要进行配置
使用ObjecMapper时:
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
在Springboot项目当中,在配置文件中进行设置:
jackson:deserialization.UNWRAP_ROOT_VALUE: true
若不进行配置,
在使用了@JsonRootName的注解后,@JsonRootName中的值应当与Json字符串的root的值一致,否则会反序列化失败二)、Read注解
1、_@_JsonSetter
当进行反序列化时,JSON字段与setter方法无法匹配时,通过该注解来指定setter函数,也可认为@JsonProperty的逆向操作
{"id" : 1234,"name" : "John"}
此处id与成员变量personId无法匹配,因此指定setter方法来进行数据的封装
public class Person {private long personId = 0;private String name = null;public long getPersonId() { return this.personId; }@JsonSetter("id")public void setPersonId(long personId) { this.personId = personId; }public String getName() { return name; }public void setName(String name) { this.name = name; }}
@JsonSetter注解中指定的值是要与此setter方法匹配的JSON字段的名称。 在这种情况下,名称为id,因为这是我们要映射到setPersonId()setter方法的JSON对象中字段的名称。
2、_@_JsonAnySetter
Jackson注解@JsonAnySetter表示Jackson为JSON对象中所有无法识别的字段调用相同的setter方法。 “无法识别”是指尚未映射到Java对象中的属性或设置方法的所有字段。
实体类@ToStringpublic class Bag {private Map<String,Object> properties=new HashMap<>();private int size;public void setSize(int size) {this.size = size;}@JsonAnySetterpublic void set(String fieldName,Object value){this.properties.put(fieldName,value);}public Object get(String fieldName){return this.properties.get(fieldName);}}
{"id" : 1234,"name" : "John","size":5}
显然可知,id和name都不存在对应的setter函数,无法自动进行数据的封装,通过@JsonAnySetter指定该setter处理无法识别的id和name,进行数据封装,最后便可以正常装配,而对于size,存在对应的setter函数,因此正常装配即可,与@JsonAnySetter无关
3、_@_JsonCreator
Jackson注解@JsonCreator用于告诉Jackson该Java对象具有一个构造函数(“创建者”),该构造函数可以将JSON对象的字段与Java对象的字段进行匹配。
public class PersonImmutable {private long id = 0;private String name = null;@JsonCreatorpublic PersonImmutable(@JsonProperty("id") long id,@JsonProperty("name") String name ) {this.id = id;this.name = name;}public long getId() {return id;}public String getName() {return name;}}
要告诉Jackson应该调用PersonImmutable的构造函数,我们必须在构造函数中添加@JsonCreator注解。 我们还必须注解构造函数的参数,以告诉Jackson将JSON对象中的哪些字段传递给哪些构造函数参数。
三)、Write注解
Jackson还包含一组注解,这些注解可以影响Jackson将Java对象序列化(写入)到JSON的方式。
1、_@_JsonInclude
Jackson注解@JsonInclude告诉Jackson仅在某些情况下包括属性。 例如,仅当属性为非null,非空或具有非默认值时,才应包括该属性。 这是显示如何使用@JsonInclude注解的示例:
import com.fasterxml.jackson.annotation.JsonInclude;@JsonInclude(JsonInclude.Include.NON_EMPTY)public class PersonInclude {public long personId = 0;public String name = null;}
此处表示该类的参数不能为null且不能为空字符串
同时还有者NON_ABSENT,NON_EMPTY等其他参数
ALWAYS:表示总是序列化所有属性
- NON_NULL:表示序列化非null属性
- NON_ABSENT:表示序列化非null或者引用类型缺省值,例如java8的Optional类,这个选中通常与Optional一起使用
- NON_EMPTY:表示序列化非Empty的属性,例如空的集合不会被序列化
- NON_DEFAULT:仅包含与POJO属性默认值不同的值
CUSTOM:由{_@_link JsonInclude#valueFilter}指定值本身,或由{_@_link JsonInclude#contentFilter}指定结构化类型的内容,由过滤器对象的equals方法进行序列化,返回true则会被排除,返回false会被序列化
USE_DEFAULTS:使用默认值2、_@_JsonGetter
_@_JsonGetter Jackson注解用于告诉Jackson,应该通过调用getter方法而不是通过直接字段访问来获取某个字段值
3、_@_JsonAnyGetter
_@_JsonAnyGetter Jackson注解使您可以将Map用作要序列化为JSON的属性的容器。
public class PersonAnyGetter {private Map<String, Object> properties = new HashMap<>();@JsonAnyGetterpublic Map<String, Object> properties() {return properties;}}
@Testpublic void test3(){Map<String,Object> map=new HashMap<>();map.put("name","Jhon Wick");Car car=new Car();car.setBrand("ford");car.setDoors(3);car.setType("oil");car.setDriver(null);map.put("car",car);map.put("age",29);PersonAnyGetter personAnyGetter=new PersonAnyGetter();personAnyGetter.setProperties(map);ObjectMapper objectMapper=new ObjectMapper();try {String s = objectMapper.writeValueAsString(personAnyGetter);System.out.println(s);} catch (JsonProcessingException e) {e.printStackTrace();}}
序列化的结果为:
{"car":{"brand":"ford","type":"oil","doors":3,"Driver":null},"name":"Jhon Wick","age":29}
当看到@JsonAnyGetter注解时,Jackson将从@JsonAnyGetter注解的方法中获取返回的Map,并将该Map中的每个键值对都视为一个属性。 换句话说,Map中的所有键值对都将作为PersonAnyGetter对象的一部分序列化为JSON。
4、_@_JsonPropertyOrder
_@_JsonPropertyOrder Jackson注解可用于指定将Java对象的字段序列化为JSON的顺序。
将上一个注解的结果进行排序后的结果为:@JsonPropertyOrder({"brand","type","doors","driver"})
{"car":{"brand":"ford","type":"oil","doors":3,"Driver":null},"name":"Jhon Wick","age":29}
5、_@_JsonRawValue
_@_JsonRawValue Jackson注解告诉Jackson该属性值应直接写入JSON输出。 如果该属性是字符串,Jackson通常会将值括在引号中,但是如果使用@JsonRawValue属性进行注解,Jackson将不会这样做。
@Datapublic class Driver {private String name;@JsonRawValueprivate String sex;private int age;}
{"name":"Jhon Wick","sex":male,"age":29}
对比name与sex的结果,可以发现同为字符串,sex的引号消失
下面这个例子可以说明此注解究竟有何用处
public class PersonRawValue {public long personId = 0;@JsonRawValuepublic String address ="{ \"street\" : \"Wall Street\", \"no\":1}";}
序列化结果:得到了一个嵌套字段
{"personId":0,"address":{ "street" : "Wall Street","no":1}}
如果没有该注解,则得到以下结果,显然不是预期的结果
{"personId":0,"address":"{ \"street\" : \"Wall Street\", \"no\":1}"}
6、_@_JsonValue
Jackson注解@JsonValue告诉Jackson,Jackson不应该尝试按照常规方法序列化对象本身,而应在对象上调用将对象序列化为JSON字符串的方法。
在下面的例子当中,按照自己自定义的toJson方法进行序列化@Datapublic class Driver {private String name;@JsonRawValueprivate String sex;private int age;@JsonValuepublic String toJson(){return this.name+","+this.age;}}
得到的结果为:
"Jhon Wick,29"
注:得到的Json字符串中引号也属于其中的一部分,即s.charAt(0)=”
原文1:https://www.cnblogs.com/klhans/p/12583751.html
原文2:https://blog.csdn.net/boling_cavalry/article/details/107135958
原文3:https://juejin.cn/post/6844904166809157639
