6
6
import java .lang .reflect .Type ;
7
7
import java .lang .reflect .TypeVariable ;
8
8
import java .util .ArrayDeque ;
9
+ import java .util .ArrayList ;
9
10
import java .util .Arrays ;
10
11
import java .util .Collection ;
11
12
import java .util .Deque ;
12
13
import java .util .Iterator ;
13
14
import java .util .List ;
14
15
import java .util .Map ;
16
+ import java .util .Set ;
15
17
16
18
import static com .cedarsoftware .util .io .JsonObject .ITEMS ;
17
19
import static com .cedarsoftware .util .io .JsonObject .KEYS ;
57
59
* See the License for the specific language governing permissions and
58
60
* limitations under the License.
59
61
*/
62
+ @ SuppressWarnings ({ "rawtypes" , "unchecked" , "Convert2Diamond" })
60
63
public class ObjectResolver extends Resolver
61
64
{
62
65
private final ClassLoader classLoader ;
@@ -208,8 +211,8 @@ else if (rhs.getClass().isArray())
208
211
}
209
212
else if (rhs instanceof JsonObject )
210
213
{
211
- final JsonObject <String , Object > jObj = (JsonObject ) rhs ;
212
- final Long ref = jObj .getReferenceId ();
214
+ final JsonObject <String , Object > jsRhs = (JsonObject ) rhs ;
215
+ final Long ref = jsRhs .getReferenceId ();
213
216
214
217
if (ref != null )
215
218
{ // Correct field references
@@ -226,10 +229,19 @@ else if (rhs instanceof JsonObject)
226
229
}
227
230
else
228
231
{ // Assign ObjectMap's to Object (or derived) fields
229
- field .set (target , createJavaObjectInstance (fieldType , jObj ));
230
- if (!MetaUtils .isLogicalPrimitive (jObj .getTargetClass ()))
232
+ Object fieldObject = createJavaObjectInstance (fieldType , jsRhs );
233
+ field .set (target , fieldObject );
234
+ if (!MetaUtils .isLogicalPrimitive (jsRhs .getTargetClass ()))
231
235
{
232
- stack .addFirst ((JsonObject ) rhs );
236
+ // GOTCHA : if the field is an immutable collection,
237
+ // "work instance", where one can accumulate items in (ArrayList)
238
+ // and "final instance' (say List.of() ) can _not_ be the same.
239
+ // So, the later the assignment, the better.
240
+ Object javaObj = convertMapsToObjects (jsRhs );
241
+ if (javaObj != fieldObject )
242
+ {
243
+ field .set (target , javaObj );
244
+ }
233
245
}
234
246
}
235
247
}
@@ -390,12 +402,20 @@ private static String safeToString(Object o)
390
402
*/
391
403
protected void traverseCollection (final Deque <JsonObject <String , Object >> stack , final JsonObject <String , Object > jsonObj )
392
404
{
405
+ final String className = jsonObj .type ;
393
406
final Object [] items = jsonObj .getArray ();
394
407
if (items == null || items .length == 0 )
395
408
{
409
+ if (className != null && className .startsWith ("java.util.Immutable" ))
410
+ if (className .contains ("Set" )) {
411
+ jsonObj .target = Set .of ();
412
+ } else if (className .contains ("List" )) {
413
+ jsonObj .target = List .of ();
414
+ }
396
415
return ;
397
416
}
398
- final Collection col = (Collection ) jsonObj .target ;
417
+ final boolean isImmutable = className != null && className .startsWith ("java.util.Immutable" );
418
+ final Collection col = isImmutable ? new ArrayList () : (Collection ) jsonObj .target ;
399
419
final boolean isList = col instanceof List ;
400
420
int idx = 0 ;
401
421
@@ -462,9 +482,43 @@ else if (element.getClass().isArray())
462
482
idx ++;
463
483
}
464
484
485
+ //if (isImmutable) {
486
+ reconciliateCollection (jsonObj , col );
487
+ //}
488
+
465
489
jsonObj .remove (ITEMS ); // Reduce memory required during processing
466
490
}
467
491
492
+ static public void reconciliateCollection (JsonObject jsonObj , Collection col )
493
+ {
494
+ final String className = jsonObj .type ;
495
+ final boolean isImmutable = className != null && className .startsWith ("java.util.Immutable" );
496
+ if (!isImmutable ) return ;
497
+
498
+ if (col == null && jsonObj .target instanceof Collection ) col = (Collection ) jsonObj .target ;
499
+ if (col == null ) return ;
500
+
501
+ if (className .contains ("List" ))
502
+ {
503
+ if (col .stream ().noneMatch (c -> c == null || c instanceof JsonObject ))
504
+ {
505
+ jsonObj .target = List .of (col .toArray ());
506
+ }
507
+ else
508
+ {
509
+ jsonObj .target = col ;
510
+ }
511
+ }
512
+ else if (className .contains ("Set" ))
513
+ {
514
+ jsonObj .target = Set .of (col .toArray ());
515
+ }
516
+ else
517
+ {
518
+ jsonObj .target = col ;
519
+ }
520
+ }
521
+
468
522
/**
469
523
* Traverse the JsonObject associated to an array (of any type). Convert and
470
524
* assign the list of items in the JsonObject (stored in the @items field)
@@ -699,7 +753,7 @@ protected Object readIfMatching(final Object o, final Class compType, final Dequ
699
753
{
700
754
read = ((JsonReader .JsonClassReader )closestReader ).read (o , stack );
701
755
}
702
- return read ;
756
+ return read ;
703
757
}
704
758
705
759
private void markUntypedObjects (final Type type , final Object rhs , final Map <String , Field > classFields )
0 commit comments