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

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

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

import gw.lang.reflect.Expando;
import gw.lang.reflect.Modifier;
import manifold.util.ReflectUtil;

import javax.script.Bindings;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 */
public interface IJsonIO
{
  String TYPE = "$construct_type";

  static  E read( Bindings bindings )
  {
    return read( null, bindings );
  }
  static  E read( String tag, Bindings bindings )
  {
    if( tag != null && !tag.isEmpty() )
    {
      bindings = (Bindings)bindings.get( tag );
      if( bindings == null )
      {
        return null;
      }
    }

    String fqn = (String)bindings.get( TYPE );
    try
    {
      //noinspection unchecked
      E obj = (E)Class.forName( fqn ).newInstance();
      obj.load( bindings );
      return obj;
    }
    catch( Exception e )
    {
      throw new RuntimeException( e );
    }
  }

  static  void write( E obj, Bindings bindings )
  {
    write( null, obj, bindings );
  }
  static  void write( String tag, E obj, Bindings bindings )
  {
    if( obj == null )
    {
      if( tag != null && !tag.isEmpty() )
      {
        bindings.put( tag, obj );
      }
    }
    else
    {
      if( tag != null && !tag.isEmpty() )
      {
        Bindings objBindings = new Expando();
        obj.save( objBindings );
        bindings.put( tag, objBindings );
      }
      else
      {
        obj.save( bindings );
      }
    }
  }

  static  List readList( Bindings bindings )
  {
    return readList( null, bindings ); 
  }
  static  List readList( String tag, Bindings bindings )
  {
    //noinspection unchecked
    List list = (List)bindings.get( tag );
    if( list == null )
    {
      return Collections.emptyList();
    }

    List objs = list.isEmpty() ? Collections.emptyList() : new ArrayList<>();
    for( Bindings elem: list )
    {
      objs.add( read( elem ) );
    }
    return objs;
  }

  static  void writeList( String tag, List list, Bindings bindings )
  {
    if( list == null )
    {
      bindings.put( tag, null );
    }
    else if( list.isEmpty() )
    {
      bindings.put( tag, Collections.emptyList() );
    }
    else
    {
      List blist = new ArrayList<>();
      for( E e : list )
      {
        Bindings b = new Expando();
        e.save( b );
        blist.add( b );
      }
      bindings.put( tag, blist );
    }
  }

  /**
   * Implement this method to control loading from the Json bindings.  The
   * default behavior simply loads values corresponding with your class's
   * field values.
   * 

* The bindings is just a simple map with name value pairs, which usually * maps directly to your class's fields. But anything goes; you can read * and write anything from/to the Bindings. *

* Use #read() etc. to read proper Json data. * * @param bindings */ default void load( Bindings bindings ) { Class cls = getClass(); loadFields( this, cls, bindings ); } /** * Implement this method to control saving to a Json bindings. The default * behavior simply saves all your class's non-transient instance fields. *

* Basically, the bindings is a simple map where you write name/value pairs * representing your class's format. Typically you save just your field * values, but you can save anything you like. *

* Use #write(String, Object, Bindings) etc. to write proper Json data. * * @param bindings */ default void save( Bindings bindings ) { Class cls = getClass(); bindings.put( TYPE, cls.getName() ); saveFields( this, cls, bindings ); } static void loadFields( IJsonIO obj, Class cls, Bindings bindings ) { Field[] fields = cls.getDeclaredFields(); for( Field f: fields ) { if( f.isSynthetic() || Modifier.isStatic( f.getModifiers() ) || Modifier.isTransient( f.getModifiers() ) ) { continue; } ReflectUtil.setAccessible( f ); try { Object value = bindings.get( f.getName() ); if( value instanceof Bindings ) { value = read( (Bindings)value ); } else if( value instanceof List && ((List)value).size() > 0 && ((List)value).get( 0 ) instanceof Bindings ) { value = readList( bindings ); } else if( f.getType().isEnum() && value instanceof String ) { value = Enum.valueOf( (Class)f.getType(), (String)value ); } else if( f.getType() == Boolean.class || f.getType() == boolean.class ) { value = (Integer)value != 0; } else if( !isSimpleType( f.getType() ) ) { throw new UnsupportedOperationException( "Unsupported Json type: " + f.getType() ); } f.set( obj, value ); } catch( IllegalAccessException e ) { throw new RuntimeException( e ); } } Class superclass = cls.getSuperclass(); if( superclass != null ) { loadFields( obj, superclass, bindings ); } } static void saveFields( IJsonIO obj, Class cls, Bindings bindings ) { Class superclass = cls.getSuperclass(); if( superclass != null ) { saveFields( obj, superclass, bindings ); } Field[] fields = cls.getDeclaredFields(); for( Field f: fields ) { if( f.isSynthetic() || Modifier.isStatic( f.getModifiers() ) || Modifier.isTransient( f.getModifiers() ) ) { continue; } ReflectUtil.setAccessible( f ); try { Object value = f.get( obj ); if( isSimpleType( value ) ) { bindings.put( f.getName(), value ); } else if( value instanceof Enum ) { bindings.put( f.getName(), ((Enum)value).name() ); } else if( value instanceof Boolean ) { bindings.put( f.getName(), (Boolean)value ? 1 : 0 ); } else if( value instanceof List ) { if( !((List)value).isEmpty() ) { if( isSimpleType( ((List)value).get( 0 ) ) ) { bindings.put( f.getName(), value ); } else { writeList( f.getName(), (List)value, bindings ); } } else { bindings.put( f.getName(), value ); } } else if( value instanceof IJsonIO ) { write( f.getName(), (IJsonIO)value, bindings ); } else { throw new UnsupportedOperationException( "Type: " + value.getClass() + " does not implement " + IJsonIO.class.getName() ); } } catch( IllegalAccessException e ) { throw new RuntimeException( e ); } } } static boolean isSimpleType( Object value ) { if( value == null ) { return true; } return isSimpleType( value.getClass() ); } static boolean isSimpleType( Class cls ) { return cls == null || cls == int.class || cls == long.class || cls == float.class || cls == double.class || cls == String.class || cls == Integer.class || cls == Long.class || cls == Float.class || cls == Double.class; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy