org.apache.juneau.json.JsonSerializer Maven / Gradle / Ivy
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
// * with the License. You may obtain a copy of the License at *
// * *
// * http://www.apache.org/licenses/LICENSE-2.0 *
// * *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
package org.apache.juneau.json;
import java.util.*;
import org.apache.juneau.*;
import org.apache.juneau.serializer.*;
/**
* Serializes POJO models to JSON.
*
* Media types:
*
* Handles Accept
types: application/json, text/json
*
* Produces Content-Type
types: application/json
*
*
Description:
*
* The conversion is as follows...
*
* -
* Maps (e.g. {@link HashMap HashMaps}, {@link TreeMap TreeMaps}) are converted to JSON objects.
*
-
* Collections (e.g. {@link HashSet HashSets}, {@link LinkedList LinkedLists}) and Java arrays are converted to
* JSON arrays.
*
-
* {@link String Strings} are converted to JSON strings.
*
-
* {@link Number Numbers} (e.g. {@link Integer}, {@link Long}, {@link Double}) are converted to JSON numbers.
*
-
* {@link Boolean Booleans} are converted to JSON booleans.
*
-
* {@code nulls} are converted to JSON nulls.
*
-
* {@code arrays} are converted to JSON arrays.
*
-
* {@code beans} are converted to JSON objects.
*
*
*
* The types above are considered "JSON-primitive" object types.
* Any non-JSON-primitive object types are transformed into JSON-primitive object types through
* {@link org.apache.juneau.transform.PojoSwap PojoSwaps} associated through the
* {@link CoreObjectBuilder#pojoSwaps(Class...)} method.
* Several default transforms are provided for transforming Dates, Enums, Iterators, etc...
*
*
* This serializer provides several serialization options.
* Typically, one of the predefined DEFAULT serializers will be sufficient.
* However, custom serializers can be constructed to fine-tune behavior.
*
*
Behavior-specific subclasses
*
* The following direct subclasses are provided for convenience:
*
* -
* {@link Simple} - Default serializer, single quotes, simple mode.
*
-
* {@link SimpleReadable} - Default serializer, single quotes, simple mode, with whitespace.
*
*
* Example:
*
* // Use one of the default serializers to serialize a POJO
* String json = JsonSerializer.DEFAULT .serialize(someObject);
*
* // Create a custom serializer for lax syntax using single quote characters
* JsonSerializer serializer = new JsonSerializerBuilder().simple().sq().build();
*
* // Clone an existing serializer and modify it to use single-quotes
* JsonSerializer serializer = JsonSerializer.DEFAULT .builder().sq().build();
*
* // Serialize a POJO to JSON
* String json = serializer.serialize(someObject);
*
*/
public class JsonSerializer extends WriterSerializer {
//-------------------------------------------------------------------------------------------------------------------
// Configurable properties
//-------------------------------------------------------------------------------------------------------------------
private static final String PREFIX = "JsonSerializer.";
/**
* Configuration property: Simple JSON mode.
*
*
* - Name:
"JsonSerializer.simpleMode"
* - Data type:
Boolean
* - Default:
false
* - Session-overridable:
true
*
*
*
* If true , JSON attribute names will only be quoted when necessary.
* Otherwise, they are always quoted.
*/
public static final String JSON_simpleMode = PREFIX + "simpleMode";
/**
* Configuration property: Prefix solidus '/' characters with escapes.
*
*
* - Name:
"JsonSerializer.escapeSolidus"
* - Data type:
Boolean
* - Default:
false
* - Session-overridable:
true
*
*
*
* If true , solidus (e.g. slash) characters should be escaped.
* The JSON specification allows for either format.
* However, if you're embedding JSON in an HTML script tag, this setting prevents confusion when trying to serialize
* <\/script> .
*/
public static final String JSON_escapeSolidus = PREFIX + "escapeSolidus";
/**
* Configuration property: Add "_type" properties when needed.
*
*
* - Name:
"JsonSerializer.addBeanTypeProperties"
* - Data type:
Boolean
* - Default:
false
* - Session-overridable:
true
*
*
*
* If true , then "_type" properties will be added to beans if their type cannot be inferred
* through reflection.
* This is used to recreate the correct objects during parsing if the object types cannot be inferred.
* For example, when serializing a {@code Map} field, where the bean class cannot be determined from
* the value type.
*
*
* When present, this value overrides the {@link #SERIALIZER_addBeanTypeProperties} setting and is
* provided to customize the behavior of specific serializers in a {@link SerializerGroup}.
*/
public static final String JSON_addBeanTypeProperties = PREFIX + "addBeanTypeProperties";
//-------------------------------------------------------------------------------------------------------------------
// Predefined instances
//-------------------------------------------------------------------------------------------------------------------
/** Default serializer, all default settings.*/
public static final JsonSerializer DEFAULT = new JsonSerializer(PropertyStore.create());
/** Default serializer, all default settings.*/
public static final JsonSerializer DEFAULT_READABLE = new Readable(PropertyStore.create());
/** Default serializer, single quotes, simple mode. */
public static final JsonSerializer DEFAULT_LAX = new Simple(PropertyStore.create());
/** Default serializer, single quotes, simple mode, with whitespace. */
public static final JsonSerializer DEFAULT_LAX_READABLE = new SimpleReadable(PropertyStore.create());
/**
* Default serializer, single quotes, simple mode, with whitespace and recursion detection.
* Note that recursion detection introduces a small performance penalty.
*/
public static final JsonSerializer DEFAULT_LAX_READABLE_SAFE = new SimpleReadableSafe(PropertyStore.create());
//-------------------------------------------------------------------------------------------------------------------
// Predefined subclasses
//-------------------------------------------------------------------------------------------------------------------
/** Default serializer, with whitespace. */
public static class Readable extends JsonSerializer {
/**
* Constructor.
*
* @param propertyStore The property store containing all the settings for this object.
*/
public Readable(PropertyStore propertyStore) {
super(
propertyStore.copy()
.append(SERIALIZER_useWhitespace, true)
);
}
}
/** Default serializer, single quotes, simple mode. */
public static class Simple extends JsonSerializer {
/**
* Constructor.
*
* @param propertyStore The property store containing all the settings for this object.
*/
public Simple(PropertyStore propertyStore) {
super(
propertyStore.copy()
.append(JSON_simpleMode, true)
.append(SERIALIZER_quoteChar, '\''),
"application/json",
"application/json+simple", "application/json+simple+*", "text/json+simple", "text/json+simple+*"
);
}
}
/** Default serializer, single quotes, simple mode, with whitespace. */
public static class SimpleReadable extends JsonSerializer {
/**
* Constructor.
*
* @param propertyStore The property store containing all the settings for this object.
*/
public SimpleReadable(PropertyStore propertyStore) {
super(
propertyStore.copy()
.append(JSON_simpleMode, true)
.append(SERIALIZER_quoteChar, '\'')
.append(SERIALIZER_useWhitespace, true)
);
}
}
/**
* Default serializer, single quotes, simple mode, with whitespace and recursion detection.
* Note that recursion detection introduces a small performance penalty.
*/
public static class SimpleReadableSafe extends JsonSerializer {
/**
* Constructor.
*
* @param propertyStore The property store containing all the settings for this object.
*/
public SimpleReadableSafe(PropertyStore propertyStore) {
super(
propertyStore.copy()
.append(JSON_simpleMode, true)
.append(SERIALIZER_quoteChar, '\'')
.append(SERIALIZER_useWhitespace, true)
.append(SERIALIZER_detectRecursions, true)
);
}
}
//-------------------------------------------------------------------------------------------------------------------
// Instance
//-------------------------------------------------------------------------------------------------------------------
final JsonSerializerContext ctx;
private volatile JsonSchemaSerializer schemaSerializer;
/**
* Constructor.
*
* @param propertyStore
* The property store containing all the settings for this object.
*/
public JsonSerializer(PropertyStore propertyStore) {
this(propertyStore, "application/json", "application/json", "application/json+*", "text/json", "text/json+*");
}
/**
* Constructor.
*
* @param propertyStore
* The property store containing all the settings for this object.
* @param produces
* The media type that this serializer produces.
* @param accept
* The accept media types that the serializer can handle.
*
* Can contain meta-characters per the media-type
specification of
* RFC2616/14.1
*
* If empty, then assumes the only media type supported is produces
.
*
* For example, if this serializer produces "application/json" but should handle media types of
* "application/json" and "text/json" , then the arguments should be:
*
super (propertyStore, "application/json" , "application/json" , "text/json" );
*
...or...
*
super (propertyStore, "application/json" , "*/json" );
*/
public JsonSerializer(PropertyStore propertyStore, String produces, String...accept) {
super(propertyStore, produces, accept);
this.ctx = createContext(JsonSerializerContext.class);
}
@Override /* CoreObject */
public JsonSerializerBuilder builder() {
return new JsonSerializerBuilder(propertyStore);
}
/**
* Returns the schema serializer based on the settings of this serializer.
*
* @return The schema serializer.
*/
public JsonSchemaSerializer getSchemaSerializer() {
if (schemaSerializer == null)
schemaSerializer = new JsonSchemaSerializer(propertyStore);
return schemaSerializer;
}
//--------------------------------------------------------------------------------
// Entry point methods
//--------------------------------------------------------------------------------
@Override /* Serializer */
public WriterSerializerSession createSession(SerializerSessionArgs args) {
return new JsonSerializerSession(ctx, args);
}
}