blob: 1ba5f273bcd9f8597934015178269af888b7c6de [file]
/*
* Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package jakarta.json.bind;
import jakarta.json.bind.adapter.JsonbAdapter;
import jakarta.json.bind.config.PropertyNamingStrategy;
import jakarta.json.bind.config.PropertyVisibilityStrategy;
import jakarta.json.bind.serializer.JsonbDeserializer;
import jakarta.json.bind.serializer.JsonbSerializer;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
/**
* <p>
* <a id="supportedProps"></a>
* <b>Supported Properties</b><br>
* <blockquote>
* <p>
* All JSON Binding providers are required to support the following set of properties.
* Some providers may support additional properties.
* <dl>
* <dt><code>jsonb.to.json.formatted</code> - java.lang.Boolean
* <dd>Controls whether or not the {@link jakarta.json.bind.Jsonb Jsonb} {@code toJson()}
* methods will format the resulting JSON data with line breaks and indentation. A
* true value for this property indicates human readable indented
* data, while a false value indicates unformatted data.
* Default value is false (unformatted) if this property is not specified.
* </dl>
* <dl>
* <dt><code>jsonb.to.json.encoding</code> - java.lang.String
* <dd>The {@link jakarta.json.bind.Jsonb Jsonb} serialization {@code toJson()} methods
* will default to this property for encoding of output JSON data. Default
* value is 'UTF-8' if this property is not specified.
* </dl>
* <dl>
* <dt><code>jsonb.from.json.encoding</code> - java.lang.String
* <dd>The {@link jakarta.json.bind.Jsonb Jsonb} deserialization {@code fromJson()}
* methods will default to this property encoding of input JSON data if the
* encoding cannot be detected.
* </dl>
* </blockquote>
*
* This object is not thread safe. Implementations are expected to make a defensive copy
* of the object before applying the configuration.
*
* @since JSON Binding 1.0
*/
public class JsonbConfig {
private final Map<String, Object> configuration = new HashMap<>();
/**
* Property used to specify whether or not the serialized
* JSON data is formatted with line feeds and indentation.
*/
public static final String FORMATTING = "jsonb.formatting";
/**
* The Jsonb serialization {@code toJson()} methods will default to this property
* for encoding of output JSON data. Default value is 'UTF-8'.
*
* The Jsonb deserialization {@code fromJson()} methods will default to this
* property encoding of input JSON data if the encoding cannot be detected
* automatically.
*/
public static final String ENCODING = "jsonb.encoding";
/**
* Property used to specify custom naming strategy.
*/
public static final String PROPERTY_NAMING_STRATEGY = "jsonb.property-naming-strategy";
/**
* Property used to specify custom order strategy.
*/
public static final String PROPERTY_ORDER_STRATEGY = "jsonb.property-order-strategy";
/**
* Property used to specify null values serialization behavior.
*/
public static final String NULL_VALUES = "jsonb.null-values";
/**
* Property used to specify strict I-JSON serialization compliance.
*/
public static final String STRICT_IJSON = "jsonb.strict-ijson";
/**
* Property used to specify custom visibility strategy.
*/
public static final String PROPERTY_VISIBILITY_STRATEGY = "jsonb.property-visibility-strategy";
/**
* Property used to specify custom mapping adapters for generic types.
*/
public static final String ADAPTERS = "jsonb.adapters";
/**
* Property used to specify custom serializers.
*/
public static final String SERIALIZERS = "jsonb.serializers";
/**
* Property used to specify custom deserializers.
*/
public static final String DESERIALIZERS = "jsonb.derializers";
/**
* Property used to specify custom binary data strategy.
*/
public static final String BINARY_DATA_STRATEGY = "jsonb.binary-data-strategy";
/**
* Property used to specify custom date format globally.
*/
public static final String DATE_FORMAT = "jsonb.date-format";
/**
* Property used to specify locale globally.
*/
public static final String LOCALE = "jsonb.locale";
/**
* Property used to specify required creator parameters.
*/
public static final String CREATOR_PARAMETERS_REQUIRED = "jsonb.creator-parameters-required";
/**
* Set the particular configuration property to a new value. The method can
* only be used to set one of the standard JSON Binding properties defined in
* this class or a provider specific property.
*
* @param name
* The name of the property to be set. This value can either
* be specified using one of the constant fields or a user supplied
* string.
* @param value
* The value of the property to be set
*
* @return This JsonbConfig instance.
*
* @throws NullPointerException if the name parameter is null.
*/
public final JsonbConfig setProperty(final String name, final Object value) {
configuration.put(name, value);
return this;
}
/**
* Return value of particular configuration property. The method can
* only be used to retrieve one of the standard JSON Binding properties defined
* in this class or a provider specific property. Attempting to get an undefined
* property will result in an empty Optional value.
* See <a href="#supportedProps"> Supported Properties</a>.
*
* @param name
* The name of the property to retrieve
*
* @return The value of the requested property
*
* @throws NullPointerException if the name parameter is null.
*/
public final Optional<Object> getProperty(final String name) {
return Optional.ofNullable(configuration.get(name));
}
/**
* Return all configuration properties as an unmodifiable map.
*
* @return All configuration properties as an unmodifiable map
*/
public final Map<String, Object> getAsMap() {
return Collections.unmodifiableMap(configuration);
}
/**
* Property used to specify whether or not the serialized JSON data is formatted
* with linefeeds and indentation.
*
* Configures value of {@link #FORMATTING} property.
*
* @param formatted
* True means serialized data is formatted, false (default)
* means no formatting.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withFormatting(final Boolean formatted) {
return setProperty(FORMATTING, formatted);
}
/**
* Property used to specify whether null values should be serialized to JSON document or skipped.
*
* Configures value of {@link #NULL_VALUES} property.
*
* @param serializeNullValues
* True means that null values will be serialized into JSON document,
* otherwise they will be effectively skipped.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withNullValues(final Boolean serializeNullValues) {
return setProperty(NULL_VALUES, serializeNullValues);
}
/**
* The binding operations will default to this property
* for encoding of JSON data. For input data (fromJson), selected encoding is used if
* the encoding cannot be detected automatically. Default value is 'UTF-8'.
*
* Configures value of {@link #ENCODING} property.
*
* @param encoding
* Valid character encoding as defined in the
* <a href="http://tools.ietf.org/html/rfc7159">RFC 7159</a> and supported by
* Java Platform.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withEncoding(final String encoding) {
return setProperty(ENCODING, encoding);
}
/**
* Property used to specify whether strict I-JSON serialization compliance should be enforced.
*
* Configures value of {@link #STRICT_IJSON} property.
*
* @param enabled
* True means data is serialized in strict compliance according to RFC 7493.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withStrictIJSON(final Boolean enabled) {
return setProperty(STRICT_IJSON, enabled);
}
/**
* Property used to specify custom naming strategy.
*
* Configures value of {@link #PROPERTY_NAMING_STRATEGY} property.
*
* @param propertyNamingStrategy
* Custom naming strategy which affects serialization and deserialization.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withPropertyNamingStrategy(final PropertyNamingStrategy propertyNamingStrategy) {
return setProperty(PROPERTY_NAMING_STRATEGY, propertyNamingStrategy);
}
/**
* Property used to specify custom naming strategy.
*
* Configures value of {@link #PROPERTY_NAMING_STRATEGY} property.
*
* @param propertyNamingStrategy
* Predefined naming strategy which affects serialization and deserialization.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withPropertyNamingStrategy(final String propertyNamingStrategy) {
return setProperty(PROPERTY_NAMING_STRATEGY, propertyNamingStrategy);
}
/**
* Property used to specify property order strategy.
*
* Configures values of {@link #PROPERTY_ORDER_STRATEGY} property.
*
* @param propertyOrderStrategy
* Predefined property order strategy which affects serialization.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withPropertyOrderStrategy(final String propertyOrderStrategy) {
return setProperty(PROPERTY_ORDER_STRATEGY, propertyOrderStrategy);
}
/**
* Property used to specify custom property visibility strategy.
*
* Configures value of {@link #PROPERTY_VISIBILITY_STRATEGY} property.
*
* @param propertyVisibilityStrategy
* Custom property visibility strategy which affects serialization and deserialization.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withPropertyVisibilityStrategy(final PropertyVisibilityStrategy
propertyVisibilityStrategy) {
return setProperty(PROPERTY_VISIBILITY_STRATEGY, propertyVisibilityStrategy);
}
/**
* Property used to specify custom mapping adapters.
*
* Configures value of {@link #ADAPTERS} property.
*
* Calling withAdapters more than once will merge the adapters with previous value.
*
* @param adapters
* Custom mapping adapters which affects serialization and deserialization.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withAdapters(final JsonbAdapter... adapters) {
mergeProperties(ADAPTERS, adapters, JsonbAdapter.class);
return this;
}
/**
* Property used to specify custom serializers.
*
* Configures value of {@link #SERIALIZERS} property.
*
* Calling withSerializers more than once will merge the serializers with previous value.
*
* @param serializers
* Custom serializers which affects serialization.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withSerializers(final JsonbSerializer... serializers) {
mergeProperties(SERIALIZERS, serializers, JsonbSerializer.class);
return this;
}
/**
* Property used to specify custom deserializers.
*
* Configures value of {@link #DESERIALIZERS} property.
*
* Calling withDeserializers more than once will merge the deserializers with previous value.
*
* @param deserializers
* Custom deserializers which affects deserialization.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withDeserializers(final JsonbDeserializer... deserializers) {
mergeProperties(DESERIALIZERS, deserializers, JsonbDeserializer.class);
return this;
}
/**
* Property used to specify custom binary data strategy.
*
* Configures value of {@link #BINARY_DATA_STRATEGY} property.
*
* @param binaryDataStrategy
* Custom binary data strategy which affects serialization and deserialization.
*
* @return This JsonbConfig instance.
*/
public final JsonbConfig withBinaryDataStrategy(final String binaryDataStrategy) {
return setProperty(BINARY_DATA_STRATEGY, binaryDataStrategy);
}
/**
* Property used to specify custom date format. This format will be used by default for all date classes
* serialization and deserialization.
*
* Configures values of {@link #DATE_FORMAT} and {@link #LOCALE} properties.
*
* @param dateFormat
* Custom date format as specified in {@link java.time.format.DateTimeFormatter}.
* @param locale
* Locale, if null is specified {@link Locale#getDefault} will be used.
* @return This JsonbConfig instance.
*/
public final JsonbConfig withDateFormat(final String dateFormat, final Locale locale) {
return setProperty(DATE_FORMAT, dateFormat)
.setProperty(LOCALE, locale != null ? locale : Locale.getDefault());
}
/**
* Property used to specify custom locale.
*
* Configures value of {@link #LOCALE} property.
*
* @param locale
* Locale, must not be null.
* @return This JsonbConfig instance.
*/
public final JsonbConfig withLocale(final Locale locale) {
return setProperty(LOCALE, locale);
}
/**
* Property used to specify whether all creator parameters should be treated as required.
* <br>
* Default value is {@code false}.
*
* @param requiredParameters Whether creator parameters are required
* @return This JsonbConfig instance.
*/
public final JsonbConfig withCreatorParametersRequired(final boolean requiredParameters) {
return setProperty(CREATOR_PARAMETERS_REQUIRED, requiredParameters);
}
@SuppressWarnings("unchecked")
private <T> void mergeProperties(final String propertyKey, final T[] values, final Class<T> tClass) {
final Optional<Object> property = getProperty(propertyKey);
if (!property.isPresent()) {
setProperty(propertyKey, values);
return;
}
T[] storedValues = (T[]) property.get();
T[] newValues = (T[]) Array.newInstance(tClass, storedValues.length + values.length);
System.arraycopy(storedValues, 0, newValues, 0, storedValues.length);
System.arraycopy(values, 0, newValues, storedValues.length, values.length);
setProperty(propertyKey, newValues);
}
}