/* * MicroJIAC - A Lightweight Agent Framework * This file is part of MicroJIAC MIDlet-Maven-Plugin. * * Copyright (c) 2007-2012 DAI-Labor, Technische Universität Berlin * * This library includes software developed at DAI-Labor, Technische * Universität Berlin (http://www.dai-labor.de) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> */ /* * $Id$ */ package de.jiac.micro.reflect; import java.io.PrintStream; import java.lang.reflect.Method; import org.objectweb.asm.Type; import de.dailab.jiac.common.aamm.beans.IndexedPropertyDescriptor; import de.dailab.jiac.common.aamm.beans.MappedPropertyDescriptor; import de.dailab.jiac.common.aamm.beans.MethodDescriptor; import de.dailab.jiac.common.aamm.beans.PropertyDescriptor; import de.jiac.micro.reflect.ClassInfoReducer.ReducedClassInfo; /** * TODO: Das Ding hier zu warten ist die Pest. Hat jemand eine Idee wie man die * Codeerzeugung besser machen koennte? -- marcel * * * @author Marcel Patzlaff * @version $Revision$ */ public class ReflectorGenerator extends GeneratorUtil { public static final String SUPER_CLASS = "ReflectorStub"; public static final String MY_PACKAGE = "de.jiac.micro.internal.latebind"; public static final String MY_NAME = "Reflector"; public static void generateReflector(PrintStream out, ReducedClassInfo[] classes) { printHeader(out); out.println("package " + MY_PACKAGE + ";"); out.println("public final class " + MY_NAME + " extends " + SUPER_CLASS + " {"); generateWriteProperty(out, "\t", classes); generateInvokeMethodWithDescriptor(out, "\t", classes); generateInvokeMethod(out, "\t", classes); out.println('}'); out.flush(); } private static void generateWriteProperty(PrintStream out, String indent, ReducedClassInfo[] classes) { String objParam = "obj"; String propParam = "prop"; String argsParam = "args"; String myIndent = indent + "\t\t"; out.println(indent + "protected void writeProperty0(Object " + objParam + ", String " + propParam + ", Object[] " + argsParam + ") throws Exception {"); for (ReducedClassInfo current : classes) { if (current.hasWritablePropertiesForMask()) { String cast = getJavaSourceClassName(current.getClassDescriptor().getClazz()); out.println(indent + "\tif(" + objParam + " instanceof " + cast + "){"); for (PropertyDescriptor pd : current.getPropertyDescriptors()) { generatePropertyWriteClause(out, myIndent, cast, objParam, propParam, argsParam, pd); } out.println(indent + "\t}"); } } out.println(indent + "\tthrow new IllegalArgumentException(\"property '\" + " + propParam + " + \"' is either not defined or not writable!\");"); out.println(indent + "}"); } private static void generateInvokeMethodWithDescriptor(PrintStream out, String indent, ReducedClassInfo[] classes) { String objParam = "obj"; String clsParam = "cls"; String mNameParam= "mName"; String mDescrParam= "mDescr"; String argumentsParam = "arguments"; out.println(indent + "protected Object invokeMethodWithDescriptor0(Object " + objParam + ", Class " + clsParam + ", String " + mNameParam + ", String " + mDescrParam + ", Object[] " + argumentsParam + ") throws Exception {"); for(ReducedClassInfo ci : classes) { if(ci.needsMethodsWithDescriptors()) { MethodDescriptor[] mds= ci.getMethodDescriptors(); if(mds == null || mds.length <= 0) { continue; } final String fqCls= getJavaSourceClassName(ci.getClassDescriptor().getClazz()); out.println(indent + "\tif(" + fqCls + ".class.isAssignableFrom(" + clsParam + ")) {"); for(MethodDescriptor md : mds) { Method m= md.getMethod(); out.println(indent + "\t\tif(\"" + m.getName() + "\".equals(" + mNameParam + ") && \"" + Type.getMethodDescriptor(md.getMethod()) + "\".equals(" + mDescrParam + ")) {"); StringBuilder call= new StringBuilder(); call.append("((" + fqCls + ")" + objParam + ")." + m.getName() + "("); Class<?>[] pts= m.getParameterTypes(); for(int i= 0; i < pts.length; ++i) { insertFromObjectConversion(call, pts[i], argumentsParam + "[" + i + "]"); if(i < pts.length - 1) { call.append(','); } } call.append(")"); Class<?> rt= m.getReturnType(); if(rt == void.class) { out.append(indent + "\t\t\t").append(call).println(';'); out.println(indent + "\t\t\treturn null;"); } else { out.append(indent + "\t\t\treturn "); insertToObjectConversion(out, rt, call); out.println(';'); } out.println(indent + "\t\t}"); } out.println(indent + "\t}"); } } out.println(indent + "\tthrow new IllegalArgumentException(\"method not found\");"); out.println(indent + "}"); } private static void generateInvokeMethod(PrintStream out, String indent, ReducedClassInfo[] classes) { String objParam = "obj"; String nameParam = "name"; String argumentsParam = "arguments"; out.println(indent + "protected Object invokeMethod0(Object " + objParam + ", String " + nameParam + ", Object[] "+ argumentsParam + ") throws Exception {"); // TODO out.println(indent + "\tthrow new RuntimeException(\"unsupported operation\");"); out.println(indent + "}"); } private static void generatePropertyWriteClause(PrintStream out, String indent, String cast, String objParam, String propParam, String argsParam, PropertyDescriptor pd) { if (!pd.isWritable()) { return; } Method writeMethod = pd.getWriteMethod(); Method twoArgWriteMethod= null; if(pd instanceof IndexedPropertyDescriptor) { twoArgWriteMethod= ((IndexedPropertyDescriptor) pd).getIndexedWriteMethod(); } else if(pd instanceof MappedPropertyDescriptor) { twoArgWriteMethod= ((MappedPropertyDescriptor) pd).getMappedWriteMethod(); } out.println(indent + "if(\"" + pd.getName() + "\".equals(" + propParam + ")){"); if (writeMethod != null) { out.println(indent + "\tif(" + argsParam + ".length == 1){"); out.append(indent + "\t((" + cast + ")" + objParam + ")." + writeMethod.getName() + "("); Class<?> valueType = writeMethod.getParameterTypes()[0]; if (valueType.isPrimitive()) { insertWrap(out, valueType, argsParam + "[0]"); out.println(");"); } else if (valueType.isArray()) { Class<?> compType = valueType.getComponentType(); String valueCast = "[]"; while (compType.isArray()) { valueCast = valueCast + "[]"; compType= compType.getComponentType(); } valueCast = getJavaSourceClassName(compType) + valueCast; out.println("(" + valueCast + ")" + argsParam + "[0]);"); } else { out.println("(" + getJavaSourceClassName(valueType) + ")" + argsParam + "[0]);"); } out.println(indent + "\t\treturn;"); out.println(indent + "\t}"); } if (twoArgWriteMethod != null) { out.println(indent + "\tif(" + argsParam + ".length == 2){"); out.append(indent + "\t\t((" + cast + ")" + objParam + ")." + twoArgWriteMethod.getName()); if(twoArgWriteMethod.getParameterTypes()[0] == int.class) { out.append("(((Integer)" + argsParam + "[0]).intValue(), "); } else { out.append("((String) " + argsParam + "[0], "); } Class<?> valueType = twoArgWriteMethod.getParameterTypes()[1]; if (valueType.isPrimitive()) { insertWrap(out, valueType, argsParam + "[1]"); out.println(");"); } else if (valueType.isArray()) { Class<?> compType = valueType.getComponentType(); String valueCast = "[]"; while (compType.isArray()) { valueCast = valueCast + "[]"; compType= compType.getComponentType(); } valueCast = getJavaSourceClassName(compType) + valueCast; out.println("(" + valueCast + ")" + argsParam + "[1]);"); } else { out.println("(" + getJavaSourceClassName(valueType) + ")" + argsParam + "[1]);"); } out.println(indent + "\t\treturn;"); out.println(indent + "\t}"); } out.println(indent + "}"); } private static void insertWrap(PrintStream out, Class<?> argType, String variable) { out.append(variable + ".getClass() == String.class ? "); if (argType == boolean.class) { out.append("(((String)" + variable + ").charAt(0) == 't' ? true : false) : " + "((Boolean)" + variable + ").booleanValue()"); } else if (argType == byte.class) { out.append("Byte.parseByte((String)" + variable + ") : " + "((Byte)" + variable + ").byteValue()"); } else if (argType == char.class) { out.append("((String)" + variable + ").charAt(0) : " + "((Character)" + variable + ").charValue()"); } else if (argType == double.class) { out.append("Double.parseDouble((String)" + variable + ") : " + "((Double)" + variable + ").doubleValue()"); } else if (argType == float.class) { out.append("Float.parseFloat((String)" + variable + ") : " + "((Float)" + variable + ").floatValue()"); } else if (argType == int.class) { out.append("Integer.parseInt((String)" + variable + ") : " + "((Integer)" + variable + ").intValue()"); } else if (argType == long.class) { out.append("Long.parseLong((String)" + variable + ") : " + "((Long)" + variable + ").longValue()"); } else if (argType == short.class) { out.append("Short.parseShort((String)" + variable + ") : " + "((Short)" + variable + ").shortValue()"); } } }