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