Package org.luaj.vm2.lib.jse

Source Code of org.luaj.vm2.lib.jse.CoerceLuaToJava

/*******************************************************************************
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib.jse;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;

/**
* Helper class to coerce values from lua to Java within the luajava library.
* <p>
* This class is primarily used by the {@link LuajavaLib},
* but can also be used directly when working with Java/lua bindings.
* <p>
* To coerce to specific Java values, generally the {@code toType()} methods
* on {@link LuaValue} may be used:
* <ul>
* <li>{@link LuaValue#toboolean()}</li>
* <li>{@link LuaValue#tobyte()}</li>
* <li>{@link LuaValue#tochar()}</li>
* <li>{@link LuaValue#toshort()}</li>
* <li>{@link LuaValue#toint()}</li>
* <li>{@link LuaValue#tofloat()}</li>
* <li>{@link LuaValue#todouble()}</li>
* <li>{@link LuaValue#tojstring()}</li>
* <li>{@link LuaValue#touserdata()}</li>
* <li>{@link LuaValue#touserdata(Class)}</li>
* </ul>
* <p>
* For data in lua tables, the various methods on {@link LuaTable} can be used directly
* to convert data to something more useful.
*
* @see LuajavaLib
* @see CoerceJavaToLua
*/
public class CoerceLuaToJava {

  static int SCORE_NULL_VALUE     =    0x10;
  static int SCORE_WRONG_TYPE     =   0x100;
  static int SCORE_UNCOERCIBLE    = 0x10000;
 
  static interface Coercion {
    public int score( LuaValue value );
    public Object coerce( LuaValue value );
  };

  /**
   * Coerce a LuaValue value to a specified java class
   * @param value LuaValue to coerce
   * @param clazz Class to coerce into
   * @return Object of type clazz (or a subclass) with the corresponding value.
   */
  public static Object coerce(LuaValue value, Class clazz) {
    return getCoercion(clazz).coerce(value);
  }
 
  static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
 
  static final class BoolCoercion implements Coercion {
    public String toString() {
      return "BoolCoercion()";
    }
    public int score( LuaValue value ) {
      switch ( value.type() ) {
      case LuaValue.TBOOLEAN:
        return 0;
      }
      return 1;
    }

    public Object coerce(LuaValue value) {
      return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
    }
  }

  static final class NumericCoercion implements Coercion {
    static final int TARGET_TYPE_BYTE = 0;
    static final int TARGET_TYPE_CHAR = 1;
    static final int TARGET_TYPE_SHORT = 2;
    static final int TARGET_TYPE_INT = 3;
    static final int TARGET_TYPE_LONG = 4;
    static final int TARGET_TYPE_FLOAT = 5;
    static final int TARGET_TYPE_DOUBLE = 6;
    static final String[] TYPE_NAMES = { "byte", "char", "short", "int", "long", "float", "double" };
    final int targetType;
    public String toString() {
      return "NumericCoercion("+TYPE_NAMES[targetType]+")";
    }
    NumericCoercion(int targetType) {
      this.targetType = targetType;
    }
    public int score( LuaValue value ) {
      if ( value.isint() ) {
        switch ( targetType ) {
        case TARGET_TYPE_BYTE: {
          int i = value.toint();
          return (i==(byte)i)? 0: SCORE_WRONG_TYPE;
        }
        case TARGET_TYPE_CHAR: {
          int i = value.toint();
          return (i==(byte)i)? 1: (i==(char)i)? 0: SCORE_WRONG_TYPE;
        }
        case TARGET_TYPE_SHORT: {
          int i = value.toint();
          return (i==(byte)i)? 1: (i==(short)i)? 0: SCORE_WRONG_TYPE;
        }
        case TARGET_TYPE_INT: {
          int i = value.toint();
          return (i==(byte)i)? 2: ((i==(char)i) || (i==(short)i))? 1: 0;
        }
        case TARGET_TYPE_FLOAT: return 1;
        case TARGET_TYPE_LONG: return 1;
        case TARGET_TYPE_DOUBLE: return 2;
        default: return SCORE_WRONG_TYPE;
        }
      } else if ( value.isnumber() ) {
        switch ( targetType ) {
        case TARGET_TYPE_BYTE: return SCORE_WRONG_TYPE;
        case TARGET_TYPE_CHAR: return SCORE_WRONG_TYPE;
        case TARGET_TYPE_SHORT: return SCORE_WRONG_TYPE;
        case TARGET_TYPE_INT: return SCORE_WRONG_TYPE;
        case TARGET_TYPE_LONG: {
          double d = value.todouble();
          return (d==(long)d)? 0: SCORE_WRONG_TYPE;
        }
        case TARGET_TYPE_FLOAT: {
          double d = value.todouble();
          return (d==(float)d)? 0: SCORE_WRONG_TYPE;
        }
        case TARGET_TYPE_DOUBLE: {
          double d = value.todouble();
          return ((d==(long)d) || (d==(float)d))? 1: 0;
        }
        default: return SCORE_WRONG_TYPE;
        }
      } else {
        return SCORE_UNCOERCIBLE;
      }
    }

