目前主流的json解析类库有jackson,fastjson,gson,gson的serialization deserialization解析功能无疑是最强大的,基本上完美支持复杂对象的json化和反json化,其余两个库在转换复杂对象时都容易出现问题。若是在不考虑效率的状况下,我强烈推荐使用gson类库。java
首先须要添加依赖git
//gradle dependencies { compile 'com.google.code.gson:gson:2.8.2' } //maven <dependencies> <!-- Gson: Java to Json conversion --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.2</version> <scope>compile</scope> </dependency> </dependencies>
接下来看一些代码例子,gson设计的很是易用,基本上一看就懂。github
// 建立gson对象,gson对象是内部无状态的,因此建立一个能够屡次使用,能够想象成一个转换器 Gson gson = new Gson(); //转换成json只用直接放入对象就行,gson在内部会提取对象的类型信息 gson.toJson(1); // ==> 1 gson.toJson("abcd"); // ==> "abcd" gson.toJson(new Long(10)); // ==> 10 int[] values = { 1 }; gson.toJson(values); // ==> [1] // 反json化,此时须要传入类型参数,由于json中是没有保存关于java类型的信息的 int one = gson.fromJson("1", int.class); Integer one = gson.fromJson("1", Integer.class); Long one = gson.fromJson("1", Long.class); String str = gson.fromJson("\"abc\"", String.class);
固然,gson也支持对对象类型的转换json
class BagOfPrimitives { private int value1 = 1; private String value2 = "abc"; //使用transient标识的变量不会被json化 private transient int value3 = 3; BagOfPrimitives() { // no-args constructor } } // Serialization BagOfPrimitives obj = new BagOfPrimitives(); Gson gson = new Gson(); String json = gson.toJson(obj); // ==> json is {"value1":1,"value2":"abc"}
不过注意你不能json化一个具备循环引用的对象,会致使死循环(简单来讲就是a有一个变量为b,b也有一个变量为a,此时不管json化谁都会致使死循环)数组
1.彻底可使用private修饰变量类型,由于gson内部是使用反射来进行json化的,因此private也彻底能够读取的到
2.彻底没有必要使用任何的annotations 来标注哪一个字段须要被包含(有不少其余库是使用annotations 来标记的),gson默认会序列化当前类中的全部字段(包括他的全部父类)
3.若是一个字段被标记为transient,他不会被Json化
4.gson对值为null的字段有很好的支持maven
Gson gson = new Gson(); int[] ints = {1, 2, 3, 4, 5}; String[] strings = {"abc", "def", "ghi"}; // Serialization gson.toJson(ints); // ==> [1,2,3,4,5] gson.toJson(strings); // ==> ["abc", "def", "ghi"] // Deserialization int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
对集合类型是作了特殊支持的,输出的效果基本和数组同样,除了元素以外不会输出其余的字段例如 size之类的ide
Gson gson = new Gson(); Collection<Integer> ints = Arrays.asList(1,2,3,4,5); // Serialization String json = gson.toJson(ints); // ==> json is [1,2,3,4,5] // Deserialization //对于泛型类型,由于直接取得的class并不包括泛型类型,因此须要建立type再传入 Type collectionType = new TypeToken<Collection<Integer>>(){}.getType(); Collection<Integer> ints2 = gson.fromJson(json, collectionType);
由于gson内部是使用getClass来获取类型信息,返回的类型都不包括泛型参数类型,因此直接像以前使用的话,序列化和反序列化都会失败
(其实不仅是gson,java的泛型自己就被吐槽好久了,各类毛病)gradle
class Foo<T> { T value; } Gson gson = new Gson(); Foo<Bar> foo = new Foo<Bar>(); gson.toJson(foo); //不能成功序列化 gson.fromJson(json, foo.getClass()); // 没法反序列化
若是想要成功序列化带有泛型类型的对象,须要使用Type对象ui
//注意这里的TypeToken带有{},实际上是一个匿名类,由于TypeToken的构造器是非Public的,不能直接构造,我也不太清楚为何要这样设计 Type fooType = new TypeToken<Foo<Bar>>() {}.getType(); gson.toJson(foo, fooType); gson.fromJson(json, fooType);
有时候你可能会在一个集合中放入不一样的类型(虽然我我的强烈不推荐这样写,由于泛型的做用就是为了省掉没必要要的cast,你还放入不一样类型,这不是自找麻烦吗?)
可是若是你真的这样写了,gson仍是能够帮你转换this
Collection collection = new ArrayList(); collection.add("hello"); collection.add(5); collection.add(new Event("GREETINGS", "guest")); class Event { private String name; private String source; private Event(String name, String source) { this.name = name; this.source = source; } }
你彻底能够像直接同样直接序列化这个集合,没有任何问题。
可是以前也说过,json没有保存关于java对象类型的任何信息(做为一个通用的数据交换格式他这样作是正确的,不然这段json数据就只有gson才能解析了)。
以前咱们在反序列化的同时都要手动传入类型参数,可是做为一个混合集合,显然没有一个所谓的’类型参数’,因此直接反序列化是不可能了。
若是你想要反序列化这样的json,有如下几种选择。
1.使用原始的json类库手动解析
2.注册一个collection 的adapter(咱们下一篇会讲),自定义解析过程(仍是须要手动解析)
因此若是想要反序列化这样的集合,不管怎么样都要手写解析,没什么办法,因此最好仍是不要在泛型集合里放入不一样的类型
除了默认的序列化和反序列化行为,gson还容许自定义某些类的序列化和反序列化行为。自定义行为通常用于须要使json对象具备和原来类不一样的表示形式,或者默认行为会报错的状况。主要分为三个类
Json Serializers: 自定义某种对象类型的序列化行为
Json Deserializers: 自定义某种对象类型的反序列化行为
Instance Creators: 自定义某种对象的建立行为
此时咱们须要配置gsonbuilder,而后用gsonbuilder来建立gson对象,builder模式你们应该很熟悉了
代码以下
GsonBuilder gsonBuilder= new GsonBuilder(); gson.registerTypeAdapter(MyType.class, new MySerializer()); gson.registerTypeAdapter(MyType.class, new MyDeserializer()); gson.registerTypeAdapter(MyType.class, new MyInstanceCreator()); Gson gson=gsonBuilder.create();
为某类型注册了自定义的序列化和反序列化行为以后,在转换的过程当中一旦遇到该类型的对象,就会调用你注册的行为来序列化。
这些的类的实现也很容易。
//自定义序列化,须要实现JsonSerializer接口 private class DateTimeSerializer implements JsonSerializer<DateTime> { public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } } //自定义序列化,须要实现DateTimeDeserializer 接口 private class DateTimeDeserializer implements JsonDeserializer<DateTime> { public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new DateTime(json.getAsJsonPrimitive().getAsString()); } } //自定义对象建立,须要实现InstanceCreator private class MoneyInstanceCreator implements InstanceCreator<Money> { public Money createInstance(Type type) { return new Money("1000000", CurrencyCode.USD); } }
在我我的使用gson的过程当中,我发现有些时候是不得不用自定义序列化和反序列化的,由于在使用默认的行为的状况下,对一些复杂对象常常出错,具体缘由我也不知道为何,不少时候都是出现了死循环,可能java一些类中自己就存在双向引用吧,此外还有一些其余的异常,主要缘由都是java一些类自己的继承结构太深了。
咱们以序列化Image为例(该类直接序列化会报错)
这个代码是我实际项目中使用的,将javafx的image对象序列化(固然对于图像对象,最后还要使用压缩流来减小体积)
public class GsonImage implements JsonSerializer<Image>,JsonDeserializer<Image> { @Override public Image deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { Gson gson=new Gson(); byte[] bs=gson.fromJson(json.getAsString(), byte[].class); BufferedImage image = null; try { //从字节数组建立图片 image = ImageIO.read(new ByteArrayInputStream(bs)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } Image image2=SwingFXUtils.toFXImage(image, null); return image2; } @Override public JsonElement serialize(Image image, Type typeOfSrc, JsonSerializationContext context) { Gson gson=new Gson(); ByteArrayOutputStream stream=new ByteArrayOutputStream(); BufferedImage bufferedImage=SwingFXUtils.fromFXImage(image, null); try { ImageIO.write(bufferedImage, "PNG", stream); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } byte[] imgBytes=stream.toByteArray(); //实际上序列化的是字节数组 String string=gson.toJson(imgBytes); return new JsonPrimitive(string); } }
除了三种自定义行为以外,gsonbuilder还提供了一些配置
setPrettyPrinting() //设置输出格式为可读性优先(默认是体积小优先) serializeNulls() //设置输出null(默认null会被忽略) excludeFieldsWithModifiers()//设置不被包括在序列化中的修饰符(默认为static //transient,可是你能够覆盖设置)
关于gson就介绍到这里
能够访问gson的github帮助页面来获取更多信息
https://github.com/google/gson/blob/master/UserGuide.md