/* * Copyright 2013 Guidewire Software, Inc. */ package gw.lang.parser.coercers; import gw.lang.reflect.IType; import gw.lang.reflect.IMethodInfo; import gw.lang.reflect.java.IJavaType; import gw.lang.reflect.java.JavaTypes; import gw.lang.reflect.java.IJavaMethodInfo; import gw.lang.reflect.IFunctionType; import gw.lang.GosuShop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.List; public class FunctionFromInterfaceCoercer extends BaseCoercer { private static FunctionFromInterfaceCoercer _instance = new FunctionFromInterfaceCoercer(); public static FunctionFromInterfaceCoercer instance() { return _instance; } private FunctionFromInterfaceCoercer() {} public boolean handlesNull() { return false; } public Object coerceValue( IType typeToCoerceTo, final Object value ) { return value; // Ideally I'd throw here, but there are places that rely on this working } public static Object doCoercion( Class classToCoerceTo, Class ifaceClass, final Object value ) { final Method originalMethod = ifaceClass.getDeclaredMethods()[0]; return Proxy.newProxyInstance(classToCoerceTo.getClassLoader(), new Class[]{classToCoerceTo}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().startsWith("invoke")) { return originalMethod.invoke(value, args); } else { return method.invoke(value, args); } } }); } public boolean isExplicitCoercion() { return false; } public static boolean areTypesCompatible( IFunctionType functionType, IType interfaceType ) { if( interfaceType.isInterface() && interfaceType instanceof IJavaType) { IJavaType javaIntrinsicType = (IJavaType)interfaceType; List<? extends IMethodInfo> list = javaIntrinsicType.getTypeInfo().getMethods(); int nonObjectMethods = 0; IMethodInfo singleMethod = null; for( IMethodInfo iMethodInfo : list ) { if( !iMethodInfo.getOwnersType().equals( JavaTypes.OBJECT() ) && iMethodInfo instanceof IJavaMethodInfo ) { nonObjectMethods++; singleMethod = iMethodInfo; } } if( nonObjectMethods == 1 ) { IFunctionType tempFunctionType = GosuShop.createFunctionType( singleMethod ); return functionType.isAssignableFrom( tempFunctionType ); } } return false; } public int getPriority( IType to, IType from ) { return 0; } }