private void autoInjectGetSet(CtClass ctClass) throws Exception { // hibernate 可能需要 setter/getter 方法,好吧 我们为它添加这些方法 for (CtField ctField : ctClass.getDeclaredFields()) { if (isFinal(ctField) || isStatic(ctField) || ctField.hasAnnotation(Validate.class)) continue; // Property name String propertyName = ctField.getName().substring(0, 1).toUpperCase() + ctField.getName().substring(1); String getter = "get" + propertyName; String setter = "set" + propertyName; try { CtMethod ctMethod = ctClass.getDeclaredMethod(getter); if (ctMethod.getParameterTypes().length > 0 || Modifier.isStatic(ctMethod.getModifiers())) { throw new NotFoundException("it's not a getter !"); } } catch (NotFoundException noGetter) { String code = "public " + ctField.getType().getName() + " " + getter + "() { return this." + ctField.getName() + "; }"; CtMethod getMethod = CtMethod.make(code, ctClass); getMethod.setModifiers(getMethod.getModifiers() | AccessFlag.SYNTHETIC); ctClass.addMethod(getMethod); } try { CtMethod ctMethod = ctClass.getDeclaredMethod(setter); if (ctMethod.getParameterTypes().length != 1 || !ctMethod.getParameterTypes()[0].equals(ctField.getType()) || Modifier.isStatic(ctMethod.getModifiers())) { throw new NotFoundException("it's not a setter !"); } } catch (NotFoundException noSetter) { CtMethod setMethod = CtMethod.make( "public void " + setter + "(" + ctField.getType().getName() + " value) { this." + ctField.getName() + " = value; }", ctClass); setMethod.setModifiers(setMethod.getModifiers() | AccessFlag.SYNTHETIC); ctClass.addMethod(setMethod); } } ctClass.defrost(); }
public static void patch(CtClass c, IPatcher patcher) throws Exception { treatClassToPatch(c); if (patcher != null) { patcher.initClass(c); } for (CtMethod m : c.getDeclaredMethods()) { boolean wasAbstract = false; String newBody = null; if (Modifier.isAbstract(m.getModifiers())) { m.setModifiers(m.getModifiers() - Modifier.ABSTRACT); wasAbstract = true; } if (patcher != null) { newBody = patcher.getNewBody(m); } if (newBody != null) { if (newBody.startsWith(AutomaticPatcher.INSERT_BEFORE)) { GwtPatcherUtils.insertBefore( m, newBody.substring(AutomaticPatcher.INSERT_BEFORE.length())); } else if (newBody.startsWith(AutomaticPatcher.INSERT_AFTER)) { GwtPatcherUtils.insertAfter(m, newBody.substring(AutomaticPatcher.INSERT_AFTER.length())); } else { GwtPatcherUtils.replaceImplementation(m, newBody); } } else if (wasAbstract) { if (patcher != null) { m.setBody( "{ throw new " + UnsupportedOperationException.class.getName() + "(\"Abstract method '" + c.getSimpleName() + "." + m.getName() + "()' is not patched by " + patcher.getClass().getName() + "\"); }"); } else { m.setBody( "{ throw new " + UnsupportedOperationException.class.getName() + "(\"Abstract method '" + c.getSimpleName() + "." + m.getName() + "()' is not patched by any declared " + IPatcher.class.getSimpleName() + " instance\"); }"); } } } if (patcher != null) { patcher.finalizeClass(c); } }
private Set<CtMethod> getPatchMethods(Set<CtClass> patchClasses) { Set<CtMethod> result = new HashSet<CtMethod>(); // add all @PatchMethod found in a temporary map Map<String, List<CtMethod>> temp = new HashMap<String, List<CtMethod>>(); for (CtClass patchClass : patchClasses) { for (CtMethod ctMethod : patchClass.getDeclaredMethods()) { if (ctMethod.hasAnnotation(PatchMethod.class)) { if (!Modifier.isStatic(ctMethod.getModifiers())) { throw new GwtTestPatchException( "@" + PatchMethod.class.getName() + " has to be static : '" + ctMethod.getLongName() + "'"); } String nameAndSignature = ctMethod.getName() + Descriptor.toString(ctMethod.getSignature()); List<CtMethod> correspondingMethods = temp.get(nameAndSignature); if (correspondingMethods == null) { correspondingMethods = new ArrayList<CtMethod>(); temp.put(nameAndSignature, correspondingMethods); } correspondingMethods.add(ctMethod); } } } // for each @PatchMethod with the same signature, filter to get one with // override=true for (Map.Entry<String, List<CtMethod>> entry : temp.entrySet()) { CtMethod methodToUse = getMethodToUse(entry.getValue(), PatchMethod.class); methodToUse.setModifiers(Modifier.PUBLIC + Modifier.STATIC); result.add(methodToUse); } return result; }
private CtMethod getInitMethod(Set<CtClass> patchClasses) { List<CtMethod> initMethods = new ArrayList<CtMethod>(); for (CtClass patchClass : patchClasses) { for (CtMethod ctMethod : patchClass.getDeclaredMethods()) { if (ctMethod.hasAnnotation(InitMethod.class)) { if (!Modifier.isStatic(ctMethod.getModifiers())) { throw new GwtTestPatchException( "@" + InitMethod.class.getName() + " has to be static : '" + ctMethod.getLongName() + "'"); } try { if (ctMethod.getParameterTypes().length != 1 || ctMethod.getParameterTypes()[0] != GwtClassPool.getCtClass(CtClass.class)) { throw new GwtTestPatchException( "@" + InitMethod.class.getName() + " method must have one and only one parameter of type '" + CtClass.class.getName() + "'"); } } catch (NotFoundException e) { // should never happen throw new GwtTestPatchException(e); } initMethods.add(ctMethod); } } } CtMethod initMethod = getMethodToUse(initMethods, InitMethod.class); if (initMethod != null) { initMethod.setModifiers(Modifier.PUBLIC + Modifier.STATIC); } return initMethod; }
private static void removeNativeModifier(CtMethod m) throws Exception { if (Modifier.isNative(m.getModifiers())) { m.setModifiers(m.getModifiers() - Modifier.NATIVE); } }
@Override public void enhanceThisClass(ApplicationClass applicationClass) throws Exception { final CtClass ctClass = makeClass(applicationClass); if (ctClass.isInterface()) { return; } if (ctClass.getName().endsWith(".package")) { return; } // Add a default constructor if needed try { boolean hasDefaultConstructor = false; for (CtConstructor constructor : ctClass.getDeclaredConstructors()) { if (constructor.getParameterTypes().length == 0) { hasDefaultConstructor = true; break; } } if (!hasDefaultConstructor && !ctClass.isInterface()) { CtConstructor defaultConstructor = CtNewConstructor.make("public " + ctClass.getSimpleName() + "() {}", ctClass); ctClass.addConstructor(defaultConstructor); } } catch (Exception e) { Logger.error(e, "Error in PropertiesEnhancer"); throw new UnexpectedException("Error in PropertiesEnhancer", e); } if (isScala(applicationClass)) { // Temporary hack for Scala. Done. applicationClass.enhancedByteCode = ctClass.toBytecode(); ctClass.defrost(); return; } for (CtField ctField : ctClass.getDeclaredFields()) { try { if (isProperty(ctField)) { // Property name String propertyName = ctField.getName().substring(0, 1).toUpperCase() + ctField.getName().substring(1); String getter = "get" + propertyName; String setter = "set" + propertyName; try { CtMethod ctMethod = ctClass.getDeclaredMethod(getter); if (ctMethod.getParameterTypes().length > 0 || Modifier.isStatic(ctMethod.getModifiers())) { throw new NotFoundException("it's not a getter !"); } } catch (NotFoundException noGetter) { // Créé le getter String code = "public " + ctField.getType().getName() + " " + getter + "() { return this." + ctField.getName() + "; }"; CtMethod getMethod = CtMethod.make(code, ctClass); getMethod.setModifiers(getMethod.getModifiers() | AccessFlag.SYNTHETIC); ctClass.addMethod(getMethod); } if (!isFinal(ctField)) { try { CtMethod ctMethod = ctClass.getDeclaredMethod(setter); if (ctMethod.getParameterTypes().length != 1 || !ctMethod.getParameterTypes()[0].equals(ctField.getType()) || Modifier.isStatic(ctMethod.getModifiers())) { throw new NotFoundException("it's not a setter !"); } } catch (NotFoundException noSetter) { // Créé le setter CtMethod setMethod = CtMethod.make( "public void " + setter + "(" + ctField.getType().getName() + " value) { this." + ctField.getName() + " = value; }", ctClass); setMethod.setModifiers(setMethod.getModifiers() | AccessFlag.SYNTHETIC); ctClass.addMethod(setMethod); createAnnotation(getAnnotations(setMethod), PlayPropertyAccessor.class); } } } } catch (Exception e) { Logger.error(e, "Error in PropertiesEnhancer"); throw new UnexpectedException("Error in PropertiesEnhancer", e); } } // Add a default constructor if needed try { boolean hasDefaultConstructor = false; for (CtConstructor constructor : ctClass.getDeclaredConstructors()) { if (constructor.getParameterTypes().length == 0) { hasDefaultConstructor = true; break; } } if (!hasDefaultConstructor) { CtConstructor defaultConstructor = CtNewConstructor.defaultConstructor(ctClass); ctClass.addConstructor(defaultConstructor); } } catch (Exception e) { Logger.error(e, "Error in PropertiesEnhancer"); throw new UnexpectedException("Error in PropertiesEnhancer", e); } // Intercept all fields access for (final CtBehavior ctMethod : ctClass.getDeclaredBehaviors()) { ctMethod.instrument( new ExprEditor() { @Override public void edit(FieldAccess fieldAccess) throws CannotCompileException { try { // Acces à une property ? if (isProperty(fieldAccess.getField())) { // TODO : vérifier que c'est bien un champ d'une classe de l'application // (fieldAccess.getClassName()) // Si c'est un getter ou un setter String propertyName = null; if (fieldAccess .getField() .getDeclaringClass() .equals(ctMethod.getDeclaringClass()) || ctMethod .getDeclaringClass() .subclassOf(fieldAccess.getField().getDeclaringClass())) { if ((ctMethod.getName().startsWith("get") || (!isFinal(fieldAccess.getField()) && ctMethod.getName().startsWith("set"))) && ctMethod.getName().length() > 3) { propertyName = ctMethod.getName().substring(3); propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); } } // On n'intercepte pas le getter de sa propre property if (propertyName == null || !propertyName.equals(fieldAccess.getFieldName())) { String invocationPoint = ctClass.getName() + "." + ctMethod.getName() + ", line " + fieldAccess.getLineNumber(); if (fieldAccess.isReader()) { // Réécris l'accés en lecture à la property fieldAccess.replace( "$_ = ($r)play.classloading.enhancers.PropertiesEnhancer.FieldAccessor.invokeReadProperty($0, \"" + fieldAccess.getFieldName() + "\", \"" + fieldAccess.getClassName() + "\", \"" + invocationPoint + "\");"); } else if (!isFinal(fieldAccess.getField()) && fieldAccess.isWriter()) { // Réécris l'accés en ecriture à la property fieldAccess.replace( "play.classloading.enhancers.PropertiesEnhancer.FieldAccessor.invokeWriteProperty($0, \"" + fieldAccess.getFieldName() + "\", " + fieldAccess.getField().getType().getName() + ".class, $1, \"" + fieldAccess.getClassName() + "\", \"" + invocationPoint + "\");"); } } } } catch (Exception e) { throw new UnexpectedException("Error in PropertiesEnhancer", e); } } }); } // Done. applicationClass.enhancedByteCode = ctClass.toBytecode(); ctClass.defrost(); }
/** * Creates a map of concrete json request handler invokers keyed by <b><code> * <service-name>/<op-name></code></b>. * * @param handlerInstance The request handler instance to generate invokers for * @return the map of generated invokers */ public static Map<String, Map<String, AbstractJSONRequestHandlerInvoker>> createInvokers( Object handlerInstance) { if (handlerInstance == null) throw new IllegalArgumentException("The passed handlerInstance was null"); Map<String, AbstractJSONRequestHandlerInvoker> subInvokerMap = new HashMap<String, AbstractJSONRequestHandlerInvoker>(); Map<String, Map<String, AbstractJSONRequestHandlerInvoker>> invokerMap = invokerCache.get(handlerInstance.getClass()); if (invokerMap != null) { LOG.info("Found Cached Invokers for [{}]", handlerInstance.getClass().getName()); return invokerMap; } invokerMap = new HashMap<String, Map<String, AbstractJSONRequestHandlerInvoker>>(1); LOG.info("Generating Invokers for [{}]", handlerInstance.getClass().getName()); JSONRequestService svc = handlerInstance.getClass().getAnnotation(JSONRequestService.class); final String invokerServiceKey = svc.name(); final String invokerServiceDescription = svc.description(); invokerMap.put(invokerServiceKey, subInvokerMap); ClassPool cp = new ClassPool(); cp.appendClassPath(new ClassClassPath(handlerInstance.getClass())); cp.appendClassPath(new ClassClassPath(AbstractJSONRequestHandlerInvoker.class)); cp.importPackage(handlerInstance.getClass().getPackage().getName()); Set<ClassLoader> classPathsAdded = new HashSet<ClassLoader>(); Set<String> packagesImported = new HashSet<String>(); try { final CtClass jsonRequestCtClass = cp.get(JSONRequest.class.getName()); final CtClass parent = cp.get(AbstractJSONRequestHandlerInvoker.class.getName()); CtClass targetClass = cp.get(handlerInstance.getClass().getName()); Collection<Method> methods = getTargetMethods(handlerInstance.getClass()); for (Method m : methods) { final JSONRequestHandler jsonHandler = m.getAnnotation(JSONRequestHandler.class); final String opName = jsonHandler.name(); final String opDescription = jsonHandler.description(); final RequestType opType = jsonHandler.type(); int targetMethodHashCode = m.toGenericString().hashCode(); final String className = String.format( "%s-%s%s-%s-%s", handlerInstance.getClass().getName(), invokerServiceKey, opName, "ServiceInvoker", targetMethodHashCode); final CtClass invokerClass = cp.makeClass(className, parent); CtField ctf = new CtField(targetClass, "typedTarget", invokerClass); ctf.setModifiers(ctf.getModifiers() | Modifier.FINAL); invokerClass.addField(ctf); for (CtConstructor parentCtor : parent.getConstructors()) { CtConstructor invokerCtor = CtNewConstructor.copy(parentCtor, invokerClass, null); invokerCtor.setBody( "{ super($$); typedTarget = (" + handlerInstance.getClass().getName() + ")$1; }"); invokerClass.addConstructor(invokerCtor); } CtMethod invokerMethod = CtNewMethod.copy( parent.getDeclaredMethod("doInvoke", new CtClass[] {jsonRequestCtClass}), invokerClass, null); StringBuilder b = new StringBuilder("{this.typedTarget.").append(m.getName()).append("($1"); final Class<?>[] ptypes = m.getParameterTypes(); final int remainingParamCount = ptypes.length - 1; // Set<Class<?>> classPathsAdded = new HashSet<Class<?>>(); // Set<String> packagesImported = new HashSet<String>(); if (remainingParamCount > 0) { for (int i = 0; i < remainingParamCount; i++) { final Class<?> type = ptypes[i + 1]; if (type.getName().contains("UniqueIdType")) { System.err.println("Comin Up...."); } if (type.isPrimitive()) { b.append(", (").append(type.getName()).append(") null"); } else { if (classPathsAdded.add(type.getClassLoader())) { cp.appendClassPath(new LoaderClassPath(type.getClassLoader())); } try { Package p = type.getPackage(); if (p == null) { if (type.isArray()) { if (!type.getComponentType().isPrimitive()) { p = type.getComponentType().getPackage(); } } } if (type.isEnum()) { final String f = type.getEnclosingClass().getName() + "." + type.getSimpleName(); b.append(", (").append(f).append(") null"); String pack = type.getEnclosingClass().getPackage().getName(); if (packagesImported.add(pack)) { cp.importPackage(pack); } continue; } if (p != null) { if (packagesImported.add(p.getName())) { cp.importPackage(p.getName()); } } } catch (Exception ex) { ex.printStackTrace(System.err); } b.append(", (").append(type.getSimpleName()).append(") null"); } } } b.append(");}"); System.out.println("[" + m.getName() + "]: [" + b.toString() + "]"); // invokerMethod.setBody("{this.typedTarget." + m.getName() + "($1);}"); invokerMethod.setBody(b.toString()); invokerMethod.setModifiers(invokerMethod.getModifiers() & ~Modifier.ABSTRACT); invokerClass.addMethod(invokerMethod); // invokerClass.writeFile(System.getProperty("java.io.tmpdir") + File.separator + // "jsoninvokers"); Class<?> clazz = invokerClass.toClass( handlerInstance.getClass().getClassLoader(), handlerInstance.getClass().getProtectionDomain()); Constructor<?> ctor = clazz.getDeclaredConstructor( Object.class, String.class, String.class, String.class, String.class, RequestType.class); AbstractJSONRequestHandlerInvoker invokerInstance = (AbstractJSONRequestHandlerInvoker) ctor.newInstance( handlerInstance, invokerServiceKey, invokerServiceDescription, opName, opDescription, opType); subInvokerMap.put(opName, invokerInstance); } invokerCache.put(handlerInstance.getClass(), invokerMap); return invokerMap; } catch (Exception ex) { LOG.error( "Failed to create RequestHandlerInvoker for [{}]", handlerInstance.getClass().getName(), ex); throw new RuntimeException( "Failed to create RequestHandlerInvoker [" + handlerInstance.getClass().getName() + "]", ex); } }