BAEL-7335: Polymorphism with Gson (#16320)
This commit is contained in:
parent
eead7a451c
commit
e4c43225b9
|
@ -0,0 +1,5 @@
|
|||
package com.baeldung.gson.polymorphic;
|
||||
|
||||
public interface Shape {
|
||||
double getArea();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.gson.polymorphic;
|
||||
|
||||
import com.google.gson.*;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class ShapeTypeAdapter implements JsonSerializer<Shape>, JsonDeserializer<Shape> {
|
||||
@Override
|
||||
public JsonElement serialize(Shape shape, Type type, JsonSerializationContext context) {
|
||||
JsonElement elem = new Gson().toJsonTree(shape);
|
||||
elem.getAsJsonObject().addProperty("type", shape.getClass().getName());
|
||||
return elem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
|
||||
JsonObject jsonObject = json.getAsJsonObject();
|
||||
String typeName = jsonObject.get("type").getAsString();
|
||||
|
||||
try {
|
||||
Class<? extends Shape> cls = (Class<? extends Shape>) Class.forName(typeName);
|
||||
return new Gson().fromJson(json, cls);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new JsonParseException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package com.baeldung.gson.polymorphic;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TypeAdapterUnitTest {
|
||||
@Test
|
||||
void testSerialize() {
|
||||
List<Shape> shapes = Arrays.asList(
|
||||
new Circle(4d),
|
||||
new Square(5d)
|
||||
);
|
||||
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.registerTypeHierarchyAdapter(Shape.class, new ShapeTypeAdapter());
|
||||
Gson gson = builder.create();
|
||||
|
||||
String json = gson.toJson(shapes);
|
||||
|
||||
assertEquals("[" +
|
||||
"{" +
|
||||
"\"radius\":4.0," +
|
||||
"\"area\":50.26548245743669," +
|
||||
"\"type\":\"com.baeldung.gson.polymorphic.TypeAdapterUnitTest$Circle\"" +
|
||||
"},{" +
|
||||
"\"side\":5.0," +
|
||||
"\"area\":25.0," +
|
||||
"\"type\":\"com.baeldung.gson.polymorphic.TypeAdapterUnitTest$Square\"" +
|
||||
"}]", json);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testDeserializeWrapper() {
|
||||
List<Shape> shapes = Arrays.asList(
|
||||
new Circle(4d),
|
||||
new Square(5d)
|
||||
);
|
||||
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.registerTypeHierarchyAdapter(Shape.class, new ShapeTypeAdapter());
|
||||
Gson gson = builder.create();
|
||||
|
||||
String json = gson.toJson(shapes);
|
||||
|
||||
Type collectionType = new TypeToken<List<Shape>>(){}.getType();
|
||||
List<Shape> result = gson.fromJson(json, collectionType);
|
||||
|
||||
assertEquals(shapes, result);
|
||||
}
|
||||
|
||||
private static class Square implements Shape {
|
||||
private final double side;
|
||||
private final double area;
|
||||
|
||||
public Square(double side) {
|
||||
this.side = side;
|
||||
this.area = side * side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Square square = (Square) o;
|
||||
return Double.compare(square.side, side) == 0 && Double.compare(square.area, area) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(side, area);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Circle implements Shape {
|
||||
private final double radius;
|
||||
|
||||
private final double area;
|
||||
|
||||
public Circle(double radius) {
|
||||
this.radius = radius;
|
||||
this.area = Math.PI * radius * radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Circle circle = (Circle) o;
|
||||
return Double.compare(circle.radius, radius) == 0 && Double.compare(circle.area, area) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(radius, area);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.baeldung.gson.polymorphic;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TypeFieldUnitTest {
|
||||
@Test
|
||||
void testSerialize() {
|
||||
List<Shape> shapes = Arrays.asList(
|
||||
new Circle(4d),
|
||||
new Square(5d)
|
||||
);
|
||||
|
||||
Gson gson = new Gson();
|
||||
String json = gson.toJson(shapes);
|
||||
|
||||
assertEquals("[" +
|
||||
"{" +
|
||||
"\"type\":\"circle\"," +
|
||||
"\"radius\":4.0," +
|
||||
"\"area\":50.26548245743669" +
|
||||
"},{" +
|
||||
"\"type\":\"square\"," +
|
||||
"\"side\":5.0," +
|
||||
"\"area\":25.0" +
|
||||
"}]", json);
|
||||
}
|
||||
|
||||
private static class Square implements Shape {
|
||||
private final String type = "square";
|
||||
private final double side;
|
||||
private final double area;
|
||||
|
||||
public Square(double side) {
|
||||
this.side = side;
|
||||
this.area = side * side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getArea() {
|
||||
return area;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Circle implements Shape {
|
||||
private final String type = "circle";
|
||||
private final double radius;
|
||||
|
||||
private final double area;
|
||||
|
||||
public Circle(double radius) {
|
||||
this.radius = radius;
|
||||
this.area = Math.PI * radius * radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getArea() {
|
||||
return area;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package com.baeldung.gson.polymorphic;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class WrapperUnitTest {
|
||||
@Test
|
||||
void testSerializeWrapper() {
|
||||
List<Wrapper> shapes = Arrays.asList(
|
||||
new Wrapper(new Circle(4d)),
|
||||
new Wrapper(new Square(5d))
|
||||
);
|
||||
|
||||
Gson gson = new Gson();
|
||||
String json = gson.toJson(shapes);
|
||||
|
||||
assertEquals("[" +
|
||||
"{" +
|
||||
"\"circle\":{" +
|
||||
"\"radius\":4.0," +
|
||||
"\"area\":50.26548245743669" +
|
||||
"}" +
|
||||
"},{" +
|
||||
"\"square\":{" +
|
||||
"\"side\":5.0," +
|
||||
"\"area\":25.0" +
|
||||
"}" +
|
||||
"}]", json);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeserializeWrapper() {
|
||||
List<Wrapper> shapes = Arrays.asList(
|
||||
new Wrapper(new Circle(4d)),
|
||||
new Wrapper(new Square(5d))
|
||||
);
|
||||
|
||||
Gson gson = new Gson();
|
||||
String json = gson.toJson(shapes);
|
||||
|
||||
Type collectionType = new TypeToken<List<Wrapper>>(){}.getType();
|
||||
List<Wrapper> result = gson.fromJson(json, collectionType);
|
||||
|
||||
assertEquals(shapes, result);
|
||||
}
|
||||
|
||||
private static class Square implements Shape {
|
||||
private final double side;
|
||||
private final double area;
|
||||
|
||||
public Square(double side) {
|
||||
this.side = side;
|
||||
this.area = side * side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Square square = (Square) o;
|
||||
return Double.compare(square.side, side) == 0 && Double.compare(square.area, area) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(side, area);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Circle implements Shape {
|
||||
private final double radius;
|
||||
|
||||
private final double area;
|
||||
|
||||
public Circle(double radius) {
|
||||
this.radius = radius;
|
||||
this.area = Math.PI * radius * radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Circle circle = (Circle) o;
|
||||
return Double.compare(circle.radius, radius) == 0 && Double.compare(circle.area, area) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(radius, area);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Wrapper {
|
||||
private final Circle circle;
|
||||
private final Square square;
|
||||
|
||||
public Wrapper(Circle circle) {
|
||||
this.circle = circle;
|
||||
this.square = null;
|
||||
}
|
||||
|
||||
public Wrapper(Square square) {
|
||||
this.square = square;
|
||||
this.circle = null;
|
||||
}
|
||||
|
||||
public Circle getCircle() {
|
||||
return circle;
|
||||
}
|
||||
|
||||
public Square getSquare() {
|
||||
return square;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Wrapper wrapper = (Wrapper) o;
|
||||
return Objects.equals(circle, wrapper.circle) && Objects.equals(square, wrapper.square);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(circle, square);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue