Skip to content

Commit 5638a55

Browse files
committed
improve doc+advanced usage of jackson module
1 parent 836333a commit 5638a55

5 files changed

Lines changed: 186 additions & 36 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.jooby.jackson;
2+
3+
import java.io.IOException;
4+
5+
import org.jooby.json.Jackson;
6+
import org.jooby.test.ServerFeature;
7+
import org.junit.Test;
8+
9+
import com.fasterxml.jackson.core.JsonGenerator;
10+
import com.fasterxml.jackson.core.JsonProcessingException;
11+
import com.fasterxml.jackson.databind.JsonSerializer;
12+
import com.fasterxml.jackson.databind.SerializerProvider;
13+
import com.fasterxml.jackson.databind.module.SimpleModule;
14+
15+
public class JacksonModuleInstanceFeature extends ServerFeature {
16+
17+
@SuppressWarnings("serial")
18+
public static class Mod extends SimpleModule {
19+
20+
public Mod() {
21+
addSerializer(Integer.class, new JsonSerializer<Integer>() {
22+
23+
@Override
24+
public void serialize(final Integer value, final JsonGenerator gen,
25+
final SerializerProvider serializers) throws IOException, JsonProcessingException {
26+
gen.writeRawValue(Integer.toString(value * 2));
27+
}
28+
29+
});
30+
}
31+
}
32+
33+
{
34+
use(new Jackson().module(new Mod()));
35+
36+
get("/jackson-mod", () -> 2);
37+
}
38+
39+
@Test
40+
public void shouldUseCustomModule() throws Exception {
41+
request().get("/jackson-mod").expect("4");
42+
}
43+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.jooby.jackson;
2+
3+
import java.io.IOException;
4+
5+
import org.jooby.json.Jackson;
6+
import org.jooby.test.ServerFeature;
7+
import org.junit.Test;
8+
9+
import com.fasterxml.jackson.core.JsonGenerator;
10+
import com.fasterxml.jackson.core.JsonProcessingException;
11+
import com.fasterxml.jackson.databind.JsonSerializer;
12+
import com.fasterxml.jackson.databind.SerializerProvider;
13+
import com.fasterxml.jackson.databind.module.SimpleModule;
14+
15+
public class JacksonModuleTypeFeature extends ServerFeature {
16+
17+
@SuppressWarnings("serial")
18+
public static class Mod extends SimpleModule {
19+
20+
public Mod() {
21+
addSerializer(Integer.class, new JsonSerializer<Integer>() {
22+
23+
@Override
24+
public void serialize(final Integer value, final JsonGenerator gen,
25+
final SerializerProvider serializers) throws IOException, JsonProcessingException {
26+
gen.writeRawValue(Integer.toString(value * 2));
27+
}
28+
29+
});
30+
}
31+
}
32+
33+
{
34+
use(new Jackson().module(Mod.class));
35+
36+
get("/jackson-mod", () -> 2);
37+
}
38+
39+
@Test
40+
public void shouldUseCustomModule() throws Exception {
41+
request().get("/jackson-mod").expect("4");
42+
}
43+
}

coverage-report/src/test/java/org/jooby/jackson/JsonCustomStringTypeFeature.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class JsonCustomStringTypeFeature extends ServerFeature {
1717

1818
{
1919

20-
use(new Jackson().types("application/vnd.github.v3+json"));
20+
use(new Jackson().type("application/vnd.github.v3+json"));
2121

2222
get("/members",
2323
req -> Lists.newArrayList(ImmutableMap.<String, Object> of("id", 1, "name", "pablo")));

jooby-jackson/src/main/java/org/jooby/json/Jackson.java

Lines changed: 96 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
*/
1919
package org.jooby.json;
2020

21-
import static com.google.common.base.Preconditions.checkNotNull;
2221
import static java.util.Objects.requireNonNull;
2322

2423
import java.text.SimpleDateFormat;
25-
import java.util.LinkedHashSet;
24+
import java.util.ArrayList;
25+
import java.util.List;
2626
import java.util.Locale;
27+
import java.util.Optional;
2728
import java.util.Set;
2829
import java.util.TimeZone;
2930
import java.util.function.Consumer;
@@ -47,13 +48,15 @@
4748
import com.typesafe.config.Config;
4849

4950
/**
51+
* <h1>jackson</h1>
52+
*
5053
* JSON support from the excellent <a href="https://github.com/FasterXML/jackson">Jackson</a>
5154
* library.
5255
*
5356
* This module provides a JSON {@link Parser} and {@link Renderer}, but also an
5457
* {@link ObjectMapper}.
5558
*
56-
* <h1>usage</h1>
59+
* <h2>usage</h2>
5760
*
5861
* <pre>
5962
* {
@@ -76,8 +79,10 @@
7679
* }
7780
* </pre>
7881
*
79-
* <h1>advanced configuration</h1> If you need a special setting or configuration for your
80-
* {@link ObjectMapper}:
82+
* <h2>advanced configuration</h2>
83+
* <p>
84+
* If you need a special setting or configuration for your {@link ObjectMapper}:
85+
* </p>
8186
*
8287
* <pre>
8388
* {
@@ -101,12 +106,9 @@
101106
* <pre>
102107
* {
103108
*
104-
* use(new Jackson());
105-
*
106-
* use((mode, config, binder) {@literal ->} {
107-
* Multibinder.newSetBinder(binder, Module.class).addBinding()
108-
* .to(MyJacksonModuleWiredByGuice.class);
109-
* });
109+
* use(new Jackson()
110+
* .module(MyJacksonModuleWiredByGuice.class)
111+
* );
110112
* }
111113
* </pre>
112114
*
@@ -126,51 +128,114 @@ public PostConfigurer(final ObjectMapper mapper, final Set<Module> jacksonModule
126128

127129
}
128130

129-
private final ObjectMapper mapper;
130-
131-
private final Set<Module> modules = new LinkedHashSet<>();
131+
private final Optional<ObjectMapper> mapper;
132132

133133
private MediaType type = MediaType.json;
134134

135+
private Consumer<ObjectMapper> configurer;
136+
137+
private List<Consumer<Multibinder<Module>>> modules = new ArrayList<>();
138+
139+
/**
140+
* Creates a new {@link Jackson} module and use the provided {@link ObjectMapper} instance.
141+
*
142+
* @param mapper {@link ObjectMapper} to apply.
143+
*/
135144
public Jackson(final ObjectMapper mapper) {
136-
this.mapper = checkNotNull(mapper, "ObjectMapper is required.");
137-
this.modules.add(new Jdk8Module());
138-
// Java 8 dates
139-
this.modules.add(new JavaTimeModule());
145+
this.mapper = Optional.of(requireNonNull(mapper, "The mapper is required."));
140146
}
141147

148+
/**
149+
* Creates a new {@link Jackson} module.
150+
*/
142151
public Jackson() {
143-
this(new ObjectMapper());
152+
this.mapper = Optional.empty();
144153
}
145154

155+
/**
156+
* Set the json type supported by this module, default is: <code>application/json</code>.
157+
*
158+
* @param type Media type.
159+
* @return This module.
160+
*/
146161
public Jackson type(final MediaType type) {
147162
this.type = type;
148163
return this;
149164
}
150165

151-
public Jackson types(final String type) {
166+
/**
167+
* Set the json type supported by this module, default is: <code>application/json</code>.
168+
*
169+
* @param type Media type.
170+
* @return This module.
171+
*/
172+
public Jackson type(final String type) {
152173
return type(MediaType.valueOf(type));
153174
}
154175

155-
public Jackson doWith(final Consumer<ObjectMapper> block) {
156-
requireNonNull(block, "A json block is required.").accept(mapper);
176+
/**
177+
* Apply advanced configuration over the provided {@link ObjectMapper}.
178+
*
179+
* @param configurer A configurer callback.
180+
* @return This module.
181+
*/
182+
public Jackson doWith(final Consumer<ObjectMapper> configurer) {
183+
this.configurer = requireNonNull(configurer, "ObjectMapper configurer is required.");
184+
return this;
185+
}
186+
187+
/**
188+
* Register the provided module.
189+
*
190+
* @param module A module instance.
191+
* @return This module.
192+
*/
193+
public Jackson module(final Module module) {
194+
requireNonNull(module, "Jackson Module is required.");
195+
modules.add(binder -> binder.addBinding().toInstance(module));
196+
return this;
197+
}
198+
199+
/**
200+
* Register the provided {@link Module}. The module will be instantiated by Guice.
201+
*
202+
* @param module Module type.
203+
* @return This module.
204+
*/
205+
public Jackson module(final Class<? extends Module> module) {
206+
requireNonNull(module, "Jackson Module is required.");
207+
modules.add(binder -> binder.addBinding().to(module));
157208
return this;
158209
}
159210

160211
@Override
161-
public void configure(final Env mode, final Config config, final Binder binder) {
162-
Locale locale = Locale.forLanguageTag(config.getString("application.lang").replace("_", "-"));
163-
// Jackson clone the date format in order to make dateFormat thread-safe
164-
mapper.setDateFormat(new SimpleDateFormat(config.getString("application.dateFormat"), locale));
165-
mapper.setLocale(locale);
166-
mapper.setTimeZone(TimeZone.getTimeZone(config.getString("application.tz")));
212+
public void configure(final Env env, final Config config, final Binder binder) {
213+
// provided or default mapper.
214+
ObjectMapper mapper = this.mapper.orElseGet(() -> {
215+
ObjectMapper m = new ObjectMapper();
216+
Locale locale = env.locale();
217+
// Jackson clone the date format in order to make dateFormat thread-safe
218+
m.setDateFormat(new SimpleDateFormat(config.getString("application.dateFormat"), locale));
219+
m.setLocale(locale);
220+
m.setTimeZone(TimeZone.getTimeZone(config.getString("application.tz")));
221+
return m;
222+
});
167223

168-
// Jackson Modules from Guice
169-
Multibinder<Module> moduleBinder = Multibinder.newSetBinder(binder, Module.class);
170-
modules.forEach(m -> moduleBinder.addBinding().toInstance(m));
224+
// some java 8 modules
225+
mapper.registerModule(new Jdk8Module());
226+
mapper.registerModule(new JavaTimeModule());
171227

228+
if (configurer != null) {
229+
configurer.accept(mapper);
230+
}
231+
232+
// bind mapper
172233
binder.bind(ObjectMapper.class).toInstance(mapper);
173234

235+
// Jackson Modules from Guice
236+
Multibinder<Module> mbinder = Multibinder.newSetBinder(binder, Module.class);
237+
modules.forEach(m -> m.accept(mbinder));
238+
174239
// Jackson Configurer (like a post construct)
175240
binder.bind(PostConfigurer.class).asEagerSingleton();
176241

md/doc/jackson/jackson.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,10 @@ It is possible to wire Jackson modules too:
6464
```java
6565
{
6666

67-
use(new Jackson());
67+
use(new Jackson()
68+
.module(MyJacksonModuleWiredByGuice.class)
69+
);
6870

69-
use((mode, config, binder) -> {
70-
Multibinder.newSetBinder(binder, Module.class).addBinding().to(MyJacksonModuleWiredByGuice.class);
71-
});
7271
}
7372
```
7473

0 commit comments

Comments
 (0)