欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

GSON實(shí)現(xiàn)Java對(duì)象與JSON格式對(duì)象相互轉(zhuǎn)換的完全教程

 更新時(shí)間:2016年06月22日 15:03:48   作者:h-loong  
GSON是Google編寫(xiě)并在在GitHub上開(kāi)源的Java序列化與反序列化JSON的類庫(kù),今天我們就來(lái)總結(jié)一下使用GSON實(shí)現(xiàn)Java對(duì)象與JSON格式對(duì)象相互轉(zhuǎn)換的完全教程

Gson是一個(gè)Java庫(kù),用來(lái)實(shí)現(xiàn)Json和Java對(duì)象之間的相互轉(zhuǎn)換。Gson是一個(gè)托管在https://github.com/google/gson的開(kāi)源項(xiàng)目。

Gson中主要的類是Gson,也可以使用類GsonBuilder在創(chuàng)建Gson對(duì)象的同時(shí)設(shè)置一些選項(xiàng)。
Gson對(duì)象在處理Json時(shí)不會(huì)保存任何狀態(tài),所以使用者能夠很輕松的對(duì)同一個(gè)Gson對(duì)象進(jìn)行多次序列化、反序列化等操作。

示例:基本使用

//Serialization
Gson gson = new Gson();
gson.toJson(1);   //==> prints 1
gson.toJson("abcd");  //==> prints "abcd"
gson.toJson(new Long(10)); //==> prints 10
int[] values = { 1 };
gson.toJson(values);  //==> prints [1]

//Deserialization
int one = gson.fromJson("1", int.class);
Integer one = gson.fromJson("1", Integer.class);
Long one = gson.fromJson("1", Long.class);
Boolean f = gson.fromJson("false", Boolean.class);
String str = gson.fromJson("\"abc\"", String.class);
String anotherStr = gson.fromJson("[\"abc\"]", String.class);

//Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj); 
//==> json is {"value1":1,"value2":"abc"}

示例:對(duì)象與Json之間轉(zhuǎn)換

定義BagOfPrimitives類:

class BagOfPrimitives {
 private int value1 = 1;
 private String value2 = "abc";
 private transient int value3 = 3;
 BagOfPrimitives() {
 // no-args constructor
 }
}

序列化為Json:

//Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj); 
//==> json is {"value1":1,"value2":"abc"}

不要序列化含有循環(huán)引用的對(duì)象,否則會(huì)造成無(wú)限的遞歸。

反序列化:

//Deserialization
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class); 
//==> obj2 is just like obj

處理對(duì)象時(shí)的一些細(xì)節(jié):

  • 推薦使用私有字段(譯者:可以通過(guò)反射獲取私有字段的名稱和值)
  • 沒(méi)有必要使用標(biāo)注指明哪些字段該被序列化或者反序列化。在當(dāng)前類(也包括其父類)中的所有字段都默認(rèn)會(huì)被序列化/反序列化。
  • 如果某字段在聲明時(shí)使用了關(guān)鍵字transient,默認(rèn)情況下不會(huì)被序列化/反序列化。
  • Gson如下處理null字段:
  • 序列化時(shí)候null字段會(huì)被跳過(guò)
  • 反序列化時(shí),類中有但Json中沒(méi)有的字段將設(shè)值為null。
  • synthetic字段不會(huì)被序列化/反序列化。
  • 在外部類(outer classes)中的內(nèi)部類(inner classes)、匿名類(anonymous classes)和局部類(local classes)中的字段不會(huì)被序列化/反序列化。

嵌套類(包括內(nèi)部類)的處理

Gson可以很輕松地序列化嵌套類,且能夠反序列化靜態(tài)的嵌套類。Gson無(wú)法自動(dòng)地反序列化純粹的內(nèi)部類,是因?yàn)閮?nèi)部類的無(wú)參構(gòu)造函數(shù)需要引用包含它的對(duì)象(即外部類的實(shí)例)。要反序列化靜態(tài)類,可以將內(nèi)部類靜態(tài)化或者提供一個(gè)自定義的實(shí)例創(chuàng)造器(instance creator)。下面是一個(gè)示例:

public class A {
 public String a;

 class B {

 public String b;