    public Object coerce(LuaValue value) {
      switch ( targetType ) {
      case TARGET_TYPE_BYTE: return new Byte( (byte) value.toint() );
      case TARGET_TYPE_CHAR: return new Character( (char) value.toint() );
      case TARGET_TYPE_SHORT: return new Short( (short) value.toint() );
      case TARGET_TYPE_INT: return new Integer( (int) value.toint() );
      case TARGET_TYPE_LONG: return new Long( (long) value.todouble() );
      case TARGET_TYPE_FLOAT: return new Float( (float) value.todouble() );
      case TARGET_TYPE_DOUBLE: return new Double( (double) value.todouble() );
      default: return null;
      }
    }
  }

  static final class StringCoercion implements Coercion {
    public static final int TARGET_TYPE_STRING = 0;
    public static final int TARGET_TYPE_BYTES = 1;
    final int targetType;
    public StringCoercion(int targetType) {
      this.targetType = targetType;
    }
    public String toString() {
      return "StringCoercion("+(targetType==TARGET_TYPE_STRING? "String": "byte[]")+")";
    }
    public int score(LuaValue value) {
      switch ( value.type() ) {
      case LuaValue.TSTRING:
        return value.checkstring().isValidUtf8()?
            (targetType==TARGET_TYPE_STRING? 0: 1):
            (targetType==TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE);
      case LuaValue.TNIL:
        return SCORE_NULL_VALUE;
      default:
        return targetType == TARGET_TYPE_STRING? SCORE_WRONG_TYPE: SCORE_UNCOERCIBLE;
      }
    }
    public Object coerce(LuaValue value) {
      if ( value.isnil() )
        return null;
      if ( targetType == TARGET_TYPE_STRING )
        return value.tojstring();
      LuaString s = value.checkstring();
      byte[] b = new byte[s.m_length];
      s.copyInto(0, b, 0, b.length);
      return b;
    }
  }

  static final class ArrayCoercion implements Coercion {
    final Class componentType;
    final Coercion componentCoercion;
    public ArrayCoercion(Class componentType) {
      this.componentType = componentType;
      this.componentCoercion = getCoercion(componentType);
    }
    public String toString() {
      return "ArrayCoercion("+componentType.getName()+")";
    }
    public int score(LuaValue value) {
      switch ( value.type() ) {
      case LuaValue.TTABLE:
        return value.length()==0? 0: componentCoercion.score( value.get(1) );
      case LuaValue.TUSERDATA:
        return inheritanceLevels( componentType, value.touserdata().getClass().getComponentType() );
      case LuaValue.TNIL:
        return SCORE_NULL_VALUE;
      default:
        return SCORE_UNCOERCIBLE;
      }
    }
    public Object coerce(LuaValue value) {
      switch ( value.type() ) {
      case LuaValue.TTABLE: {
        int n = value.length();
        Object a = Array.newInstance(componentType, n);
        for ( int i=0; i<n; i++ )
          Array.set(a, i, componentCoercion.coerce(value.get(i+1)));
        return a;
      }
      case LuaValue.TUSERDATA:
        return value.touserdata();
      case LuaValue.TNIL:
        return null;
      default:
        return null;
      }
     
    }
  }

  /**
   * Determine levels of inheritance between a base class and a subclass
   * @param baseclass base class to look for
   * @param subclass class from which to start looking
   * @return number of inheritance levels between subclass and baseclass,
   * or SCORE_UNCOERCIBLE if not a subclass
   */
  static final int inheritanceLevels( Class baseclass, Class subclass ) {
    if ( subclass == null )
      return SCORE_UNCOERCIBLE;
    if ( baseclass == subclass )
      return 0;
    int min = Math.min( SCORE_UNCOERCIBLE, inheritanceLevels( baseclass, subclass.getSuperclass() ) + 1 );
    Class[] ifaces = subclass.getInterfaces();
    for ( int i=0; i<ifaces.length; i++ )
      min = Math.min(min, inheritanceLevels(baseclass, ifaces[i]) + 1 );
    return min;
  }
 
