Package com.cedarsoftware.util.io
Class JsonWriter
- java.lang.Object
-
- com.cedarsoftware.util.io.JsonWriter
-
- All Implemented Interfaces:
Closeable
,Flushable
,AutoCloseable
public class JsonWriter extends Object implements Closeable, Flushable
Output a Java object graph in JSON format. This code handles cyclic references and can serialize any Object graph without requiring a class to be 'Serializeable' or have any specific methods on it.-
Call the static method:
JsonWriter.objectToJson(employee)
. This will convert the passed in 'employee' instance into a JSON String. - Using streams:
JsonWriter writer = new JsonWriter(stream); writer.write(employee); writer.close();
This will write the 'employee' object to the passed in OutputStream.
That's it. This can be used as a debugging tool. Output an object graph using the above code. Use the JsonWriter PRETTY_PRINT option to format the the JSON to be human readable.
This will output any object graph deeply (or null). Object references are properly handled. For example, if you had A->B, B->C, and C->A, then A will be serialized with a B object in it, B will be serialized with a C object in it, and then C will be serialized with a reference to A (ref), not a redefinition of A.
- Author:
- John DeRegnaucourt ([email protected])
Copyright (c) Cedar Software LLC
Licensed 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.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static interface
JsonWriter.JsonClassWriter
Implement this interface to customize the JSON output for a given class.static interface
JsonWriter.JsonClassWriterBase
Deprecated.static interface
JsonWriter.JsonClassWriterEx
Deprecated.
-
Field Summary
Fields Modifier and Type Field Description static String
CLASSLOADER
If set, use the specified ClassLoaderstatic String
CUSTOM_WRITER_MAP
If set, this maps class ==> CustomWriterstatic String
DATE_FORMAT
Set the date format to use within the JSON outputstatic Set<String>
EMPTY_SET
static String
ENUM_PUBLIC_ONLY
If set, indicates that private variables of ENUMs are not to be serializedstatic String
FIELD_NAME_BLACK_LIST
Set value to a Map> which will be used to control which fields on a class are not output. static String
FIELD_SPECIFIERS
Set value to a Map> which will be used to control which fields on a class are output static String
FORCE_MAP_FORMAT_ARRAY_KEYS_ITEMS
If set to true all maps are transferred to the format @keys[],@items[] regardless of the key_typestatic String
ISO_DATE_FORMAT
Constant for use as DATE_FORMAT valuestatic String
ISO_DATE_TIME_FORMAT
Constant for use as DATE_FORMAT valuestatic String
JSON_WRITER
Starting Arguments holds onto JsonWriter for custom writers using this argumentstatic String
NOT_CUSTOM_WRITER_MAP
If set, this maps class ==> CustomWriterstatic String
PRETTY_PRINT
Force nicely formatted JSON outputstatic String
SHORT_META_KEYS
If set, then @type -> @t, @keys -> @k, @items -> @istatic String
SKIP_NULL_FIELDS
If set, null fields are not writtenstatic String
TYPE
Force @type alwaysstatic String
TYPE_NAME_MAP
If set, this map will be used when writing @type values - allows short-hand abbreviations type namesstatic String
WRITE_ENUMS_AS_PRIMITIVE
If set, treats enums as primitives (like most people do) even if they have additional fields extra fields, if they exist, are ignored and will read back in.static String
WRITE_LONGS_AS_STRINGS
If set, longs are written in quotes (Javascript safe)
-
Constructor Summary
Constructors Constructor Description JsonWriter(OutputStream out)
JsonWriter(OutputStream out, Map<String,Object> optionalArgs)
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description void
addNotCustomWriter(Class c)
For no custom writing to occur for the passed in Class.static void
addStaticallyInitializedClasses(Class c)
Adds in Classes that are statically initialized with a possible sun.* class implementation beneath the scenes.void
addWriter(Class c, JsonWriter.JsonClassWriter writer)
Add a custom writer which will manage writing objects of the passed in Class in JSON format.static void
addWriterPermanent(Class c, JsonWriter.JsonClassWriter writer)
Add a permanent Customer Writer (Lifetime of JVM)void
close()
static boolean
ensureJsonPrimitiveKeys(Map map)
Ensure that all keys within the Map are String instancesvoid
flush()
static String
formatJson(String json)
Format the passed in JSON string in a nice, human readable format.static String
formatJson(String json, Map readingArgs, Map writingArgs)
Format the passed in JSON string in a nice, human readable format.Map
getObjectsReferenced()
Provide access to subclasses.Map
getObjectsVisited()
Provide access to subclasses.protected String
getSubstituteTypeName(String typeName)
Used internally to substitute type names.protected String
getSubstituteTypeNameIfExists(String typeName)
Used internally to substitute type names.static boolean
isAllowNanAndInfinity()
void
newLine()
Add newline (\n) to outputstatic String
objectToJson(Object item)
static String
objectToJson(Object item, Map<String,Object> optionalArgs)
Convert a Java Object to a JSON String.static void
setAllowNanAndInfinity(boolean lenient)
Set the writer to be out of RFC 4627: it will accept "NaN", "-Infinity" and "Infinity" values.void
tabIn()
Tab the output left (less indented)void
tabOut()
Tab the output right (more indented)protected void
traceFields(Deque<Object> stack, Object obj, Map<Class,List<Field>> fieldSpecifiers)
Reach-ability trace to visit all objects within the graph to be written.protected void
traceReferences(Object root)
Walk object graph and visit each instance, following each field, each Collection, Map and so on.void
write(Object obj)
Write the passed in Java object in JSON format.boolean
writeArrayElementIfMatching(Class arrayComponentClass, Object o, boolean showType, Writer output)
Write the passed in array element to the JSON output, if any only if, there is a customer writer for the class of the instance 'o'.protected boolean
writeCustom(Class arrayComponentClass, Object o, boolean showType, Writer output)
Perform the actual custom writing for an array element that has a custom writer.void
writeEnumSet(EnumSet<?> enumSet)
boolean
writeIfMatching(Object o, boolean showType, Writer output)
Write the passed in object (o) to the JSON output stream, if and only if, there is a custom writer associated to the Class of object (o).void
writeImpl(Object obj, boolean showType)
Main entry point (mostly used internally, but may be called from a Custom JSON writer).void
writeImpl(Object obj, boolean showType, boolean allowRef, boolean allowCustom)
Main entry point (mostly used internally, but may be called from a Custom JSON writer).static void
writeJsonUtf8String(String s, Writer output)
Write out special characters "\b, \f, \t, \n, \r", as such, backslash as \\ quote as \" and values less than an ASCII space (20hex) as "\\u00xx" format, characters in the range of ASCII space to a '~' as ASCII, and anything higher in UTF-8.void
writeObject(Object obj, boolean showType, boolean bodyOnly)
void
writeObject(Object obj, boolean showType, boolean bodyOnly, Set<String> fieldsToExclude)
-
-
-
Field Detail
-
JSON_WRITER
public static final String JSON_WRITER
Starting Arguments holds onto JsonWriter for custom writers using this argument- See Also:
- Constant Field Values
-
CUSTOM_WRITER_MAP
public static final String CUSTOM_WRITER_MAP
If set, this maps class ==> CustomWriter- See Also:
- Constant Field Values
-
NOT_CUSTOM_WRITER_MAP
public static final String NOT_CUSTOM_WRITER_MAP
If set, this maps class ==> CustomWriter- See Also:
- Constant Field Values
-
DATE_FORMAT
public static final String DATE_FORMAT
Set the date format to use within the JSON output- See Also:
- Constant Field Values
-
ISO_DATE_FORMAT
public static final String ISO_DATE_FORMAT
Constant for use as DATE_FORMAT value- See Also:
- Constant Field Values
-
ISO_DATE_TIME_FORMAT
public static final String ISO_DATE_TIME_FORMAT
Constant for use as DATE_FORMAT value- See Also:
- Constant Field Values
-
TYPE
public static final String TYPE
Force @type always- See Also:
- Constant Field Values
-
PRETTY_PRINT
public static final String PRETTY_PRINT
Force nicely formatted JSON output- See Also:
- Constant Field Values
-
FIELD_SPECIFIERS
public static final String FIELD_SPECIFIERS
Set value to a Map> which will be used to control which fields on a class are output - See Also:
- Constant Field Values
-
FIELD_NAME_BLACK_LIST
public static final String FIELD_NAME_BLACK_LIST
Set value to a Map> which will be used to control which fields on a class are not output. Black list has always priority to FIELD_SPECIFIERS - See Also:
- Constant Field Values
-
ENUM_PUBLIC_ONLY
public static final String ENUM_PUBLIC_ONLY
If set, indicates that private variables of ENUMs are not to be serialized- See Also:
- Constant Field Values
-
WRITE_LONGS_AS_STRINGS
public static final String WRITE_LONGS_AS_STRINGS
If set, longs are written in quotes (Javascript safe)- See Also:
- Constant Field Values
-
TYPE_NAME_MAP
public static final String TYPE_NAME_MAP
If set, this map will be used when writing @type values - allows short-hand abbreviations type names- See Also:
- Constant Field Values
-
SHORT_META_KEYS
public static final String SHORT_META_KEYS
If set, then @type -> @t, @keys -> @k, @items -> @i- See Also:
- Constant Field Values
-
SKIP_NULL_FIELDS
public static final String SKIP_NULL_FIELDS
If set, null fields are not written- See Also:
- Constant Field Values
-
CLASSLOADER
public static final String CLASSLOADER
If set, use the specified ClassLoader- See Also:
- Constant Field Values
-
WRITE_ENUMS_AS_PRIMITIVE
public static final String WRITE_ENUMS_AS_PRIMITIVE
If set, treats enums as primitives (like most people do) even if they have additional fields extra fields, if they exist, are ignored and will read back in.- See Also:
- Constant Field Values
-
FORCE_MAP_FORMAT_ARRAY_KEYS_ITEMS
public static final String FORCE_MAP_FORMAT_ARRAY_KEYS_ITEMS
If set to true all maps are transferred to the format @keys[],@items[] regardless of the key_type- See Also:
- Constant Field Values
-
-
Constructor Detail
-
JsonWriter
public JsonWriter(OutputStream out)
- Parameters:
out
- OutputStream to which the JSON will be written.- See Also:
JsonWriter(OutputStream, Map)
-
JsonWriter
public JsonWriter(OutputStream out, Map<String,Object> optionalArgs)
- Parameters:
out
- OutputStream to which the JSON output will be written.optionalArgs
- (optional) Map of extra arguments indicating how dates are formatted, what fields are written out (optional). For Date parameters, use the public static DATE_TIME key, and then use the ISO_DATE or ISO_DATE_TIME indicators. Or you can specify your own custom SimpleDateFormat String, or you can associate a SimpleDateFormat object, in which case it will be used. This setting is for both java.util.Date and java.sql.Date. If the DATE_FORMAT key is not used, then dates will be formatted as longs. This long can be turned back into a date by using 'new Date(longValue)'.
-
-
Method Detail
-
isAllowNanAndInfinity
public static boolean isAllowNanAndInfinity()
- Returns:
- boolean the allowsNanAndInfinity flag
-
setAllowNanAndInfinity
public static void setAllowNanAndInfinity(boolean lenient)
Set the writer to be out of RFC 4627: it will accept "NaN", "-Infinity" and "Infinity" values.- Parameters:
lenient
- boolean true allows Nan and Inifinity, -Infinity to be used within JSON.
-
getObjectsReferenced
public Map getObjectsReferenced()
Provide access to subclasses.- Returns:
- Map containing all objects that were referenced within input object graph.
-
getObjectsVisited
public Map getObjectsVisited()
Provide access to subclasses.- Returns:
- Map containing all objects that were visited within input object graph
-
getSubstituteTypeNameIfExists
protected String getSubstituteTypeNameIfExists(String typeName)
Used internally to substitute type names. For example, 'java.util.ArrayList, could have a substitute type name of 'alist'. Set substitute type names using the TYPE_NAME_MAP option.- Parameters:
typeName
- String name of type to substitute.- Returns:
- String substituted name, or null if there is no substitute.
-
getSubstituteTypeName
protected String getSubstituteTypeName(String typeName)
Used internally to substitute type names. For example, 'java.util.ArrayList, could have a substitute type name of 'alist'. Set substitute type names using the TYPE_NAME_MAP option.- Parameters:
typeName
- String name of type to substitute.- Returns:
- String substituted type name.
-
objectToJson
public static String objectToJson(Object item)
- Parameters:
item
- Object (root) to serialized to JSON String.- Returns:
- String of JSON format representing complete object graph rooted by item.
- See Also:
objectToJson(Object, java.util.Map)
-
objectToJson
public static String objectToJson(Object item, Map<String,Object> optionalArgs)
Convert a Java Object to a JSON String.- Parameters:
item
- Object to convert to a JSON String.optionalArgs
- (optional) Map of extra arguments indicating how dates are formatted, what fields are written out (optional). For Date parameters, use the public static DATE_TIME key, and then use the ISO_DATE or ISO_DATE_TIME indicators. Or you can specify your own custom SimpleDateFormat String, or you can associate a SimpleDateFormat object, in which case it will be used. This setting is for both java.util.Date and java.sql.Date. If the DATE_FORMAT key is not used, then dates will be formatted as longs. This long can be turned back into a date by using 'new Date(longValue)'.- Returns:
- String containing JSON representation of passed in object root.
-
formatJson
public static String formatJson(String json)
Format the passed in JSON string in a nice, human readable format.- Parameters:
json
- String input JSON- Returns:
- String containing equivalent JSON, formatted nicely for human readability.
-
formatJson
public static String formatJson(String json, Map readingArgs, Map writingArgs)
Format the passed in JSON string in a nice, human readable format.- Parameters:
json
- String input JSONreadingArgs
- (optional) Map of extra arguments for parsing json. Can be null.writingArgs
- (optional) Map of extra arguments for writing out json. Can be null.- Returns:
- String containing equivalent JSON, formatted nicely for human readability.
-
tabIn
public void tabIn() throws IOException
Tab the output left (less indented)- Throws:
IOException
-
newLine
public void newLine() throws IOException
Add newline (\n) to output- Throws:
IOException
-
tabOut
public void tabOut() throws IOException
Tab the output right (more indented)- Throws:
IOException
-
writeIfMatching
public boolean writeIfMatching(Object o, boolean showType, Writer output)
Write the passed in object (o) to the JSON output stream, if and only if, there is a custom writer associated to the Class of object (o).- Parameters:
o
- Object to be (potentially written)showType
- boolean indicating whether or not to show @type.output
- Writer where the actual JSON is being written to.- Returns:
- boolean true if written, false is there is no custom writer for the passed in object.
-
writeArrayElementIfMatching
public boolean writeArrayElementIfMatching(Class arrayComponentClass, Object o, boolean showType, Writer output)
Write the passed in array element to the JSON output, if any only if, there is a customer writer for the class of the instance 'o'.- Parameters:
arrayComponentClass
- Class type of the arrayo
- Object instance to writeshowType
- boolean indicating whether or not @type should be output.output
- Writer to write the JSON to (if there is a custom writer for o's Class).- Returns:
- true if the array element was written, false otherwise.
-
writeCustom
protected boolean writeCustom(Class arrayComponentClass, Object o, boolean showType, Writer output) throws IOException
Perform the actual custom writing for an array element that has a custom writer.- Parameters:
arrayComponentClass
- Class type of the arrayo
- Object instance to writeshowType
- boolean indicating whether or not @type should be output.output
- Writer to write the JSON to (if there is a custom writer for o's Class).- Returns:
- true if the array element was written, false otherwise.
- Throws:
IOException
-
addWriter
public void addWriter(Class c, JsonWriter.JsonClassWriter writer)
Add a custom writer which will manage writing objects of the passed in Class in JSON format. The custom writer will be called for objects of the passed in class, including subclasses. If this is not desired, call addNotCustomWriter(c) which will force objects of the passed in Class to be written by the standard JSON writer.- Parameters:
c
- Class to associate a custom JSON writer toowriter
- JsonClassWriter which implements the appropriate subclass of JsonClassWriter.
-
addWriterPermanent
public static void addWriterPermanent(Class c, JsonWriter.JsonClassWriter writer)
Add a permanent Customer Writer (Lifetime of JVM)- Parameters:
c
- Class to associate a custom JSON writer toowriter
- JsonClassWriter which implements the appropriate subclass of JsonClassWriter.
-
addNotCustomWriter
public void addNotCustomWriter(Class c)
For no custom writing to occur for the passed in Class.- Parameters:
c
- Class which should NOT have any custom writer associated to it. Use this to prevent a custom writer from being used due to inheritance.
-
addStaticallyInitializedClasses
public static void addStaticallyInitializedClasses(Class c)
Adds in Classes that are statically initialized with a possible sun.* class implementation beneath the scenes. These classes will never match their Field declaration and will usually cause the writer to show the @Type. Adding to this class and providing a custom writer and reader gives you the power to eliminate the type in those cases and possibly provide a primitive writer/reader.- Parameters:
c
- Class that has custom writer implementation and will never match declared field.
-
write
public void write(Object obj)
Write the passed in Java object in JSON format.- Parameters:
obj
- Object any Java Object or JsonObject.
-
traceReferences
protected void traceReferences(Object root)
Walk object graph and visit each instance, following each field, each Collection, Map and so on. Tracks visited to handle cycles and to determine if an item is referenced elsewhere. If an object is never referenced more than once, no @id field needs to be emitted for it.- Parameters:
root
- Object to be deeply traced. The objVisited and objsReferenced Maps will be written to during the trace.
-
traceFields
protected void traceFields(Deque<Object> stack, Object obj, Map<Class,List<Field>> fieldSpecifiers)
Reach-ability trace to visit all objects within the graph to be written. This API will handle any object, using either reflection APIs or by consulting a specified FIELD_SPECIFIERS map if provided.- Parameters:
stack
- Deque used to manage descent into graph (rather than using Java stack.) This allows for much larger graph processing.obj
- Object root of graphfieldSpecifiers
- Map of optional field specifiers, which are used to override the field list returned by the JDK reflection operations. This allows a subset of the actual fields on an object to be serialized.
-
writeImpl
public void writeImpl(Object obj, boolean showType) throws IOException
Main entry point (mostly used internally, but may be called from a Custom JSON writer). This method will write out whatever object type it is given, including JsonObject's. It will handle null, detecting if a custom writer should be called, array, array of JsonObject, Map, Map of JsonObjects, Collection, Collection of JsonObject, any regular object, or a JsonObject representing a regular object.- Parameters:
obj
- Object to be writtenshowType
- if set to true, the @type tag will be output. If false, it will be dropped.- Throws:
IOException
- if one occurs on the underlying output stream.
-
writeImpl
public void writeImpl(Object obj, boolean showType, boolean allowRef, boolean allowCustom) throws IOException
Main entry point (mostly used internally, but may be called from a Custom JSON writer). This method will write out whatever object type it is given, including JsonObject's. It will handle null, detecting if a custom writer should be called, array, array of JsonObject, Map, Map of JsonObjects, Collection, Collection of JsonObject, any regular object, or a JsonObject representing a regular object.- Parameters:
obj
- Object to be writtenshowType
- if set to true, the @type tag will be output. If false, it will beallowRef
- if set to true, @ref will be used, otherwise 2+ occurrence will be output as full object.allowCustom
- if set to true, the object being called will allowed to be checked for a matching custom writer to be used. This does not affect subobjects, just the top-level 'obj' being passed in.- Throws:
IOException
- if one occurs on the underlying output stream.
-
ensureJsonPrimitiveKeys
public static boolean ensureJsonPrimitiveKeys(Map map)
Ensure that all keys within the Map are String instances- Parameters:
map
- Map to inspect that all keys are primitive. This allows the output JSON to be optimized into {"key1":value1, "key2": value2} format if all the keys of the Map are Strings. If not, then a Map is written as two arrays, an @keys array and an @items array. This allows support for Maps with non-String keys.
-
writeEnumSet
public void writeEnumSet(EnumSet<?> enumSet) throws IOException
- Throws:
IOException
-
writeObject
public void writeObject(Object obj, boolean showType, boolean bodyOnly) throws IOException
- Parameters:
obj
- Object to be written in JSON formatshowType
- boolean true means show the "@type" field, false eliminates it. Many times the type can be dropped because it can be inferred from the field or array type.bodyOnly
- write only the body of the object- Throws:
IOException
- if an error occurs writing to the output stream.
-
writeObject
public void writeObject(Object obj, boolean showType, boolean bodyOnly, Set<String> fieldsToExclude) throws IOException
- Parameters:
obj
- Object to be written in JSON formatshowType
- boolean true means show the "@type" field, false eliminates it. Many times the type can be dropped because it can be inferred from the field or array type.bodyOnly
- write only the body of the objectfieldsToExclude
- field that should be excluded when writing out object (per class bases for custom writers)- Throws:
IOException
- if an error occurs writing to the output stream.
-
writeJsonUtf8String
public static void writeJsonUtf8String(String s, Writer output) throws IOException
Write out special characters "\b, \f, \t, \n, \r", as such, backslash as \\ quote as \" and values less than an ASCII space (20hex) as "\\u00xx" format, characters in the range of ASCII space to a '~' as ASCII, and anything higher in UTF-8.- Parameters:
s
- String to be written in UTF-8 format on the output stream.output
- Writer to which the UTF-8 string will be written to- Throws:
IOException
- if an error occurs writing to the output stream.
-
close
public void close()
- Specified by:
close
in interfaceAutoCloseable
- Specified by:
close
in interfaceCloseable
-
-