New unit test format

This commit is contained in:
Nick
2019-08-30 21:11:18 +01:00
parent db85c8f275
commit 6cd385e4c0
19972 changed files with 1626600 additions and 0 deletions
@@ -0,0 +1,57 @@
package org.baeldung.gson.entities;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
public class ActorGson {
private String imdbId;
private Date dateOfBirth;
private List<String> filmography;
public ActorGson(String imdbId, Date dateOfBirth, List<String> filmography) {
super();
this.imdbId = imdbId;
this.dateOfBirth = dateOfBirth;
this.filmography = filmography;
}
@Override
public String toString() {
return "ActorGson [imdbId=" + imdbId + ", dateOfBirth=" + formatDateOfBirth() + ", filmography=" + filmography + "]";
}
public String getImdbId() {
return imdbId;
}
public void setImdbId(String imdbId) {
this.imdbId = imdbId;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public List<String> getFilmography() {
return filmography;
}
public void setFilmography(List<String> filmography) {
this.filmography = filmography;
}
private String formatDateOfBirth() {
final DateFormat formatter = new SimpleDateFormat("EEE MMM dd hh:mm:ss zzz yyyy");
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
return formatter.format(dateOfBirth);
}
}
@@ -0,0 +1,5 @@
package org.baeldung.gson.entities;
public abstract class Animal {
public String type = "Animal";
}
@@ -0,0 +1,19 @@
package org.baeldung.gson.entities;
public class Cow extends Animal {
private String breed;
public Cow() {
breed = "Jersey";
type = "Cow";
}
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
}
@@ -0,0 +1,18 @@
package org.baeldung.gson.entities;
public class Dog extends Animal {
private String petName;
public Dog() {
petName = "Milo";
type = "Dog";
}
public String getPetName() {
return petName;
}
public void setPetName(String petName) {
this.petName = petName;
}
}
@@ -0,0 +1,36 @@
package org.baeldung.gson.entities;
public class Employee {
private int id;
private String name;
private String address;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
@@ -0,0 +1,48 @@
package org.baeldung.gson.entities;
import java.util.List;
public class Movie {
private String imdbId;
private String director;
private List<ActorGson> actors;
public Movie(String imdbID, String director, List<ActorGson> actors) {
super();
this.imdbId = imdbID;
this.director = director;
this.actors = actors;
}
@Override
public String toString() {
return "Movie [imdbId=" + imdbId + ", director=" + director + ", actors=" + actors + "]";
}
public String getImdbID() {
return imdbId;
}
public void setImdbID(String imdbID) {
this.imdbId = imdbID;
}
public String getDirector() {
return director;
}
public void setDirector(String director) {
this.director = director;
}
public List<ActorGson> getActors() {
return actors;
}
public void setActors(List<ActorGson> actors) {
this.actors = actors;
}
}
@@ -0,0 +1,46 @@
package org.baeldung.gson.entities;
import com.google.gson.annotations.Expose;
import java.util.List;
public class MovieWithNullValue {
@Expose
private String imdbId;
private String director;
@Expose
private List<ActorGson> actors;
public MovieWithNullValue(String imdbID, String director, List<ActorGson> actors) {
super();
this.imdbId = imdbID;
this.director = director;
this.actors = actors;
}
public String getImdbID() {
return imdbId;
}
public void setImdbID(String imdbID) {
this.imdbId = imdbID;
}
public String getDirector() {
return director;
}
public void setDirector(String director) {
this.director = director;
}
public List<ActorGson> getActors() {
return actors;
}
public void setActors(List<ActorGson> actors) {
this.actors = actors;
}
}
@@ -0,0 +1,49 @@
package org.baeldung.gson.entities;
import java.util.Objects;
public class MyClass {
private int id;
private String name;
public MyClass(int id, String name) {
this.id = id;
this.name = name;
}
public MyClass() { }
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MyClass myClass = (MyClass) o;
return id == myClass.id && Objects.equals(name, myClass.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}
@@ -0,0 +1,19 @@
package org.baeldung.gson.entities;
public class User {
private int id;
private String name;
private transient String nationality;
public User(int id, String name, String nationality) {
this.id = id;
this.name = name;
this.nationality = nationality;
}
public User(int id, String name) {
this(id, name, null);
}
}
@@ -0,0 +1,40 @@
package org.baeldung.gson.entities;
import com.google.gson.annotations.SerializedName;
public class Weather {
@SerializedName(value = "location", alternate = "place")
private String location;
@SerializedName(value = "temp", alternate = "temperature")
private int temp;
@SerializedName(value = "outlook", alternate = "weather")
private String outlook;
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public int getTemp() {
return temp;
}
public void setTemp(int temp) {
this.temp = temp;
}
public String getOutlook() {
return outlook;
}
public void setOutlook(String outlook) {
this.outlook = outlook;
}
}
@@ -0,0 +1,9 @@
package org.baeldung.gson.primitives.models;
public class BooleanExample {
public boolean value;
public String toString() {
return "{boolean: " + value + "}";
}
}
@@ -0,0 +1,9 @@
package org.baeldung.gson.primitives.models;
public class ByteExample {
public byte value = (byte) 1;
public String toString() {
return "{byte: " + value + "}";
}
}
@@ -0,0 +1,9 @@
package org.baeldung.gson.primitives.models;
public class CharExample {
public char value;
public String toString() {
return "{char: " + value + "}";
}
}
@@ -0,0 +1,9 @@
package org.baeldung.gson.primitives.models;
public class DoubleExample {
public double value;
public String toString() {
return "{float: " + value + "}";
}
}
@@ -0,0 +1,9 @@
package org.baeldung.gson.primitives.models;
public class FloatExample {
public float value;
public String toString() {
return "{float: " + value + "}";
}
}
@@ -0,0 +1,6 @@
package org.baeldung.gson.primitives.models;
public class InfinityValuesExample {
public float negativeInfinity;
public float positiveInfinity;
}
@@ -0,0 +1,9 @@
package org.baeldung.gson.primitives.models;
public class LongExample {
public long value = 1;
public String toString() {
return "{byte: " + value + "}";
}
}
@@ -0,0 +1,19 @@
package org.baeldung.gson.primitives.models;
public class PrimitiveBundle {
public byte byteValue;
public short shortValue;
public int intValue;
public long longValue;
public float floatValue;
public double doubleValue;
public boolean booleanValue;
public char charValue;
public String toString() {
return "{" + "byte: " + byteValue + ", " + "short: " + shortValue + ", "
+ "int: " + intValue + ", " + "long: " + longValue + ", "
+ "float: " + floatValue + ", " + "double: " + doubleValue + ", "
+ "boolean: " + booleanValue + ", " + "char: " + charValue + "}";
}
}
@@ -0,0 +1,18 @@
package org.baeldung.gson.primitives.models;
public class PrimitiveBundleInitialized {
// @formatter:off
public byte byteValue = (byte) 1;
public short shortValue = (short) 1;
public int intValue = 1;
public long longValue = 1L;
public float floatValue = 1.0f;
public double doubleValue = 1;
// @formatter:on
public String toString() {
return "{" + "byte: " + byteValue + ", " + "short: " + shortValue + ", "
+ "int: " + intValue + ", " + "long: " + longValue + ", "
+ "float: " + floatValue + ", " + "double: " + doubleValue + "}";
}
}
@@ -0,0 +1,46 @@
package org.baeldung.gson.serialization;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import org.baeldung.gson.entities.ActorGson;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
public class ActorGsonDeserializer implements JsonDeserializer<ActorGson> {
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
@Override
public ActorGson deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final JsonElement jsonImdbId = jsonObject.get("imdbId");
final JsonElement jsonDateOfBirth = jsonObject.get("dateOfBirth");
final JsonArray jsonFilmography = jsonObject.getAsJsonArray("filmography");
final ArrayList<String> filmList = new ArrayList<String>();
if (jsonFilmography != null) {
for (int i = 0; i < jsonFilmography.size(); i++) {
filmList.add(jsonFilmography.get(i).getAsString());
}
}
ActorGson actorGson = null;
try {
actorGson = new ActorGson(jsonImdbId.getAsString(), sdf.parse(jsonDateOfBirth.getAsString()), filmList);
} catch (final ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return actorGson;
}
}
@@ -0,0 +1,33 @@
package org.baeldung.gson.serialization;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.baeldung.gson.entities.ActorGson;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.stream.Collectors;
public class ActorGsonSerializer implements JsonSerializer<ActorGson> {
private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
@Override
public JsonElement serialize(ActorGson actor, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject actorJsonObj = new JsonObject();
actorJsonObj.addProperty("<strong>IMDB Code</strong>", actor.getImdbId());
actorJsonObj.addProperty("<strong>Date Of Birth</strong>", actor.getDateOfBirth() != null ? sdf.format(actor.getDateOfBirth()) : null);
actorJsonObj.addProperty("<strong>N° Film:</strong> ", actor.getFilmography() != null ? actor.getFilmography().size() : null);
actorJsonObj.addProperty("filmography", actor.getFilmography() != null ? convertFilmography(actor.getFilmography()) : null);
return actorJsonObj;
}
private String convertFilmography(List<String> filmography) {
return filmography.stream().collect(Collectors.joining("-"));
}
}
@@ -0,0 +1,35 @@
package org.baeldung.gson.serialization;
import com.google.gson.Gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import org.baeldung.gson.entities.Animal;
public class AnimalDeserializer implements JsonDeserializer<Animal> {
private String animalTypeElementName;
private Gson gson;
private Map<String, Class<? extends Animal>> animalTypeRegistry;
public AnimalDeserializer(String animalTypeElementName) {
this.animalTypeElementName = animalTypeElementName;
this.gson = new Gson();
this.animalTypeRegistry = new HashMap<>();
}
public void registerBarnType(String animalTypeName, Class<? extends Animal> animalType) {
animalTypeRegistry.put(animalTypeName, animalType);
}
public Animal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
JsonObject animalObject = json.getAsJsonObject();
JsonElement animalTypeElement = animalObject.get(animalTypeElementName);
Class<? extends Animal> animalType = animalTypeRegistry.get(animalTypeElement.getAsString());
return gson.fromJson(animalObject, animalType);
}
}
@@ -0,0 +1,64 @@
package org.baeldung.gson.serialization;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.baeldung.gson.entities.Employee;
import com.google.gson.*;
public class MapDeserializer implements JsonDeserializer<Map<String, Object>> {
@Override
public Map<String, Object> deserialize(JsonElement elem, Type type, JsonDeserializationContext context) throws JsonParseException {
return elem.getAsJsonObject()
.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().isJsonPrimitive() ?
toPrimitive(e.getValue().getAsJsonPrimitive(), context)
: context.deserialize(e.getValue(), Employee.class)
));
}
private Object toPrimitive(JsonPrimitive jsonValue, JsonDeserializationContext context) {
if (jsonValue.isBoolean())
return jsonValue.getAsBoolean();
else if (jsonValue.isString())
return jsonValue.getAsString();
else {
BigDecimal bigDec = jsonValue.getAsBigDecimal();
Long l;
Integer i;
if ((i = toInteger(bigDec)) != null) {
return i;
} else if ((l = toLong(bigDec)) != null) {
return l;
} else {
return bigDec.doubleValue();
}
}
}
private Long toLong(BigDecimal val) {
try {
return val.toBigIntegerExact().longValue();
} catch (ArithmeticException e) {
return null;
}
}
private Integer toInteger(BigDecimal val) {
try {
return val.intValueExact();
} catch (ArithmeticException e) {
return null;
}
}
}
@@ -0,0 +1,44 @@
package org.baeldung.gson.serialization;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
public class StringDateMapDeserializer implements JsonDeserializer<Map<String, Date>> {
private static final Logger logger = LoggerFactory.getLogger(StringDateMapDeserializer.class);
private SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
@Override
public Map<String, Date> deserialize(JsonElement elem, Type type, JsonDeserializationContext jsonDeserializationContext) {
System.out.println("Deserializer called");
logger.info("Deserializer called");
return elem.getAsJsonObject()
.entrySet()
.stream()
.filter(e -> e.getValue().isJsonPrimitive())
.filter(e -> e.getValue().getAsJsonPrimitive().isString())
.collect(Collectors.toMap(Map.Entry::getKey, e -> formatDate(e.getValue())));
}
private Date formatDate(JsonElement value) {
try {
return format.parse(value.getAsString());
} catch (ParseException ex) {
throw new JsonParseException(ex);
}
}
}
@@ -0,0 +1,11 @@
package org.baeldung.gson.serializationwithexclusions;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Exclude {
}
@@ -0,0 +1,13 @@
package org.baeldung.gson.serializationwithexclusions;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MyClass {
private long id;
private String name;
private String other;
private MySubClass subclass;
}
@@ -0,0 +1,20 @@
package org.baeldung.gson.serializationwithexclusions;
import com.google.gson.annotations.Expose;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MyClassWithAnnotatedFields {
@Expose
private long id;
@Expose
private String name;
private String other;
@Expose
private MySubClassWithAnnotatedFields subclass;
}
@@ -0,0 +1,16 @@
package org.baeldung.gson.serializationwithexclusions;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MyClassWithCustomAnnotatedFields {
private long id;
private String name;
@Exclude
private String other;
private MySubClassWithCustomAnnotatedFields subclass;
}
@@ -0,0 +1,15 @@
package org.baeldung.gson.serializationwithexclusions;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MyClassWithTransientFields {
private long id;
private String name;
private transient String other;
private MySubClassWithTransientFields subclass;
}
@@ -0,0 +1,12 @@
package org.baeldung.gson.serializationwithexclusions;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MySubClass {
private long id;
private String description;
private String otherVerboseInfo;
}
@@ -0,0 +1,15 @@
package org.baeldung.gson.serializationwithexclusions;
import com.google.gson.annotations.Expose;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MySubClassWithAnnotatedFields {
@Expose private long id;
@Expose private String description;
private String otherVerboseInfo;
}
@@ -0,0 +1,14 @@
package org.baeldung.gson.serializationwithexclusions;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MySubClassWithCustomAnnotatedFields {
private long id;
private String description;
@Exclude
private String otherVerboseInfo;
}
@@ -0,0 +1,13 @@
package org.baeldung.gson.serializationwithexclusions;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MySubClassWithTransientFields {
private long id;
private String description;
private transient String otherVerboseInfo;
}
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN"/>
<logger name="org.springframework.transaction" level="WARN"/>
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
<logger name="org.springframework.web.servlet.mvc" level="WARN"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
@@ -0,0 +1,117 @@
package org.baeldung.gson.advance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.baeldung.gson.entities.Animal;
import org.baeldung.gson.entities.Cow;
import org.baeldung.gson.entities.Dog;
import org.baeldung.gson.entities.MyClass;
import org.baeldung.gson.serialization.AnimalDeserializer;
import org.junit.Test;
public class GsonAdvanceUnitTest {
@Test
public void givenListOfMyClass_whenSerializing_thenCorrect() {
List<MyClass> list = Arrays.asList(new MyClass(1, "name1"), new MyClass(2, "name2"));
Gson gson = new Gson();
String jsonString = gson.toJson(list);
String expectedString = "[{\"id\":1,\"name\":\"name1\"},{\"id\":2,\"name\":\"name2\"}]";
assertEquals(expectedString, jsonString);
}
@Test(expected = ClassCastException.class)
public void givenJsonString_whenIncorrectDeserializing_thenThrowClassCastException() {
String inputString = "[{\"id\":1,\"name\":\"name1\"},{\"id\":2,\"name\":\"name2\"}]";
Gson gson = new Gson();
List<MyClass> outputList = gson.fromJson(inputString, ArrayList.class);
assertEquals(1, outputList.get(0).getId());
}
@Test
public void givenJsonString_whenDeserializing_thenReturnListOfMyClass() {
String inputString = "[{\"id\":1,\"name\":\"name1\"},{\"id\":2,\"name\":\"name2\"}]";
List<MyClass> inputList = Arrays.asList(new MyClass(1, "name1"), new MyClass(2, "name2"));
Type listOfMyClassObject = new TypeToken<ArrayList<MyClass>>() {}.getType();
Gson gson = new Gson();
List<MyClass> outputList = gson.fromJson(inputString, listOfMyClassObject);
assertEquals(inputList, outputList);
}
@Test
public void givenPolymorphicList_whenSerializeWithTypeAdapter_thenCorrect() {
String expectedString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]";
List<Animal> inList = new ArrayList<>();
inList.add(new Dog());
inList.add(new Cow());
String jsonString = new Gson().toJson(inList);
assertEquals(expectedString, jsonString);
}
@Test
public void givenPolymorphicList_whenDeserializeWithTypeAdapter_thenCorrect() {
String inputString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]";
AnimalDeserializer deserializer = new AnimalDeserializer("type");
deserializer.registerBarnType("Dog", Dog.class);
deserializer.registerBarnType("Cow", Cow.class);
Gson gson = new GsonBuilder()
.registerTypeAdapter(Animal.class, deserializer)
.create();
List<Animal> outList = gson.fromJson(inputString, new TypeToken<List<Animal>>(){}.getType());
assertEquals(2, outList.size());
assertTrue(outList.get(0) instanceof Dog);
assertTrue(outList.get(1) instanceof Cow);
}
@Test
public void givenPolymorphicList_whenSerializeWithRuntimeTypeAdapter_thenCorrect() {
String expectedString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]";
List<Animal> inList = new ArrayList<>();
inList.add(new Dog());
inList.add(new Cow());
String jsonString = new Gson().toJson(inList);
assertEquals(expectedString, jsonString);
}
@Test
public void givenPolymorphicList_whenDeserializeWithRuntimeTypeAdapter_thenCorrect() {
String inputString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]";
Type listOfAnimals = new TypeToken<ArrayList<Animal>>() {}.getType();
RuntimeTypeAdapterFactory<Animal> adapter = RuntimeTypeAdapterFactory.of(Animal.class, "type")
.registerSubtype(Dog.class)
.registerSubtype(Cow.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(adapter).create();
List<Animal> outList = gson.fromJson(inputString, listOfAnimals);
assertEquals(2, outList.size());
assertTrue(outList.get(0) instanceof Dog);
assertTrue(outList.get(1) instanceof Cow);
}
}
@@ -0,0 +1,265 @@
package org.baeldung.gson.advance;
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.internal.Streams;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
/**
* Adapts values whose runtime type may differ from their declaration type. This
* is necessary when a field's type is not the same type that GSON should create
* when deserializing that field. For example, consider these types:
* <pre> {@code
* abstract class Shape {
* int x;
* int y;
* }
* class Circle extends Shape {
* int radius;
* }
* class Rectangle extends Shape {
* int width;
* int height;
* }
* class Diamond extends Shape {
* int width;
* int height;
* }
* class Drawing {
* Shape bottomShape;
* Shape topShape;
* }
* }</pre>
* <p>Without additional type information, the serialized JSON is ambiguous. Is
* the bottom shape in this drawing a rectangle or a diamond? <pre> {@code
* {
* "bottomShape": {
* "width": 10,
* "height": 5,
* "x": 0,
* "y": 0
* },
* "topShape": {
* "radius": 2,
* "x": 4,
* "y": 1
* }
* }}</pre>
* This class addresses this problem by adding type information to the
* serialized JSON and honoring that type information when the JSON is
* deserialized: <pre> {@code
* {
* "bottomShape": {
* "type": "Diamond",
* "width": 10,
* "height": 5,
* "x": 0,
* "y": 0
* },
* "topShape": {
* "type": "Circle",
* "radius": 2,
* "x": 4,
* "y": 1
* }
* }}</pre>
* Both the type field name ({@code "type"}) and the type labels ({@code
* "Rectangle"}) are configurable.
*
* <h3>Registering Types</h3>
* Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field
* name to the {@link #of} factory method. If you don't supply an explicit type
* field name, {@code "type"} will be used. <pre> {@code
* RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory
* = RuntimeTypeAdapterFactory.of(Shape.class, "type");
* }</pre>
* Next register all of your subtypes. Every subtype must be explicitly
* registered. This protects your application from injection attacks. If you
* don't supply an explicit type label, the type's simple name will be used.
* <pre> {@code
* shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
* shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
* shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
* }</pre>
* Finally, register the type adapter factory in your application's GSON builder:
* <pre> {@code
* Gson gson = new GsonBuilder()
* .registerTypeAdapterFactory(shapeAdapterFactory)
* .create();
* }</pre>
* Like {@code GsonBuilder}, this API supports chaining: <pre> {@code
* RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
* .registerSubtype(Rectangle.class)
* .registerSubtype(Circle.class)
* .registerSubtype(Diamond.class);
* }</pre>
*/
public final class RuntimeTypeAdapterFactory<T> implements TypeAdapterFactory {
private final Class<?> baseType;
private final String typeFieldName;
private final Map<String, Class<?>> labelToSubtype = new LinkedHashMap<String, Class<?>>();
private final Map<Class<?>, String> subtypeToLabel = new LinkedHashMap<Class<?>, String>();
private final boolean maintainType;
private RuntimeTypeAdapterFactory(Class<?> baseType, String typeFieldName, boolean maintainType) {
if (typeFieldName == null || baseType == null) {
throw new NullPointerException();
}
this.baseType = baseType;
this.typeFieldName = typeFieldName;
this.maintainType = maintainType;
}
/**
* Creates a new runtime type adapter using for {@code baseType} using {@code
* typeFieldName} as the type field name. Type field names are case sensitive.
* {@code maintainType} flag decide if the type will be stored in pojo or not.
*/
public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName, boolean maintainType) {
return new RuntimeTypeAdapterFactory<T>(baseType, typeFieldName, maintainType);
}
/**
* Creates a new runtime type adapter using for {@code baseType} using {@code
* typeFieldName} as the type field name. Type field names are case sensitive.
*/
public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName) {
return new RuntimeTypeAdapterFactory<T>(baseType, typeFieldName, false);
}
/**
* Creates a new runtime type adapter for {@code baseType} using {@code "type"} as
* the type field name.
*/
public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType) {
return new RuntimeTypeAdapterFactory<T>(baseType, "type", false);
}
/**
* Registers {@code type} identified by {@code label}. Labels are case
* sensitive.
*
* @throws IllegalArgumentException if either {@code type} or {@code label}
* have already been registered on this type adapter.
*/
public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type, String label) {
if (type == null || label == null) {
throw new NullPointerException();
}
if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) {
throw new IllegalArgumentException("types and labels must be unique");
}
labelToSubtype.put(label, type);
subtypeToLabel.put(type, label);
return this;
}
/**
* Registers {@code type} identified by its {@link Class#getSimpleName simple
* name}. Labels are case sensitive.
*
* @throws IllegalArgumentException if either {@code type} or its simple name
* have already been registered on this type adapter.
*/
public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type) {
return registerSubtype(type, type.getSimpleName());
}
public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
if (type.getRawType() != baseType) {
return null;
}
final Map<String, TypeAdapter<?>> labelToDelegate
= new LinkedHashMap<String, TypeAdapter<?>>();
final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate
= new LinkedHashMap<Class<?>, TypeAdapter<?>>();
for (Map.Entry<String, Class<?>> entry : labelToSubtype.entrySet()) {
TypeAdapter<?> delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue()));
labelToDelegate.put(entry.getKey(), delegate);
subtypeToDelegate.put(entry.getValue(), delegate);
}
return new TypeAdapter<R>() {
@Override public R read(JsonReader in) throws IOException {
JsonElement jsonElement = Streams.parse(in);
JsonElement labelJsonElement;
if (maintainType) {
labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName);
} else {
labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName);
}
if (labelJsonElement == null) {
throw new JsonParseException("cannot deserialize " + baseType
+ " because it does not define a field named " + typeFieldName);
}
String label = labelJsonElement.getAsString();
@SuppressWarnings("unchecked") // registration requires that subtype extends T
TypeAdapter<R> delegate = (TypeAdapter<R>) labelToDelegate.get(label);
if (delegate == null) {
throw new JsonParseException("cannot deserialize " + baseType + " subtype named "
+ label + "; did you forget to register a subtype?");
}
return delegate.fromJsonTree(jsonElement);
}
@Override public void write(JsonWriter out, R value) throws IOException {
Class<?> srcType = value.getClass();
String label = subtypeToLabel.get(srcType);
@SuppressWarnings("unchecked") // registration requires that subtype extends T
TypeAdapter<R> delegate = (TypeAdapter<R>) subtypeToDelegate.get(srcType);
if (delegate == null) {
throw new JsonParseException("cannot serialize " + srcType.getName()
+ "; did you forget to register a subtype?");
}
JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject();
if (maintainType) {
Streams.write(jsonObject, out);
return;
}
JsonObject clone = new JsonObject();
if (jsonObject.has(typeFieldName)) {
throw new JsonParseException("cannot serialize " + srcType.getName()
+ " because it already defines a field named " + typeFieldName);
}
clone.add(typeFieldName, new JsonPrimitive(label));
for (Map.Entry<String, JsonElement> e : jsonObject.entrySet()) {
clone.add(e.getKey(), e.getValue());
}
Streams.write(clone, out);
}
}.nullSafe();
}
}
@@ -0,0 +1,33 @@
package org.baeldung.gson.conversion;
import com.google.gson.*;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
public class JsonObjectConversionsUnitTest {
@Test
void whenUsingJsonParser_thenConvertToJsonObject() throws Exception {
// Example 1: Using JsonParser
String json = "{ \"name\": \"Baeldung\", \"java\": true }";
JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
Assert.assertTrue(jsonObject.isJsonObject());
Assert.assertTrue(jsonObject.get("name").getAsString().equals("Baeldung"));
Assert.assertTrue(jsonObject.get("java").getAsBoolean() == true);
}
@Test
void whenUsingGsonInstanceFromJson_thenConvertToJsonObject() throws Exception {
// Example 2: Using fromJson
String json = "{ \"name\": \"Baeldung\", \"java\": true }";
JsonObject convertedObject = new Gson().fromJson(json, JsonObject.class);
Assert.assertTrue(convertedObject.isJsonObject());
Assert.assertTrue(convertedObject.get("name").getAsString().equals("Baeldung"));
Assert.assertTrue(convertedObject.get("java").getAsBoolean() == true);
}
}
@@ -0,0 +1,61 @@
package org.baeldung.gson.deserialization;
public class Foo {
public int intValue;
public String stringValue;
public Foo(final int intValue, final String stringValue) {
this.intValue = intValue;
this.stringValue = stringValue;
}
public Foo(final String stringValue) {
this.stringValue = stringValue;
}
public Foo() {
super();
}
// API
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result) + intValue;
result = (prime * result) + ((stringValue == null) ? 0 : stringValue.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Foo other = (Foo) obj;
if (intValue != other.intValue) {
return false;
}
if (stringValue == null) {
if (other.stringValue != null) {
return false;
}
} else if (!stringValue.equals(other.stringValue)) {
return false;
}
return true;
}
@Override
public String toString() {
return "TargetClass{" + "intValue= " + intValue + ", stringValue= " + stringValue + '}';
}
}
@@ -0,0 +1,26 @@
package org.baeldung.gson.deserialization;
import java.lang.reflect.Type;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
public class FooDeserializer implements JsonDeserializer<Foo[]> {
@Override
public Foo[] deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException {
final JsonArray jArray = json.getAsJsonArray();
final Foo[] scArray = new Foo[jArray.size()];
int index = 0;
for (final JsonElement jElement : jArray) {
final int i = jElement.getAsJsonObject().get("intValue").getAsInt();
final String s = jElement.getAsJsonObject().get("stringValue").getAsString();
scArray[index++] = new Foo(i, s);
}
return scArray;
}
}
@@ -0,0 +1,21 @@
package org.baeldung.gson.deserialization;
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
public class FooDeserializerFromJsonWithDifferentFields implements JsonDeserializer<Foo> {
@Override
public Foo deserialize(final JsonElement jElement, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException {
final JsonObject jObject = jElement.getAsJsonObject();
final int intValue = jObject.get("valueInt").getAsInt();
final String stringValue = jObject.get("valueString").getAsString();
return new Foo(intValue, stringValue);
}
}
@@ -0,0 +1,14 @@
package org.baeldung.gson.deserialization;
import java.lang.reflect.Type;
import com.google.gson.InstanceCreator;
public class FooInstanceCreator implements InstanceCreator<Foo> {
@Override
public Foo createInstance(Type type) {
return new Foo("sample");
}
}
@@ -0,0 +1,24 @@
package org.baeldung.gson.deserialization;
public class FooWithInner {
public int intValue;
public String stringValue;
public InnerFoo innerFoo;
public FooWithInner(int intValue, String stringValue, String name) {
super();
this.intValue = intValue;
this.stringValue = stringValue;
this.innerFoo = new InnerFoo(name);
}
public class InnerFoo {
public String name;
public InnerFoo(String name) {
super();
this.name = name;
}
}
}
@@ -0,0 +1,18 @@
package org.baeldung.gson.deserialization;
public class GenericFoo<T> {
public T theValue;
public GenericFoo(final T value) {
theValue = value;
}
//
@Override
public final String toString() {
return "GenericTargetClass{" + "intField=" + theValue + '}';
}
}
@@ -0,0 +1,39 @@
package org.baeldung.gson.deserialization;
import static org.junit.Assert.assertEquals;
import org.baeldung.gson.entities.Weather;
import org.junit.Test;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonAlternateUnitTest {
@Test
public void givenTwoJsonFormats_whenDeserialized_thenWeatherObjectsCreated() throws Exception {
Gson gson = new GsonBuilder().create();
Weather weather = gson.fromJson("{" +
"\"location\": \"London\"," +
"\"temp\": 15," +
"\"weather\": \"Cloudy\"" +
"}", Weather.class);
assertEquals("London", weather.getLocation());
assertEquals("Cloudy", weather.getOutlook());
assertEquals(15, weather.getTemp());
weather = gson.fromJson("{" +
"\"place\": \"Lisbon\"," +
"\"temperature\": 35," +
"\"outlook\": \"Sunny\"" +
"}", Weather.class);
assertEquals("Lisbon", weather.getLocation());
assertEquals("Sunny", weather.getOutlook());
assertEquals(35, weather.getTemp());
}
}
@@ -0,0 +1,40 @@
package org.baeldung.gson.deserialization;
import java.text.ParseException;
import org.baeldung.gson.entities.ActorGson;
import org.baeldung.gson.entities.Movie;
import org.baeldung.gson.serialization.ActorGsonDeserializer;
import org.junit.Assert;
import org.junit.Test;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonDeserializeUnitTest {
@Test
public void whenSimpleDeserialize_thenCorrect() throws ParseException {
final String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\":" + "[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"Tue Sep 21 11:00:00 GMT 1982\",\"filmography\":" + "[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}";
final Gson gson = new GsonBuilder().setDateFormat("EEE MMM dd hh:mm:ss zzz yyyy").create();
final Movie outputMovie = gson.fromJson(jsonInput, Movie.class);
final String expectedOutput = "Movie [imdbId=tt0472043, director=null, actors=[ActorGson [imdbId=nm2199632, dateOfBirth=Tue Sep 21 11:00:00 GMT 1982, filmography=[Apocalypto, Beatdown, Wind Walkers]]]]";
Assert.assertEquals(outputMovie.toString(), expectedOutput);
}
@Test
public void whenCustomDeserialize_thenCorrect() throws ParseException {
final String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\":" + "[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\",\"filmography\":" + "[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}";
final Gson gson = new GsonBuilder().registerTypeAdapter(ActorGson.class, new ActorGsonDeserializer()).create();
final Movie outputMovie = gson.fromJson(jsonInput, Movie.class);
final String expectedOutput = "Movie [imdbId=tt0472043, director=null, actors=[ActorGson [imdbId=nm2199632, dateOfBirth=Tue Sep 21 11:00:00 GMT 1982, filmography=[Apocalypto, Beatdown, Wind Walkers]]]]";
Assert.assertEquals(outputMovie.toString(), expectedOutput);
}
}
@@ -0,0 +1,112 @@
package org.baeldung.gson.deserialization;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import org.apache.commons.lang3.time.DateUtils;
import org.baeldung.gson.entities.Employee;
import org.baeldung.gson.serialization.MapDeserializer;
import org.baeldung.gson.serialization.StringDateMapDeserializer;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.internal.LinkedTreeMap;
import com.google.gson.reflect.TypeToken;
public class MapDeserializationUnitTest {
private static final Logger logger = LoggerFactory.getLogger(MapDeserializationUnitTest.class);
@Test
public void whenUsingMapClass_thenShouldReturnMapWithDefaultClasses() {
String jsonString = "{'employee.name':'Bob','employee.salary':10000, 'employee.active':true, "
+ "'employee':{'id':10, 'name': 'Bob Willis', 'address':'London'}}";
Gson gson = new Gson();
Map map = gson.fromJson(jsonString, Map.class);
logger.info("The converted map: {}", map);
Assert.assertEquals(4, map.size());
Assert.assertEquals(Double.class, map.get("employee.salary").getClass());
Assert.assertEquals(LinkedTreeMap.class, map.get("employee").getClass());
}
@Test(expected = JsonSyntaxException.class)
public void whenUsingJsonStringWithDuplicateKey_thenShouldThrowJsonSyntaxException() {
String jsonString = "{'employee.name':'Bob', 'employee.name':'Jenny','employee.salary':10000, "
+ "'employee.active':true, " + "'employee':{'id':10, 'name': 'Bob Willis', 'address':'London'}}";
Gson gson = new Gson();
Map map = gson.fromJson(jsonString, Map.class);
logger.info("The converted map: {}", map);
}
@Test
public void whenUsingTypeToken_thenShouldReturnMapWithProperClass() {
String jsonString = "{'Bob':{'id':10, 'name': 'Bob Willis', 'address':'UK'},"
+ "'Jenny':{'id':10, 'name': 'Jenny McCarthy', 'address':'USA'}, "
+ "'Steve':{'id':10, 'name': 'Steven Waugh', 'address':'Australia'}}";
Gson gson = new Gson();
Type empMapType = new TypeToken<Map<String, Employee>>(){}.getType();
Map<String, Employee> nameEmployeeMap = gson.fromJson(jsonString, empMapType);
logger.info("The converted map: {}", nameEmployeeMap);
Assert.assertEquals(3, nameEmployeeMap.size());
Assert.assertEquals(Employee.class, nameEmployeeMap.get("Bob").getClass());
}
@Test
public void whenUsingCustomDeserializer_thenShouldReturnMapWithProperClass() {
String jsonString = "{'employee.name':'Bob','employee.salary':10000, 'employee.active':true, "
+ "'employee':{'id':10, 'name': 'Bob Willis', 'address':'London'}}";
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Gson gson = new GsonBuilder()
.registerTypeAdapter(type, new MapDeserializer())
.create();
Map<String, Object> blendedMap = gson.fromJson(jsonString, type);
logger.info("The converted map: {}", blendedMap);
Assert.assertEquals(4, blendedMap.size());
Assert.assertEquals(Integer.class, blendedMap.get("employee.salary").getClass());
Assert.assertEquals(Employee.class, blendedMap.get("employee").getClass());
}
@Test
public void whenUsingCustomDateDeserializer_thenShouldReturnMapWithDate() {
String jsonString = "{'Bob': '2017/06/01', 'Jennie':'2015/01/03'}";
Type type = new TypeToken<Map<String, Date>>(){}.getType();
Gson gson = new GsonBuilder()
.registerTypeAdapter(type, new StringDateMapDeserializer())
.create();
Map<String, Date> empJoiningDateMap = gson.fromJson(jsonString, type);
logger.info("The converted map: {}", empJoiningDateMap);
logger.info("The map class {}", empJoiningDateMap.getClass());
Assert.assertEquals(2, empJoiningDateMap.size());
Assert.assertEquals(Date.class, empJoiningDateMap.get("Bob").getClass());
Date dt = null;
try {
dt = DateUtils.parseDate("2017-06-01", "yyyy-MM-dd");
Assert.assertEquals(dt, empJoiningDateMap.get("Bob"));
} catch (ParseException e) {
logger.error("Could not parse date", e);
}
}
}
@@ -0,0 +1,138 @@
package org.baeldung.gson.deserialization.test;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import org.baeldung.gson.deserialization.Foo;
import org.baeldung.gson.deserialization.FooDeserializerFromJsonWithDifferentFields;
import org.baeldung.gson.deserialization.FooInstanceCreator;
import org.baeldung.gson.deserialization.FooWithInner;
import org.baeldung.gson.deserialization.GenericFoo;
import org.junit.Test;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
public class GsonDeserializationUnitTest {
// tests - single element
@Test
public final void whenDeserializingToSimpleObject_thenCorrect() {
final String json = "{\"intValue\":1,\"stringValue\":\"one\"}";
final Foo targetObject = new Gson().fromJson(json, Foo.class);
assertEquals(targetObject.intValue, 1);
assertEquals(targetObject.stringValue, "one");
}
@Test
public final void givenJsonHasExtraValues_whenDeserializing_thenCorrect() {
final String json = "{\"intValue\":1,\"stringValue\":\"one\",\"extraString\":\"two\",\"extraFloat\":2.2}";
final Foo targetObject = new Gson().fromJson(json, Foo.class);
assertEquals(targetObject.intValue, 1);
assertEquals(targetObject.stringValue, "one");
}
@Test
public final void givenJsonHasNonMatchingFields_whenDeserializingWithCustomDeserializer_thenCorrect() {
final String json = "{\"valueInt\":7,\"valueString\":\"seven\"}";
final GsonBuilder gsonBldr = new GsonBuilder();
gsonBldr.registerTypeAdapter(Foo.class, new FooDeserializerFromJsonWithDifferentFields());
final Foo targetObject = gsonBldr.create().fromJson(json, Foo.class);
assertEquals(targetObject.intValue, 7);
assertEquals(targetObject.stringValue, "seven");
}
@Test
public final void whenDeserializingToGenericObject_thenCorrect() {
final Type typeToken = new TypeToken<GenericFoo<Integer>>() {
}.getType();
final String json = "{\"theValue\":1}";
final GenericFoo<Integer> targetObject = new Gson().fromJson(json, typeToken);
assertEquals(targetObject.theValue, new Integer(1));
}
// tests - multiple elements
@Test
public final void givenJsonArrayOfFoos_whenDeserializingToArray_thenCorrect() {
final String json = "[{\"intValue\":1,\"stringValue\":\"one\"}," + "{\"intValue\":2,\"stringValue\":\"two\"}]";
final Foo[] targetArray = new GsonBuilder().create().fromJson(json, Foo[].class);
assertThat(Lists.newArrayList(targetArray), hasItem(new Foo(1, "one")));
assertThat(Lists.newArrayList(targetArray), hasItem(new Foo(2, "two")));
assertThat(Lists.newArrayList(targetArray), not(hasItem(new Foo(1, "two"))));
}
@Test
public final void givenJsonArrayOfFoos_whenDeserializingCollection_thenCorrect() {
final String json = "[{\"intValue\":1,\"stringValue\":\"one\"},{\"intValue\":2,\"stringValue\":\"two\"}]";
final Type targetClassType = new TypeToken<ArrayList<Foo>>() {
}.getType();
final Collection<Foo> targetCollection = new Gson().fromJson(json, targetClassType);
assertThat(targetCollection, instanceOf(ArrayList.class));
}
//
@Test
public void whenDeserializingJsonIntoElements_thenCorrect() {
final String jsonSourceObject = "{\"valueInt\":7,\"valueString\":\"seven\"}";
final JsonParser jParser = new JsonParser();
final JsonElement jElement = jParser.parse(jsonSourceObject);
final JsonObject jObject = jElement.getAsJsonObject();
final int intValue = jObject.get("valueInt").getAsInt();
final String stringValue = jObject.get("valueString").getAsString();
final Foo targetObject = new Foo(intValue, stringValue);
assertEquals(targetObject.intValue, 7);
assertEquals(targetObject.stringValue, "seven");
}
// new examples
@Test
public void whenDeserializingToNestedObjects_thenCorrect() {
final String json = "{\"intValue\":1,\"stringValue\":\"one\",\"innerFoo\":{\"name\":\"inner\"}}";
final FooWithInner targetObject = new Gson().fromJson(json, FooWithInner.class);
assertEquals(targetObject.intValue, 1);
assertEquals(targetObject.stringValue, "one");
assertEquals(targetObject.innerFoo.name, "inner");
}
@Test
public void whenDeserializingUsingInstanceCreator_thenCorrect() {
final String json = "{\"intValue\":1}";
final GsonBuilder gsonBldr = new GsonBuilder();
gsonBldr.registerTypeAdapter(Foo.class, new FooInstanceCreator());
final Foo targetObject = gsonBldr.create().fromJson(json, Foo.class);
assertEquals(targetObject.intValue, 1);
assertEquals(targetObject.stringValue, "sample");
}
}
@@ -0,0 +1,248 @@
package org.baeldung.gson.primitives;
import com.google.gson.*;
import org.baeldung.gson.primitives.models.*;
import org.junit.Test;
import java.lang.reflect.Type;
import static junit.framework.TestCase.*;
public class PrimitiveValuesUnitTest {
@Test public void whenSerializingToJSON_thenShouldCreateJSON() {
PrimitiveBundle primitiveBundle = new PrimitiveBundle();
// @formatter:off
primitiveBundle.byteValue = (byte) 0x00001111;
primitiveBundle.shortValue = (short) 3;
primitiveBundle.intValue = 3;
primitiveBundle.longValue = 3;
primitiveBundle.floatValue = 3.5f;
primitiveBundle.doubleValue = 3.5;
primitiveBundle.booleanValue = true;
primitiveBundle.charValue = 'a';
// @formatter:on
Gson gson = new Gson();
String expected = "{\"byteValue\":17,\"shortValue\":3,\"intValue\":3,"
+ "\"longValue\":3,\"floatValue\":3.5" + ",\"doubleValue\":3.5"
+ ",\"booleanValue\":true,\"charValue\":\"a\"}";
assertEquals(expected, gson.toJson(primitiveBundle));
}
@Test(expected = IllegalArgumentException.class) public void
whenSerializingInfinity_thenShouldRaiseAnException() {
InfinityValuesExample model = new InfinityValuesExample();
model.negativeInfinity = Float.NEGATIVE_INFINITY;
model.positiveInfinity = Float.POSITIVE_INFINITY;
Gson gson = new Gson();
gson.toJson(model);
}
@Test(expected = IllegalArgumentException.class) public void
whenSerializingNaN_thenShouldRaiseAnException() {
FloatExample model = new FloatExample();
model.value = Float.NaN;
Gson gson = new Gson();
gson.toJson(model);
}
@Test public void whenDeserializingFromJSON_thenShouldParseTheValueInTheString() {
String json = "{\"byteValue\": 17, \"shortValue\": 3, \"intValue\": 3, "
+ "\"longValue\": 3, \"floatValue\": 3.5" + ", \"doubleValue\": 3.5"
+ ", \"booleanValue\": true, \"charValue\": \"a\"}";
Gson gson = new Gson();
PrimitiveBundle model = gson.fromJson(json, PrimitiveBundle.class);
// @formatter:off
assertEquals(17, model.byteValue);
assertEquals(3, model.shortValue);
assertEquals(3, model.intValue);
assertEquals(3, model.longValue);
assertEquals(3.5, model.floatValue, 0.0001);
assertEquals(3.5, model.doubleValue, 0.0001);
assertTrue( model.booleanValue);
assertEquals('a', model.charValue);
// @formatter:on
}
@Test public void whenDeserializingHighPrecissionNumberIntoFloat_thenShouldPerformRounding() {
String json = "{\"value\": 12.123425589123456}";
Gson gson = new Gson();
FloatExample model = gson.fromJson(json, FloatExample.class);
assertEquals(12.123426f, model.value, 0.000001);
}
@Test public void whenDeserializingHighPrecissiongNumberIntoDouble_thenShouldPerformRounding() {
String json = "{\"value\": 12.123425589123556}";
Gson gson = new Gson();
DoubleExample model = gson.fromJson(json, DoubleExample.class);
assertEquals(12.123425589124f, model.value, 0.000001);
}
@Test public void whenDeserializingValueThatOverflows_thenShouldOverflowSilently() {
Gson gson = new Gson();
String json = "{\"value\": \"300\"}";
ByteExample model = gson.fromJson(json, ByteExample.class);
assertEquals(44, model.value);
}
@Test public void whenDeserializingRealIntoByte_thenShouldRaiseAnException() {
Gson gson = new Gson();
String json = "{\"value\": 2.3}";
try {
gson.fromJson(json, ByteExample.class);
} catch (Exception ex) {
assertTrue(ex instanceof JsonSyntaxException);
assertTrue(ex.getCause() instanceof NumberFormatException);
return;
}
fail();
}
@Test public void whenDeserializingRealIntoLong_thenShouldRaiseAnException() {
Gson gson = new Gson();
String json = "{\"value\": 2.3}";
try {
gson.fromJson(json, LongExample.class);
} catch (Exception ex) {
assertTrue(ex instanceof JsonSyntaxException);
assertTrue(ex.getCause() instanceof NumberFormatException);
return;
}
fail();
}
@Test public void whenDeserializingRealWhoseDecimalPartIs0_thenShouldParseItCorrectly() {
Gson gson = new Gson();
String json = "{\"value\": 2.0}";
LongExample model = gson.fromJson(json, LongExample.class);
assertEquals(2, model.value);
}
@Test public void whenDeserializingUnicodeChar_thenShouldParseItCorrectly() {
Gson gson = new Gson();
String json = "{\"value\": \"\\u00AE\"}";
CharExample model = gson.fromJson(json, CharExample.class);
assertEquals('\u00AE', model.value);
}
@Test public void whenDeserializingNullValues_thenShouldIgnoreThoseFields() {
Gson gson = new Gson();
// @formatter:off
String json = "{\"byteValue\": null, \"shortValue\": null, "
+ "\"intValue\": null, " + "\"longValue\": null, \"floatValue\": null"
+ ", \"doubleValue\": null}";
// @formatter:on
PrimitiveBundleInitialized model = gson.fromJson(json,
PrimitiveBundleInitialized.class);
assertEquals(1, model.byteValue);
assertEquals(1, model.shortValue);
assertEquals(1, model.intValue);
assertEquals(1, model.longValue);
assertEquals(1, model.floatValue, 0.0001);
assertEquals(1, model.doubleValue, 0.0001);
}
@Test(expected = JsonSyntaxException.class) public void
whenDeserializingTheEmptyString_thenShouldRaiseAnException() {
Gson gson = new Gson();
// @formatter:off
String json = "{\"byteValue\": \"\", \"shortValue\": \"\", "
+ "\"intValue\": \"\", " + "\"longValue\": \"\", \"floatValue\": \"\""
+ ", \"doubleValue\": \"\"" + ", \"booleanValue\": \"\"}";
// @formatter:on
gson.fromJson(json, PrimitiveBundleInitialized.class);
}
@Test public void whenDeserializingTheEmptyStringIntoChar_thenShouldHaveTheEmtpyChar() {
Gson gson = new Gson();
// @formatter:off
String json = "{\"charValue\": \"\"}";
// @formatter:on
CharExample model = gson.fromJson(json, CharExample.class);
assertEquals(Character.MIN_VALUE, model.value);
}
@Test public void whenDeserializingValidValueAppearingInAString_thenShouldParseTheValue() {
Gson gson = new Gson();
// @formatter:off
String json = "{\"byteValue\": \"15\", \"shortValue\": \"15\", "
+ "\"intValue\": \"15\", " + "\"longValue\": \"15\", \"floatValue\": \"15.0\""
+ ", \"doubleValue\": \"15.0\"}";
// @formatter:on
PrimitiveBundleInitialized model = gson.fromJson(json,
PrimitiveBundleInitialized.class);
assertEquals(15, model.byteValue);
assertEquals(15, model.shortValue);
assertEquals(15, model.intValue);
assertEquals(15, model.longValue);
assertEquals(15, model.floatValue, 0.0001);
assertEquals(15, model.doubleValue, 0.0001);
}
@Test public void whenDeserializingABooleanFrom0Or1Integer_thenShouldRaiseAnException() {
String json = "{\"value\": 1}";
Gson gson = new Gson();
try {
gson.fromJson(json, BooleanExample.class);
} catch (Exception ex) {
assertTrue(ex instanceof JsonSyntaxException);
assertTrue(ex.getCause() instanceof IllegalStateException);
return;
}
fail();
}
@Test public void whenDeserializingWithCustomDeserializerABooleanFrom0Or1Integer_thenShouldWork() {
String json = "{\"value\": 1}";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(BooleanExample.class,
new BooleanAs2ValueIntegerDeserializer());
Gson gson = builder.create();
BooleanExample model = gson.fromJson(json, BooleanExample.class);
assertTrue(model.value);
}
// @formatter:off
static class BooleanAs2ValueIntegerDeserializer implements JsonDeserializer<BooleanExample> {
@Override public BooleanExample deserialize(
JsonElement jsonElement,
Type type,
JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
BooleanExample model = new BooleanExample();
int value = jsonElement.getAsJsonObject().getAsJsonPrimitive("value").getAsInt();
if (value == 0) {
model.value = false;
} else if (value == 1) {
model.value = true;
} else {
throw new JsonParseException("Unexpected value. Trying to deserialize "
+ "a boolean from an integer different than 0 and 1.");
}
return model;
}
}
// @formatter:on
}
@@ -0,0 +1,24 @@
package org.baeldung.gson.serialization;
import java.lang.reflect.Type;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class DifferentNameSerializer implements JsonSerializer<SourceClass> {
@Override
public JsonElement serialize(final SourceClass src, final Type typeOfSrc, final JsonSerializationContext context) {
final String otherIntValueName = "otherIntValue";
final String otherStringValueName = "otherStringValue";
final JsonObject jObject = new JsonObject();
jObject.addProperty(otherIntValueName, src.getIntValue());
jObject.addProperty(otherStringValueName, src.getStringValue());
return jObject;
}
}
@@ -0,0 +1,48 @@
package org.baeldung.gson.serialization;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import org.baeldung.gson.entities.ActorGson;
import org.baeldung.gson.entities.Movie;
import org.baeldung.gson.entities.MovieWithNullValue;
import org.junit.Assert;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
public class GsonSerializeUnitTest {
@Test
public void whenSimpleSerialize_thenCorrect() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
ActorGson rudyYoungblood = new ActorGson("nm2199632", sdf.parse("21-09-1982"), Arrays.asList("Apocalypto", "Beatdown", "Wind Walkers"));
Movie movie = new Movie("tt0472043", "Mel Gibson", Arrays.asList(rudyYoungblood));
String expectedOutput = "{\"imdbId\":\"tt0472043\",\"director\":\"Mel Gibson\",\"actors\":[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"Sep 21, 1982 12:00:00 AM\",\"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}";
Assert.assertEquals(new Gson().toJson(movie), expectedOutput);
}
@Test
public void whenCustomSerialize_thenCorrect() throws ParseException {
Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().serializeNulls().disableHtmlEscaping().registerTypeAdapter(ActorGson.class, new ActorGsonSerializer()).create();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
ActorGson rudyYoungblood = new ActorGson("nm2199632", sdf.parse("21-09-1982"), Arrays.asList("Apocalypto", "Beatdown", "Wind Walkers"));
MovieWithNullValue movieWithNullValue = new MovieWithNullValue(null, "Mel Gibson", Arrays.asList(rudyYoungblood));
String expectedOutput = new GsonBuilder()
.setPrettyPrinting()
.serializeNulls()
.disableHtmlEscaping()
.create()
.toJson(new JsonParser()
.parse("{\"imdbId\":null,\"actors\":[{\"<strong>IMDB Code</strong>\":\"nm2199632\",\"<strong>Date Of Birth</strong>\":\"21-09-1982\",\"<strong>N° Film:</strong> \":3,\"filmography\":\"Apocalypto-Beatdown-Wind Walkers\"}]}"));
Assert.assertEquals(gson.toJson(movieWithNullValue), expectedOutput);
}
}
@@ -0,0 +1,27 @@
package org.baeldung.gson.serialization;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
public class IgnoringFieldsNotMatchingCriteriaSerializer implements JsonSerializer<SourceClass> {
@Override
public JsonElement serialize(SourceClass src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jObject = new JsonObject();
// Criteria: intValue >= 0
if (src.getIntValue() >= 0) {
String intValue = "intValue";
jObject.addProperty(intValue, src.getIntValue());
}
String stringValue = "stringValue";
jObject.addProperty(stringValue, src.getStringValue());
return jObject;
}
}
@@ -0,0 +1,19 @@
package org.baeldung.gson.serialization;
import java.lang.reflect.Type;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class IgnoringFieldsSerializer implements JsonSerializer<SourceClass> {
@Override
public JsonElement serialize(final SourceClass src, final Type typeOfSrc, final JsonSerializationContext context) {
final String intValue = "intValue";
final JsonObject jObject = new JsonObject();
jObject.addProperty(intValue, src.getIntValue());
return jObject;
}
}
@@ -0,0 +1,52 @@
package org.baeldung.gson.serialization;
public class SourceClass {
private int intValue;
private String stringValue;
public SourceClass(final int intValue, final String stringValue) {
this.intValue = intValue;
this.stringValue = stringValue;
}
// API
public int getIntValue() {
return intValue;
}
public String getStringValue() {
return stringValue;
}
//
@Override
public String toString() {
return "SourceClass{" + "intValue=" + intValue + ", stringValue='" + stringValue + '\'' + '}';
}
@Override
public boolean equals(final Object o) {
if (this == o)
return true;
if (!(o instanceof SourceClass))
return false;
final SourceClass that = (SourceClass) o;
if (intValue != that.intValue)
return false;
if (!stringValue.equals(that.stringValue))
return false;
return true;
}
@Override
public int hashCode() {
int result = intValue;
result = 31 * result + stringValue.hashCode();
return result;
}
}
@@ -0,0 +1,95 @@
package org.baeldung.gson.serialization.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Type;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import org.baeldung.gson.serialization.DifferentNameSerializer;
import org.baeldung.gson.serialization.IgnoringFieldsNotMatchingCriteriaSerializer;
import org.baeldung.gson.serialization.IgnoringFieldsSerializer;
import org.baeldung.gson.serialization.SourceClass;
import org.joda.time.DateTime;
import org.junit.Test;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
public class GsonSerializationUnitTest {
@Test
public void givenArrayOfObjects_whenSerializing_thenCorrect() {
final SourceClass[] sourceArray = { new SourceClass(1, "one"), new SourceClass(2, "two") };
final String jsonString = new Gson().toJson(sourceArray);
// test
final String expectedResult = "[{\"intValue\":1,\"stringValue\":\"one\"},{\"intValue\":2,\"stringValue\":\"two\"}]";
assertEquals(expectedResult, jsonString);
}
@Test
public void givenCollection_whenSerializing_thenCorrect() {
final Collection<SourceClass> sourceCollection = Lists.newArrayList(new SourceClass(1, "one"), new SourceClass(2, "two"));
final String jsonCollection = new Gson().toJson(sourceCollection);
final String expectedResult = "[{\"intValue\":1,\"stringValue\":\"one\"},{\"intValue\":2,\"stringValue\":\"two\"}]";
assertEquals(expectedResult, jsonCollection);
}
@Test
public void givenUsingCustomSerializer_whenChangingNameOfFieldOnSerializing_thenCorrect() {
final SourceClass sourceObject = new SourceClass(7, "seven");
final GsonBuilder gsonBuildr = new GsonBuilder();
gsonBuildr.registerTypeAdapter(SourceClass.class, new DifferentNameSerializer());
final String jsonString = gsonBuildr.create().toJson(sourceObject);
final String expectedResult = "{\"otherIntValue\":7,\"otherStringValue\":\"seven\"}";
assertEquals(expectedResult, jsonString);
}
@Test
public void givenIgnoringAField_whenSerializingWithCustomSerializer_thenFieldIgnored() {
final SourceClass sourceObject = new SourceClass(7, "seven");
final GsonBuilder gsonBuildr = new GsonBuilder();
gsonBuildr.registerTypeAdapter(SourceClass.class, new IgnoringFieldsSerializer());
final String jsonString = gsonBuildr.create().toJson(sourceObject);
final String expectedResult = "{\"intValue\":7}";
assertEquals(expectedResult, jsonString);
}
@Test
public void givenUsingCustomDeserializer_whenFieldNotMatchesCriteria_thenIgnored() {
final SourceClass sourceObject = new SourceClass(-1, "minus 1");
final GsonBuilder gsonBuildr = new GsonBuilder();
gsonBuildr.registerTypeAdapter(SourceClass.class, new IgnoringFieldsNotMatchingCriteriaSerializer());
final Gson gson = gsonBuildr.create();
final Type sourceObjectType = new TypeToken<SourceClass>() {
}.getType();
final String jsonString = gson.toJson(sourceObject, sourceObjectType);
final String expectedResult = "{\"stringValue\":\"minus 1\"}";
assertEquals(expectedResult, jsonString);
}
@Test
public void givenDate_whenSerializing_thenCorrect() {
Date sourceDate = new DateTime().withYear(2000).withMonthOfYear(1).withDayOfMonth(1).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).toDate();
final Gson gson = new Gson();
Type sourceDateType = new TypeToken<Date>() {
}.getType();
String jsonDate = gson.toJson(sourceDate, sourceDateType);
System.out.println("jsonDate:\n" + jsonDate);
String expectedResult = "\"Jan 1, 2000 12:00:00 AM\"";
assertEquals(expectedResult, jsonDate);
}
}
@@ -0,0 +1,43 @@
package org.baeldung.gson.serialization.test;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.baeldung.gson.entities.User;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@RunWith(Parameterized.class)
public class JsonFileUnitTest {
@Parameter
public Object object;
@Parameters
public static Object[] data() {
return new Object[] { 123.45, new User(1, "Tom", "American") };
}
@Test
public void givenProperData_whenStoredInFile_shouldSaveJsonSuccessfully() {
String filePath = "target/output.json";
try (Writer writer = new FileWriter(filePath)) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
gson.toJson(object, writer);
Assert.assertTrue(Files.exists(Paths.get(filePath)));
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,104 @@
package org.baeldung.gson.serializationwithexclusions;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
class SerializationWithExclusionsUnitTest {
final String expectedResult = "{\"id\":1,\"name\":\"foo\",\"subclass\":{\"id\":42,\"description\":\"the answer\"}}";
@Test
public void givenClassWithTransientFields_whenSerializing_thenCorrectWithoutTransientFields() {
MyClassWithTransientFields source = new MyClassWithTransientFields(1L, "foo", "bar", new MySubClassWithTransientFields(42L, "the answer", "Verbose field which we don't want to be serialized"));
String jsonString = new Gson().toJson(source);
assertEquals(expectedResult, jsonString);
}
@Test
public void givenClassAnnotated_whenSerializing_thenCorrectWithoutNotAnnotatedFields() {
MyClassWithAnnotatedFields source = new MyClassWithAnnotatedFields(1L, "foo", "bar", new MySubClassWithAnnotatedFields(42L, "the answer", "Verbose field which we don't want to be serialized"));
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
.create();
String jsonString = gson.toJson(source);
assertEquals(expectedResult, jsonString);
}
@Test
public void givenExclusionStrategyByClassesAndFields_whenSerializing_thenFollowStrategy() {
MyClass source = new MyClass(1L, "foo", "bar", new MySubClass(42L, "the answer", "Verbose field which we don't want to be serialized"));
ExclusionStrategy strategy = new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes field) {
if (field.getDeclaringClass() == MyClass.class && field.getName()
.equals("other"))
return true;
if (field.getDeclaringClass() == MySubClass.class && field.getName()
.equals("otherVerboseInfo"))
return true;
return false;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
};
Gson gson = new GsonBuilder().addSerializationExclusionStrategy(strategy)
.create();
String jsonString = gson.toJson(source);
assertEquals(expectedResult, jsonString);
}
@Test
public void givenExclusionStrategyByStartsWith_whenSerializing_thenFollowStrategy() {
MyClass source = new MyClass(1L, "foo", "bar", new MySubClass(42L, "the answer", "Verbose field which we don't want to be serialized"));
ExclusionStrategy strategy = new ExclusionStrategy() {
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
@Override
public boolean shouldSkipField(FieldAttributes field) {
return field.getName().startsWith("other");
}
};
Gson gson = new GsonBuilder().setExclusionStrategies(strategy)
.create();
String jsonString = gson.toJson(source);
assertEquals(expectedResult, jsonString);
}
@Test
public void givenExclusionStrategyByCustomAnnotation_whenSerializing_thenFollowStrategy() {
MyClassWithCustomAnnotatedFields source = new MyClassWithCustomAnnotatedFields(1L, "foo", "bar", new MySubClassWithCustomAnnotatedFields(42L, "the answer", "Verbose field which we don't want to be serialized"));
ExclusionStrategy strategy = new ExclusionStrategy() {
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
@Override
public boolean shouldSkipField(FieldAttributes field) {
return field.getAnnotation(Exclude.class) != null;
}
};
Gson gson = new GsonBuilder().setExclusionStrategies(strategy)
.create();
String jsonString = gson.toJson(source);
assertEquals(expectedResult, jsonString);
}
}
+13
View File
@@ -0,0 +1,13 @@
*.class
#folders#
/target
/neoDb*
/data
/src/main/webapp/WEB-INF/classes
*/META-INF/*
# Packaged files #
*.jar
*.war
*.ear
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN"/>
<logger name="org.springframework.transaction" level="WARN"/>
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
<logger name="org.springframework.web.servlet.mvc" level="WARN"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>