1818 */
1919package org .jooby .json ;
2020
21- import static com .google .common .base .Preconditions .checkNotNull ;
2221import static java .util .Objects .requireNonNull ;
2322
2423import java .text .SimpleDateFormat ;
25- import java .util .LinkedHashSet ;
24+ import java .util .ArrayList ;
25+ import java .util .List ;
2626import java .util .Locale ;
27+ import java .util .Optional ;
2728import java .util .Set ;
2829import java .util .TimeZone ;
2930import java .util .function .Consumer ;
4748import 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 * {
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 * {
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
0 commit comments