 public B() {
  // No args constructor for B
 }
 }
}

上面的類B無(wú)法被Gson序列化。由于類B是一個(gè)(非靜態(tài)的)內(nèi)部類,Gson也無(wú)法反序列化{"b":"abc"}到類B的實(shí)例中。如果B被聲明為static class B,那么Gson就能對(duì)這個(gè)字符串反序列化了。

另外一個(gè)解決方法是為B寫(xiě)一個(gè)實(shí)例創(chuàng)建器:

public class InstanceCreatorForB implements InstanceCreator<A.B> {
 private final A a;
 public InstanceCreatorForB(A a) {
 this.a = a;
 }
 public A.B createInstance(Type type) {
 return a.new B();
 }
}

這種方法是可行的,但是不推薦。(譯者表示沒(méi)看懂這個(gè)實(shí)例創(chuàng)建器,不知道該怎么用)

示例:數(shù)組

Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};

//Serialization
gson.toJson(ints);  ==> prints [1,2,3,4,5]
gson.toJson(strings); ==> prints ["abc", "def", "ghi"]

//Deserialization
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
==> ints2 will be same as ints

Gson也支持具有復(fù)雜數(shù)據(jù)類型的多維數(shù)組。

示例:集合(Collection)

Gson gson = new Gson();
Collection<Integer> ints = Lists.immutableList(1,2,3,4,5);

//Serialization
String json = gson.toJson(ints); //==> json is [1,2,3,4,5]

//Deserialization
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
//ints2 is same as ints

處理集合(Collection)時(shí)的限制:

  • 可以序列化任意對(duì)象的集合,反序列化就不行了。
  • 反序列化時(shí),集合必須是指定的泛型。

序列化/反序列化泛型

當(dāng)使用toJson(obj)時(shí),Gson調(diào)用obj.getClass()獲取字段信息以在序列化中使用。類似的,也可以將對(duì)象MyClass.class作為參數(shù)傳遞給fromJson(json, MyClass.class)方法,這可以在在對(duì)象不是泛型的時(shí)候使用。不過(guò),當(dāng)對(duì)象是一個(gè)泛型類型的對(duì)象,由于Java中類型擦除(Type Erasure)這一機(jī)制,泛型類型信息會(huì)丟失。下面的例子將說(shuō)明這一點(diǎn):

class Foo<T> {
 T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly

gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar

上面的代碼將value解釋為Bar類型,這是因?yàn)镚son調(diào)用foo.getClass()獲取類的信息,但是這種那個(gè)方法返回的是一個(gè)原始的類,即Foo.class。這意味著Gson無(wú)法知道這是一個(gè)Foo<Bar>類型的對(duì)象。

要解決這個(gè)問(wèn)題,可以是為你的泛型指定正確的參數(shù)化的類型??梢允褂肨ypeToken類做到:

Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);
gson.fromJson(json, fooType);

fooType實(shí)際上定義了一個(gè)匿名的內(nèi)部類,這個(gè)內(nèi)部類含有一個(gè)可以返回全部參數(shù)化類型的getType()方法。

序列化/反序列化含有任意類型的對(duì)象的集合

有時(shí)候處理的JSON包含了混合的類型,例如:

['hello',5,{name:'GREETINGS',source:'guest'}]

對(duì)應(yīng)的集合應(yīng)該是:

Collection collection = new ArrayList();
collection.add("hello");
collection.add(5);
collection.add(new Event("GREETINGS", "guest"));

其中的Event類如下定義:

class Event {
 private String name;
 private String source;
 private Event(String name, String source) {
 this.name = name;
 this.source = source;
 }
}

通過(guò)Gson,你不需要做任何特殊的事情就可以序列化集合:toJson(collection)會(huì)輸出令人滿意的結(jié)果。

然而,通過(guò)fromJson(json, Collection.class)反序列化是不行的,這是因?yàn)镚son無(wú)法將json中的的內(nèi)容與類型對(duì)應(yīng)起來(lái)。Gson需要你在fromJson中提供一個(gè)通用版本的集合類型。你有三個(gè)選擇:

