序列化和反序列化
序列化: 把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。 核心作用是对象状态的保存与重建。
反序列化:客户端从文件中或网络上获得序列化后的对象字节流,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。
通俗一点:
序列化: 对象--->JSON
反序列化: JSON ---> 对象
MappingProvider
MappinProvider是一个接口, 图中虚线箭头代表实现,下方六个是MappingProvider的实现类.
JsonPath将自动尝试将结果强制转换为调用方所期望的类型。
计算路径时需要知道路径是明确的还是不明确的,明确的返回单个值,不明确的返回一个List.
默认情况下,一个简单的对象映射器由MappingProvider SPI提供。JsonPath提供了默认的实现: JsonSmartMappingProvider。但是不能将json字符串转为POJO对象。
JsonPath提供的MappingProvider如下:
JsonSmartMappingProvider(默认)
GsonMappingProvider
JacksonMappingProvider
JakartaMappingProvider
JsonOrgMappingProvider
TapestryMappingProvider
MappingProvider内只有两个方法:
public interface MappingProvider {
/**
*
* @param source object to map
* @param targetType the type the source object should be mapped to
* @param configuration current configuration
* @param <T> the mapped result type
* @return return the mapped object
*/
<T> T map(Object source, Class<T> targetType, Configuration configuration);
/**
*
* @param source object to map
* @param targetType the type the source object should be mapped to
* @param configuration current configuration
* @param <T> the mapped result type
* @return return the mapped object
*/
<T> T map(Object source, TypeRef<T> targetType, Configuration configuration);
}
API
很容易理解, map将源对象返回指定类型.
JsonSmartMappingProvider
JsonSmartMappingProvider提供了基本数据类型的转换:
static {
DEFAULT.registerReader(Long.class, new LongReader());
DEFAULT.registerReader(long.class, new LongReader());
DEFAULT.registerReader(Integer.class, new IntegerReader());
DEFAULT.registerReader(int.class, new IntegerReader());
DEFAULT.registerReader(Double.class, new DoubleReader());
DEFAULT.registerReader(double.class, new DoubleReader());
DEFAULT.registerReader(Float.class, new FloatReader());
DEFAULT.registerReader(float.class, new FloatReader());
DEFAULT.registerReader(BigDecimal.class, new BigDecimalReader());
DEFAULT.registerReader(String.class, new StringReader());
DEFAULT.registerReader(Date.class, new DateReader());
DEFAULT.registerReader(BigInteger.class, new BigIntegerReader());
DEFAULT.registerReader(boolean.class, new BooleanReader());
}
方法实现:
@Override
public <T> T map(Object source, Class<T> targetType, Configuration configuration) {
if(source == null){
/*
判断传入映射对象是否为空,空直接返回null
*/
return null;
}
if (targetType.isAssignableFrom(source.getClass())) {
/*
确定此class对象表示的类或接口是否与指定class参数表示的类或接口相同,或为其超类或超
接口。如果是,它返回true;否则返回false。如果这个Class对象表示一个基元类型,如果.
指.定的Class参数正是这个Class对象,这个方法返回true;否则返回false。
具体来说,此方法测试是否可以通过标识转换或通过扩展引用转换将指定Class参数表示的类.
型.转换为此Class对象表示的类型。
*/
return (T) source;
}
try {
/*
如果source既不是Map映射也不是Array数组,
直接返回.
*/
if(!configuration.jsonProvider().isMap(source) && !configuration.jsonProvider().isArray(source)){
return factory.call().getMapper(targetType).convert(source);
}
/*
转换为targetType类型
*/
String s = configuration.jsonProvider().toJson(source);
return (T) JSONValue.parse(s, targetType);
} catch (Exception e) {
throw new MappingException(e);
}
}
@Override
public <T> T map(Object source, TypeRef<T> targetType, Configuration configuration) {
throw new UnsupportedOperationException("Json-smart provider does not support TypeRef! Use a Jackson or Gson based provider");
}
JsonSmartMappingProvider不支持TyprRef, JacksonMappingProvider或者GsonMappingProvider支持.
继续看JsonReader下的convert方法
一下子就和上面JsonSmartMappingProvider提供的基本数据类型的转换联系起来.
列举一个:
private static class IntegerReader extends JsonReaderI<Integer> {
public IntegerReader() {
super(null);
}
public Integer convert(Object src) {
if(src == null){
return null;
}
if(Integer.class.isAssignableFrom(src.getClass())){
return (Integer) src;
} else if (Long.class.isAssignableFrom(src.getClass())) {
return ((Long) src).intValue();
} else if (Double.class.isAssignableFrom(src.getClass())) {
return ((Double) src).intValue();
} else if (BigDecimal.class.isAssignableFrom(src.getClass())) {
return ((BigDecimal) src).intValue();
} else if (Float.class.isAssignableFrom(src.getClass())) {
return ((Float) src).intValue();
} else if (String.class.isAssignableFrom(src.getClass())) {
return Integer.valueOf(src.toString());
}
throw new MappingException("can not map a " + src.getClass() + " to " + Integer.class.getName());
}
}
既然JsonSmartMappingProvider不支持TyprRef, 而JacksonMappingProvider或者GsonMappingProvider支持. 如何切换Provider呢? 实际上是可以自己切换的, 比如切换到
JacksonJsonMappingProvider:
Configuration.setDefaults(new Configuration.Defaults() {
private final JsonProvider jsonProvider = new JacksonJsonProvider();
private final MappingProvider mappingProvider = new JacksonMappingProvider();
@Override
public JsonProvider jsonProvider() {
return jsonProvider;
}
@Override
public MappingProvider mappingProvider() {
return mappingProvider;
}
@Override
public Set<Option> options() {
return EnumSet.noneOf(Option.class);
}
});
如果将JsonPath配置为使用JacksonMappingProvider或GsonMappingProvider,可以将JsonPath输出直接映射到POJO中。
代码:
Book 类:
public class Book{
private String category;
private String author;
private String title;
private Double price;
private String isbn;
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
@Override
public String toString(){
if (this.isbn != null){
return "category : " + getCategory() + " author: " + getAuthor()
+ " title : " + getTitle() + " price : " + getPrice() + " isbn : " + getIsbn();
}
return "category : " + getCategory() + " author: " + getAuthor()
+ " title : " + getTitle() + " price : " + getPrice();
}
}
Demo:
public class JacksonMappingProviderDemo {
public static void main(String[] args) {
// 转化成反序列化成Date类
String json1 = "{\"date_as_long\" : 1658908587321}";
Date date = JsonPath.parse(json1).read("$['date_as_long']", Date.class);
System.out.println(date);
Configuration conf = Configuration
.builder()
.mappingProvider(new JacksonMappingProvider())
.build();
Book[] books = JsonPath.using(conf).parse(json).read("$.store.book[*]", Book[].class);
for (Book book : books) {
System.out.println(book.toString());
}
TypeRef<List<String>> typeRef = new TypeRef<List<String>>() {};
List<String> titles = JsonPath.using(conf).parse(json).read("$.store.book[*].title", typeRef);
System.out.println(titles);
}
static String json = """
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}""";
}
测试结果: