Skip to content

Commit b0145ad

Browse files
committed
Adds support for JSON-B (JSR 367) using yasson as the implementation.
There was a previous similar addition for jooby 1 that was not included in jooby 2: jooby-project#1248 https://jooby.io/v1/doc/yasson/
1 parent d0ee044 commit b0145ad

File tree

8 files changed

+357
-0
lines changed

8 files changed

+357
-0
lines changed

docs/asciidoc/modules/modules.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Available modules are listed next.
3535
=== JSON
3636
* link:/modules/gson[Gson]: Gson module for Jooby.
3737
* link:/modules/jackson[Jackson]: Jackson module for Jooby.
38+
* link:/modules/yasson[JSON-B]: JSON-B module for Jooby.
3839

3940
=== OpenAPI
4041
* link:/modules/openapi[OpenAPI]: OpenAPI supports.

docs/asciidoc/modules/yasson.adoc

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
== JSON-B
2+
3+
JSON support using https://github.com/eclipse-ee4j/jsonb-api[Jakarta JSON Binding (JSON-B)] api and https://github.com/eclipse-ee4j/yasson[Yasson] implementation.
4+
5+
=== Usage
6+
7+
1) Add the dependency:
8+
9+
[dependency, artifactId="jooby-yasson"]
10+
.
11+
12+
2) Install and encode/decode JSON
13+
14+
.Java
15+
[source, java, role="primary"]
16+
----
17+
import io.jooby.json.YassonModule;
18+
19+
{
20+
install(new YassonModule()); <1>
21+
22+
get("/", ctx -> {
23+
MyObject myObject = ...;
24+
return myObject; <2>
25+
});
26+
27+
post("/", ctx -> {
28+
MyObject myObject = ctx.body(MyObject.class); <3>
29+
...
30+
});
31+
}
32+
----
33+
34+
.Kotlin
35+
[source, kt, role="secondary"]
36+
----
37+
import io.jooby.json.YassonModule
38+
39+
{
40+
install(YassonModule()) <1>
41+
42+
get("/") {
43+
val myObject = ...;
44+
myObject <2>
45+
}
46+
47+
post("/") {
48+
val myObject = ctx.body<MyObject>() <3>
49+
...
50+
}
51+
}
52+
----
53+
54+
<1> Install JSON-B Yasson Module
55+
<2> Use JSON-B to encode arbitrary object as JSON
56+
<3> Use JSON-B to decode JSON to Java object. Client must specify the `Content-Type: application/json` header
57+
58+
=== Working with JSON-B
59+
60+
Access to default object mapper is available via require call:
61+
62+
.Default object mapper
63+
[source, java, role="primary"]
64+
----
65+
import io.jooby.json.YassonModule;
66+
67+
{
68+
install(new YassonModule());
69+
70+
Jsonb jsonb = require(Jsonb.class);
71+
72+
...
73+
}
74+
----
75+
76+
.Kotlin
77+
[source, kt, role="secondary"]
78+
----
79+
import io.jooby.json.YassonModule
80+
81+
{
82+
install(YassonModule())
83+
84+
val mapper = require<Jsonb>()
85+
}
86+
----
87+
88+
You can provide your own `Jsonb`:
89+
90+
.Custom ObjectMapper
91+
[source, java, role="primary"]
92+
----
93+
import io.jooby.json.YassonModule;
94+
95+
{
96+
Jsonb jsonb = JsonbBuilder.create();
97+
98+
install(new YassonModule(jsonb));
99+
}
100+
----
101+
102+
.Kotlin
103+
[source, kt, role="secondary"]
104+
----
105+
import io.jooby.json.YassonModule
106+
107+
{
108+
val jsonb = JsonbBuilder.create()
109+
110+
install(YassonModule(jsonb))
111+
}
112+
----

modules/jooby-bom/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,12 @@
186186
<version>${jooby.version}</version>
187187
<type>jar</type>
188188
</dependency>
189+
<dependency>
190+
<groupId>io.jooby</groupId>
191+
<artifactId>jooby-yasson</artifactId>
192+
<version>${jooby.version}</version>
193+
<type>jar</type>
194+
</dependency>
189195
<dependency>
190196
<groupId>io.jooby</groupId>
191197
<artifactId>jooby-openapi</artifactId>