方案1:使用Gson解析器的API(低級(jí)的流解析器或者DOM解析器JsonParser)去解析數(shù)組元素,然后使用Gson.fromJson()處理每一個(gè)數(shù)組元素。這是首選的方案。
方案2:為Collection.class注冊(cè)一類型適配器將數(shù)組中的元素映射到合適的對(duì)象。這種方法的缺點(diǎn)是會(huì)使你在處理其他的集合類型時(shí)候產(chǎn)生不便。
方案3:為MyCollectionMemberType注冊(cè)一個(gè)類型適配器,在fromJson中使用Collection<MyCollectionMemberType>。只有當(dāng)數(shù)組看起來(lái)像一個(gè)高級(jí)的元素或者你能夠?qū)⒆侄晤愋透某蒀ollection<MyCollectionMemberType>,這種方法才比較可行。
內(nèi)置的序列化/反序列化器

Gson為常用的但是默認(rèn)表示可能并不合適的類提供了序列化/反序列化器。
下面是這些類的一個(gè)列表:

  • java.net.URL,例如會(huì)序列化為字符串 http://code.google.com/p/google-gson/
  • java.net.URI,例如會(huì)序列化為字符串/p/google-gson/

自定義序列化/反序列化

有時(shí)候,Gson的默認(rèn)實(shí)現(xiàn)并不是你想要的,這在處理一些類庫(kù)時(shí)(例如DateTime)時(shí)比較常見(jiàn)。

Gson允許你注冊(cè)自定義的序列化/反序列化器。要這樣做的話,你需要實(shí)現(xiàn)以下幾個(gè)部分:

Json序列化器:需要為一個(gè)對(duì)象自定義序列化
Json反序列化器:需要為一個(gè)類型自定義反序列化
類創(chuàng)建器:如果存在無(wú)參構(gòu)造函數(shù)或者已經(jīng)注冊(cè)了一個(gè)反序列化器,就不需要了。

GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(MyType2.class, new MyTypeAdapter());
gson.registerTypeAdapter(MyType.class, new MySerializer());
gson.registerTypeAdapter(MyType.class, new MyDeserializer());
gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());

registerTypeAdapter會(huì)檢查類型適配器是否實(shí)現(xiàn)了多個(gè)接口,并為這些接口注冊(cè)類型適配器。

寫(xiě)一個(gè)序列化器

下面是一個(gè)為DateTime自定義序列化器的示例:

private class DateTimeSerializer implements JsonSerializer<DateTime> {
 public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
 return new JsonPrimitive(src.toString());
 }
}

Gson在序列化DateTime實(shí)例時(shí)會(huì)調(diào)用toJson()。

寫(xiě)一個(gè)反序列化器

下面的示例是講如何寫(xiě)一個(gè)DateTime類的反序列化器:

private class DateTimeDeserializer implements JsonDeserializer<DateTime> {
 public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
  throws JsonParseException {
 return new DateTime(json.getAsJsonPrimitive().getAsString());
 }
}

當(dāng)Gson需要將一個(gè)JSON字符串發(fā)反序列化為DateTime對(duì)象時(shí),會(huì)調(diào)用 fromJson()。

對(duì)于序列化器/反序列化器,應(yīng)注意:

  • 很多情況下,你想要注冊(cè)一個(gè)處理程序?qū)⒎盒团c一個(gè)原始類型對(duì)應(yīng)起來(lái),
  • 例如,假如你有一個(gè)叫做Id的類來(lái)表示和轉(zhuǎn)換Id
  • Id<T>類型中,所有的泛型擁有相同的序列化器,這個(gè)序列化器就是輸出id的值
  • 反序列化器很像,但并不會(huì)完全一樣。例如要返回一個(gè)Id<T>對(duì)象,需要調(diào)用new Id(Class<T>, String)。
  • Gson支持注冊(cè)一個(gè)處理程序,你也可以為指定的泛型注冊(cè)指定的處理程序。toJson和fromJson的Type參數(shù)包含了泛型信息以幫助你寫(xiě)出一個(gè)可以將所有的泛型與同一個(gè)原始類型對(duì)應(yīng)起來(lái)的處理程序。

寫(xiě)一個(gè)實(shí)例創(chuàng)建器

