001package io.avaje.jsonb;
002
003import io.avaje.jsonb.core.DefaultBootstrap;
004import io.avaje.jsonb.spi.AdapterFactory;
005import io.avaje.jsonb.spi.Bootstrap;
006import io.avaje.jsonb.spi.JsonStreamAdapter;
007import io.avaje.jsonb.spi.PropertyNames;
008
009import java.io.InputStream;
010import java.io.OutputStream;
011import java.io.Reader;
012import java.io.Writer;
013import java.lang.reflect.Type;
014import java.util.Iterator;
015import java.util.ServiceLoader;
016
017/**
018 * Provides access to json adapters by type.
019 *
020 * <h4>Initialise with defaults</h3>
021 *
022 * <pre>{@code
023 *   Jsonb jsonb = Jsonb.builder().build();
024 * }</pre>
025 *
026 * <h4>Initialise with some configuration</h3>
027 *
028 * <pre>{@code
029 *   Jsonb jsonb = Jsonb.builder()
030 *     .serializeNulls(true)
031 *     .serializeEmpty(true)
032 *     .failOnUnknown(true)
033 *     .build();
034 * }</pre>
035 *
036 * <h4>Initialise using Jackson core with configuration</h3>
037 * <p>
038 * We need to include the dependency <code>io.avaje:avaje-jsonb-jackson</code> to do this.
039 * This will use Jackson core JsonParser and JsonGenerator to do the underlying parsing and generation.
040 * </p>
041 * <pre>{@code
042 *
043 *   // create the Jackson JsonFactory
044 *   JsonFactory customFactory = ...;
045 *
046 *   var jacksonAdapter = JacksonAdapter.builder()
047 *     .serializeNulls(true)
048 *     .jsonFactory(customFactory)
049 *     .build();
050 *
051 *   Jsonb jsonb = Jsonb.builder()
052 *     .adapter(jacksonAdapter)
053 *     .build();
054 *
055 * }</pre>
056 *
057 * <h4>fromJson</h4>
058 * <p>
059 * Read json content from: String, byte[], Reader, InputStream, JsonReader
060 * </p>
061 * <pre>{@code
062 *
063 *  JsonType<Customer> customerType = jsonb.type(Customer.class);
064 *
065 *  Customer customer = customerType.fromJson(content);
066 *
067 * }</pre>
068 *
069 * <h4>toJson</h4>
070 * <p>
071 * Write json content to: String, byte[], Writer, OutputStream, JsonWriter
072 * </p>
073 * <pre>{@code
074 *
075 *  JsonType<Customer> customerType = jsonb.type(Customer.class);
076 *
077 *  String asJson = customerType.toJson(customer);
078 *
079 * }</pre>
080 */
081public interface Jsonb {
082
083  /**
084   * Create a new Jsonb.Builder to configure and build the Jsonb instance.
085   * <p>
086   * We can register JsonAdapter's to use for specific types before building and returning
087   * the Jsonb instance to use.
088   * <p>
089   * Note that JsonAdapter's that are generated are automatically registered via service
090   * loading so there is no need to explicitly register those generated JsonAdapters.
091   *
092   * <pre>{@code
093   *
094   *   Jsonb jsonb = Jsonb.builder()
095   *     .serializeNulls(true)
096   *     .serializeEmpty(true)
097   *     .failOnUnknown(true)
098   *     .build();
099   *
100   * }</pre>
101   */
102  static Builder builder() {
103    Iterator<Bootstrap> bootstrapService = ServiceLoader.load(Bootstrap.class).iterator();
104    if (bootstrapService.hasNext()) {
105      return bootstrapService.next().builder();
106    }
107    return DefaultBootstrap.builder();
108  }
109
110  /**
111   * Migrate to builder().
112   */
113  @Deprecated
114  static Builder newBuilder() {
115    return builder();
116  }
117
118  /**
119   * Return json content for the given object.
120   * <p>
121   * This is a convenience method for {@code jsonb.type(Object.class).toJson(any) }
122   *
123   * @param any The object to return as json string
124   * @return Return json content for the given object.
125   */
126  String toJson(Object any);
127
128  /**
129   * Return json content in pretty format for the given object.
130   * <p>
131   * This is a convenience method for {@code jsonb.type(Object.class).toJsonPretty(any) }
132   *
133   * @param any The object to return as json string in pretty format
134   * @return Return json content in pretty format for the given object.
135   */
136  String toJsonPretty(Object any);
137
138  /**
139   * Return the value as json content in bytes form.
140   * <p>
141   * This is a convenience method for {@code jsonb.type(Object.class).toJsonBytes(any) }
142   */
143  byte[] toJsonBytes(Object any);
144
145  /**
146   * Write to the given writer.
147   * <p>
148   * This is a convenience method for {@code jsonb.type(Object.class).toJson(any, writer) }
149   */
150  void toJson(Object any, Writer writer);
151
152  /**
153   * Write to the given outputStream.
154   * <p>
155   * This is a convenience method for {@code jsonb.type(Object.class).toJsonBytes(any, outputStream) }
156   */
157  void toJson(Object any, OutputStream outputStream);
158
159  /**
160   * Write to the given writer.
161   * <p>
162   * This is a convenience method for {@code jsonb.type(Object.class).toJson(any, writer) }
163   */
164  void toJson(Object any, JsonWriter jsonWriter);
165
166  /**
167   * Return the JsonType used to read and write json for the given class.
168   *
169   * <h3>fromJson() example</h3>
170   * <pre>{@code
171   *
172   *   Customer customer = jsonb
173   *     .type(Customer.class)
174   *     .fromJson(jsonContent);
175   *
176   *
177   *   // list
178   *   List<Customer> customers = jsonb
179   *     .type(Customer.class)
180   *     .list()
181   *     .fromJson(jsonContent);
182   *
183   * }</pre>
184   *
185   * <h3>toJson() example</h3>
186   * <pre>{@code
187   *
188   *   Customer customer = ...
189   *
190   *   String jsonContent = jsonb
191   *     .type(Customer.class)
192   *     .toJson(customer);
193   *
194   * }</pre>
195   *
196   * <h3>Using Object.class</h3>
197   * <p>
198   * We can use <code>type(Object.class)</code> when we don't know the specific type that is being
199   * written toJson or read fromJson.
200   * <p>
201   *
202   * <h3>Object toJson()</h3>
203   * <pre>{@code
204   *
205   *   Object any = ...
206   *
207   *   String jsonContent = jsonb
208   *     .type(Object.class)
209   *     .toJson(any);
210   *
211   *   // the same as
212   *   String jsonContent = jsonb.toJson(any);
213   *
214   * }</pre>
215   * <p>
216   * When using <code>Object.class</code> and writing <code>toJson()</code> then the underlying JsonAdapter
217   * is determined dynamically based on the type of the object value passed in.
218   * <p>
219   * When using <code>Object.class</code> and reading <code>fromJson()</code> then the java types used in
220   * the result are determined dynamically based on the json types being read and the resulting java types
221   * are ArrayList, LinkedHashMap, String, boolean, and double.
222   */
223  <T> JsonType<T> type(Class<T> cls);
224
225  /**
226   * Return the JsonType used to read and write json for the given type.
227   * <p>
228   * We can use {@link Types} to obtain common generic types for List, Set, Map, Array etc.
229   *
230   * <h3>Example</h3>
231   * <pre>{@code
232   *
233   *   JsonType<List<String>> listOfStringType = jsonb.type(Types.listOf(String.class))
234   *
235   *   JsonType<List<Customer>> listOfCustomerType = jsonb.type(Types.listOf(Customer.class))
236   *
237   *   JsonType<Map<String,Integer>> adapter = jsonb.type(Types.mapOf(Integer.class))
238   *
239   * }</pre>
240   *
241   * <h3>Using Object.class</h3>
242   * <p>
243   * We can use <code>type(Object.class)</code> when we don't know the specific type that is being
244   * written toJson or read fromJson.
245   *
246   * <h3>Object toJson()</h3>
247   * <pre>{@code
248   *
249   *   Object any = ...
250   *
251   *   String jsonContent = jsonb
252   *     .type(Object.class)
253   *     .toJson(any);
254   *
255   *   // the same as
256   *   String jsonContent = jsonb.toJson(any);
257   *
258   * }</pre>
259   * <p>
260   * When using <code>Object.class</code> and writing <code>toJson()</code> then the underlying JsonAdapter
261   * is determined dynamically based on the type of the object value passed in.
262   * <p>
263   * When using <code>Object.class</code> and reading <code>fromJson()</code> then the java types used in
264   * the result are determined dynamically based on the json types being read and the resulting java types
265   * are ArrayList, LinkedHashMap, String, boolean, and double.
266   */
267  <T> JsonType<T> type(Type type);
268
269  /**
270   * Return the JsonType for the given value using the class of the value being passed in.
271   * <p>
272   * This is a helper method that supports returning an inferred generic type.
273   *
274   * @param value The value of the given type
275   * @param <T>   The inferred generic parameter type
276   * @return JsonType for the given value
277   */
278  <T> JsonType<T> typeOf(Object value);
279
280  /**
281   * Return the JsonReader used to read the given json content.
282   */
283  JsonReader reader(String json);
284
285  /**
286   * Return the JsonReader used to read the given json content in bytes.
287   */
288  JsonReader reader(byte[] jsonBytes);
289
290  /**
291   * Return the JsonReader used to read the json content from the given reader.
292   */
293  JsonReader reader(Reader reader);
294
295  /**
296   * Return the JsonReader used to read the json content from the given inputStream.
297   */
298  JsonReader reader(InputStream inputStream);
299
300  /**
301   * Return the JsonWriter used to write json to the given writer.
302   */
303  JsonWriter writer(Writer writer);
304
305  /**
306   * Return the JsonWriter used to write json to the given outputStream.
307   */
308  JsonWriter writer(OutputStream outputStream);
309
310  /**
311   * Return the property names as PropertyNames.
312   * <p>
313   * Provides the option of optimising the writing of json for property names
314   * by having them already escaped and encoded rather than as plain strings.
315   */
316  PropertyNames properties(String... names);
317
318  /**
319   * Return the JsonAdapter used to read and write json for the given class.
320   * <p>
321   * JsonAdapter is generally used by generated code and your application code
322   * is expected to use {@link Jsonb#type(Class)} and {@link JsonType} instead.
323   */
324  <T> JsonAdapter<T> adapter(Class<T> cls);
325
326  /**
327   * Return the JsonAdapter used to read and write json for the given type.
328   * <p>
329   * JsonAdapter is generally used by generated code and your application code
330   * is expected to use {@link Jsonb#type(Type)} and {@link JsonType} instead.
331   */
332  <T> JsonAdapter<T> adapter(Type type);
333
334  /**
335   * Raw JsonAdapter for raw json content.
336   */
337  JsonAdapter<String> rawAdapter();
338
339  /**
340   * Build the Jsonb instance adding JsonAdapter, Factory or AdapterBuilder.
341   */
342  interface Builder {
343
344    /**
345     * Set to serialise null values or not.
346     * <p>
347     * Default is to not serialise nulls.
348     */
349    Builder serializeNulls(boolean serializeNulls);
350
351    /**
352     * Set to serialise empty collections or not.
353     * <p>
354     * Default is to not serialise empty collections.
355     */
356    Builder serializeEmpty(boolean serializeEmpty);
357
358    /**
359     * Set failOnUnknown to true such that an exception is thrown when unknown
360     * properties are read in the json content.
361     */
362    Builder failOnUnknown(boolean failOnUnknown);
363
364    /**
365     * Set to true for BigDecimal and BigInteger to serialise as String values rather than number values.
366     */
367    Builder mathTypesAsString(boolean mathTypesAsString);
368
369    /**
370     * Explicitly set the adapter to use.
371     * <p>
372     * When not set the JsonStreamAdapter is service loaded using {@link AdapterFactory}
373     * with a fallback default of using the builtin implementation.
374     *
375     * @param streamAdapter The underlying adapter to use when generating and parsing
376     */
377    Builder adapter(JsonStreamAdapter streamAdapter);
378
379    /**
380     * Add a JsonAdapter to use for the given type.
381     */
382    <T> Builder add(Type type, JsonAdapter<T> jsonAdapter);
383
384    /**
385     * Add a AdapterBuilder which provides a JsonAdapter to use for the given type.
386     */
387    Builder add(Type type, AdapterBuilder builder);
388
389    /**
390     * Add a Component which can provide multiple JsonAdapters and or configuration.
391     */
392    Builder add(Jsonb.Component component);
393
394    /**
395     * Add a JsonAdapter.Factory which provides JsonAdapters to use.
396     */
397    Builder add(JsonAdapter.Factory factory);
398
399    /**
400     * Build and return the Jsonb instance with all the given adapters and factories registered.
401     */
402    Jsonb build();
403  }
404
405  /**
406   * Function to build a JsonAdapter that needs Jsonb.
407   */
408  @FunctionalInterface
409  interface AdapterBuilder {
410
411    /**
412     * Create a JsonAdapter given the Jsonb instance.
413     */
414    JsonAdapter<?> build(Jsonb jsonb);
415  }
416
417  /**
418   * Components register JsonAdapters Jsonb.Builder
419   */
420  @FunctionalInterface
421  interface Component {
422
423    /**
424     * Register JsonAdapters with the Builder.
425     */
426    void register(Builder builder);
427  }
428}