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