在反序列化一個(gè)對(duì)象時(shí),Gson需要?jiǎng)?chuàng)建一個(gè)類的實(shí)例。在序列化/反序列化時(shí)具有良好表現(xiàn)的類是指這個(gè)類擁有一個(gè)無(wú)參構(gòu)造函數(shù)。通常,當(dāng)處理一個(gè)類庫(kù)中沒(méi)有無(wú)參構(gòu)造函數(shù)的類時(shí),需要使用實(shí)例創(chuàng)建器。

實(shí)例創(chuàng)建器示例:

private class MoneyInstanceCreator implements InstanceCreator<Money> {
 public Money createInstance(Type type) {
 return new Money("1000000", CurrencyCode.USD);
 }
}

參數(shù)化類型的實(shí)例創(chuàng)建器

有時(shí)候要實(shí)例化的類型會(huì)是一個(gè)參數(shù)化類型??偟膩?lái)說(shuō),由于真正的實(shí)例是一個(gè)原始類型,所以這不是什么問(wèn)題。下面是一個(gè)示例:

class MyList<T> extends ArrayList<T> {
}

class MyListInstanceCreator implements InstanceCreator<MyList<?>> {
 @SuppressWarnings("unchecked")
 public MyList<?> createInstance(Type type) {
 // No need to use a parameterized list since the actual instance will have the raw type anyway.
 return new MyList();
 }
}

不過(guò),有時(shí)你需要基于真正的參數(shù)化類型來(lái)創(chuàng)建實(shí)例。在這種情況下,你可以將類型參數(shù)傳遞給createInstance方法。下面是一個(gè)例子:

public class Id<T> {
 private final Class<T> classOfId;
 private final long value;
 public Id(Class<T> classOfId, long value) {
 this.classOfId = classOfId;
 this.value = value;
 }
}

class IdInstanceCreator implements InstanceCreator<Id<?>> {
 public Id<?> createInstance(Type type) {
 Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments();
 Type idType = typeParameters[0]; // Id has only one parameterized type T
 return Id.get((Class)idType, 0L);
 }
}

在上面的示例中,如果沒(méi)有將真正的類型傳遞給參數(shù)化類型,Id類的實(shí)例是無(wú)法創(chuàng)建的。通過(guò)給方法傳遞參數(shù)type,我們才得以解決這個(gè)問(wèn)題。這里,type對(duì)象可以看做是Id<Foo>的Java參數(shù)化類型的表示,相應(yīng)的實(shí)例應(yīng)該被綁定到Id<Foo>。由于類Id只有一個(gè)參數(shù)化類型的參數(shù)T,我們使用getActualTypeArgument()返回的類型數(shù)組的第0個(gè)元素,在這個(gè)例子中就是Foo.class。

緊湊的輸出 VS 優(yōu)美的輸出

Gson中Json默認(rèn)的輸出是緊湊的JSON格式。也就是說(shuō)在JSON中沒(méi)有多余的空白符。所以在JSON的輸出中字段名和字段值之間、字段之間、數(shù)組元素之間是沒(méi)有空白的。另外,null字段不會(huì)被輸出(注意:在集合和數(shù)組對(duì)象中null會(huì)被保留的)。

如果要輸出的優(yōu)美些,你需要使用GsonBuilder對(duì)Gson的實(shí)例進(jìn)行配置。JsonFormatter不存在于公有API中,所以客戶端無(wú)法配置默認(rèn)的輸出設(shè)置?,F(xiàn)在我們只提供了JsonPrintFormatter,其默認(rèn)情況下每行80個(gè)字符,縮進(jìn)使用2個(gè)字符,右邊距是4個(gè)字符。

下面的示例展示了如何讓Gson實(shí)例使用JsonPrintFormatter,而不是使用默認(rèn)的JsonCompactFormatter。

Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(someObject);

空對(duì)象

在Gson的默認(rèn)實(shí)現(xiàn)中,null對(duì)象是被忽略的。這可以讓輸出格式(既可以認(rèn)為是序列化的結(jié)果)更加緊密;不過(guò)客戶端必須為其定義一個(gè)默認(rèn)的值,以使得JSON能夠正常的反序列化。

如果要讓Gson實(shí)例可以序列化null,可以:

Gson gson = new GsonBuilder().serializeNulls().create();

