文章目录
- Jackson组成
- JSON和对象系列
- JSON和POJO互转示例
- TreeNode和ObjectNode
- 配置
- 未知字段
- 忽略字段
- 忽略null值
- 字段别名
- 使用自定义序列化和反序列化
- 处理日期格式
- 类型转换
- XML和对象系列
- 序列化字符串
- 反序列化字符串
- 序列化xml文件
- 反序列化xml文件
- List和xml的序列化和反序列化
- 高级特性
- 自定义序列化器根据属性值有条件的序列化对象
- 枚举类序列化和反序列化
- 字段可见性
- 比较JSON对象
记录下Jackson常用的功能
Jackson组成
jackson是java处理json的标准库
Jackson核心有三个包
core,annotation,databind, databind依赖前两者,所以使用时直接引入databind即可
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.17.0</version></dependency>
JSON和对象系列
JSON和POJO互转示例
使用ObjectMapper进行JSON字符串和类,List,Map的互转,字段若私有,则需提供getter和setter方法
ObjectMapper objectMapper = new ObjectMapper();Information information = new Information();information.setHost("12414142");information.setN ame("111");information.setPassword("123");Email email = new Email();email.setTitle("email-1");email.setInformation(information);String string = objectMapper.writeValueAsString(email);System.out.println(string);Email email1 = objectMapper.readValue(string, Email.class);System.out.println(email1);List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});Map<String, Object> map = objectMapper.readValue(json, new TypeReference<Map<String,Object>>(){});
public class Email {private Information information;private String title;public Information getInformation() {return information;}public void setInformation(Information information) {this.information = information;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}
}
public class Information {private String name;private String password;private String host;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getHost() {return host;}public void setHost(String host) {this.host = host;}
}
// Note: can use getters/setters as well; here we just use public fields directly:
public class MyValue {public String name;public int age;// NOTE: if using getters/setters, can keep fields `protected` or `private`
}
TreeNode和ObjectNode
针对非对象类,动态场景,动态字段场景
// can be read as generic JsonNode, if it can be Object or Array; or,
// if known to be Object, as ObjectNode, if array, ArrayNode etc:
JsonNode root = mapper.readTree("{ \"name\": \"Joe\", \"age\": 13 }");
String name = root.get("name").asText();
int age = root.get("age").asInt();// can modify as well: this adds child Object as property 'other', set property 'type'
root.withObject("/other").put("type", "student");
String json = mapper.writeValueAsString(root); // prints below/*
with above, we end up with something like as 'json' String:
{"name" : "Bob","age" : 13,"other" : {"type" : "student"}
}
*/
// Some parts of this json are modeled in our code, some are not
JsonNode root = mapper.readTree(complexJson);
Person p = mapper.treeToValue(root.get("person"), Person.class); // known single pojo
Map<String, Object> dynamicmetadata = mapper.treeToValue(root.get("dynamicmetadata"), Map.class); // unknown smallish subfield, convert all to collections
int singledeep = root.get("deep").get("large").get("hiearchy").get("important").intValue(); // single value in very deep optional subfield, ignoring the rest
int singledeeppath = root.at("/deep/large/hiearchy/important").intValue(); // json path
int singledeeppathunique = root.findValue("important").intValue(); // by unique field name// Send an aggregate json from heterogenous sources
ObjectNode root = mapper.createObjectNode();
root.putPOJO("person", new Person("Joe")); // simple pojo
root.putPOJO("friends", List.of(new Person("Jane"), new Person("Jack"))); // generics
Map<String, Object> dynamicmetadata = Map.of("Some", "Metadata");
root.putPOJO("dynamicmetadata", dynamicmetadata); // collections
root.putPOJO("dynamicmetadata", mapper.valueToTree(dynamicmetadata)); // same thing
root.set("dynamicmetadata", mapper.valueToTree(dynamicmetadata)); // same thing
root.withObject("deep").withObject("large").withObject("hiearchy").put("important", 42); // create as you go
root.withObject("/deep/large/hiearchy").put("important", 42); // json path
mapper.writeValueAsString(root);
配置
未知字段
//反序列化时候忽略未知字段(多的字段)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);Car car = objectMapper.readValue(jsonString, Car.class);JsonNode jsonNodeRoot = objectMapper.readTree(jsonString);JsonNode jsonNodeYear = jsonNodeRoot.get("year");String year = jsonNodeYear.asText();
//单个类反序列化时忽略未知字段
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyDtoIgnoreUnknown { ... }
//反序列化时支持反序列化不完整的JSON//设置是否允许基础字段为nullobjectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
//是否允许将枚举值序列化/反序列化为数字objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);
忽略字段
基本都要用对应注解,
四个维度:类,字段,过滤器,类型字段忽略
忽略null值
1.配置单个类或者单个字段用相应注解
2.mapper上配置
mapper.setSerializationInclusion(Include.NON_NULL);
字段别名
@JsonProperty注解
使用自定义序列化和反序列化
public class CustomCarSerializer extends StdSerializer<Car> {public CustomCarSerializer() {this(null);}public CustomCarSerializer(Class<Car> t) {super(t);}@Overridepublic void serialize(Car car, JsonGenerator jsonGenerator, SerializerProvider serializer) {jsonGenerator.writeStartObject();jsonGenerator.writeStringField("car_brand", car.getType());jsonGenerator.writeEndObject();}}public class CustomCarDeserializer extends StdDeserializer<Car> {public CustomCarDeserializer() {this(null);}public CustomCarDeserializer(Class<?> vc) {super(vc);}@Overridepublic Car deserialize(JsonParser parser, DeserializationContext deserializer) {Car car = new Car();ObjectCodec codec = parser.getCodec();JsonNode node = codec.readTree(parser);// try catch blockJsonNode colorNode = node.get("color");String color = colorNode.asText();car.setColor(color);return car;}}
ObjectMapper mapper = new ObjectMapper();SimpleModule module = new SimpleModule("CustomCarSerializer", new Version(1, 0, 0, null, null, null));module.addSerializer(Car.class, new CustomCarSerializer());mapper.registerModule(module);Car car = new Car("yellow", "renault");String carJson = mapper.writeValueAsString(car);String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
ObjectMapper mapper = new ObjectMapper();
SimpleModule module =new SimpleModule("CustomCarDeserializer", new Version(1, 0, 0, null, null, null));
module.addDeserializer(Car.class, new CustomCarDeserializer());
mapper.registerModule(module);
Car car = mapper.readValue(json, Car.class);
处理日期格式
ObjectMapper objectMapper = new ObjectMapper();DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");objectMapper.setDateFormat(df);String carAsString = objectMapper.writeValueAsString(request);// 输出: {"car":{"color":"yellow","type":"renault"},"datePurchased":"2016-07-03 11:43 AM CEST"}
类型转换
// Convert from List<Integer> to int[]
List<Integer> sourceList = ...;
int[] ints = mapper.convertValue(sourceList, int[].class);
// Convert a POJO into Map!
Map<String,Object> propertyMap = mapper.convertValue(pojoValue, Map.class);
// ... and back
PojoType pojo = mapper.convertValue(propertyMap, PojoType.class);
// decode Base64! (default byte[] representation is base64-encoded String)
String base64 = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz";
byte[] binary = mapper.convertValue(base64, byte[].class);
XML和对象系列
xml依赖
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.17.0</version></dependency>
序列化字符串
XmlMapper xmlMapper = new XmlMapper();String xml = xmlMapper.writeValueAsString(new Person());
反序列化字符串
XmlMapper xmlMapper = new XmlMapper();SimpleBean value= xmlMapper.readValue("<SimpleBean><x>1</x><y>2</y></SimpleBean>", SimpleBean.class);
序列化xml文件
xmlMapper.writeValue(new File("person_bean.xml"), new Person());
反序列化xml文件
XmlMapper xmlMapper = new XmlMapper();String xml = inputStreamToString(new FileInputStream(file));SimpleBean value = xmlMapper.readValue(xml, SimpleBean.class);public String inputStreamToString(InputStream is) throws IOException {StringBuilder sb = new StringBuilder();String line;BufferedReader br = new BufferedReader(new InputStreamReader(is));while ((line = br.readLine()) != null) {sb.append(line);}br.close();return sb.toString();
}
List和xml的序列化和反序列化
<Person><firstName>Rohan</firstName><lastName>Daye</lastName><phoneNumbers><phoneNumbers>9911034731</phoneNumbers><phoneNumbers>9911033478</phoneNumbers></phoneNumbers><address><streetName>Name1</streetName><city>City1</city></address><address><streetName>Name2</streetName><city>City2</city></address>
</Person>
public final class Person {private String firstName;private String lastName;private List<String> phoneNumbers = new ArrayList<>();@JacksonXmlElementWrapper(useWrapping = false)private List<Address> address = new ArrayList<>();//standard setters and getters}
XmlMapper xmlMapper = new XmlMapper();Person person = testPerson(); // test dataByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();xmlMapper.writeValue(byteArrayOutputStream, person);
高级特性
自定义序列化器根据属性值有条件的序列化对象
自定义序列化器根据属性值有条件的序列化对象
枚举类序列化和反序列化
//默认输出序列化枚举类 枚举名称
https://baeldung-cn.com/jackson-serialize-enums#45-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%99%A8
字段可见性
有两个维度,全局维度配置和类维度
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class MyDtoNoAccessors { ... }
比较JSON对象
JsonNode.equals()
// Jackson还提供了JsonNode.equals(comparator, JsonNode),以配置自定义Java比较器对象。//可以自定义比较器实现自己的比较逻辑