diff --git a/json-modules/gson-4/gson-module-opens/pom.xml b/json-modules/gson-4/gson-module-opens/pom.xml new file mode 100644 index 000000000000..2be112fa19b8 --- /dev/null +++ b/json-modules/gson-4/gson-module-opens/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + + com.baeldung + gson-4 + 1.0.0-SNAPSHOT + + + gson-module-opens + jar + + diff --git a/json-modules/gson-4/gson-module-opens/src/main/java/gson/exception/ConferencePojo.java b/json-modules/gson-4/gson-module-opens/src/main/java/gson/exception/ConferencePojo.java new file mode 100644 index 000000000000..e10425669823 --- /dev/null +++ b/json-modules/gson-4/gson-module-opens/src/main/java/gson/exception/ConferencePojo.java @@ -0,0 +1,23 @@ +package gson.exception; + +public class ConferencePojo { + + private String name; + private int numberOfParticipants; + + public String getName() { + return name; + } + + public int getNumberOfParticipants() { + return numberOfParticipants; + } + + public void setName(String name) { + this.name = name; + } + + public void setNumberOfParticipants(int numberOfParticipants) { + this.numberOfParticipants = numberOfParticipants; + } +} diff --git a/json-modules/gson-4/gson-module-opens/src/main/java/gson/exception/ConferencePojoWithDate.java b/json-modules/gson-4/gson-module-opens/src/main/java/gson/exception/ConferencePojoWithDate.java new file mode 100644 index 000000000000..88916ccd6f3b --- /dev/null +++ b/json-modules/gson-4/gson-module-opens/src/main/java/gson/exception/ConferencePojoWithDate.java @@ -0,0 +1,34 @@ +package gson.exception; + +import java.time.LocalDate; + +public class ConferencePojoWithDate { + + private String name; + private int numberOfParticipants; + private LocalDate conferenceStart; + + public String getName() { + return name; + } + + public int getNumberOfParticipants() { + return numberOfParticipants; + } + + public void setName(String name) { + this.name = name; + } + + public void setNumberOfParticipants(int numberOfParticipants) { + this.numberOfParticipants = numberOfParticipants; + } + + public LocalDate getConferenceStart() { + return conferenceStart; + } + + public void setConferenceStart(LocalDate conferenceStart) { + this.conferenceStart = conferenceStart; + } +} diff --git a/json-modules/gson-4/gson-module-opens/src/main/java/gson/exception/GsonModuleMain.java b/json-modules/gson-4/gson-module-opens/src/main/java/gson/exception/GsonModuleMain.java new file mode 100644 index 000000000000..efc7faa67a8e --- /dev/null +++ b/json-modules/gson-4/gson-module-opens/src/main/java/gson/exception/GsonModuleMain.java @@ -0,0 +1,36 @@ +package gson.exception; + +import java.time.LocalDate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +public class GsonModuleMain { + + static Logger log = LoggerFactory.getLogger(GsonModuleMain.class); + + public static void main(String[] args) { + + String moduleName = GsonModuleMain.class.getModule() + .getName(); + + if (moduleName == null) { + log.info("Mode: [ Class Path ] (Class in the Unnamed Module)"); + } else { + log.info("Mode: [ Module Path ] - Module name: " + moduleName); + } + LocalDate excpectedDate = LocalDate.of(2026, 8, 17); + Gson gson = new Gson(); + String json = "{\"name\":\"Java Conference\"}"; + + try { + ConferencePojo pojo = gson.fromJson(json, ConferencePojo.class); + log.info("Deserialization successful! Object " + pojo); + } catch (Exception e) { + log.info("Expected exception caught!"); + e.printStackTrace(); + } + } +} diff --git a/json-modules/gson-4/gson-module-opens/src/main/java/module-info.java b/json-modules/gson-4/gson-module-opens/src/main/java/module-info.java new file mode 100644 index 000000000000..073dbc9dfa81 --- /dev/null +++ b/json-modules/gson-4/gson-module-opens/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module gson.exception { + + requires com.google.gson; + requires org.slf4j; + + opens gson.exception to com.google.gson; + + exports gson.exception; +} \ No newline at end of file diff --git a/json-modules/gson-4/gson-module-opens/src/test/java/gson/exception/ModularOpensGsonUnitTest.java b/json-modules/gson-4/gson-module-opens/src/test/java/gson/exception/ModularOpensGsonUnitTest.java new file mode 100644 index 000000000000..eaea47f71452 --- /dev/null +++ b/json-modules/gson-4/gson-module-opens/src/test/java/gson/exception/ModularOpensGsonUnitTest.java @@ -0,0 +1,26 @@ +package gson.exception; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; + +import com.google.gson.Gson; + +class ModularOpensGsonUnitTest { + + @Test + void givenModularAndOpens_whenDeserializingPojo_thenSuccess() { + String json = "{\"name\":\"Java Conference\",\"numberOfParticipants\":150}"; + Gson gson = new Gson(); + + ConferencePojo result = assertDoesNotThrow(() -> { + return gson.fromJson(json, ConferencePojo.class); + }); + + assertNotNull(result); + assertEquals("Java Conference", result.getName()); + } + +} diff --git a/json-modules/gson-4/gson-module-opens/src/test/java/gson/exception/ModularStructureConfirmationUnitTest.java b/json-modules/gson-4/gson-module-opens/src/test/java/gson/exception/ModularStructureConfirmationUnitTest.java new file mode 100644 index 000000000000..dc31e51aa561 --- /dev/null +++ b/json-modules/gson-4/gson-module-opens/src/test/java/gson/exception/ModularStructureConfirmationUnitTest.java @@ -0,0 +1,17 @@ +package gson.exception; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class ModularStructureConfirmationUnitTest { + + @Test + void whenModular_thenModuleIsNamed() { + Module module = this.getClass() + .getModule(); + + assertTrue(module.isNamed(), "Test run on Classpath, JPMS strong encapsulation won't work!"); + } + +} diff --git a/json-modules/gson-4/gson-module-opens/src/test/java/gson/exception/PojoWithLocalDateUnitTest.java b/json-modules/gson-4/gson-module-opens/src/test/java/gson/exception/PojoWithLocalDateUnitTest.java new file mode 100644 index 000000000000..24d16ad7c13c --- /dev/null +++ b/json-modules/gson-4/gson-module-opens/src/test/java/gson/exception/PojoWithLocalDateUnitTest.java @@ -0,0 +1,45 @@ +package gson.exception; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +class PojoWithLocalDateUnitTest { + + @Test + void whenObjectDateFormat_thenSuccessfulDeserialization() { + String correctJson = "{" + + "\"name\":\"Java Conference\"," + + "\"numberOfParticipants\":500," + + "\"conferenceStart\":{\"year\":2026,\"month\":8,\"day\":17}" + + "}"; + + Gson gson = new Gson(); + ConferencePojoWithDate result = gson.fromJson(correctJson, ConferencePojoWithDate.class); + + LocalDate excpectedDate = LocalDate.of(2026, 8, 17); + assertEquals(excpectedDate, result.getConferenceStart(), "Date should be the same as in JSON"); + } + + @Test + void whenISOTextFormat_thenJsonSyntaxException() { + + String wrongDateInJson = "{" + + "\"name\":\"Java Conference\"," + + "\"numberOfParticipants\":500," + + "\"conferenceStart\":\"2026-08-17\"" + + "}"; + + Gson gson = new Gson(); + assertThrows(JsonSyntaxException.class, () -> { + gson.fromJson(wrongDateInJson, ConferencePojoWithDate.class); + }, "JsonSyntaxException was expected due to an incompatible date format"); + + } +} diff --git a/json-modules/gson-4/gson-module/pom.xml b/json-modules/gson-4/gson-module/pom.xml new file mode 100644 index 000000000000..def51e551bff --- /dev/null +++ b/json-modules/gson-4/gson-module/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + + + com.baeldung + gson-4 + 1.0.0-SNAPSHOT + + + gson-module + jar + diff --git a/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferencePojo.java b/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferencePojo.java new file mode 100644 index 000000000000..e10425669823 --- /dev/null +++ b/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferencePojo.java @@ -0,0 +1,23 @@ +package gson.exception; + +public class ConferencePojo { + + private String name; + private int numberOfParticipants; + + public String getName() { + return name; + } + + public int getNumberOfParticipants() { + return numberOfParticipants; + } + + public void setName(String name) { + this.name = name; + } + + public void setNumberOfParticipants(int numberOfParticipants) { + this.numberOfParticipants = numberOfParticipants; + } +} diff --git a/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferencePojoAdapter.java b/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferencePojoAdapter.java new file mode 100644 index 000000000000..7973212d3413 --- /dev/null +++ b/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferencePojoAdapter.java @@ -0,0 +1,40 @@ +package gson.exception; + +import java.io.IOException; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +public class ConferencePojoAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, ConferencePojo value) throws IOException { + throw new UnsupportedOperationException("This adapter is for deserialization only!"); + } + + @Override + public ConferencePojo read(JsonReader in) throws IOException { + String name = null; + int numberOfParticipants = 0; + + in.beginObject(); + while (in.hasNext()) { + String key = in.nextName(); + if ("name".equals(key)) { + name = in.nextString(); + } else if ("numberOfParticipants".equals(key)) { + numberOfParticipants = in.nextInt(); + } else { + in.skipValue(); + } + } + in.endObject(); + + ConferencePojo result = new ConferencePojo(); + result.setName(name); + result.setNumberOfParticipants(numberOfParticipants); + + return result; + } +} diff --git a/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferencePojoPublic.java b/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferencePojoPublic.java new file mode 100644 index 000000000000..2c91707bb67d --- /dev/null +++ b/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferencePojoPublic.java @@ -0,0 +1,7 @@ +package gson.exception; + +public class ConferencePojoPublic { + + public String name; + public int numberOfParticipants; +} diff --git a/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferenceRecord.java b/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferenceRecord.java new file mode 100644 index 000000000000..efe6128c7c35 --- /dev/null +++ b/json-modules/gson-4/gson-module/src/main/java/gson/exception/ConferenceRecord.java @@ -0,0 +1,5 @@ +package gson.exception; + +public record ConferenceRecord(String name, int numberOfParticipants) { + +} diff --git a/json-modules/gson-4/gson-module/src/main/java/gson/exception/GsonModuleMain.java b/json-modules/gson-4/gson-module/src/main/java/gson/exception/GsonModuleMain.java new file mode 100644 index 000000000000..c2c0dae8c204 --- /dev/null +++ b/json-modules/gson-4/gson-module/src/main/java/gson/exception/GsonModuleMain.java @@ -0,0 +1,34 @@ +package gson.exception; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +public class GsonModuleMain { + + static Logger log = LoggerFactory.getLogger(GsonModuleMain.class); + + public static void main(String[] args) { + + String moduleName = GsonModuleMain.class.getModule() + .getName(); + + if (moduleName == null) { + log.info("Mode: [ Class Path ] (Class in the Unnamed Module)"); + } else { + log.info("Mode: [ Module Path ] - Module name: " + moduleName); + } + + Gson gson = new Gson(); + String json = "{\"name\":\"Java Conference\"}"; + + try { + ConferencePojo pojo = gson.fromJson(json, ConferencePojo.class); + log.info("Deserialization successful! Object " + pojo); + } catch (Exception e) { + log.info("Expected exception caught!"); + e.printStackTrace(); + } + } +} diff --git a/json-modules/gson-4/gson-module/src/main/java/module-info.java b/json-modules/gson-4/gson-module/src/main/java/module-info.java new file mode 100644 index 000000000000..9401a2cc7bc5 --- /dev/null +++ b/json-modules/gson-4/gson-module/src/main/java/module-info.java @@ -0,0 +1,7 @@ +module gson.exception { + + requires com.google.gson; + requires org.slf4j; + + exports gson.exception; +} diff --git a/json-modules/gson-4/gson-module/src/test/java/gson/exception/ModularGsonUnitTest.java b/json-modules/gson-4/gson-module/src/test/java/gson/exception/ModularGsonUnitTest.java new file mode 100644 index 000000000000..5fc9e79b4e91 --- /dev/null +++ b/json-modules/gson-4/gson-module/src/test/java/gson/exception/ModularGsonUnitTest.java @@ -0,0 +1,50 @@ +package gson.exception; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +import com.google.gson.Gson; +import com.google.gson.JsonIOException; + +public class ModularGsonUnitTest { + + @Test + void givenModularAndExportedPackage_whenDeserializingPojo_thenJsonIOException() { + String json = "{\"name\":\"Java Conference\",\"numberOfParticipants\":150}"; + Gson gson = new Gson(); + + assertThrows(JsonIOException.class, () -> { + gson.fromJson(json, ConferencePojo.class); + }); + } + + @Test + void givenModularAndExportedPackage_whenDeserializingRecord_thenSuccess() { + String json = "{\"name\":\"Java Conference\",\"numberOfParticipants\":150}"; + Gson gson = new Gson(); + + ConferenceRecord result = assertDoesNotThrow(() -> { + return gson.fromJson(json, ConferenceRecord.class); + }); + + assertNotNull(result); + assertEquals("Java Conference", result.name()); + } + + @Test + void givenModularAndExportedPackage_whenDeserializingPublicPojo_thenSuccess() { + String json = "{\"name\":\"Java Conference\",\"numberOfParticipants\":150}"; + Gson gson = new Gson(); + + ConferencePojoPublic result = assertDoesNotThrow(() -> { + return gson.fromJson(json, ConferencePojoPublic.class); + }); + + assertNotNull(result); + assertEquals("Java Conference", result.name); + } +} diff --git a/json-modules/gson-4/gson-module/src/test/java/gson/exception/ModularGsonWithAdapterUnitTest.java b/json-modules/gson-4/gson-module/src/test/java/gson/exception/ModularGsonWithAdapterUnitTest.java new file mode 100644 index 000000000000..80b03af6cd6a --- /dev/null +++ b/json-modules/gson-4/gson-module/src/test/java/gson/exception/ModularGsonWithAdapterUnitTest.java @@ -0,0 +1,26 @@ +package gson.exception; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class ModularGsonWithAdapterUnitTest { + + @Test + void whenAdapterForPojo_thenSuccess() { + Gson gson = new GsonBuilder() + .registerTypeAdapter(ConferencePojo.class, new ConferencePojoAdapter()) + .create(); + + String jsonInput = "{\"name\":\"Java Conference\", \"numberOfParticipants\":100}"; + + ConferencePojo result = gson.fromJson(jsonInput, ConferencePojo.class); + + assertNotNull(result); + assertEquals("Java Conference", result.getName()); + } +} diff --git a/json-modules/gson-4/gson-module/src/test/java/gson/exception/ModularStructureConfirmationUnitTest.java b/json-modules/gson-4/gson-module/src/test/java/gson/exception/ModularStructureConfirmationUnitTest.java new file mode 100644 index 000000000000..db9e41ac851b --- /dev/null +++ b/json-modules/gson-4/gson-module/src/test/java/gson/exception/ModularStructureConfirmationUnitTest.java @@ -0,0 +1,16 @@ +package gson.exception; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class ModularStructureConfirmationUnitTest { + + @Test + void whenModular_thenModuleIsNamed() { + Module module = this.getClass() + .getModule(); + assertTrue(module.isNamed(), "Test run on Classpath, JPMS strong encapsulation won't work!"); + } + +} diff --git a/json-modules/gson-4/pom.xml b/json-modules/gson-4/pom.xml new file mode 100644 index 000000000000..bea764b429ba --- /dev/null +++ b/json-modules/gson-4/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + gson-4 + pom + gson-4 + + + json-modules + com.baeldung + 1.0.0-SNAPSHOT + + + + gson-module + gson-module-opens + + + + 2.14.0 + 17 + + + + + com.google.code.gson + gson + ${gson.version} + + + + + diff --git a/json-modules/pom.xml b/json-modules/pom.xml index 59f7feebc6cf..3751b3e91d94 100644 --- a/json-modules/pom.xml +++ b/json-modules/pom.xml @@ -25,6 +25,7 @@ gson gson-2 gson-3 + gson-4