Java 11497 (#12399)
* Added/created parent module (json-modules) * moved json(submodule) to json-modules(parent) * moved json-2(submodule) to json-modules(parent) * moved json-path(submodule) to json-modules(parent) * moved gson(submodule) to json-modules(parent) * deleted sub-modules that we moved to json-modules Co-authored-by: panagiotiskakos <panagiotis.kakos@libra-is.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
package com.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 com.baeldung.gson.entities;
|
||||
|
||||
public abstract class Animal {
|
||||
public String type = "Animal";
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.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 com.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 com.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 com.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 com.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 com.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 com.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 com.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;
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.gson.primitives.models;
|
||||
|
||||
public class BooleanExample {
|
||||
public boolean value;
|
||||
|
||||
public String toString() {
|
||||
return "{boolean: " + value + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.gson.primitives.models;
|
||||
|
||||
public class ByteExample {
|
||||
public byte value = (byte) 1;
|
||||
|
||||
public String toString() {
|
||||
return "{byte: " + value + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.gson.primitives.models;
|
||||
|
||||
public class CharExample {
|
||||
public char value;
|
||||
|
||||
public String toString() {
|
||||
return "{char: " + value + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.gson.primitives.models;
|
||||
|
||||
public class DoubleExample {
|
||||
public double value;
|
||||
|
||||
public String toString() {
|
||||
return "{float: " + value + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.gson.primitives.models;
|
||||
|
||||
public class FloatExample {
|
||||
public float value;
|
||||
|
||||
public String toString() {
|
||||
return "{float: " + value + "}";
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package com.baeldung.gson.primitives.models;
|
||||
|
||||
public class InfinityValuesExample {
|
||||
public float negativeInfinity;
|
||||
public float positiveInfinity;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.gson.primitives.models;
|
||||
|
||||
public class LongExample {
|
||||
public long value = 1;
|
||||
|
||||
public String toString() {
|
||||
return "{byte: " + value + "}";
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.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 + "}";
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.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 + "}";
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.baeldung.gson.serialization;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.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;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.baeldung.gson.serialization;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.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("-"));
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.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 com.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,63 @@
|
||||
package com.baeldung.gson.serialization;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.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 {
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.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;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.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;
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.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;
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.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;
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.baeldung.gson.serializationwithexclusions;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class MySubClass {
|
||||
private long id;
|
||||
private String description;
|
||||
private String otherVerboseInfo;
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.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;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.gson.serializationwithexclusions;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class MySubClassWithCustomAnnotatedFields {
|
||||
|
||||
private long id;
|
||||
private String description;
|
||||
@Exclude
|
||||
private String otherVerboseInfo;
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.gson.serializationwithexclusions;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class MySubClassWithTransientFields {
|
||||
|
||||
private long id;
|
||||
private String description;
|
||||
private transient String otherVerboseInfo;
|
||||
}
|
||||
@@ -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 com.baeldung.gson.advance;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import com.baeldung.gson.entities.Dog;
|
||||
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 com.baeldung.gson.entities.Animal;
|
||||
import com.baeldung.gson.entities.Cow;
|
||||
import com.baeldung.gson.entities.MyClass;
|
||||
import com.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);
|
||||
}
|
||||
}
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
package com.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();
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.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 com.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 + '}';
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.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;
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.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);
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.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 com.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 com.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 + '}';
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.baeldung.gson.deserialization;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import com.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());
|
||||
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.baeldung.gson.deserialization;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
import com.baeldung.gson.entities.Movie;
|
||||
import com.baeldung.gson.serialization.ActorGsonDeserializer;
|
||||
import com.baeldung.gson.entities.ActorGson;
|
||||
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);
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
package com.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 com.baeldung.gson.entities.Employee;
|
||||
import com.baeldung.gson.serialization.MapDeserializer;
|
||||
import com.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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
package com.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 com.baeldung.gson.deserialization.Foo;
|
||||
import com.baeldung.gson.deserialization.FooDeserializerFromJsonWithDifferentFields;
|
||||
import com.baeldung.gson.deserialization.FooInstanceCreator;
|
||||
import com.baeldung.gson.deserialization.FooWithInner;
|
||||
import com.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");
|
||||
}
|
||||
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package com.baeldung.gson.jsoncompare;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class JsonCompareUnitTest {
|
||||
@Test
|
||||
public void givenJsonStrings_whenCompared_thenNotEqual() {
|
||||
String string1 = "{\"fullName\": \"Emily Jenkins\", \"age\": 27 }";
|
||||
String string2 = "{\"fullName\": \"Emily Jenkins\", \"age\": 27}";
|
||||
|
||||
assertNotEquals(string1, string2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIdenticalSimpleObjects_whenCompared_thenEqual() {
|
||||
JsonParser parser = new JsonParser();
|
||||
String string1 = "{\"customer\": {\"id\": \"44521\",\"fullName\": \"Emily Jenkins\", \"age\": 27 }}";
|
||||
String string2 = "{\"customer\": {\"id\": \"44521\", \"fullName\": \"Emily Jenkins\",\"age\": 27}}";
|
||||
|
||||
assertTrue(parser.parse(string1)
|
||||
.isJsonObject());
|
||||
assertEquals(parser.parse(string1), parser.parse(string2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSameObjectsInDifferentOrder_whenCompared_thenEqual() {
|
||||
JsonParser parser = new JsonParser();
|
||||
String string1 = "{\"customer\": {\"id\": \"44521\",\"fullName\": \"Emily Jenkins\", \"age\": 27 }}";
|
||||
String string2 = "{\"customer\": {\"id\": \"44521\",\"age\": 27, \"fullName\": \"Emily Jenkins\" }}";
|
||||
|
||||
JsonElement json1 = parser.parse(string1);
|
||||
JsonElement json2 = parser.parse(string2);
|
||||
|
||||
assertEquals(json1, json2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIdenticalArrays_whenCompared_thenEqual() {
|
||||
JsonParser parser = new JsonParser();
|
||||
String string1 = "[10, 20, 30]";
|
||||
String string2 = "[10, 20, 30]";
|
||||
|
||||
assertTrue(parser.parse(string1)
|
||||
.isJsonArray());
|
||||
assertEquals(parser.parse(string1), parser.parse(string2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenArraysInDifferentOrder_whenCompared_thenNotEqual() {
|
||||
JsonParser parser = new JsonParser();
|
||||
String string1 = "[20, 10, 30]";
|
||||
String string2 = "[10, 20, 30]";
|
||||
|
||||
assertNotEquals(parser.parse(string1), parser.parse(string2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIdenticalNestedObjects_whenCompared_thenEqual() {
|
||||
JsonParser parser = new JsonParser();
|
||||
String string1 = "{\"customer\": {\"id\": \"44521\",\"fullName\": \"Emily Jenkins\", \"age\": 27, \"consumption_info\" : {\"fav_product\": \"Coke\", \"last_buy\": \"2012-04-23\"}}}";
|
||||
String string2 = "{\"customer\": {\"id\": \"44521\",\"fullName\": \"Emily Jenkins\", \"age\": 27, \"consumption_info\" : {\"last_buy\": \"2012-04-23\", \"fav_product\": \"Coke\"}}}";
|
||||
|
||||
JsonElement json1 = parser.parse(string1);
|
||||
JsonElement json2 = parser.parse(string2);
|
||||
|
||||
assertEquals(json1, json2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIdenticalNestedObjectsWithArray_whenCompared_thenEqual() {
|
||||
JsonParser parser = new JsonParser();
|
||||
String string1 = "{\"customer\": {\"id\": \"44521\",\"fullName\": \"Emily Jenkins\", \"age\": 27, \"consumption_info\" : {\"last_buy\": \"2012-04-23\", \"prouducts\": [\"banana\", \"eggs\"]}}}";
|
||||
String string2 = "{\"customer\": {\"id\": \"44521\",\"fullName\": \"Emily Jenkins\", \"age\": 27, \"consumption_info\" : {\"last_buy\": \"2012-04-23\", \"prouducts\": [\"banana\", \"eggs\"]}}}";
|
||||
|
||||
JsonElement json1 = parser.parse(string1);
|
||||
JsonElement json2 = parser.parse(string2);
|
||||
|
||||
assertEquals(json1, json2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNestedObjectsDifferentArrayOrder_whenCompared_thenNotEqual() {
|
||||
JsonParser parser = new JsonParser();
|
||||
String string1 = "{\"customer\": {\"id\": \"44521\",\"fullName\": \"Emily Jenkins\", \"age\": 27, \"consumption_info\" : {\"last_buy\": \"2012-04-23\", \"prouducts\": [\"banana\", \"eggs\"]}}}";
|
||||
String string2 = "{\"customer\": {\"id\": \"44521\",\"fullName\": \"Emily Jenkins\", \"age\": 27, \"consumption_info\" : {\"last_buy\": \"2012-04-23\", \"prouducts\": [\"eggs\", \"banana\"]}}}";
|
||||
|
||||
JsonElement json1 = parser.parse(string1);
|
||||
JsonElement json2 = parser.parse(string2);
|
||||
|
||||
assertNotEquals(json1, json2);
|
||||
}
|
||||
}
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
package com.baeldung.gson.primitives;
|
||||
|
||||
import com.baeldung.gson.primitives.models.*;
|
||||
import com.google.gson.*;
|
||||
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
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.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;
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.baeldung.gson.serialization;
|
||||
|
||||
import com.baeldung.gson.entities.Movie;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.baeldung.gson.entities.ActorGson;
|
||||
import com.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);
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.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;
|
||||
}
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.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 com.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;
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package com.baeldung.gson.serialization.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import com.baeldung.gson.serialization.DifferentNameSerializer;
|
||||
import com.baeldung.gson.serialization.IgnoringFieldsNotMatchingCriteriaSerializer;
|
||||
import com.baeldung.gson.serialization.IgnoringFieldsSerializer;
|
||||
import com.baeldung.gson.serialization.SourceClass;
|
||||
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.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 com.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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
*.class
|
||||
|
||||
#folders#
|
||||
/target
|
||||
/neoDb*
|
||||
/data
|
||||
/src/main/webapp/WEB-INF/classes
|
||||
*/META-INF/*
|
||||
|
||||
# Packaged files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user