From eec22a8d46bcb89a5eb65af6d994947ee5ded98d Mon Sep 17 00:00:00 2001
From: Josiah Noel <32279667+SentryMan@users.noreply.github.com>
Date: Fri, 19 Apr 2024 14:25:12 -0400
Subject: [PATCH 1/3] adds moshi adapter
---
avaje-http-client-moshi/pom.xml | 37 +++++
.../http/client/moshi/MoshiBodyAdapter.java | 139 ++++++++++++++++++
.../src/main/java/module-info.java | 7 +
.../java/io/avaje/http/client/moshi/Foo.java | 9 ++
.../client/moshi/MoshiBodyAdapterTest.java | 58 ++++++++
.../src/main/java/module-info.java | 4 +-
pom.xml | 1 +
7 files changed, 253 insertions(+), 2 deletions(-)
create mode 100644 avaje-http-client-moshi/pom.xml
create mode 100644 avaje-http-client-moshi/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java
create mode 100644 avaje-http-client-moshi/src/main/java/module-info.java
create mode 100644 avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/Foo.java
create mode 100644 avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java
diff --git a/avaje-http-client-moshi/pom.xml b/avaje-http-client-moshi/pom.xml
new file mode 100644
index 00000000..152e5dca
--- /dev/null
+++ b/avaje-http-client-moshi/pom.xml
@@ -0,0 +1,37 @@
+
+ 4.0.0
+
+ io.avaje
+ avaje-http-parent
+ 2.4
+
+ avaje-http-client-moshi
+
+
+
+
+ com.squareup.moshi
+ moshi
+ 1.15.1
+ true
+
+
+
+ io.avaje
+ avaje-http-client
+ ${project.version}
+ provided
+
+
+
+
+
+ io.avaje
+ junit
+ 1.4
+ test
+
+
+
+
+
\ No newline at end of file
diff --git a/avaje-http-client-moshi/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java b/avaje-http-client-moshi/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java
new file mode 100644
index 00000000..ddd4ea58
--- /dev/null
+++ b/avaje-http-client-moshi/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java
@@ -0,0 +1,139 @@
+package io.avaje.http.client.moshi;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.squareup.moshi.JsonAdapter;
+import com.squareup.moshi.Moshi;
+import com.squareup.moshi.Types;
+
+import io.avaje.http.client.BodyAdapter;
+import io.avaje.http.client.BodyContent;
+import io.avaje.http.client.BodyReader;
+import io.avaje.http.client.BodyWriter;
+
+/**
+ * Moshi BodyAdapter to read and write beans as JSON.
+ *
+ *
{@code
+ * HttpClient.builder()
+ * .baseUrl(baseUrl)
+ * .bodyAdapter(new MoshiBodyAdapter())
+ * .build();
+ *
+ * }
+ */
+public final class MoshiBodyAdapter implements BodyAdapter {
+
+ private final Moshi moshi;
+ private final ConcurrentHashMap> beanWriterCache = new ConcurrentHashMap<>();
+ private final ConcurrentHashMap> beanReaderCache = new ConcurrentHashMap<>();
+ private final ConcurrentHashMap> listReaderCache = new ConcurrentHashMap<>();
+
+ /** Create passing the Moshi to use. */
+ public MoshiBodyAdapter(Moshi moshi) {
+ this.moshi = moshi;
+ }
+
+ /** Create with a default Moshi that allows unknown properties. */
+ public MoshiBodyAdapter() {
+ this(new Moshi.Builder().build());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public BodyWriter beanWriter(Class> cls) {
+ return (BodyWriter)
+ beanWriterCache.computeIfAbsent(cls, aClass -> new JWriter<>(moshi.adapter(cls)));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public BodyWriter beanWriter(Type type) {
+ return (BodyWriter)
+ beanWriterCache.computeIfAbsent(type, aClass -> new JWriter<>(moshi.adapter(type)));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public BodyReader beanReader(Class cls) {
+ return (BodyReader)
+ beanReaderCache.computeIfAbsent(cls, aClass -> new JReader<>(moshi.adapter(cls)));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public BodyReader beanReader(Type type) {
+ return (BodyReader)
+ beanReaderCache.computeIfAbsent(type, aClass -> new JReader<>(moshi.adapter(type)));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public BodyReader> listReader(Type type) {
+
+ return (BodyReader>)
+ listReaderCache.computeIfAbsent(
+ type,
+ aClass -> new JReader<>(moshi.adapter(Types.newParameterizedType(List.class, type))));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public BodyReader> listReader(Class cls) {
+ return (BodyReader>)
+ listReaderCache.computeIfAbsent(
+ cls,
+ aClass -> new JReader<>(moshi.adapter(Types.newParameterizedType(List.class, cls))));
+ }
+
+ private static class JReader implements BodyReader {
+
+ private final JsonAdapter reader;
+
+ JReader(JsonAdapter reader) {
+ this.reader = reader;
+ }
+
+ @Override
+ public T readBody(String content) {
+ try {
+ return reader.fromJson(content);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public T read(BodyContent bodyContent) {
+ try {
+ return reader.fromJson(bodyContent.contentAsUtf8());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static class JWriter implements BodyWriter {
+
+ private final JsonAdapter writer;
+
+ public JWriter(JsonAdapter writer) {
+ this.writer = writer;
+ }
+
+ @Override
+ public BodyContent write(T bean, String contentType) {
+ // ignoring the requested contentType and always
+ // writing the body as json content
+ return write(bean);
+ }
+
+ @Override
+ public BodyContent write(T bean) {
+ return BodyContent.of(writer.toJson(bean));
+ }
+ }
+}
diff --git a/avaje-http-client-moshi/src/main/java/module-info.java b/avaje-http-client-moshi/src/main/java/module-info.java
new file mode 100644
index 00000000..4c68c474
--- /dev/null
+++ b/avaje-http-client-moshi/src/main/java/module-info.java
@@ -0,0 +1,7 @@
+module io.avaje.http.client.gson {
+
+ exports io.avaje.http.client.moshi;
+
+ requires transitive io.avaje.http.client;
+ requires transitive com.squareup.moshi;
+}
diff --git a/avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/Foo.java b/avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/Foo.java
new file mode 100644
index 00000000..ec78ac26
--- /dev/null
+++ b/avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/Foo.java
@@ -0,0 +1,9 @@
+package io.avaje.http.client.moshi;
+
+public class Foo {
+
+ public long id;
+
+ public String name;
+
+}
diff --git a/avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java b/avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java
new file mode 100644
index 00000000..1dcc4649
--- /dev/null
+++ b/avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java
@@ -0,0 +1,58 @@
+package io.avaje.http.client.moshi;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import io.avaje.http.client.BodyContent;
+import io.avaje.http.client.BodyReader;
+import io.avaje.http.client.BodyWriter;
+
+class MoshiBodyAdapterTest {
+
+ private final MoshiBodyAdapter adapter = new MoshiBodyAdapter();
+
+ @Test
+ void beanWriter() {
+
+ final Foo foo = new Foo();
+ foo.id = 42;
+ foo.name = "bar";
+
+ final BodyWriter writer = adapter.beanWriter(Foo.class);
+ final BodyContent content = writer.write(foo);
+
+ final String json = new String(content.content(), StandardCharsets.UTF_8);
+ assertEquals("{\"id\":42,\"name\":\"bar\"}", json);
+ }
+
+ @Test
+ void beanReader() {
+
+ final BodyReader reader = adapter.beanReader(Foo.class);
+
+ final Foo read = reader.read(content("{\"id\":42, \"name\":\"bar\"}"));
+ assertEquals(42, read.id);
+ assertEquals("bar", read.name);
+ }
+
+ @Test
+ void listReader() {
+
+ final BodyReader> reader = adapter.listReader(Foo.class);
+
+ final List read =
+ reader.read(content("[{\"id\":42, \"name\":\"bar\"},{\"id\":43, \"name\":\"baz\"}]"));
+
+ assertEquals(2, read.size());
+ assertEquals(42, read.get(0).id);
+ assertEquals(43, read.get(1).id);
+ }
+
+ BodyContent content(String raw) {
+ return BodyContent.of(raw.getBytes());
+ }
+}
diff --git a/http-client-gson-adapter/src/main/java/module-info.java b/http-client-gson-adapter/src/main/java/module-info.java
index 9933af68..0a9b1f4e 100644
--- a/http-client-gson-adapter/src/main/java/module-info.java
+++ b/http-client-gson-adapter/src/main/java/module-info.java
@@ -2,6 +2,6 @@
exports io.avaje.http.client.gson;
- requires io.avaje.http.client;
- requires com.google.gson;
+ requires transitive io.avaje.http.client;
+ requires transitive com.google.gson;
}
diff --git a/pom.xml b/pom.xml
index 93d149d0..9c58a913 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,6 +44,7 @@
http-generator-javalin
http-generator-jex
http-generator-client
+ avaje-http-client-moshi
From dc1f638e7a258a5083d73dbb22325be475ac8d61 Mon Sep 17 00:00:00 2001
From: Rob Bygrave
Date: Mon, 22 Apr 2024 08:45:40 +1200
Subject: [PATCH 2/3] Move moshi module to be consistent with gson module
---
{avaje-http-client-moshi => http-client-moshi-adapter}/pom.xml | 0
.../main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java | 0
.../src/main/java/module-info.java | 0
.../src/test/java/io/avaje/http/client/moshi/Foo.java | 0
.../java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java | 0
pom.xml | 2 +-
6 files changed, 1 insertion(+), 1 deletion(-)
rename {avaje-http-client-moshi => http-client-moshi-adapter}/pom.xml (100%)
rename {avaje-http-client-moshi => http-client-moshi-adapter}/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java (100%)
rename {avaje-http-client-moshi => http-client-moshi-adapter}/src/main/java/module-info.java (100%)
rename {avaje-http-client-moshi => http-client-moshi-adapter}/src/test/java/io/avaje/http/client/moshi/Foo.java (100%)
rename {avaje-http-client-moshi => http-client-moshi-adapter}/src/test/java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java (100%)
diff --git a/avaje-http-client-moshi/pom.xml b/http-client-moshi-adapter/pom.xml
similarity index 100%
rename from avaje-http-client-moshi/pom.xml
rename to http-client-moshi-adapter/pom.xml
diff --git a/avaje-http-client-moshi/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java b/http-client-moshi-adapter/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java
similarity index 100%
rename from avaje-http-client-moshi/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java
rename to http-client-moshi-adapter/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java
diff --git a/avaje-http-client-moshi/src/main/java/module-info.java b/http-client-moshi-adapter/src/main/java/module-info.java
similarity index 100%
rename from avaje-http-client-moshi/src/main/java/module-info.java
rename to http-client-moshi-adapter/src/main/java/module-info.java
diff --git a/avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/Foo.java b/http-client-moshi-adapter/src/test/java/io/avaje/http/client/moshi/Foo.java
similarity index 100%
rename from avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/Foo.java
rename to http-client-moshi-adapter/src/test/java/io/avaje/http/client/moshi/Foo.java
diff --git a/avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java b/http-client-moshi-adapter/src/test/java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java
similarity index 100%
rename from avaje-http-client-moshi/src/test/java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java
rename to http-client-moshi-adapter/src/test/java/io/avaje/http/client/moshi/MoshiBodyAdapterTest.java
diff --git a/pom.xml b/pom.xml
index 9c58a913..2f73594d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,12 +39,12 @@
http-api-javalin
http-client
http-client-gson-adapter
+ http-client-moshi-adapter
http-inject-plugin
http-generator-core
http-generator-javalin
http-generator-jex
http-generator-client
- avaje-http-client-moshi
From 1ca9ff6b246c4946fe42c9f54e21d3e2404492de Mon Sep 17 00:00:00 2001
From: Rob Bygrave
Date: Mon, 22 Apr 2024 08:48:25 +1200
Subject: [PATCH 3/3] Use UncheckedIOException and format
---
.../http/client/moshi/MoshiBodyAdapter.java | 38 +++++++++----------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/http-client-moshi-adapter/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java b/http-client-moshi-adapter/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java
index ddd4ea58..80e754bc 100644
--- a/http-client-moshi-adapter/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java
+++ b/http-client-moshi-adapter/src/main/java/io/avaje/http/client/moshi/MoshiBodyAdapter.java
@@ -1,6 +1,7 @@
package io.avaje.http.client.moshi;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.lang.reflect.Type;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
@@ -32,12 +33,16 @@ public final class MoshiBodyAdapter implements BodyAdapter {
private final ConcurrentHashMap> beanReaderCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap> listReaderCache = new ConcurrentHashMap<>();
- /** Create passing the Moshi to use. */
+ /**
+ * Create passing the Moshi to use.
+ */
public MoshiBodyAdapter(Moshi moshi) {
this.moshi = moshi;
}
- /** Create with a default Moshi that allows unknown properties. */
+ /**
+ * Create with a default Moshi that allows unknown properties.
+ */
public MoshiBodyAdapter() {
this(new Moshi.Builder().build());
}
@@ -45,48 +50,43 @@ public MoshiBodyAdapter() {
@SuppressWarnings("unchecked")
@Override
public BodyWriter beanWriter(Class> cls) {
- return (BodyWriter)
- beanWriterCache.computeIfAbsent(cls, aClass -> new JWriter<>(moshi.adapter(cls)));
+ return (BodyWriter) beanWriterCache.computeIfAbsent(cls, aClass -> new JWriter<>(moshi.adapter(cls)));
}
@SuppressWarnings("unchecked")
@Override
public BodyWriter beanWriter(Type type) {
- return (BodyWriter)
- beanWriterCache.computeIfAbsent(type, aClass -> new JWriter<>(moshi.adapter(type)));
+ return (BodyWriter) beanWriterCache.computeIfAbsent(type, aClass -> new JWriter<>(moshi.adapter(type)));
}
@SuppressWarnings("unchecked")
@Override
public BodyReader beanReader(Class cls) {
- return (BodyReader)
- beanReaderCache.computeIfAbsent(cls, aClass -> new JReader<>(moshi.adapter(cls)));
+ return (BodyReader) beanReaderCache.computeIfAbsent(cls, aClass -> new JReader<>(moshi.adapter(cls)));
}
@SuppressWarnings("unchecked")
@Override
public BodyReader beanReader(Type type) {
- return (BodyReader)
- beanReaderCache.computeIfAbsent(type, aClass -> new JReader<>(moshi.adapter(type)));
+ return (BodyReader) beanReaderCache.computeIfAbsent(type, aClass -> new JReader<>(moshi.adapter(type)));
}
@SuppressWarnings("unchecked")
@Override
public BodyReader> listReader(Type type) {
-
return (BodyReader>)
- listReaderCache.computeIfAbsent(
- type,
- aClass -> new JReader<>(moshi.adapter(Types.newParameterizedType(List.class, type))));
+ listReaderCache.computeIfAbsent(
+ type,
+ aClass -> new JReader<>(moshi.adapter(Types.newParameterizedType(List.class, type))));
}
@SuppressWarnings("unchecked")
@Override
public BodyReader> listReader(Class cls) {
return (BodyReader>)
- listReaderCache.computeIfAbsent(
- cls,
- aClass -> new JReader<>(moshi.adapter(Types.newParameterizedType(List.class, cls))));
+ listReaderCache.computeIfAbsent(
+ cls,
+ aClass -> new JReader<>(moshi.adapter(Types.newParameterizedType(List.class, cls))));
}
private static class JReader implements BodyReader {
@@ -102,7 +102,7 @@ public T readBody(String content) {
try {
return reader.fromJson(content);
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new UncheckedIOException(e);
}
}
@@ -111,7 +111,7 @@ public T read(BodyContent bodyContent) {
try {
return reader.fromJson(bodyContent.contentAsUtf8());
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new UncheckedIOException(e);
}
}
}