All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gw.lang.reflect.json.Json Maven / Gradle / Ivy

There is a newer version: 1.18.2
Show newest version
package gw.lang.reflect.json;


import gw.util.concurrent.LocklessLazyVar;

import javax.script.Bindings;
import javax.script.ScriptException;
import java.util.List;

/**
 */
public class Json
{
  private static String _parser = System.getProperty( "gosu.json.parser" );
  public static String getParserName()
  {
    return _parser;
  }
  @SuppressWarnings("UnusedDeclaration")
  public static void setParserName( String fqn )
  {
    _parser = fqn;
    PARSER.clear();
  }

  private static final LocklessLazyVar PARSER =
    new LocklessLazyVar() {

      @Override
      protected IJsonParser init()
      {
        String fqn = getParserName();
        return fqn == null ? IJsonParser.getDefaultParser() : makeParser( fqn );
      }

      private IJsonParser makeParser( String fqn )
      {
        try
        {
          return (IJsonParser)Class.forName( fqn ).newInstance();
        }
        catch( Exception e )
        {
          throw new RuntimeException( e );
        }
      }
    };

  /**
   * Parse the JSON string as one of a javax.script.Bindings instance.
   *
   * @param json A Standard JSON formatted string
   * @return A javax.script.Bindings instance
   */
  @SuppressWarnings("UnusedDeclaration")
  public static Bindings fromJson( String json )
  {
    try
    {
      return PARSER.get().parseJson( json );
    }
    catch( ScriptException e )
    {
      throw new RuntimeException( e );
    }
  }

  /**
   * Makes a tree of structure types reflecting the Bindings.
   *

* A structure type contains a property member for each name/value pair in the Bindings. A property has the same name as the key and follows these rules: *

    *
  • If the type of the value is a "simple" type, such as a String or Integer, the type of the property matches the simple type exactly *
  • Otherwise, if the value is a Bindings type, the property type is that of a child structure with the same name as the property and recursively follows these rules *
  • Otherwise, if the value is a List, the property is a List parameterized with the component type, and the component type recursively follows these rules *
*/ public static String makeStructureTypes( String nameForStructure, Bindings bindings, boolean mutable ) { JsonStructureType type = (JsonStructureType)transformJsonObject( nameForStructure, null, bindings ); StringBuilder sb = new StringBuilder(); type.render( sb, 0, mutable ); return sb.toString(); } private static IJsonType transformJsonObject( String name, IJsonParentType parent, Object jsonObj ) { IJsonType type = null; if( parent != null ) { type = parent.findChild( name ); } if( jsonObj == null ) { return DynamicType.instance(); } else if( jsonObj instanceof Bindings ) { if( type == null ) { type = new JsonStructureType( parent, name ); } for( Object k: ((Bindings)jsonObj).keySet() ) { String key = (String)k; Object value = ((Bindings)jsonObj).get( key ); IJsonType memberType = transformJsonObject( key, (IJsonParentType)type, value ); if( memberType != null ) { ((JsonStructureType)type).addMember( key, memberType ); } } if( parent != null ) { parent.addChild( name, (IJsonParentType)type ); } } else if( jsonObj instanceof List ) { if( type == null ) { type = new JsonListType( parent ); } IJsonType compType = ((JsonListType)type).getComponentType(); if( !((List)jsonObj).isEmpty() ) { for( Object elem : (List)jsonObj ) { IJsonType csr = transformJsonObject( name, (IJsonParentType)type, elem ); if( compType != null && csr != compType && compType != DynamicType.instance() ) { csr = mergeTypes( compType, csr ); } compType = csr; } } else if( compType == null ) { // Empty list implies dynamic component type System.out.println( "\nWarning: there are no sample elements in list: " + name + "\nThe component type for this list will be Dynamic.\n" ); compType = DynamicType.instance(); } ((JsonListType)type).setComponentType( compType ); if( parent != null ) { parent.addChild( name, (IJsonParentType)type ); } } else { type = JsonSimpleType.get( jsonObj ); } return type; } public static IJsonType mergeTypes( IJsonType type1, IJsonType type2 ) { if( type1 == null && type2 != null ) { return type2; } if( type2 == null && type1 != null ) { return type1; } if( type1.equals( type2 ) ) { return type1; } if( type1 == DynamicType.instance() ) { // Keep the more specific type (Dynamic type is inferred from a 'null', thus the more specific type wins) return type2; } if( type2 == DynamicType.instance() ) { // Keep the more specific type return type1; } IJsonType mergedType = null; if( type1 instanceof JsonSimpleType && type2 instanceof JsonSimpleType ) { mergedType = ((JsonSimpleType)type1).merge( (JsonSimpleType)type2 ); } if( type1 instanceof JsonStructureType && type2 instanceof JsonStructureType ) { mergedType = ((JsonStructureType)type1).merge( (JsonStructureType)type2 ); } if( type1 instanceof JsonListType && type2 instanceof JsonListType ) { mergedType = ((JsonListType)type1).merge( (JsonListType)type2 ); } if( mergedType != null ) { return mergedType; } // if the existing type is dynamic, override it with a more specific type, // otherwise the types disagree... throw new RuntimeException( "Incompatible types: " + type1.getName() + " vs: " + type2.getName() ); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy