diff --git a/gson/pom.xml b/gson/pom.xml
index 6e7779d26a..8222cb50e1 100644
--- a/gson/pom.xml
+++ b/gson/pom.xml
@@ -1,73 +1,73 @@
- 4.0.0
- com.baeldung
- gson
- 0.1-SNAPSHOT
- gson
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+ com.baeldung
+ gson
+ 0.1-SNAPSHOT
+ gson
-
- com.baeldung
- parent-java
- 0.0.1-SNAPSHOT
- ../parent-java
-
+
+ com.baeldung
+ parent-java
+ 0.0.1-SNAPSHOT
+ ../parent-java
+
-
-
-
- org.projectlombok
- lombok
- ${lombok.version}
- provided
-
-
- joda-time
- joda-time
- ${joda-time.version}
-
-
- commons-io
- commons-io
- ${commons-io.version}
-
-
- org.apache.commons
- commons-collections4
- ${commons-collections4.version}
-
-
- org.apache.commons
- commons-lang3
- ${commons-lang3.version}
-
-
-
- com.google.code.gson
- gson
- ${gson.version}
-
-
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+ joda-time
+ joda-time
+ ${joda-time.version}
+
+
+ commons-io
+ commons-io
+ ${commons-io.version}
+
+
+ org.apache.commons
+ commons-collections4
+ ${commons-collections4.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+
+ com.google.code.gson
+ gson
+ ${gson.version}
+
+
-
- gson
-
-
- src/main/resources
- true
-
-
-
+
+ gson
+
+
+ src/main/resources
+ true
+
+
+
-
-
- 2.8.0
-
- 3.5
- 4.1
- 2.9.6
+
+
+ 2.8.0
+
+ 3.5
+ 4.1
+ 2.9.6
1.16.10
-
+
\ No newline at end of file
diff --git a/gson/src/main/java/org/baeldung/gson/entities/Employee.java b/gson/src/main/java/org/baeldung/gson/entities/Employee.java
new file mode 100644
index 0000000000..cedcd6572e
--- /dev/null
+++ b/gson/src/main/java/org/baeldung/gson/entities/Employee.java
@@ -0,0 +1,36 @@
+package org.baeldung.gson.entities;
+
+public class Employee {
+ private int id;
+ private String name;
+ private String address;
+
+ public Employee(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+}
diff --git a/gson/src/main/java/org/baeldung/gson/serialization/HashMapDeserializer.java b/gson/src/main/java/org/baeldung/gson/serialization/HashMapDeserializer.java
new file mode 100644
index 0000000000..bb73e32559
--- /dev/null
+++ b/gson/src/main/java/org/baeldung/gson/serialization/HashMapDeserializer.java
@@ -0,0 +1,66 @@
+package org.baeldung.gson.serialization;
+
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.baeldung.gson.entities.Employee;
+
+import com.google.gson.*;
+
+public class HashMapDeserializer implements JsonDeserializer> {
+
+ @Override
+ public HashMap deserialize(JsonElement elem, Type type, JsonDeserializationContext context) throws JsonParseException {
+ HashMap map = new HashMap<>();
+ for (Map.Entry entry : elem.getAsJsonObject().entrySet()) {
+ JsonElement jsonValue = entry.getValue();
+ Object value = null;
+ if (jsonValue.isJsonPrimitive()) {
+ value = toPrimitive(jsonValue.getAsJsonPrimitive(), context);
+ } else {
+ value = context.deserialize(jsonValue, Employee.class);
+ }
+ map.put(entry.getKey(), value);
+ }
+ return map;
+
+ }
+
+ 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;
+ }
+ }
+
+}
diff --git a/gson/src/main/resources/logback.xml b/gson/src/main/resources/logback.xml
index 56af2d397e..7bd5154680 100644
--- a/gson/src/main/resources/logback.xml
+++ b/gson/src/main/resources/logback.xml
@@ -7,13 +7,13 @@
-
-
+
+
-
+
-
+
\ No newline at end of file
diff --git a/gson/src/test/java/org/baeldung/gson/deserialization/HashMapDeserializationUnitTest.java b/gson/src/test/java/org/baeldung/gson/deserialization/HashMapDeserializationUnitTest.java
new file mode 100644
index 0000000000..6905ade0da
--- /dev/null
+++ b/gson/src/test/java/org/baeldung/gson/deserialization/HashMapDeserializationUnitTest.java
@@ -0,0 +1,86 @@
+package org.baeldung.gson.deserialization;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+
+import org.baeldung.gson.entities.Employee;
+import org.baeldung.gson.serialization.HashMapDeserializer;
+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 HashMapDeserializationUnitTest {
+
+ private static final Logger logger = LoggerFactory.getLogger(HashMapDeserializationUnitTest.class);
+
+ @Test
+ public void whenUsingHashMapClass_thenShouldReturnMapWithDefaultClasses() {
+
+ String jsonString = "{'employee.name':'Bob','employee.salary':10000, 'employee.active':true, "
+ + "'employee':{'id':10, 'name': 'Bob Willis', 'address':'London'}}";
+
+ Gson gson = new Gson();
+ HashMap map = gson.fromJson(jsonString, HashMap.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();
+ HashMap map = gson.fromJson(jsonString, HashMap.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>(){}.getType();
+ HashMap 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>(){}.getType();
+ Gson gson = new GsonBuilder()
+ .registerTypeAdapter(type, new HashMapDeserializer())
+ .create();
+ HashMap 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());
+
+ }
+
+}
diff --git a/gson/src/test/resources/logback-test.xml b/gson/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..7bd5154680
--- /dev/null
+++ b/gson/src/test/resources/logback-test.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file