  static final class ObjectCoercion implements Coercion {
    final Class targetType;
    ObjectCoercion(Class targetType) {
      this.targetType = targetType;
    }
    public String toString() {
      return "ObjectCoercion("+targetType.getName()+")";
    }
    public int score(LuaValue value) {
      switch ( value.type() ) {
      case LuaValue.TNUMBER:
        return inheritanceLevels( targetType, value.isint()? Integer.class: Double.class );
      case LuaValue.TBOOLEAN:
        return inheritanceLevels( targetType, Boolean.class );
      case LuaValue.TSTRING:
        return inheritanceLevels( targetType, String.class );
      case LuaValue.TUSERDATA:
        return inheritanceLevels( targetType, value.touserdata().getClass() );
      case LuaValue.TNIL:
        return SCORE_NULL_VALUE;
      default:
        return inheritanceLevels( targetType, value.getClass() );
      }
    }
    public Object coerce(LuaValue value) {
      switch ( value.type() ) {
      case LuaValue.TNUMBER:
        return value.isint()? (Object)new Integer(value.toint()): (Object)new Double(value.todouble());
      case LuaValue.TBOOLEAN:
        return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
      case LuaValue.TSTRING:
        return value.tojstring();
      case LuaValue.TUSERDATA:
        return value.optuserdata(targetType, null);
      case LuaValue.TNIL:
        return null;
      default:
        return value;
      }
    }
  }

  static {
    Coercion boolCoercion   = new BoolCoercion();
    Coercion byteCoercion   = new NumericCoercion(NumericCoercion.TARGET_TYPE_BYTE);
    Coercion charCoercion   = new NumericCoercion(NumericCoercion.TARGET_TYPE_CHAR);
    Coercion shortCoercion  = new NumericCoercion(NumericCoercion.TARGET_TYPE_SHORT);
    Coercion intCoercion    = new NumericCoercion(NumericCoercion.TARGET_TYPE_INT);
    Coercion longCoercion   = new NumericCoercion(NumericCoercion.TARGET_TYPE_LONG);
    Coercion floatCoercion  = new NumericCoercion(NumericCoercion.TARGET_TYPE_FLOAT);
    Coercion doubleCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_DOUBLE);
    Coercion stringCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_STRING);
    Coercion bytesCoercion  = new StringCoercion(StringCoercion.TARGET_TYPE_BYTES);
   
    COERCIONS.put( Boolean.TYPE, boolCoercion );
    COERCIONS.put( Boolean.class, boolCoercion );
    COERCIONS.put( Byte.TYPE, byteCoercion );
    COERCIONS.put( Byte.class, byteCoercion );
    COERCIONS.put( Character.TYPE, charCoercion );
    COERCIONS.put( Character.class, charCoercion );
    COERCIONS.put( Short.TYPE, shortCoercion );
    COERCIONS.put( Short.class, shortCoercion );
    COERCIONS.put( Integer.TYPE, intCoercion );
    COERCIONS.put( Integer.class, intCoercion );
    COERCIONS.put( Long.TYPE, longCoercion );
    COERCIONS.put( Long.class, longCoercion );
    COERCIONS.put( Float.TYPE, floatCoercion );
    COERCIONS.put( Float.class, floatCoercion );
    COERCIONS.put( Double.TYPE, doubleCoercion );
    COERCIONS.put( Double.class, doubleCoercion );
    COERCIONS.put( String.class, stringCoercion );
    COERCIONS.put( byte[].class, bytesCoercion );
  }
 
  static Coercion getCoercion(Class c) {
    Coercion co = (Coercion) COERCIONS.get( c );
    if ( co != null ) {
      return co;
    }
    if ( c.isArray() ) {
      Class typ = c.getComponentType();
      co = new ArrayCoercion(c.getComponentType());
    } else {
      co = new ObjectCoercion(c);
    }
    COERCIONS.put( c, co );
    return co;
  }
}
TOP

Related Classes of org.luaj.vm2.lib.jse.CoerceLuaToJava

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.