Skip to content

Jdk9 immutable #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<groupId>com.cedarsoftware</groupId>
<artifactId>json-io</artifactId>
<packaging>bundle</packaging>
<version>4.14.0</version>
<version>4.14.1-SNAPSHOT</version>
<description>Java JSON serialization</description>
<url>https://github.com/jdereg/json-io</url>

Expand Down Expand Up @@ -137,8 +137,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>11</source>
<target>11</target>
<!-- <release>1.8</release>-->
<compilerId>groovy-eclipse-compiler</compilerId>
<!-- <verbose>true</verbose> -->
Expand Down
16 changes: 15 additions & 1 deletion src/main/java/com/cedarsoftware/util/io/JsonObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ public class JsonObject<K, V> extends LinkedHashMap<K, V>
primitiveWrappers.add("java.lang.Short");
}

public String toString()
{
return "mLen:" + getLenientSize() + " type:" + type + " l,c:" + line + "," + col + " id:" + id;
}


public long getId()
{
Expand Down Expand Up @@ -234,6 +239,15 @@ public Object[] getArray()

public int getLength()
{
Integer items = getLenientSize();
if (items != null)
{
return items;
}
throw new JsonIoException("getLength() called on a non-collection, line " + line + ", col " + col);
}

private Integer getLenientSize() {
if (isArray())
{
if (target == null)
Expand All @@ -248,7 +262,7 @@ public int getLength()
Object[] items = (Object[]) get(ITEMS);
return items == null ? 0 : items.length;
}
throw new JsonIoException("getLength() called on a non-collection, line " + line + ", col " + col);
return null;
}

public Class getComponentType()
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/cedarsoftware/util/io/JsonReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ public Object getRefTarget(JsonObject jObj)
*/
public Object readObject()
{
JsonParser parser = new JsonParser(input, objsRead, getArgs());
JsonParser parser = new JsonParser(input, objsRead, getArgs(), maxParseDepth);
JsonObject<String, Object> root = new JsonObject();
Object o;
try
Expand Down
16 changes: 14 additions & 2 deletions src/main/java/com/cedarsoftware/util/io/MetaUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,11 @@ public int compare(Constructor c1, Constructor c2)
// Try each constructor (public, protected, private, package-private) with null values for non-primitives.
for (Constructor constructor : constructorList)
{
constructor.setAccessible(true);
try {
constructor.setAccessible(true);
} catch (Exception ignore) {
continue;
}
Class[] argTypes = constructor.getParameterTypes();
Object[] values = fillArgs(argTypes, true);
try
Expand All @@ -641,7 +645,11 @@ public int compare(Constructor c1, Constructor c2)
// Try each constructor (public, protected, private, package-private) with non-null values for non-primitives.
for (Constructor constructor : constructorList)
{
constructor.setAccessible(true);
try {
constructor.setAccessible(true);
} catch (Exception e) {
continue;
}
Class[] argTypes = constructor.getParameterTypes();
Object[] values = fillArgs(argTypes, false);
try
Expand Down Expand Up @@ -809,6 +817,10 @@ else if (argType == Object.class)
{
values[i] = new Object();
}
else if (argType.isArray())
{
values[i] = new Object[0];
}
else
{
values[i] = null;
Expand Down
68 changes: 61 additions & 7 deletions src/main/java/com/cedarsoftware/util/io/ObjectResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.cedarsoftware.util.io.JsonObject.ITEMS;
import static com.cedarsoftware.util.io.JsonObject.KEYS;
Expand Down Expand Up @@ -57,6 +59,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@SuppressWarnings({ "rawtypes", "unchecked", "Convert2Diamond" })
public class ObjectResolver extends Resolver
{
private final ClassLoader classLoader;
Expand Down Expand Up @@ -208,8 +211,8 @@ else if (rhs.getClass().isArray())
}
else if (rhs instanceof JsonObject)
{
final JsonObject<String, Object> jObj = (JsonObject) rhs;
final Long ref = jObj.getReferenceId();
final JsonObject<String, Object> jsRhs = (JsonObject) rhs;
final Long ref = jsRhs.getReferenceId();

if (ref != null)
{ // Correct field references
Expand All @@ -226,10 +229,19 @@ else if (rhs instanceof JsonObject)
}
else
{ // Assign ObjectMap's to Object (or derived) fields
field.set(target, createJavaObjectInstance(fieldType, jObj));
if (!MetaUtils.isLogicalPrimitive(jObj.getTargetClass()))
Object fieldObject = createJavaObjectInstance(fieldType, jsRhs);
field.set(target, fieldObject);
if (!MetaUtils.isLogicalPrimitive(jsRhs.getTargetClass()))
{
stack.addFirst((JsonObject) rhs);
// GOTCHA : if the field is an immutable collection,
// "work instance", where one can accumulate items in (ArrayList)
// and "final instance' (say List.of() ) can _not_ be the same.
// So, the later the assignment, the better.
Object javaObj = convertMapsToObjects(jsRhs);
if (javaObj != fieldObject)
{
field.set(target, javaObj);
}
}
}
}
Expand Down Expand Up @@ -390,12 +402,20 @@ private static String safeToString(Object o)
*/
protected void traverseCollection(final Deque<JsonObject<String, Object>> stack, final JsonObject<String, Object> jsonObj)
{
final String className = jsonObj.type;
final Object[] items = jsonObj.getArray();
if (items == null || items.length == 0)
{
if (className != null && className.startsWith("java.util.Immutable"))
if (className.contains("Set")) {
jsonObj.target = Set.of();
} else if (className.contains("List")) {
jsonObj.target = List.of();
}
return;
}
final Collection col = (Collection) jsonObj.target;
final boolean isImmutable = className != null && className.startsWith("java.util.Immutable");
final Collection col = isImmutable ? new ArrayList() : (Collection) jsonObj.target;
final boolean isList = col instanceof List;
int idx = 0;

Expand Down Expand Up @@ -462,9 +482,43 @@ else if (element.getClass().isArray())
idx++;
}

//if (isImmutable) {
reconciliateCollection(jsonObj, col);
//}

jsonObj.remove(ITEMS); // Reduce memory required during processing
}

static public void reconciliateCollection(JsonObject jsonObj, Collection col)
{
final String className = jsonObj.type;
final boolean isImmutable = className != null && className.startsWith("java.util.Immutable");
if (!isImmutable) return;

if (col == null && jsonObj.target instanceof Collection) col = (Collection) jsonObj.target;
if (col == null) return;

if (className.contains("List"))
{
if (col.stream().noneMatch(c -> c == null || c instanceof JsonObject))
{
jsonObj.target = List.of(col.toArray());
}
else
{
jsonObj.target = col;
}
}
else if (className.contains("Set"))
{
jsonObj.target = Set.of(col.toArray());
}
else
{
jsonObj.target = col;
}
}

/**
* 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)
Expand Down Expand Up @@ -699,7 +753,7 @@ protected Object readIfMatching(final Object o, final Class compType, final Dequ
{
read = ((JsonReader.JsonClassReader)closestReader).read(o, stack);
}
return read;
return read;
}

private void markUntypedObjects(final Type type, final Object rhs, final Map<String, Field> classFields)
Expand Down
36 changes: 32 additions & 4 deletions src/main/java/com/cedarsoftware/util/io/Resolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.*
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
abstract class Resolver
{
final Collection<UnresolvedReference> unresolvedRefs = new ArrayList<>();
Expand Down Expand Up @@ -98,6 +99,7 @@ static final class UnresolvedReference
/**
* stores missing fields information to notify client after the complete deserialization resolution
*/
@SuppressWarnings("FieldMayBeFinal")
protected static class Missingfields
{
private Object target;
Expand Down Expand Up @@ -146,7 +148,7 @@ protected JsonReader getReader()
*/
protected Object convertMapsToObjects(final JsonObject<String, Object> root)
{
final Deque<JsonObject<String, Object>> stack = new ArrayDeque<JsonObject<String, Object>>();
final Deque<JsonObject<String, Object>> stack = new ArrayDeque<>();
stack.addFirst(root);

while (!stack.isEmpty())
Expand Down Expand Up @@ -389,10 +391,18 @@ else if (singletonMap.isAssignableFrom(c))
Object value = jsonObj.values().iterator().next();
mate = Collections.singletonMap(key, value);
}
else
else if (!c.getName().startsWith("java.util.Immutable"))
{
mate = newInstance(c, jsonObj);
}
else if (c.getName().contains("Set"))
{
mate = new ArrayList<>();
}
else if (c.getName().contains("List"))
{
mate = new ArrayList<>();
}
}
}
else
Expand Down Expand Up @@ -577,11 +587,29 @@ protected void patchUnresolvedReferences()
{ // Patch up Indexable Collections
List list = (List) objToFix;
list.set(ref.index, objReferenced.target);
String containingTypeName = ref.referencingObj.type;
if (containingTypeName != null && containingTypeName.startsWith("java.util.Immutable") && containingTypeName.contains("List"))
{
if (list.stream().noneMatch(c -> c == null || c instanceof JsonObject))
{
list = List.of(list.toArray());
ref.referencingObj.target = list;
}
}
}
else if (objToFix instanceof Collection)
{ // Add element (since it was not indexable, add it to collection)
{
String containingTypeName = ref.referencingObj.type;
Collection col = (Collection) objToFix;
col.add(objReferenced.target);
if (containingTypeName != null && containingTypeName.startsWith("java.util.Immutable") && containingTypeName.contains("Set"))
{
throw new JsonIoException("Error setting set entry of ImmutableSet '" + ref.referencingObj.type + "', @ref = " + ref.refId);
}
else
{
// Add element (since it was not indexable, add it to collection)
col.add(objReferenced.target);
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class TestCollection {
private Set _strs_c;
private Set _strs_d;
private HashSet _typedSet;
private List<String> _imm_lst_0;
private List<String> _imm_lst_1;

private void init() {
Collection array = new ArrayList()
Expand Down Expand Up @@ -191,6 +193,10 @@ class TestCollection {
_typedSet.add(true)
_typedSet.add(17.76)
_typedSet.add(TimeZone.getTimeZone("PST"))

_imm_lst_0 = List.of()
_imm_lst_1 = List.of("One")

}
}

Expand Down Expand Up @@ -655,4 +661,4 @@ class TestCollection {
TestUtil.printLine(json)
assertTrue(json.contains('list":[]'))
}
}
}
Loading