Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package com.cedarsoftware.io;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;
import com.cedarsoftware.io.JsonReader.MissingFieldHandler;
import com.cedarsoftware.io.reflect.Injector;
import com.cedarsoftware.util.ClassUtilities;
import com.cedarsoftware.util.ClassValueMap;
import com.cedarsoftware.util.CompactCIHashMap;
import com.cedarsoftware.util.CompactCIHashSet;
import com.cedarsoftware.util.CompactCILinkedMap;
import com.cedarsoftware.util.CompactCILinkedSet;
import com.cedarsoftware.util.CompactLinkedMap;
import com.cedarsoftware.util.CompactLinkedSet;
import com.cedarsoftware.util.CompactMap;
import com.cedarsoftware.util.CompactSet;
import com.cedarsoftware.util.ConcurrentList;
import com.cedarsoftware.util.ConcurrentNavigableSetNullSafe;
import com.cedarsoftware.util.ConcurrentSet;
import com.cedarsoftware.util.StringUtilities;
import com.cedarsoftware.util.convert.Converter;
/**
* This class is used to convert a source of Java Maps that were created from
* the JsonParser. These are in 'raw' form with no 'pointers'. This code will
* reconstruct the 'shape' of the graph by connecting @ref's to @ids.
*
* The subclasses that override this class can build an object graph using Java
* classes or a Map-of-Map representation. In both cases, the @ref value will
* be replaced with the Object (or Map) that had the corresponding @id.
*
* @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
*
* 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.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public abstract class Resolver {
private static final String NO_FACTORY = "_︿_ψ_☼";
final Collection unresolvedRefs = new ArrayList<>();
protected final Deque stack = new ArrayDeque<>();
private final Collection mapsToRehash = new ArrayList<>();
// store the missing field found during deserialization to notify any client after the complete resolution is done
final Collection missingFields = new ArrayList<>();
private ReadOptions readOptions;
private ReferenceTracker references;
private final Converter converter;
private SealedSupplier sealedSupplier = new SealedSupplier();
/**
* UnresolvedReference is created to hold a logical pointer to a reference that
* could not yet be loaded, as the @ref appears ahead of the referenced object's
* definition. This can point to a field reference or an array/Collection element reference.
*/
static final class UnresolvedReference {
private final JsonObject referencingObj;
private String field;
private final long refId;
private int index = -1;
UnresolvedReference(JsonObject referrer, String fld, long id) {
referencingObj = referrer;
field = fld;
refId = id;
}
UnresolvedReference(JsonObject referrer, int idx, long id) {
referencingObj = referrer;
index = idx;
refId = id;
}
}
/**
* stores missing fields information to notify client after the complete deserialization resolution
*/
protected static class Missingfields {
private final Object target;
private final String fieldName;
private final Object value;
public Missingfields(Object target, String fieldName, Object value) {
this.target = target;
this.fieldName = fieldName;
this.value = value;
}
}
protected Resolver(ReadOptions readOptions, ReferenceTracker references, Converter converter) {
this.readOptions = readOptions;
this.references = references;
this.converter = converter;
}
public ReadOptions getReadOptions() {
return readOptions;
}
public ReferenceTracker getReferences() {
return references;
}
public Converter getConverter() {
return converter;
}
/**
*
Convert a Parsed JsonObject to a Fully Resolved Java Object
*
*
* This method converts a root-level {@code JsonObject}—a Map-of-Maps representation of parsed JSON—into an actual
* Java object instance. The {@code JsonObject} is typically produced by a prior call to {@code JsonIo.toObjects(String)}
* or {@code JsonIo.toObjects(InputStream)} when using the {@code ReadOptions.returnAsJsonObjects()} setting.
* The conversion process uses the provided root parameter, a {@link java.lang.reflect.Type} that represents
* the expected root type (including any generic type parameters). Although the full type information is preserved for
* resolution, the {@code JsonObject}'s legacy {@code hintType} field (which remains a {@code Class>}) is set using the
* raw class extracted from the provided type.
*
*
*
* The resolution process works as follows:
*
*
*
* Reference Resolution: If the {@code JsonObject} is a reference, it is resolved using the internal
* reference map. If a referenced object is found, it is returned immediately.
*
*
* Already Converted Check: If the {@code JsonObject} has already been fully converted (i.e. its
* {@code isFinished} flag is set), then its target (the converted Java object) is returned.
*
*
* Instance Creation and Traversal: Otherwise, the method sets the hint type on the {@code JsonObject}
* (using the raw class extracted from the provided full {@code Type}), creates a new instance (if necessary),
* and then traverses the object graph to resolve nested references and perform conversions.
*
*
*
*
Parameters
*
*
* rootObj - The root {@code JsonObject} (a Map-of-Maps) representing the parsed JSON data.
*
*
* root - A {@code Type} representing the expected Java type (including full generic details) for the resulting
* object. If {@code null}, type inference defaults to a generic {@code Map} representation.
*
*
*
*
Return Value
*
* Returns a Java object that represents the fully resolved version of the JSON data. Depending on the JSON structure
* and the provided type hint, the result may be a user-defined DTO, a collection, an array, or a primitive value.
*
*
* @param rootObj the root {@code JsonObject} representing parsed JSON data.
* @param rootType a {@code Type} representing the expected Java type (with full generic details) for the root object; may be {@code null}.
* @param the type of the resulting Java object.
* @return a fully resolved Java object representing the JSON data.
*/
@SuppressWarnings("unchecked")
public T toJavaObjects(JsonObject rootObj, Type rootType) {
if (rootObj == null) {
return null;
}
// If the JsonObject is a reference, resolve it.
if (rootObj.isReference()) {
rootObj = getReferences().get(rootObj.refId);
if (rootObj != null) {
return (T) rootObj;
}
}
// If already converted, return its target.
if (rootObj.isFinished) {
return (T) rootObj.getTarget();
} else {
if (rootObj.getType() == null) {
rootObj.setType(rootType);
}
Object instance = (rootObj.getTarget() == null ? createInstance(rootObj) : rootObj.getTarget());
if (rootObj.isFinished) {
return (T) instance;
} else {
return traverseJsonObject(rootObj);
}
}
}
/**
* Walk a JsonObject (Map of String keys to values) and return the
* Java object equivalent filled in as good as possible (everything
* except unresolved reference fields or unresolved array/collection elements).
*
* @param root JsonObject reference to a Map-of-Maps representation of the JSON
* input after it has been completely read.
* @return Properly constructed, typed, Java object graph built from a Map
* of Maps representation (JsonObject root).
*/
public T traverseJsonObject(JsonObject root) {
push(root);
while (!stack.isEmpty()) {
final JsonObject jsonObj = stack.pop();
if (jsonObj.isFinished) {
continue;
}
traverseSpecificType(jsonObj);
}
return (T) root.getTarget();
}
protected void traverseSpecificType(JsonObject jsonObj) {
if (jsonObj.isArray()) {
traverseArray(jsonObj);
} else if (jsonObj.isCollection()) {
traverseCollection(jsonObj);
} else if (jsonObj.isMap()) {
traverseMap(jsonObj);
} else {
traverseObject(jsonObj);
}
}
protected void traverseObject(JsonObject jsonObj) {
if (jsonObj.isFinished) {
return;
}
Object special;
if ((special = readWithFactoryIfExists(jsonObj, null)) != null) {
jsonObj.setTarget(special);
} else {
traverseFields(jsonObj);
}
}
public SealedSupplier getSealedSupplier() {
return sealedSupplier;
}
/**
* Push a JsonObject on the work stack that has not yet had it's fields move over to it's Java peer (.target)
* @param jsonObject JsonObject that supplies the source values for the Java peer (target)
*/
public void push(JsonObject jsonObject) {
stack.push(jsonObject);
}
public abstract void traverseFields(final JsonObject jsonObj);
protected abstract Object readWithFactoryIfExists(final Object o, final Type compType);
protected abstract void traverseCollection(JsonObject jsonObj);
protected abstract void traverseArray(JsonObject jsonObj);
protected void cleanup() {
patchUnresolvedReferences();
rehashMaps();
references.clear();
unresolvedRefs.clear();
mapsToRehash.clear();
handleMissingFields();
missingFields.clear();
stack.clear();
references = null;
readOptions = null;
sealedSupplier.seal();
sealedSupplier = null;
}
// calls the missing field handler if any for each recorded missing field.
private void handleMissingFields() {
MissingFieldHandler missingFieldHandler = readOptions.getMissingFieldHandler();
if (missingFieldHandler != null) {
for (Missingfields mf : missingFields) {
missingFieldHandler.fieldMissing(mf.target, mf.fieldName, mf.value);
}
}//else no handler so ignore.
}
/**
* Process java.util.Map and it's derivatives. These are written specially
* so that the serialization does not expose the class internals
* (internal fields of TreeMap for example).
*
* @param jsonObj a Map-of-Map representation of the JSON input stream.
*/
protected void traverseMap(JsonObject jsonObj) {
if (jsonObj.isFinished) {
return;
}
jsonObj.setFinished();
Map.Entry