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}