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   *   Object anything = ...
189   *   String jsonContent = jsonb.toJson(anything);
190   *
191   *   Customer customer = ...
192   *
193   *   // any type toJson()
194   *   String jsonContent = jsonb.toJson(customer);
195   *
196   *   // or use .type(Customer.class) if we like
197   *   String jsonContent = jsonb
198   *     .type(Customer.class)
199   *     .toJson(customer);
200   *
201   * }</pre>
202   *
203   * <h3>Using Object.class</h3>
204   * <p>
205   * We can use <code>type(Object.class)</code> when we don't know the specific type that is being
206   * written toJson or read fromJson.
207   * <p>
208   *
209   * <h3>Object toJson()</h3>
210   * <pre>{@code
211   *
212   *   Object any = ...
213   *
214   *   String jsonContent = jsonb
215   *     .type(Object.class)
216   *     .toJson(any);
217   *
218   *   // which is the same as
219   *   String jsonContent = jsonb.toJson(any);
220   *
221   * }</pre>
222   * <p>
223   * When using <code>Object.class</code> and writing <code>toJson()</code> then the underlying JsonAdapter
224   * is determined dynamically based on the type of the object value passed in.
225   * <p>
226   * When using <code>Object.class</code> and reading <code>fromJson()</code> then the java types used in
227   * the result are determined dynamically based on the json types being read and the resulting java types
228   * are ArrayList, LinkedHashMap, String, boolean, and double.
229   */
230  <T> JsonType<T> type(Class<T> cls);
231
232  /**
233   * Return the JsonType used to read and write json for the given type.
234   * <p>
235   * We can use {@link Types} to obtain common generic types for List, Set, Map, Array etc.
236   *
237   * <h3>Example</h3>
238   * <pre>{@code
239   *
240   *   JsonType<List<String>> listOfStringType = jsonb.type(Types.listOf(String.class))
241   *
242   *   JsonType<List<Customer>> listOfCustomerType = jsonb.type(Types.listOf(Customer.class))
243   *
244   *   JsonType<Map<String,Integer>> adapter = jsonb.type(Types.mapOf(Integer.class))
245   *
246   * }</pre>
247   *
248   * <h3>Using Object.class</h3>
249   * <p>
250   * We can use <code>type(Object.class)</code> when we don't know the specific type that is being
251   * written toJson or read fromJson.
252   *
253   * <h3>Object toJson()</h3>
254   * <pre>{@code
255   *
256   *   Object any = ...
257   *
258   *   String jsonContent = jsonb
259   *     .type(Object.class)
260   *     .toJson(any);
261   *
262   *   // the same as
263   *   String jsonContent = jsonb.toJson(any);
264   *
265   * }</pre>
266   * <p>
267   * When using <code>Object.class</code> and writing <code>toJson()</code> then the underlying JsonAdapter
268   * is determined dynamically based on the type of the object value passed in.
269   * <p>
270   * When using <code>Object.class</code> and reading <code>fromJson()</code> then the java types used in
271   * the result are determined dynamically based on the json types being read and the resulting java types
272   * are ArrayList, LinkedHashMap, String, boolean, and double.
273   */
274  <T> JsonType<T> type(Type type);
275
276  /**
277   * Return the JsonType for the given value using the class of the value being passed in.
278   * <p>
279   * This is a helper method that supports returning an inferred generic type.
280   *
281   * @param value The value of the given type
282   * @param <T>   The inferred generic parameter type
283   * @return JsonType for the given value
284   */
285  <T> JsonType<T> typeOf(Object value);
286
287  /**
288   * Return the JsonReader used to read the given json content.
289   */
290  JsonReader reader(String json);
291
292  /**
293   * Return the JsonReader used to read the given json content in bytes.
294   */
295  JsonReader reader(byte[] jsonBytes);
296
297  /**
298   * Return the JsonReader used to read the json content from the given reader.
299   */
300  JsonReader reader(Reader reader);
301
302  /**
303   * Return the JsonReader used to read the json content from the given inputStream.
304   */
305  JsonReader reader(InputStream inputStream);
306
307  /**
308   * Return the JsonWriter used to write json to the given writer.
309   */
310  JsonWriter writer(Writer writer);
311
312  /**
313   * Return the JsonWriter used to write json to the given outputStream.
314   */
315  JsonWriter writer(OutputStream outputStream);
316
317  /**
318   * Return the property names as PropertyNames.
319   * <p>
320   * Provides the option of optimising the writing of json for property names
321   * by having them already escaped and encoded rather than as plain strings.
322   */
323  PropertyNames properties(String... names);
324
325  /**
326   * Return the JsonAdapter used to read and write json for the given class.
327   * <p>
328   * JsonAdapter is generally used by generated code and your application code
329   * is expected to use {@link Jsonb#type(Class)} and {@link JsonType} instead.
330   */
331  <T> JsonAdapter<T> adapter(Class<T> cls);
332
333  /**
334   * Return the JsonAdapter used to read and write json for the given type.
335   * <p>
336   * JsonAdapter is generally used by generated code and your application code
337   * is expected to use {@link Jsonb#type(Type)} and {@link JsonType} instead.
338   */
339  <T> JsonAdapter<T> adapter(Type type);
340
341  /**
342   * Raw JsonAdapter for raw json content.
343   */
344  JsonAdapter<String> rawAdapter();
345
346  /**
347   * Build the Jsonb instance adding JsonAdapter, Factory or AdapterBuilder.
348   */
349  interface Builder {
350
351    /**
352     * Set to serialise null values or not.
353     * <p>
354     * Default is to not serialise nulls.
355     */
356    Builder serializeNulls(boolean serializeNulls);
357
358    /**
359     * Set to serialise empty collections or not.
360     * <p>
361     * Default is to not serialise empty collections.
362     */
363    Builder serializeEmpty(boolean serializeEmpty);
364
365    /**
366     * Set failOnUnknown to true such that an exception is thrown when unknown
367     * properties are read in the json content.
368     */
369    Builder failOnUnknown(boolean failOnUnknown);
370
371    /**
372     * Set to true for BigDecimal and BigInteger to serialise as String values rather than number values.
373     */
374    Builder mathTypesAsString(boolean mathTypesAsString);
375
376    /**
377     * Explicitly set the adapter to use.
378     * <p>
379     * When not set the JsonStreamAdapter is service loaded using {@link AdapterFactory}
380     * with a fallback default of using the builtin implementation.
381     *
382     * @param streamAdapter The underlying adapter to use when generating and parsing
383     */
384    Builder adapter(JsonStreamAdapter streamAdapter);
385
386    /**
387     * Add a JsonAdapter to use for the given type.
388     */
389    <T> Builder add(Type type, JsonAdapter<T> jsonAdapter);
390
391    /**
392     * Add a AdapterBuilder which provides a JsonAdapter to use for the given type.
393     */
394    Builder add(Type type, AdapterBuilder builder);
395
396    /**
397     * Add a Component which can provide multiple JsonAdapters and or configuration.
398     */
399    Builder add(JsonbComponent component);
400
401    /**
402     * Add a JsonAdapter.Factory which provides JsonAdapters to use.
403     */
404    Builder add(JsonAdapter.Factory factory);
405
406    /**
407     * Build and return the Jsonb instance with all the given adapters and factories registered.
408     */
409    Jsonb build();
410  }
411
412  /**
413   * Function to build a JsonAdapter that needs Jsonb.
414   */
415  @FunctionalInterface
416  interface AdapterBuilder {
417
418    /**
419     * Create a JsonAdapter given the Jsonb instance.
420     */
421    JsonAdapter<?> build(Jsonb jsonb);
422  }
423
424  /**
425   * Components register JsonAdapters Jsonb.Builder
426   */
427  @FunctionalInterface
428  interface GeneratedComponent extends JsonbComponent {
429
430    /**
431     * Register JsonAdapters with the Builder.
432     */
433    void register(Builder builder);
434  }
435}