private static void addDefaultConstructor(CtClass c) throws CannotCompileException {
   CtConstructor cons;
   try {
     cons = c.getDeclaredConstructor(new CtClass[] {});
     cons.setModifiers(Modifier.PUBLIC);
   } catch (NotFoundException e) {
     cons = new CtConstructor(new CtClass[] {}, c);
     cons.setBody(";");
     c.addConstructor(cons);
   }
 }
Example #2
0
 public void onWrite(ClassPool pool, String className)
     throws NotFoundException, CannotCompileException {
   CtClass cc = pool.get(className);
   try {
     if (isPersistent(className)) {
       CtClass base = cc.getSuperclass();
       CtConstructor cons = new CtConstructor(constructorParams, cc);
       if (base.subclassOf(persistent) || base == object) {
         cons.setBody(null);
         cc.addConstructor(cons);
         if (base == object) {
           cc.setSuperclass(persistent);
         }
       } else {
         if (!isPersistent(base.getName())) {
           throw new NotFoundException(
               "Base class " + base.getName() + " was not declared as persistent");
         }
         cons.setBody("super($0);");
         cc.addConstructor(cons);
       }
       preprocessMethods(cc, true, true);
       if (base == persistent || base == object) {
         CtMethod m = new CtMethod(isRecursive, cc, null);
         m.setBody("return false;");
         cc.addMethod(m);
         addSerializeMethods(cc, false);
       } else if (base.subtypeOf(serializable)) {
         addSerializeMethods(cc, true);
       }
       if ((cc.getModifiers() & Modifier.PRIVATE) == 0) {
         CtClass f = pool.makeClass(className + "LoadFactory");
         f.addInterface(factory);
         CtMethod c = new CtMethod(create, f, null);
         c.setBody("return new " + className + "($1);");
         f.addMethod(c);
         CtNewConstructor.defaultConstructor(f);
       }
     } else {
       preprocessMethods(
           cc, cc.subtypeOf(persistent) && cc != persistent, !className.startsWith("org.nachodb"));
     }
   } catch (Exception x) {
     x.printStackTrace();
   }
 }
 private void createConstructor(final CtClass ctClass) {
   try {
     final CtConstructor ctConstructor =
         new CtConstructor(
             new CtClass[] {
               classPool.getCtClass(RingBuffer.class.getName()),
               classPool.getCtClass(DropListener.class.getName()),
               classPool.getCtClass(MessagePublicationListener.class.getName())
             },
             ctClass);
     ctConstructor.setBody("{ringBuffer = $1;dropListener = $2;messagePublicationListener = $3;}");
     ctClass.addConstructor(ctConstructor);
   } catch (NotFoundException e) {
     throw new RuntimeException("Unable to create constructor", e);
   } catch (CannotCompileException e) {
     throw new RuntimeException("Unable to create constructor", e);
   }
 }
  private static void findConstructors(
      CtClass ctClass, Set<CtConstructor> set, Class<?>... argsClasses) {
    try {

      if (ctClass == null) {
        return;
      }

      CtConstructor[] constructors = ctClass.getDeclaredConstructors();

      if (constructors.length == 0) {
        findConstructors(ctClass.getSuperclass(), set, argsClasses);
      } else if (constructors.length == 1 && argsClasses.length == 0) {
        set.add(constructors[0]);
      } else {
        for (CtConstructor c : constructors) {

          if (c.getParameterTypes().length != argsClasses.length) {
            continue;
          }

          boolean sameArgs = true;
          for (int i = 0; i < argsClasses.length; i++) {
            String requestedClassName = argsClasses[i].getName();
            String currentClassName = c.getParameterTypes()[i].getName();

            if (!requestedClassName.equals(currentClassName)) {
              sameArgs = false;
            }
          }

          if (sameArgs) {
            set.add(c);
          }
        }
      }
    } catch (NotFoundException e) {
      // should never happen
      throw new GwtTestPatchException(
          "Error while trying find a constructor in class '" + ctClass.getName() + "'", e);
    }
  }
  /**
   * @param pool The AOPClassPool to create the optimized invocation class in
   * @param makeInnerClass If true creates the new class as an inner class of className
   * @param outerClass The class to create the invocation class as an inner class of if
   *     makeInnerClass==true
   * @param className The full class name (including package info) of the invocation class to be
   *     created
   * @param superInvocation The super class of this invocation
   * @return The created invocation class
   */
  public static CtClass makeInvocationClass(
      AOPClassPool pool,
      boolean makeInnerClass,
      CtClass outerClass,
      String className,
      CtClass superInvocation)
      throws CannotCompileException, NotFoundException {

    CtClass invocation =
        makeInvocationClassNoCtors(pool, makeInnerClass, outerClass, className, superInvocation);

    // Add the invocation constructor
    CtConstructor[] cons = superInvocation.getDeclaredConstructors();
    for (int i = 0; i < cons.length; i++) {
      CtConstructor conTemplate = superInvocation.getDeclaredConstructors()[i];
      CtConstructor icon =
          CtNewConstructor.make(
              conTemplate.getParameterTypes(), conTemplate.getExceptionTypes(), invocation);
      invocation.addConstructor(icon);
    }

    return invocation;
  }
