diff --git a/libraries-3/pom.xml b/libraries-3/pom.xml
index 5dccebd196..4bb1a4fba1 100644
--- a/libraries-3/pom.xml
+++ b/libraries-3/pom.xml
@@ -73,6 +73,16 @@
${cache2k.version}
pom
+
+ com.squareup.moshi
+ moshi
+ ${moshi.version}
+
+
+ com.squareup.moshi
+ moshi-adapters
+ ${moshi.version}
+
com.jcabi
@@ -135,7 +145,7 @@
0.43
2.7.2
1.2.3.Final
-
+ 1.9.2
0.22.6
1.9.2
0.14.1
diff --git a/libraries-3/src/test/java/com/baeldung/moshi/AlternativeAdapterUnitTest.java b/libraries-3/src/test/java/com/baeldung/moshi/AlternativeAdapterUnitTest.java
new file mode 100644
index 0000000000..63d80bfe58
--- /dev/null
+++ b/libraries-3/src/test/java/com/baeldung/moshi/AlternativeAdapterUnitTest.java
@@ -0,0 +1,105 @@
+package com.baeldung.moshi;
+
+import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.time.Instant;
+
+import com.squareup.moshi.FromJson;
+import com.squareup.moshi.JsonAdapter;
+import com.squareup.moshi.JsonQualifier;
+import com.squareup.moshi.Moshi;
+import com.squareup.moshi.ToJson;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.junit.Test;
+
+public class AlternativeAdapterUnitTest {
+ @Test
+ public void whenSerializing_thenAlternativeAdapterUsed() {
+ Moshi moshi = new Moshi.Builder()
+ .add(new EpochMillisAdapter())
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ String json = jsonAdapter.toJson(new Post("Introduction to Moshi Json", "Baeldung", Instant.now()));
+ System.out.println(json);
+ }
+
+ @Test
+ public void whenDeserializing_thenAlternativeAdapterUsed() throws IOException {
+ Moshi moshi = new Moshi.Builder()
+ .add(new EpochMillisAdapter())
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ String json = "{\"author\":\"Baeldung\",\"posted\":1582095269204,\"title\":\"Introduction to Moshi Json\"}";
+ Post post = jsonAdapter.fromJson(json);
+ System.out.println(post);
+
+ }
+
+ public static class Post {
+ String title;
+ String author;
+ @EpochMillis Instant posted;
+
+ public Post() {
+ }
+
+ public Post(String title, String author, Instant posted) {
+ this.title = title;
+ this.author = author;
+ this.posted = posted;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public Instant getPosted() {
+ return posted;
+ }
+
+ public void setPosted(Instant posted) {
+ this.posted = posted;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append("title", title).append("author", author).append("posted", posted)
+ .toString();
+ }
+ }
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
+ @JsonQualifier
+ public @interface EpochMillis {
+ }
+
+ public static class EpochMillisAdapter {
+ @ToJson
+ public Long toJson(@EpochMillis Instant input) {
+ return input.toEpochMilli();
+ }
+ @FromJson
+ @EpochMillis
+ public Instant fromJson(Long input) {
+ return Instant.ofEpochMilli(input);
+ }
+
+ }
+}
diff --git a/libraries-3/src/test/java/com/baeldung/moshi/ArrayUnitTest.java b/libraries-3/src/test/java/com/baeldung/moshi/ArrayUnitTest.java
new file mode 100644
index 0000000000..83bb2bb128
--- /dev/null
+++ b/libraries-3/src/test/java/com/baeldung/moshi/ArrayUnitTest.java
@@ -0,0 +1,36 @@
+package com.baeldung.moshi;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.List;
+
+import com.squareup.moshi.JsonAdapter;
+import com.squareup.moshi.Moshi;
+import com.squareup.moshi.Types;
+import org.junit.Test;
+
+public class ArrayUnitTest {
+ @Test
+ public void whenSerializingList_thenJsonArrayProduced() {
+ Moshi moshi = new Moshi.Builder()
+ .build();
+ Type type = Types.newParameterizedType(List.class, String.class);
+ JsonAdapter> jsonAdapter = moshi.adapter(type);
+
+ String json = jsonAdapter.toJson(Arrays.asList("One", "Two", "Three"));
+ System.out.println(json);
+ }
+
+ @Test
+ public void whenDeserializingJsonArray_thenListProduced() throws IOException {
+ Moshi moshi = new Moshi.Builder()
+ .build();
+ Type type = Types.newParameterizedType(List.class, String.class);
+ JsonAdapter> jsonAdapter = moshi.adapter(type);
+
+ String json = "[\"One\",\"Two\",\"Three\"]";
+ List result = jsonAdapter.fromJson(json);
+ System.out.println(result);
+ }
+}
diff --git a/libraries-3/src/test/java/com/baeldung/moshi/ComplexAdapterUnitTest.java b/libraries-3/src/test/java/com/baeldung/moshi/ComplexAdapterUnitTest.java
new file mode 100644
index 0000000000..f0f8e9a95d
--- /dev/null
+++ b/libraries-3/src/test/java/com/baeldung/moshi/ComplexAdapterUnitTest.java
@@ -0,0 +1,94 @@
+package com.baeldung.moshi;
+
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import com.squareup.moshi.FromJson;
+import com.squareup.moshi.JsonAdapter;
+import com.squareup.moshi.Moshi;
+import com.squareup.moshi.ToJson;
+import org.junit.Test;
+
+public class ComplexAdapterUnitTest {
+ @Test
+ public void whenSerializing_thenCorrectJsonProduced() {
+ Moshi moshi = new Moshi.Builder()
+ .add(new JsonDateTimeAdapter())
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(ZonedDateTime.class);
+
+ String json = jsonAdapter.toJson(ZonedDateTime.now());
+ System.out.println(json);
+ }
+
+ @Test
+ public void whenDeserializing_thenCorrectJsonConsumed() throws IOException {
+ Moshi moshi = new Moshi.Builder()
+ .add(new JsonDateTimeAdapter())
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(ZonedDateTime.class);
+
+ String json = "{\"date\":\"2020-02-17\",\"time\":\"07:53:27.064\",\"timezone\":\"Europe/London\"}";
+ ZonedDateTime now = jsonAdapter.fromJson(json);
+ System.out.println(now);
+
+ }
+
+ public static class JsonDateTimeAdapter {
+ @ToJson
+ public JsonDateTime toJson(ZonedDateTime input) {
+ String date = input.toLocalDate().toString();
+ String time = input.toLocalTime().toString();
+ String timezone = input.getZone().toString();
+ return new JsonDateTime(date, time, timezone);
+ }
+ @FromJson
+ public ZonedDateTime fromJson(JsonDateTime input) {
+ LocalDate date = LocalDate.parse(input.getDate());
+ LocalTime time = LocalTime.parse(input.getTime());
+ ZoneId timezone = ZoneId.of(input.getTimezone());
+ return ZonedDateTime.of(date, time, timezone);
+ }
+ }
+ public static class JsonDateTime {
+ private String date;
+ private String time;
+ private String timezone;
+
+ public JsonDateTime() {
+ }
+
+ public JsonDateTime(String date, String time, String timezone) {
+ this.date = date;
+ this.time = time;
+ this.timezone = timezone;
+ }
+
+ public String getDate() {
+ return date;
+ }
+
+ public void setDate(String date) {
+ this.date = date;
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public void setTime(String time) {
+ this.time = time;
+ }
+
+ public String getTimezone() {
+ return timezone;
+ }
+
+ public void setTimezone(String timezone) {
+ this.timezone = timezone;
+ }
+ }
+}
diff --git a/libraries-3/src/test/java/com/baeldung/moshi/DefaultUnitTest.java b/libraries-3/src/test/java/com/baeldung/moshi/DefaultUnitTest.java
new file mode 100644
index 0000000000..0b4ecc23a5
--- /dev/null
+++ b/libraries-3/src/test/java/com/baeldung/moshi/DefaultUnitTest.java
@@ -0,0 +1,68 @@
+package com.baeldung.moshi;
+
+import java.io.IOException;
+import java.time.Instant;
+
+import com.squareup.moshi.JsonAdapter;
+import com.squareup.moshi.Moshi;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.junit.Test;
+
+public class DefaultUnitTest {
+
+ @Test
+ public void whenDeserializing_thenFieldsGetDefaultValues() throws IOException {
+ Moshi moshi = new Moshi.Builder()
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ String json = "{\"title\":\"My Post\"}";
+ Post post = jsonAdapter.fromJson(json);
+ System.out.println(post);
+ }
+ public static class Post {
+ private String title;
+ private String author;
+ private String posted;
+
+ public Post() {
+ posted = Instant.now().toString();
+ }
+
+ public Post(String title, String author, String posted) {
+ this.title = title;
+ this.author = author;
+ this.posted = posted;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getPosted() {
+ return posted;
+ }
+
+ public void setPosted(String posted) {
+ this.posted = posted;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append("title", title).append("author", author).append("posted", posted)
+ .toString();
+ }
+ }
+}
diff --git a/libraries-3/src/test/java/com/baeldung/moshi/PrimitiveUnitTest.java b/libraries-3/src/test/java/com/baeldung/moshi/PrimitiveUnitTest.java
new file mode 100644
index 0000000000..e26e93ba8c
--- /dev/null
+++ b/libraries-3/src/test/java/com/baeldung/moshi/PrimitiveUnitTest.java
@@ -0,0 +1,77 @@
+package com.baeldung.moshi;
+
+import java.io.IOException;
+
+import com.squareup.moshi.JsonAdapter;
+import com.squareup.moshi.Moshi;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.junit.Test;
+
+public class PrimitiveUnitTest {
+ @Test
+ public void whenSerializing_thenCorrectJsonProduced() {
+ Moshi moshi = new Moshi.Builder()
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ Post post = new Post("My Post", "Baeldung", "This is my post");
+ String json = jsonAdapter.toJson(post);
+ System.out.println(json);
+ }
+
+ @Test
+ public void whenDeserializing_thenCorrectJsonConsumed() throws IOException {
+ Moshi moshi = new Moshi.Builder()
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ String json = "{\"author\":\"Baeldung\",\"text\":\"This is my post\",\"title\":\"My Post\"}";
+ Post post = jsonAdapter.fromJson(json);
+ System.out.println(post);
+ }
+
+ public static class Post {
+ private String title;
+ private String author;
+ private String text;
+
+ public Post() {
+ }
+
+ public Post(String title, String author, String text) {
+ this.title = title;
+ this.author = author;
+ this.text = text;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append("title", title).append("author", author).append("text", text)
+ .toString();
+ }
+ }
+}
diff --git a/libraries-3/src/test/java/com/baeldung/moshi/RenameUnitTest.java b/libraries-3/src/test/java/com/baeldung/moshi/RenameUnitTest.java
new file mode 100644
index 0000000000..2118538a19
--- /dev/null
+++ b/libraries-3/src/test/java/com/baeldung/moshi/RenameUnitTest.java
@@ -0,0 +1,68 @@
+package com.baeldung.moshi;
+
+import java.io.IOException;
+
+import com.squareup.moshi.Json;
+import com.squareup.moshi.JsonAdapter;
+import com.squareup.moshi.Moshi;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.junit.jupiter.api.Test;
+
+public class RenameUnitTest {
+
+ @Test
+ public void whenSerializing_thenFieldsGetRenamed() {
+ Moshi moshi = new Moshi.Builder()
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ Post post = new Post("My Post", "Baeldung");
+ String json = jsonAdapter.toJson(post);
+ System.out.println(json);
+ }
+
+ @Test
+ public void whenSerializing_thenRenamedFieldsGetConsumed() throws IOException {
+ Moshi moshi = new Moshi.Builder()
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ String json = "{\"authored_by\":\"Baeldung\",\"title\":\"My Post\"}";
+ Post post = jsonAdapter.fromJson(json);
+ System.out.println(post);
+ }
+ public static class Post {
+ private String title;
+ @Json(name = "authored_by")
+ private String author;
+
+ public Post() {
+ }
+
+ public Post(String title, String author) {
+ this.title = title;
+ this.author = author;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append("title", title).append("author", author).toString();
+ }
+ }
+}
diff --git a/libraries-3/src/test/java/com/baeldung/moshi/SimpleAdapterUnitTest.java b/libraries-3/src/test/java/com/baeldung/moshi/SimpleAdapterUnitTest.java
new file mode 100644
index 0000000000..e0be2f8a66
--- /dev/null
+++ b/libraries-3/src/test/java/com/baeldung/moshi/SimpleAdapterUnitTest.java
@@ -0,0 +1,129 @@
+package com.baeldung.moshi;
+
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.squareup.moshi.FromJson;
+import com.squareup.moshi.JsonAdapter;
+import com.squareup.moshi.Moshi;
+import com.squareup.moshi.ToJson;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.junit.Test;
+
+public class SimpleAdapterUnitTest {
+ @Test
+ public void whenSerializing_thenAdapterUsed() {
+ Moshi moshi = new Moshi.Builder()
+ .add(new AuthorAdapter())
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ Post post = new Post("My Post", new Author("Baeldung", "baeldung@example.com"), "This is my post");
+ String json = jsonAdapter.toJson(post);
+ System.out.println(json);
+ }
+
+ @Test
+ public void whenDeserializing_thenAdapterUsed() throws IOException {
+ Moshi moshi = new Moshi.Builder()
+ .add(new AuthorAdapter())
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ String json = "{\"author\":\"Baeldung \",\"text\":\"This is my post\",\"title\":\"My Post\"}";
+ Post post = jsonAdapter.fromJson(json);
+ System.out.println(post);
+ }
+ public static class AuthorAdapter {
+ private Pattern pattern = Pattern.compile("^(.*) <(.*)>$");
+ @ToJson
+ public String toJson(Author author) {
+ return author.name + " <" + author.email + ">";
+ }
+
+ @FromJson
+ public Author fromJson(String author) {
+ Matcher matcher = pattern.matcher(author);
+ return matcher.find() ? new Author(matcher.group(1), matcher.group(2)) : null;
+ }
+ }
+
+ public static class Author {
+ private String name;
+ private String email;
+
+ public Author() {
+ }
+
+ public Author(String name, String email) {
+ this.name = name;
+ this.email = email;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append("name", name).append("email", email).toString();
+ }
+ }
+ public static class Post {
+ private String title;
+ private Author author;
+ private String text;
+
+ public Post() {
+ }
+
+ public Post(String title, Author author, String text) {
+ this.title = title;
+ this.author = author;
+ this.text = text;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public Author getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(Author author) {
+ this.author = author;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append("title", title).append("author", author).append("text", text)
+ .toString();
+ }
+ }
+}
diff --git a/libraries-3/src/test/java/com/baeldung/moshi/TransientUnitTest.java b/libraries-3/src/test/java/com/baeldung/moshi/TransientUnitTest.java
new file mode 100644
index 0000000000..2554e937b3
--- /dev/null
+++ b/libraries-3/src/test/java/com/baeldung/moshi/TransientUnitTest.java
@@ -0,0 +1,66 @@
+package com.baeldung.moshi;
+
+import java.io.IOException;
+
+import com.squareup.moshi.JsonAdapter;
+import com.squareup.moshi.Moshi;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.junit.jupiter.api.Test;
+
+public class TransientUnitTest {
+
+ @Test
+ public void whenSerializing_thenTransientFieldIgnored() {
+ Moshi moshi = new Moshi.Builder()
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ Post post = new Post("My Post", "Baeldung");
+ String json = jsonAdapter.toJson(post);
+ System.out.println(json);
+ }
+
+ @Test
+ public void whenDeserializing_thenTransientFieldIgnored() throws IOException {
+ Moshi moshi = new Moshi.Builder()
+ .build();
+ JsonAdapter jsonAdapter = moshi.adapter(Post.class);
+
+ String json = "{\"authored_by\":\"Baeldung\",\"title\":\"My Post\"}";
+ Post post = jsonAdapter.fromJson(json);
+ System.out.println(post);
+ }
+ public static class Post {
+ private String title;
+ private transient String author;
+
+ public Post() {
+ }
+
+ public Post(String title, String author) {
+ this.title = title;
+ this.author = author;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append("title", title).append("author", author).toString();
+ }
+ }
+}