package php.runtime.ext.java; import php.runtime.Memory; import php.runtime.common.HintType; import php.runtime.env.Environment; import php.runtime.memory.ArrayMemory; import php.runtime.memory.LongMemory; import php.runtime.memory.ObjectMemory; import php.runtime.memory.StringMemory; import php.runtime.memory.support.MemoryUtils; import php.runtime.reflection.ClassEntity; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import static php.runtime.annotation.Reflection.*; @Name("php\\lang\\JavaMethod") final public class JavaMethod extends JavaReflection { protected Method method; protected MemoryUtils.Converter[] converters; protected MemoryUtils.Converter resultConverter; protected Class<?>[] paramTypes; public JavaMethod(Environment env, ClassEntity clazz) { super(env, clazz); } public void setMethod(Method method) { this.method = method; method.setAccessible(true); this.paramTypes = method.getParameterTypes(); converters = MemoryUtils.getConverters(paramTypes); resultConverter = MemoryUtils.getConverter(method.getReturnType()); } @Signature({@Arg(value = "object", typeClass = "php\\lang\\JavaObject", optional = @Optional("NULL"))}) public Memory invoke(Environment env, Memory... args){ int len = args.length - 1; if (len < paramTypes.length || len > paramTypes.length) exception(env, new IllegalArgumentException("Invalid argument count")); Object[] passed = new Object[len]; int i = 0; for(MemoryUtils.Converter converter : converters){ Memory arg = args[i + 1]; if (arg.instanceOf("php\\lang\\JavaObject")){ passed[i] = ((JavaObject)arg.toValue(ObjectMemory.class).value).getObject(); } else { if (converter != null) { passed[i] = converter.run(args[i + 1]); } else { passed[i] = null; } } i++; } Object obj = args[0].isNull() ? null : ((JavaObject)args[0].toValue(ObjectMemory.class).value).getObject(); try { Object result = method.invoke(obj, passed); if (result == null) return Memory.NULL; if (resultConverter != null) return MemoryUtils.valueOf(result); else { if (method.getReturnType() == void.class) return Memory.NULL; return new ObjectMemory(JavaObject.of(env, result)); } } catch (IllegalAccessException e) { exception(env, e); } catch (InvocationTargetException e) { exception(env, e.getTargetException()); } return Memory.NULL; } @Signature({ @Arg(value = "object", typeClass = "php\\lang\\JavaObject", optional = @Optional("NULL")), @Arg(value = "arguments", type = HintType.ARRAY, optional = @Optional) }) public Memory invokeArgs(Environment env, Memory... args){ Memory[] tmp = args[1].toValue(ArrayMemory.class).values(); Memory[] passed = new Memory[tmp.length + 1]; System.arraycopy(tmp, 0, passed, 1, tmp.length); passed[0] = args[0]; return invoke(env, passed); } @Signature public Memory isStatic(Environment env, Memory... args){ return Modifier.isStatic(method.getModifiers()) ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isFinal(Environment env, Memory... args){ return Modifier.isFinal(method.getModifiers()) ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isPrivate(Environment env, Memory... args){ return Modifier.isPrivate(method.getModifiers()) ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isProtected(Environment env, Memory... args){ return Modifier.isProtected(method.getModifiers()) ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isPublic(Environment env, Memory... args){ return Modifier.isPublic(method.getModifiers()) ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isAbstract(Environment env, Memory... args){ return Modifier.isAbstract(method.getModifiers()) ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isNative(Environment env, Memory... args){ return Modifier.isNative(method.getModifiers()) ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isSynchronized(Environment env, Memory... args){ return Modifier.isSynchronized(method.getModifiers()) ? Memory.TRUE : Memory.FALSE; } @Signature public Memory getDeclaringClass(Environment env, Memory... args){ return new ObjectMemory(JavaClass.of(env, method.getDeclaringClass())); } @Signature public Memory getReturnedType(Environment env, Memory... args){ return new ObjectMemory(JavaClass.of(env, method.getReturnType())); } @Signature public Memory getModifiers(Environment env, Memory... args){ return LongMemory.valueOf(method.getModifiers()); } @Signature public Memory getName(Environment env, Memory... args){ return StringMemory.valueOf(method.getName()); } @Signature public Memory isVarArgs(Environment env, Memory... args){ return method.isVarArgs() ? Memory.TRUE : Memory.FALSE; } @Signature(@Arg("annotationClass")) public Memory isAnnotationPresent(Environment env, Memory... args){ try { return method.isAnnotationPresent((Class<? extends Annotation>) Class.forName(args[0].toString())) ? Memory.TRUE : Memory.FALSE; } catch (ClassNotFoundException | ClassCastException e) { exception(env, e); } return Memory.NULL; } @Signature public Memory getParameterTypes(Environment env, Memory... args){ ArrayMemory result = new ArrayMemory(); for(Class<?> el : method.getParameterTypes()){ result.add(new ObjectMemory(JavaClass.of(env, el))); } return result.toConstant(); } @Signature public Memory getParameterCount(Environment env, Memory... args){ return LongMemory.valueOf(method.getParameterTypes().length); } public static JavaMethod of(Environment env, Method method){ JavaMethod javaMethod = new JavaMethod(env, env.fetchClass("php\\lang\\JavaMethod")); javaMethod.setMethod(method); return javaMethod; } public static Object[] makePassed(Environment env, MemoryUtils.Converter[] converters, Memory... args){ Object[] passed = new Object[converters.length]; int i = 0; for(MemoryUtils.Converter converter : converters){ Memory arg = args[i]; if (arg.instanceOf("php\\lang\\JavaObject")){ passed[i] = ((JavaObject)arg.toValue(ObjectMemory.class).value).getObject(); } else { if (converter != null) { passed[i] = converter.run(args[i]); } else { passed[i] = null; } } i++; } return passed; } }