注意,當(dāng)序列化null的時(shí),會(huì)在JsonElement結(jié)構(gòu)中添加一個(gè)JsonNull元素。因此,我們可以可以在自定義的序列化器/反序列化器中使用這個(gè)對(duì)象(gson)。

下面是一個(gè)例子:

public class Foo {
 private final String s;
 private final int i;

 public Foo() {
 this(null, 5);
 }

 public Foo(String s, int i) {
 this.s = s;
 this.i = i;
 }
}

Gson gson = new GsonBuilder().serializeNulls().create();
Foo foo = new Foo();
String json = gson.toJson(foo);
System.out.println(json);

json = gson.toJson(null);
System.out.println(json);

輸出:

{"s":null,"i":5}
null

版本支持

可以使用@Since標(biāo)注來(lái)維護(hù)同一個(gè)對(duì)象的多個(gè)版本。這個(gè)標(biāo)注可以用在類和字段上,將來(lái)也會(huì)支持用在方法上。為了使用這個(gè)特性,你需要配置Gson實(shí)例,讓其忽略大于某個(gè)版本號(hào)的字段和對(duì)象。如果沒(méi)有在Gson對(duì)象中設(shè)置版本,序列化/反序列化時(shí)會(huì)使用所有的字段和類。

public class VersionedClass {
 @Since(1.1) private final String newerField;
 @Since(1.0) private final String newField;
 private final String field;

 public VersionedClass() {
 this.newerField = "newer";
 this.newField = "new";
 this.field = "old";
 }
}

VersionedClass versionedObject = new VersionedClass();
Gson gson = new GsonBuilder().setVersion(1.0).create();
String jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);
System.out.println();

gson = new Gson();
jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);

輸出:

{"newField":"new","field":"old"}

{"newerField":"newer","newField":"new","field":"old"}

從序列化/反序列化中排除字段

Gson支持使用很多方法來(lái)去除類、字段、字段類型。如果下面的方法無(wú)法滿足你的需求,可以使用自定義序列化/反序列化器的方法。

1.Java Modifier Exclusion

默認(rèn)情況下,如果將一個(gè)字段聲明為transient,這個(gè)字段就會(huì)被排除。另外,如果一個(gè)字段被聲明為static,默認(rèn)情況下這個(gè)字段也會(huì)被排除。如果要包含某些聲明為transient的字段,你可以這樣做:

import java.lang.reflect.Modifier;

Gson gson = new GsonBuilder()
 .excludeFieldsWithModifiers(Modifier.STATIC)
 .create();

注意,在excludeFieldsWithModifiers方法中,你可以使用任意數(shù)量的Modifier常量。例如:

Gson gson = new GsonBuilder()
 .excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE)
 .create();

2.使用@Expose字段排除

這個(gè)特性允許你在類中標(biāo)記特定的字段使其在序列化/反序列化中不被排除/被排除。要使用這個(gè)標(biāo)注,你應(yīng)該使用new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()創(chuàng)建Gson。Gson實(shí)例會(huì)排除類中所有沒(méi)被@Expose標(biāo)注的字段。

3.用戶定義排除策略

如果上面的排除方法無(wú)法滿足需求,你也可以自定義自己的排除策略。更多內(nèi)容,可以參考ExclusionStrategy JavaDoc。

下面的例子展示了如何排除使用了@Foo標(biāo)注的字段,排除String類的頂級(jí)類型或者聲明的字段類型:

 

@Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.FIELD})
 public @interface Foo {
 // Field tag only annotation
 }

 public class SampleObjectForTest {
 @Foo private final int annotatedField;
 private final String stringField;
 private final long longField;
 private final Class<?> clazzField;

 public SampleObjectForTest() {
  annotatedField = 5;
  stringField = "someDefaultValue";
  longField = 1234;
 }
 }

 public class MyExclusionStrategy implements ExclusionStrategy {
 private final Class<?> typeToSkip;

 private MyExclusionStrategy(Class<?> typeToSkip) {
  this.typeToSkip = typeToSkip;
 }

 public boolean shouldSkipClass(Class<?> clazz) {
  return (clazz == typeToSkip);
 }

 public boolean shouldSkipField(FieldAttributes f) {
  return f.getAnnotation(Foo.class) != null;
 }
 }

 public static void main(String[] args) {
 Gson gson = new GsonBuilder()
  .setExclusionStrategies(new MyExclusionStrategy(String.class))
  .serializeNulls()
  .create();
 SampleObjectForTest src = new SampleObjectForTest();
 String json = gson.toJson(src);
 System.out.println(json);
 }

