Class ObjectResolver


  • public class ObjectResolver
    extends Object

    The ObjectResolver converts the raw Maps created from the JsonParser to Java objects (a graph of Java instances). The Maps have an optional type entry associated to them to indicate what Java peer instance to create. The reason type is optional is because it can be inferred in a couple instances. A non-primitive field that points to an object that is of the same type of the field, does not require the '@type' because it can be inferred from the field. This is not always the case. For example, if a Person field points to an Employee object (where Employee is a subclass of Person), then the resolver cannot create an instance of the field type (Person) because this is not the proper type. (It had an Employee record with more fields in this example). In this case, the writer recognizes that the instance type and field type are not the same and therefore it writes the @type.

    A similar case as above occurs with specific array types. If there is a Person[] containing Person and Employee instances, then the Person instances will not have the '@type' but the employee instances will (because they are more derived than Person).

    The resolver 'wires' the original object graph. It does this by replacing '@ref' values in the Maps with pointers (on the field of the associated instance of the Map) to the object that has the same ID. If the object has not yet been read, then an UnresolvedReference is created. These are back-patched at the end of the resolution process. UnresolvedReference keeps track of what field or array element the actual value should be stored within, and then locates the object (by id), and updates the appropriate value.

    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.
    • Constructor Detail

      • ObjectResolver

        protected ObjectResolver​(JsonReader reader,
                                 ClassLoader classLoader)
        Constructor
        Parameters:
        reader - JsonReader instance being used
        classLoader - ClassLoader that was set in the passed in 'options' arguments to JsonReader.
    • Method Detail

      • traverseFields

        public void traverseFields​(Deque<JsonObject<String,​Object>> stack,
                                   JsonObject<String,​Object> jsonObj)
        Walk the Java object fields and copy them from the JSON object to the Java object, performing any necessary conversions on primitives, or deep traversals for field assignments to other objects, arrays, Collections, or Maps.
        Parameters:
        stack - Stack (Deque) used for graph traversal.
        jsonObj - a Map-of-Map representation of the current object being examined (containing all fields).
      • traverseFields

        public void traverseFields​(Deque<JsonObject<String,​Object>> stack,
                                   JsonObject<String,​Object> jsonObj,
                                   Set<String> excludeFields)
        Walk the Java object fields and copy them from the JSON object to the Java object, performing any necessary conversions on primitives, or deep traversals for field assignments to other objects, arrays, Collections, or Maps.
        Parameters:
        stack - Stack (Deque) used for graph traversal.
        jsonObj - a Map-of-Map representation of the current object being examined (containing all fields).
      • assignField

        protected void assignField​(Deque<JsonObject<String,​Object>> stack,
                                   JsonObject jsonObj,
                                   Field field,
                                   Object rhs)
        Map Json Map object field to Java object field.
        Parameters:
        stack - Stack (Deque) used for graph traversal.
        jsonObj - a Map-of-Map representation of the current object being examined (containing all fields).
        field - a Java Field object representing where the jsonObj should be converted and stored.
        rhs - the JSON value that will be converted and stored in the 'field' on the associated Java target object.
      • handleMissingField

        protected void handleMissingField​(Deque<JsonObject<String,​Object>> stack,
                                          JsonObject jsonObj,
                                          Object rhs,
                                          String missingField)
        Try to create a java object from the missing field. Mostly primitive types and jsonObject that contains @type attribute will be candidate for the missing field callback, others will be ignored. All missing field are stored for later notification
        Parameters:
        stack - Stack (Deque) used for graph traversal.
        jsonObj - a Map-of-Map representation of the current object being examined (containing all fields).
        rhs - the JSON value that will be converted and stored in the 'field' on the associated Java target object.
        missingField - name of the missing field in the java object.
      • traverseCollection

        protected void traverseCollection​(Deque<JsonObject<String,​Object>> stack,
                                          JsonObject<String,​Object> jsonObj)
        Process java.util.Collection and it's derivatives. Collections are written specially so that the serialization does not expose the Collection's internal structure, for example, a TreeSet. All entries are processed, except unresolved references, which are filled in later. For an indexable collection, the unresolved references are set back into the proper element location. For non-indexable collections (Sets), the unresolved references are added via .add().
        Parameters:
        jsonObj - a Map-of-Map representation of the JSON input stream.
      • reconcileCollection

        public static void reconcileCollection​(JsonObject jsonObj,
                                               Collection col)
      • traverseArray

        protected void traverseArray​(Deque<JsonObject<String,​Object>> stack,
                                     JsonObject<String,​Object> jsonObj)
        Traverse the JsonObject associated to an array (of any type). Convert and assign the list of items in the JsonObject (stored in the @items field) to each array element. All array elements are processed excluding elements that reference an unresolved object. These are filled in later.
        Parameters:
        stack - a Stack (Deque) used to support graph traversal.
        jsonObj - a Map-of-Map representation of the JSON input stream.
      • readIfMatching

        protected Object readIfMatching​(Object o,
                                        Class compType,
                                        Deque<JsonObject<String,​Object>> stack)
        Convert the passed in object (o) to a proper Java object. If the passed in object (o) has a custom reader associated to it, then have it convert the object. If there is no custom reader, then return null.
        Parameters:
        o - Object to read (convert). Will be either a JsonObject or a JSON primitive String, long, boolean, double, or null.
        compType - Class destination type to which the passed in object should be converted to.
        stack - a Stack (Deque) used to support graph traversal.
        Returns:
        Java object converted from the passed in object o, or if there is no custom reader.
      • getRawType

        public static Class getRawType​(Type t)
        Given the passed in Type t, return the raw type of it, if the passed in value is a ParameterizedType.
        Parameters:
        t - Type to attempt to get raw type from.
        Returns:
        Raw type obtained from the passed in parameterized type or null if T is not a ParameterizedType
      • convertMapsToObjects

        protected Object convertMapsToObjects​(JsonObject<String,​Object> root)
        Walk a JsonObject (Map of String keys to values) and return the Java object equivalent filled in as best as possible (everything except unresolved reference fields or unresolved array/collection elements).
        Parameters:
        root - JsonObject reference to a Map-of-Maps representation of the JSON input after it has been completely read.
        Returns:
        Properly constructed, typed, Java object graph built from a Map of Maps representation (JsonObject root).
      • cleanup

        protected void cleanup()
      • traverseMap

        protected void traverseMap​(Deque<JsonObject<String,​Object>> stack,
                                   JsonObject<String,​Object> jsonObj)
        Process java.util.Map and it's derivatives. These can be written specially so that the serialization would not expose the derivative class internals (internal fields of TreeMap for example).
        Parameters:
        stack - a Stack (Deque) used to support graph traversal.
        jsonObj - a Map-of-Map representation of the JSON input stream.
      • convertMapToKeysItems

        protected static void convertMapToKeysItems​(JsonObject<String,​Object> map)
        Convert an input JsonObject map (known to represent a Map.class or derivative) that has regular keys and values to have its keys placed into @keys, and its values placed into @items.
        Parameters:
        map - Map to convert
      • createJavaObjectInstance

        protected Object createJavaObjectInstance​(Class clazz,
                                                  JsonObject jsonObj)
        This method creates a Java Object instance based on the passed in parameters. If the JsonObject contains a key '@type' then that is used, as the type was explicitly set in the JSON stream. If the key '@type' does not exist, then the passed in Class is used to create the instance, handling creating an Array or regular Object instance.
        The '@type' is not often specified in the JSON input stream, as in many cases it can be inferred from a field reference or array component type.
        Parameters:
        clazz - Instance will be create of this class.
        jsonObj - Map-of-Map representation of object to create.
        Returns:
        a new Java object of the appropriate type (clazz) using the jsonObj to provide enough hints to get the right class instantiated. It is not populated when returned.
      • coerceCertainTypes

        protected Object coerceCertainTypes​(String type)
      • getReferencedObj

        protected JsonObject getReferencedObj​(Long ref)
      • patchUnresolvedReferences

        protected void patchUnresolvedReferences()
        For all fields where the value was "@ref":"n" where 'n' was the id of an object that had not yet been encountered in the stream, make the final substitution.
      • rehashMaps

        protected void rehashMaps()
        Process Maps/Sets (fix up their internal indexing structure) This is required because Maps hash items using hashCode(), which will change between VMs. Rehashing the map fixes this.
        If useMaps==true, then move @keys to keys and @items to values and then drop these two entries from the map.
        This hashes both Sets and Maps because the JDK sets are implemented as Maps. If you have a custom built Set, this would not 'treat' it and you would need to provider a custom reader for that set.
      • notCustom

        protected boolean notCustom​(Class cls)