modules/jooby-yasson/pom.xml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
6+
<parent>
7+
<groupId>io.jooby</groupId>
8+
<artifactId>modules</artifactId>
9+
<version>2.10.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<modelVersion>4.0.0</modelVersion>
13+
<artifactId>jooby-yasson</artifactId>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>io.jooby</groupId>
18+
<artifactId>jooby</artifactId>
19+
<version>${jooby.version}</version>
20+
</dependency>
21+
22+
<dependency>
23+
<groupId>jakarta.json.bind</groupId>
24+
<artifactId>jakarta.json.bind-api</artifactId>
25+
<scope>compile</scope>
26+
</dependency>
27+
28+
<dependency>
29+
<groupId>org.eclipse</groupId>
30+
<artifactId>yasson</artifactId>
31+
<scope>runtime</scope>
32+
</dependency>
33+
34+
<!-- Test dependencies -->
35+
<dependency>
36+
<groupId>org.junit.jupiter</groupId>
37+
<artifactId>junit-jupiter-engine</artifactId>
38+
<scope>test</scope>
39+
</dependency>
40+
41+
<dependency>
42+
<groupId>org.jacoco</groupId>
43+
<artifactId>org.jacoco.agent</artifactId>
44+
<classifier>runtime</classifier>
45+
<scope>test</scope>
46+
</dependency>
47+
48+
<dependency>
49+
<groupId>org.mockito</groupId>
50+
<artifactId>mockito-core</artifactId>
51+
<scope>test</scope>
52+
</dependency>
53+
</dependencies>
54+
</project>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package io.jooby.json;
2+
3+
import static java.nio.charset.StandardCharsets.UTF_8;
4+
5+
import io.jooby.Body;
6+
import io.jooby.Context;
7+
import io.jooby.Extension;
8+
import io.jooby.Jooby;
9+
import io.jooby.MediaType;
10+
import io.jooby.MessageDecoder;
11+
import io.jooby.MessageEncoder;
12+
import io.jooby.ServiceRegistry;
13+
14+
import java.io.IOException;
15+
import java.io.InputStream;
16+
import java.io.InputStreamReader;
17+
import java.lang.reflect.Type;
18+
import javax.annotation.Nonnull;
19+
import javax.annotation.Nullable;
20+
import javax.json.bind.Jsonb;
21+
import javax.json.bind.JsonbBuilder;
22+
23+
/**
24+
* JSON module using JSON-B: https://github.com/eclipse-ee4j/jsonb-api.
25+
*
26+
* Usage:
27+
*
28+
* <pre>{@code
29+
* {
30+
*
31+
* install(new YassonModule());
32+
*
33+
* get("/", ctx -> {
34+
* MyObject myObject = ...;
35+
* // send json
36+
* return myObject;
37+
* });
38+
*
39+
* post("/", ctx -> {
40+
* // read json
41+
* MyObject myObject = ctx.body(MyObject.class);
42+
* // send json
43+
* return myObject;
44+
* });
45+
* }
46+
* }</pre>
47+
*
48+
* For body decoding the client must specify the <code>Content-Type</code> header set to
49+
* <code>application/json</code>.
50+
*
51+
* You can retrieve the {@link Jsonb} object via require call:
52+
*
53+
* <pre>{@code
54+
* {
55+
*
56+
* Jsonb jsonb = require(Jsonb.class);
57+
*
58+
* }
59+
* }</pre>
60+
*
61+
* Complete documentation is available at: https://jooby.io/modules/jsonb.
62+
*
63+
*/
64+
public class YassonModule implements Extension, MessageDecoder, MessageEncoder {
65+
66+
private final Jsonb jsonb;
67+
68+
/**
69+
* Creates a new Jsonb module.
70+
*/
71+
public YassonModule() {
72+
jsonb = JsonbBuilder.create();
73+
}
74+
75+
/**
76+
* Creates a new module and use a Jsonb instance.
77+
*
78+
* @param jsonb Jsonb to use.
79+
*/
80+
public YassonModule(@Nonnull final Jsonb jsonb) {
81+
this.jsonb = jsonb;
82+
}
83+
84+
@Override
85+
public void install(@Nonnull final Jooby application) throws Exception {
86+
application.decoder(MediaType.json, this);
87+
application.encoder(MediaType.json, this);
88+
89+
ServiceRegistry services = application.getServices();
90+
services.put(Jsonb.class, jsonb);
91+
}
92+
93+
@Nonnull
94+
@Override
95+
public Object decode(
96+
@Nonnull final Context ctx,
97+
@Nonnull final Type type) throws IOException {
98+
99+
Body body = ctx.body();
100+
try (InputStream stream = body.stream()) {
101+
return jsonb.fromJson(new InputStreamReader(stream), type);
102+
}
103+
}
104+
105+
@Nullable
106+
@Override
107+
public byte[] encode(
108+
@Nonnull final Context ctx,
109+
@Nonnull final Object value) {
110+
ctx.setDefaultResponseType(MediaType.json);
111+
return jsonb.toJson(value).getBytes(UTF_8);
112+
}
113+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package io.jooby.json;
2+
3+
import io.jooby.Body;
4+
import io.jooby.Context;
5+
import io.jooby.MediaType;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.io.ByteArrayInputStream;
9+
import java.io.IOException;
10+
import java.nio.charset.StandardCharsets;
11+
12+
import static org.junit.jupiter.api.Assertions.assertEquals;
13+
import static org.mockito.Mockito.mock;
14+
import static org.mockito.Mockito.verify;
15+
import static org.mockito.Mockito.when;
16+
17+
public class YassonModuleTest {
18+
19+
public static class User {
20+
public long id;
21+
public String name;
22+
public int age;
23+
}
24+
25+
@Test
26+
public void render() {
27+
28+
YassonModule YassonModule = new YassonModule();
29+
User user = new User();
30+
user.id = -1;
31+
user.name = "Lorem €@!?";
32+
user.age = Integer.MAX_VALUE;
33+
34+
Context ctx = mock(Context.class);
35+
byte[] bytes = YassonModule.encode(ctx, user);
36+
assertEquals("{\"age\":2147483647,\"id\":-1,\"name\":\"Lorem €@!?\"}", new String(bytes, StandardCharsets.UTF_8));
37+
38+
verify(ctx).setDefaultResponseType(MediaType.json);
39+
}
40+
41+
@Test
42+
public void parse() throws IOException {
43+
byte[] bytes = "{\"age\":2147483647,\"id\":-1,\"name\":\"Lorem €@!?\"}".getBytes(StandardCharsets.UTF_8);
44+
Body body = mock(Body.class);
45+
when(body.stream()).thenReturn(new ByteArrayInputStream(bytes));
46+
47+
Context ctx = mock(Context.class);
48+
when(ctx.body()).thenReturn(body);
49+
50+
YassonModule YassonModule = new YassonModule();
51+
52+
User user = (User) YassonModule.decode(ctx, User.class);
53+
54+
assertEquals(-1, user.id);
55+
assertEquals(Integer.MAX_VALUE, user.age);
56+
assertEquals("Lorem €@!?", user.name);
57+
}
58+
}

modules/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
<module>jooby-jackson</module>
4545
<module>jooby-gson</module>
46+
<module>jooby-yasson</module>
4647
<module>jooby-graphql</module>
4748
<module>jooby-graphiql</module>
4849
<module>jooby-graphql-playground</module>

pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,18 @@
573573
<version>${gson.version}</version>
574574
</dependency>
575575

576+
<dependency>
577+
<groupId>jakarta.json.bind</groupId>
578+
<artifactId>jakarta.json.bind-api</artifactId>
579+
<version>1.0.2</version>
580+
</dependency>
581+
582+
<dependency>
583+
<groupId>org.eclipse</groupId>
584+
<artifactId>yasson</artifactId>
585+
<version>1.0.9</version>
586+
</dependency>
587+
576588
<!-- Jackson 2.x -->
577589
<dependency>
578590
<groupId>com.fasterxml.jackson.core</groupId>

0 commit comments

Comments
 (0)