Example #6
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;
  }
  @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();
  }
Example #11
0
  public ClazzInfo classProcessing(String clazzName)
      throws NotFoundException, CannotCompileException {
    ClassPool classPool = ClassPool.getDefault();
    CtClass cz = classPool.get(clazzName);
    classPool.importPackage(clazzName); // 继承
    classPool.importPackage("java.lang.reflect.Method"); // 添加反射引用

    CtClass newClass = classPool.makeClass(clazzName + "$MC_IMPL"); // 新建代理类
    newClass.setSuperclass(cz); // 继承

    // 构造块
    CtConstructor tempC;
    CtConstructor[] ctConstructors = cz.getDeclaredConstructors();
    newClass.addConstructor(CtNewConstructor.defaultConstructor(newClass));
    for (CtConstructor c : ctConstructors) {
      try {
        tempC = CtNewConstructor.copy(c, newClass, null);
        tempC.setBody("{super($$);}");
        newClass.addConstructor(tempC);
      } catch (Exception e) {
        // e.printStackTrace();
      }
    }

    // 字段块
    //		CtField[] ctFields = cz.getDeclaredFields();
    //		for (CtField f : ctFields)
    //			System.out.println(f.getFieldInfo().getConstantValue());

    // 方法块
    CtMethod[] ctMethods = cz.getDeclaredMethods();
    CtMethod tempM; // 复制方法名
    Map<String, Method> tempMethod = new HashMap<String, Method>();
    for (CtMethod m : ctMethods) {
      tempMethod.put(
          String.format(
              "%s %s %s(%s);",
              Modifier.toString(m.getModifiers()),
              m.getReturnType().getName(),
              m.getName(),
              Util.getParameterTypes(m.getParameterTypes())),
          null);
      // System.err.println(String.format("%s %s %s(%s);", Modifier.toString(m.getModifiers()),
      // m.getReturnType().getName(), m.getName(), Util.getParameterTypes(m.getParameterTypes())));
      tempM = CtNewMethod.copy(m, newClass, null);
      if ("void".equals(tempM.getReturnType().getName()))
        tempM.setBody("{super." + tempM.getName() + "($$);}");
      else tempM.setBody("{ return super." + tempM.getName() + "($$);}");
      //				CtNewMethod.make(src, declaring, delegateObj, delegateMethod)
      // 方法修改
      //			if (m.getName().equals("x")) {
      //				//tempM.setBody("{$proceed($$);}", "this", "mba");
      //				//tempM.setBody("{n nn = new n();" + "Method a = n.class.getDeclaredMethod(\"a\", new
      // Class[] { Integer.TYPE });" + "a.invoke(nn, new Object[] { Integer.valueOf(1) });}");
      //				tempM.setBody("{Method a = n.class.getDeclaredMethod(\"axx\", new Class[] { Integer.TYPE
      // });}");
      //			}
      newClass.addMethod(tempM);
    }

    // 测试输出
    try {
      newClass.writeFile("D:/Desktop");
    } catch (IOException e) {
      e.printStackTrace();
    }

    //		Class clazz = newClass.toClass();
    //		System.out.println(clazz.getCanonicalName());
    //		DefaultCachePoolFactory.newInstance().addNFloop4Map(new ClazzInfo(clazz, tempMethod),
    // DefaultPool.NORNAL_BEAN, clazz.getCanonicalName());
    //		return clazz;
    return new ClazzInfo(newClass.toClass(), tempMethod);
  }
  @InitMethod
  static void initClass(CtClass c) throws CannotCompileException {
    CtConstructor cons = JavassistUtils.findConstructor(c);

    cons.insertAfter("getElement().getStyle().setProperty(\"visibility\", \"hidden\");");
  }