輸出:

{"longField":1234}

JSON字段命名的支持

Gson的一些預(yù)定義的字段命名策略,可以將標(biāo)準(zhǔn)的Java字段名稱(也就是駝峰命名法,例如sampleFieldNameInJava)轉(zhuǎn)換成一個(gè)Json的字段名(也就是sample_field_name_in_java或者SampleFieldNameInJava)。更多信息,可以參考FieldNamingPolicy。

Gson也有一個(gè)基于標(biāo)注的策略讓客戶端自定義字段的名稱。這個(gè)策略下,如果提供了一個(gè)非法的字段名作為標(biāo)注的值,會(huì)使Gson拋出Runtime異常。

下面的示例展示了如何使用這兩種Gson命名策略:

private class SomeObject {
 @SerializedName("custom_naming") private final String someField;
 private final String someOtherField;

 public SomeObject(String a, String b) {
 this.someField = a;
 this.someOtherField = b;
 }
}

SomeObject someObject = new SomeObject("first", "second");
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
String jsonRepresentation = gson.toJson(someObject);
System.out.println(jsonRepresentation);

輸出:

{"custom_naming":"first","SomeOtherField":"second"}

如果要自定義名稱,可以使用@SerializedName標(biāo)注。

在序列化器和反序列化器之間共享狀態(tài)

有時(shí)你會(huì)需要在序列化器和反序列化器之間共享狀態(tài),你可以使用下面的三個(gè)方法達(dá)到目的:

  • 在一個(gè)靜態(tài)字段中存儲(chǔ)共享狀態(tài)
  • 將序列化/反序列化器聲明為一個(gè)父類型的內(nèi)部類,然后使用父類型的實(shí)例的字段存儲(chǔ)共享狀態(tài)
  • 使用Java中的ThreadLocal

前兩種方法不是線程安全的,第三種是。


GSON解析null出錯(cuò)解決辦法
GSON有一個(gè)缺點(diǎn)就是無(wú)法設(shè)置null替換,
我們只能手動(dòng)的批量替換服務(wù)器返回的null了,正常的接口定義的時(shí)候是絕對(duì)不允許服務(wù)器返回null的,后臺(tái)結(jié)果卻總會(huì)出現(xiàn)null!
如果搜索的話有一個(gè)常見(jiàn)的答案,

Gson gson = new GsonBuilder().serializeNulls().create();

但是這個(gè)卻無(wú)法解決反序列問(wèn)題,怎么解決呢?
解決辦法如下:

Gson gson = new GsonBuilder().registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory()).create();
//然后用上面一行寫(xiě)的gson來(lái)序列化和反序列化實(shí)體類type
gson.fromJson(json, type);
gson.toJson(type);
//NullStringToEmptyAdapterFactory的代碼

public class NullStringToEmptyAdapterFactory<T> implements TypeAdapterFactory {
 @SuppressWarnings("unchecked")
 public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
  Class<T> rawType = (Class<T>) type.getRawType();
  if (rawType != String.class) {
   return null;
  }
  return (TypeAdapter<T>) new StringNullAdapter();
 }
}
// StringNullAdapter代碼

public class StringNullAdapter extends TypeAdapter<String> {
 @Override
 public String read(JsonReader reader) throws IOException {
  // TODO Auto-generated method stub
  if (reader.peek() == JsonToken.NULL) {
   reader.nextNull();
   return "";
  }
  return reader.nextString();
 }
 @Override
 public void write(JsonWriter writer, String value) throws IOException {
  // TODO Auto-generated method stub
  if (value == null) {
   writer.nullValue();
   return;
  }
  writer.value(value);
 }
}

