public void traverseFields ( final Deque < JsonObject < String , Object > > stack , final JsonObject < String , Object > jsonObj ) { final Object target = jsonObj . target ; for ( Map . Entry < String , Object > e : jsonObj . entrySet ( ) ) { final String fieldName = e . getKey ( ) ; final Field field = ( target != null ) ? MetaUtils . getField ( target . getClass ( ) , fieldName ) : null ; final Object rhs = e . getValue ( ) ; if ( rhs == null ) { jsonObj . put ( fieldName , null ) ; } else if ( rhs == JsonParser . EMPTY_OBJECT ) { jsonObj . put ( fieldName , new JsonObject ( ) ) ; } else if ( rhs . getClass ( ) . isArray ( ) ) { // RHS is an array // Trace the contents of the array (so references inside the array and into the array work) JsonObject < String , Object > jsonArray = new JsonObject < String , Object > ( ) ; jsonArray . put ( "@items" , rhs ) ; stack . addFirst ( jsonArray ) ; // Assign the array directly to the Map key (field name) jsonObj . put ( fieldName , rhs ) ; } else if ( rhs instanceof JsonObject ) { JsonObject < String , Object > jObj = ( JsonObject ) rhs ; if ( field != null && MetaUtils . isLogicalPrimitive ( field . getType ( ) ) ) { jObj . put ( "value" , MetaUtils . convert ( field . getType ( ) , jObj . get ( "value" ) ) ) ; continue ; } Long refId = jObj . getReferenceId ( ) ; if ( refId != null ) { // Correct field references JsonObject refObject = getReferencedObj ( refId ) ; jsonObj . put ( fieldName , refObject ) ; // Update Map-of-Maps reference } else { stack . addFirst ( jObj ) ; } } else if ( field != null ) { // The code below is 'upgrading' the RHS values in the passed in JsonObject Map // by using the @type class name (when specified and exists), to coerce the vanilla // JSON values into the proper types defined by the class listed in @type. This is // a cool feature of json-io, that even when reading a map-of-maps JSON file, it will // improve the final types of values in the maps RHS, to be of the field type that // was optionally specified in @type. final Class fieldType = field . getType ( ) ; if ( MetaUtils . isPrimitive ( fieldType ) || BigDecimal . class . equals ( fieldType ) || BigInteger . class . equals ( fieldType ) || Date . class . equals ( fieldType ) ) { jsonObj . put ( fieldName , MetaUtils . convert ( fieldType , rhs ) ) ; } else if ( rhs instanceof String ) { if ( fieldType != String . class && fieldType != StringBuilder . class && fieldType != StringBuffer . class ) { if ( "" . equals ( ( ( String ) rhs ) . trim ( ) ) ) { // Allow "" to null out a non-String field on the inbound JSON jsonObj . put ( fieldName , null ) ; } } } } } jsonObj . target = null ; // don't waste space (used for typed return, not for Map return) }
Walk the JsonObject fields and perform necessary substitutions so that all references matched up . This code patches