相關(guān)文章

  • 詳解Java執(zhí)行g(shù)roovy腳本的兩種方式

    詳解Java執(zhí)行g(shù)roovy腳本的兩種方式

    這篇文章主要介紹了Java執(zhí)行g(shù)roovy腳本的兩種方式,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 使用Mybatis-Plus實(shí)現(xiàn)對(duì)象屬性自動(dòng)填充功能

    使用Mybatis-Plus實(shí)現(xiàn)對(duì)象屬性自動(dòng)填充功能

    這篇文章主要介紹了如何使用Mybatis-Plus實(shí)現(xiàn)對(duì)象屬性自動(dòng)填充功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,感興趣的朋友們下面隨著小編來(lái)一起來(lái)學(xué)習(xí)吧
    2024-01-01
  • 初步解析Java中AffineTransform類的使用

    初步解析Java中AffineTransform類的使用

    這篇文章主要介紹了Java中AffineTransform類的使用,AffineTransform類經(jīng)常被用來(lái)處理圖片,需要的朋友可以參考下
    2015-10-10
  • Java super關(guān)鍵字的使用方法詳解

    Java super關(guān)鍵字的使用方法詳解

    這篇文章主要介紹了Java super關(guān)鍵字的使用方法詳解的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家對(duì)super關(guān)鍵字徹底掌握,需要的朋友可以參考下
    2017-10-10
  • java 8 lambda表達(dá)式list操作分組、過(guò)濾、求和、最值、排序、去重代碼詳解

    java 8 lambda表達(dá)式list操作分組、過(guò)濾、求和、最值、排序、去重代碼詳解

    java8的lambda表達(dá)式提供了一些方便list操作的方法,主要涵蓋分組、過(guò)濾、求和、最值、排序、去重,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • 在VSCode里使用Jupyter?Notebook調(diào)試Java代碼的詳細(xì)過(guò)程

    在VSCode里使用Jupyter?Notebook調(diào)試Java代碼的詳細(xì)過(guò)程

    Jupyter Notebook是以網(wǎng)頁(yè)的形式打開(kāi),可以在網(wǎng)頁(yè)頁(yè)面中直接編寫(xiě)代碼和運(yùn)行代碼,代碼的運(yùn)行結(jié)果也會(huì)直接在代碼塊下顯示的程序,這篇文章主要介紹了在VSCode里使用Jupyter?Notebook,調(diào)試Java代碼,需要的朋友可以參考下
    2022-07-07
  • JUnit 5中擴(kuò)展模型的深入理解

    JUnit 5中擴(kuò)展模型的深入理解

    幾乎所有的Java 開(kāi)發(fā)人員都會(huì)使用JUnit 來(lái)做測(cè)試,但其實(shí)很多自動(dòng)化測(cè)試人員也會(huì)使用Junit 。下面這篇文章主要給大家介紹了關(guān)于JUnit 5中擴(kuò)展模型的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-08-08
  • 在Java編程中使用正則表達(dá)式

    在Java編程中使用正則表達(dá)式

    這篇文章主要介紹了在Java編程中使用正則表達(dá)式,注意使用matches()方法檢測(cè)一下Java對(duì)正則表達(dá)式的支持情況,需要的朋友可以參考下
    2015-08-08
  • Java中的ArrayList.trimToSize()方法詳解

    Java中的ArrayList.trimToSize()方法詳解

    這篇文章主要介紹了Java中的ArrayList.trimToSize()方法詳解,前幾天看了Java?ArrayList,沒(méi)有明白trimToSize()這個(gè)方法是什么意思,所以看了一下源碼并且debug一下自己的一個(gè)例子,明白了其中的含義,需要的朋友可以參考下
    2023-11-11
  • Java Socket+mysql實(shí)現(xiàn)簡(jiǎn)易文件上傳器的代碼

    Java Socket+mysql實(shí)現(xiàn)簡(jiǎn)易文件上傳器的代碼

    最近在做一個(gè)小項(xiàng)目,項(xiàng)目主要需求是實(shí)現(xiàn)一個(gè)文件上傳器,通過(guò)客戶端的登陸,把本地文件上傳到服務(wù)器的數(shù)據(jù)庫(kù)(本地的)。下面通過(guò)本文給大家分享下實(shí)現(xiàn)代碼,感興趣的朋友一起看看吧
    2016-10-10

最新評(píng)論