// this GwtCreateHandler has been introduced to make possible the
  // instanciation of abstract classes
  // that gwt-test-utils doesn't patch right now
  public Object create(Class<?> classLiteral) throws Exception {
    if (classLiteral.isAnnotation()
        || classLiteral.isArray()
        || classLiteral.isEnum()
        || classLiteral.isInterface()
        || !Modifier.isAbstract(classLiteral.getModifiers())) {
      return null;
    }

    Class<?> newClass = cache.get(classLiteral);

    if (newClass != null) {
      return newClass.newInstance();
    }

    CtClass ctClass = GwtClassPool.getCtClass(classLiteral);
    CtClass subClass = GwtClassPool.get().makeClass(classLiteral.getCanonicalName() + "SubClass");

    subClass.setSuperclass(ctClass);

    for (CtMethod m : ctClass.getDeclaredMethods()) {
      if (javassist.Modifier.isAbstract(m.getModifiers())) {
        CtMethod copy = new CtMethod(m, subClass, null);
        subClass.addMethod(copy);
      }
    }

    GwtPatcherUtils.patch(subClass, null);

    newClass = subClass.toClass(GwtClassLoader.get(), null);
    cache.put(classLiteral, newClass);

    return newClass.newInstance();
  }
  public T createJavassistProxy(
      LoadBalancer loadBalance, ConcurrentMap<String, T> map, Class ifaces) throws Exception {

    Class<?>[] interfaces = ifaces.getInterfaces();

    if (interfaces.length == 1) {
      ClassPool mPool = new ClassPool(true);
      CtClass ctClass = mPool.get(interfaces[0].getName());

      // 新建代理类
      CtClass mCtc = mPool.makeClass(ifaces.getName() + "$JavassistProxy");
      mCtc.setSuperclass(ctClass);

      for (CtMethod method : ctClass.getDeclaredMethods()) {
        System.out.println(method.getName());

        //                CtMethod m = new CtMethod(method.getReturnType(),
        // ,method.getParameterTypes(), mCtc);
        //                cc.addMethod(m);
        //                m.setBody("{ x += $1; }");

        mCtc.addMethod(method);
        //                method.setBody("");

      }
      //            mCtc.debugWriteFile("/home/liguojun");

      return null;
    } else {
      return null;
    }
  }
  public static void patch(CtClass c, IPatcher patcher) throws Exception {
    treatClassToPatch(c);

    if (patcher != null) {
      patcher.initClass(c);
    }

    for (CtMethod m : c.getDeclaredMethods()) {
      boolean wasAbstract = false;
      String newBody = null;
      if (Modifier.isAbstract(m.getModifiers())) {
        m.setModifiers(m.getModifiers() - Modifier.ABSTRACT);
        wasAbstract = true;
      }
      if (patcher != null) {
        newBody = patcher.getNewBody(m);
      }
      if (newBody != null) {
        if (newBody.startsWith(AutomaticPatcher.INSERT_BEFORE)) {
          GwtPatcherUtils.insertBefore(
              m, newBody.substring(AutomaticPatcher.INSERT_BEFORE.length()));
        } else if (newBody.startsWith(AutomaticPatcher.INSERT_AFTER)) {
          GwtPatcherUtils.insertAfter(m, newBody.substring(AutomaticPatcher.INSERT_AFTER.length()));
        } else {
          GwtPatcherUtils.replaceImplementation(m, newBody);
        }
      } else if (wasAbstract) {
        if (patcher != null) {
          m.setBody(
              "{ throw new "
                  + UnsupportedOperationException.class.getName()
                  + "(\"Abstract method '"
                  + c.getSimpleName()
                  + "."
                  + m.getName()
                  + "()' is not patched by "
                  + patcher.getClass().getName()
                  + "\"); }");
        } else {
          m.setBody(
              "{ throw new "
                  + UnsupportedOperationException.class.getName()
                  + "(\"Abstract method '"
                  + c.getSimpleName()
                  + "."
                  + m.getName()
                  + "()' is not patched by any declared "
                  + IPatcher.class.getSimpleName()
                  + " instance\"); }");
        }
      }
    }

    if (patcher != null) {
      patcher.finalizeClass(c);
    }
  }
 static void nullJavassistAdapt(ClassPool pool, final byte[] b) throws Exception {
   CtClass cc = pool.makeClass(new ByteArrayInputStream(b));
   CtMethod[] ms = cc.getDeclaredMethods();
   for (int j = 0; j < ms.length; ++j) {
     if (skipDebug) {
       // is there a mean to remove the debug attributes?
     }
     if (compute) {
       // how to force recomputation of maxStack and maxLocals?
     }
   }
   cc.toBytecode();
 }
  @Override
  public void enhanceThisClass(final ApplicationClass applicationClass) throws Exception {
    final CtClass ctClass = makeClass(applicationClass);
    if (ctClass.isInterface()) {
      return;
    }

    final Map<CtField, InjectionInfo> fieldsToInject = scanForInjections(ctClass);

    // in all methods, replace the field accesses with a call to spring
    for (final CtMethod ctMethod : ctClass.getDeclaredMethods()) {
      ctMethod.instrument(
          new ExprEditor() {
            @Override
            public void edit(final FieldAccess fieldAccess) {
              try {
                final InjectionInfo injectionInfo = fieldsToInject.get(fieldAccess.getField());

                if (injectionInfo != null && fieldAccess.isReader()) {

                  switch (injectionInfo.injectionMethod) {
                    case BY_NAME:
                      fieldAccess.replace(
                          "$_ = ($r)play.utils.Java.invokeStatic(play.modules.spring.Spring.class, \"getBean\", new Object[] {\""
                              + injectionInfo.beanName
                              + "\"});");
                      break;
                    case BY_TYPE:
                      fieldAccess.replace(
                          "$_ = ($r)play.utils.Java.invokeStatic(play.modules.spring.Spring.class, \"getBeanOfType\", new Object[] {$type});");
                      break;
                  }
                }
              } catch (final Exception e) {
                Logger.error(
                    e,
                    "Error in SpringEnhancer. %s.%s has not been properly enhanced (fieldAccess %s).",
                    applicationClass.name,
                    ctMethod.getName(),
                    fieldAccess);
                throw new UnexpectedException("Error enhancing injected field", e);
              }
            }
          });
    }

    applicationClass.enhancedByteCode = ctClass.toBytecode();
    ctClass.defrost();
  }
Example #6
0
 private void preprocessMethods(CtClass cc, boolean insertLoad, boolean wrapFieldAccess)
     throws CannotCompileException {
   CtMethod[] methods = cc.getDeclaredMethods();
   for (int i = 0; i < methods.length; i++) {
     CtMethod m = methods[i];
     if (wrapFieldAccess) {
       m.instrument(
           new ExprEditor() {
             public void edit(FieldAccess fa) throws CannotCompileException {
               try {
                 if ((fa.getField().getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC)) == 0
                     && fa.getField().getDeclaringClass().subtypeOf(persistentInterface)) {
                   if (fa.isWriter()) {
                     fa.replace("{ $0.loadAndModify(); $proceed($$); }");
                   }
                   // isSelfReader is my extension of JAssist, if you
                   // use original version of JAssist comment the
                   // branch below or replace "else if" with "else".
                   // In first case Perst will not be able to handle
                   // access to foreign (non-this) fields. You should use
                   // getter/setter methods instead.
                   // In second case access to foreign fields still will be possible,
                   // but with significant degradation of performance and
                   // increased code size, because in this case before ALL access
                   // to fields of persistent capable object call of load() method
                   // will be inserted.
                   else if (!fa.isSelfReader()) {
                     fa.replace("{ $0.load(); $_ = $proceed($$); }");
                   }
                 }
               } catch (NotFoundException x) {
               }
             }
           });
     }
     if (insertLoad
         && !"recursiveLoading".equals(m.getName())
         && (m.getModifiers() & (Modifier.STATIC | Modifier.ABSTRACT)) == 0) {
       m.insertBefore("load();");
     }
   }
 }
  private Set<CtMethod> getPatchMethods(Set<CtClass> patchClasses) {
    Set<CtMethod> result = new HashSet<CtMethod>();

    // add all @PatchMethod found in a temporary map
    Map<String, List<CtMethod>> temp = new HashMap<String, List<CtMethod>>();
    for (CtClass patchClass : patchClasses) {
      for (CtMethod ctMethod : patchClass.getDeclaredMethods()) {
        if (ctMethod.hasAnnotation(PatchMethod.class)) {
          if (!Modifier.isStatic(ctMethod.getModifiers())) {
            throw new GwtTestPatchException(
                "@"
                    + PatchMethod.class.getName()
                    + " has to be static : '"
                    + ctMethod.getLongName()
                    + "'");
          }
          String nameAndSignature =
              ctMethod.getName() + Descriptor.toString(ctMethod.getSignature());
          List<CtMethod> correspondingMethods = temp.get(nameAndSignature);

          if (correspondingMethods == null) {
            correspondingMethods = new ArrayList<CtMethod>();
            temp.put(nameAndSignature, correspondingMethods);
          }

          correspondingMethods.add(ctMethod);
        }
      }
    }

    // for each @PatchMethod with the same signature, filter to get one with
    // override=true
    for (Map.Entry<String, List<CtMethod>> entry : temp.entrySet()) {
      CtMethod methodToUse = getMethodToUse(entry.getValue(), PatchMethod.class);
      methodToUse.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
      result.add(methodToUse);
    }

    return result;
  }
  private CtMethod getInitMethod(Set<CtClass> patchClasses) {
    List<CtMethod> initMethods = new ArrayList<CtMethod>();

    for (CtClass patchClass : patchClasses) {
      for (CtMethod ctMethod : patchClass.getDeclaredMethods()) {
        if (ctMethod.hasAnnotation(InitMethod.class)) {
          if (!Modifier.isStatic(ctMethod.getModifiers())) {
            throw new GwtTestPatchException(
                "@"
                    + InitMethod.class.getName()
                    + " has to be static : '"
                    + ctMethod.getLongName()
                    + "'");
          }
          try {
            if (ctMethod.getParameterTypes().length != 1
                || ctMethod.getParameterTypes()[0] != GwtClassPool.getCtClass(CtClass.class)) {
              throw new GwtTestPatchException(
                  "@"
                      + InitMethod.class.getName()
                      + " method must have one and only one parameter of type '"
                      + CtClass.class.getName()
                      + "'");
            }
          } catch (NotFoundException e) {
            // should never happen
            throw new GwtTestPatchException(e);
          }
          initMethods.add(ctMethod);
        }
      }
    }

    CtMethod initMethod = getMethodToUse(initMethods, InitMethod.class);
    if (initMethod != null) {
      initMethod.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
    }
    return initMethod;
  }
 private void enhanceJPACallback(CtClass ctClass) throws Exception {
   CtMethod[] methods = ctClass.getDeclaredMethods();
   for (CtMethod ctMethod : methods) {
     if (ctMethod.hasAnnotation(AfterSave.class)) {
       enhanceJPACallback(ctClass, ctMethod, AfterSave.class);
     }
     if (ctMethod.hasAnnotation(BeforeSave.class)) {
       enhanceJPACallback(ctClass, ctMethod, BeforeSave.class);
     }
     if (ctMethod.hasAnnotation(AfterUpdate.class)) {
       enhanceJPACallback(ctClass, ctMethod, AfterUpdate.class);
     }
     if (ctMethod.hasAnnotation(BeforeUpdate.class)) {
       enhanceJPACallback(ctClass, ctMethod, BeforeUpdate.class);
     }
     if (ctMethod.hasAnnotation(BeforeDestroy.class)) {
       enhanceJPACallback(ctClass, ctMethod, BeforeDestroy.class);
     }
     if (ctMethod.hasAnnotation(AfterLoad.class)) {
       enhanceJPACallback(ctClass, ctMethod, AfterLoad.class);
     }
   }
 }
  @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;
  }
Example #12
0
  private void enhance_(ApplicationClass applicationClass, boolean buildAuthorityRegistryOnly)
      throws Exception {
    Plugin.trace("about to enhance applicationClass: %s", applicationClass);
    CtClass ctClass = makeClass(applicationClass);
    Set<CtBehavior> s = new HashSet<CtBehavior>();
    s.addAll(Arrays.asList(ctClass.getDeclaredMethods()));
    s.addAll(Arrays.asList(ctClass.getMethods()));
    s.addAll(Arrays.asList(ctClass.getConstructors()));
    s.addAll(Arrays.asList(ctClass.getDeclaredConstructors()));
    for (final CtBehavior ctBehavior : s) {
      if (!Modifier.isPublic(ctBehavior.getModifiers())
          || javassist.Modifier.isAbstract(ctBehavior.getModifiers())) {
        continue;
      }

      boolean needsEnhance = false;
      RequireRight rr = null;
      RequirePrivilege rp = null;
      RequireAccounting ra = null;
      boolean allowSystem = false;
      Object[] aa = ctBehavior.getAnnotations();
      for (Object o : aa) {
        if (o instanceof RequirePrivilege) {
          needsEnhance = true;
          rp = (RequirePrivilege) o;
          continue;
        }
        if (o instanceof RequireRight) {
          needsEnhance = true;
          rr = (RequireRight) o;
          continue;
        }
        if (o instanceof AllowSystemAccount) {
          allowSystem = true;
          continue;
        }
        if (o instanceof RequireAccounting) {
          needsEnhance = true;
          ra = (RequireAccounting) o;
        }
      }
      if (!needsEnhance) continue;

      String key = ctBehavior.getLongName();
      String errMsg = String.format("Error enhancing class %s.%s: ", ctClass, ctBehavior);
      // process rr & rp
      if (null != rr || null != rp) {
        // check before/after enhancement
        Authority.registAuthoriable_(key, rr, rp);
        if (!buildAuthorityRegistryOnly) {
          // verify if before attribute of rr and rp is consistent
          if (null != rr && null != rp && (rr.before() != rp.before())) {
            String reason = "The before setting of RequireRight and RequirePrivilege doesn't match";
            throw new RuntimeException(errMsg + reason);
          }
          boolean before = true;
          if (null != rr) before = rr.before();
          if (null != rp) before = rp.before();
          // try best to guess the target object
          String curObj = "";
          if (null != rr) {
            // target object only impact dynamic access checking, hence rr shall not be null
            boolean isConstructor = ctBehavior instanceof CtConstructor;
            boolean isStatic = false;
            if (!isConstructor) isStatic = Modifier.isStatic(ctBehavior.getModifiers());
            int paraCnt = ctBehavior.getParameterTypes().length;
            int id = rr.target();
            // calibrate target id
            if (0 == id) {
              if (isConstructor) {
                id = -1;
              } else if (isStatic) {
                if (paraCnt > 0) id = 1;
                else id = -1;
              }
            } else if (id > paraCnt) {
              id = paraCnt;
            }
            // speculate cur target statement
            String sid = null;
            if (id == -1) sid = "_";
            if (id > -1) sid = String.valueOf(id);
            if (null != sid) {
              curObj =
                  "play.modules.aaa.PlayDynamicRightChecker.setObjectIfNoCurrent($" + sid + ");";
            }

            if (-1 == id) before = false;
          }
          // check permission enhancement
          if (before) {
            ctBehavior.insertBefore(
                curObj
                    + " play.modules.aaa.enhancer.Enhancer.Authority.checkPermission(\""
                    + key
                    + "\", "
                    + Boolean.toString(allowSystem)
                    + ");");
          } else {
            ctBehavior.insertAfter(
                curObj
                    + " play.modules.aaa.enhancer.Enhancer.Authority.checkPermission(\""
                    + key
                    + "\", "
                    + Boolean.toString(allowSystem)
                    + ");");
          }
        }
      }

      if (buildAuthorityRegistryOnly) continue;

      // process ra
      if (null != ra) {
        CtClass[] paraTypes = ctBehavior.getParameterTypes();
        String sParam = null;
        if (0 < paraTypes.length) {
          sParam = "new Object[0]";
        } else {
          sParam = "{$$}";
        }
        String msg = ra.value();
        if (null == msg || "".equals(msg)) msg = key;
        if (ra.before()) {
          ctBehavior.insertBefore(
              "play.modules.aaa.utils.Accounting.info(\""
                  + msg
                  + "\", "
                  + Boolean.toString(allowSystem)
                  + ", "
                  + sParam
                  + ");");
        } else {
          ctBehavior.insertAfter(
              "play.modules.aaa.utils.Accounting.info(\""
                  + msg
                  + "\", "
                  + Boolean.toString(allowSystem)
                  + ", "
                  + sParam
                  + ");");
        }
        CtClass etype = ClassPool.getDefault().get("java.lang.Exception");
        ctBehavior.addCatch(
            "{play.modules.aaa.utils.Accounting.error($e, \""
                + msg
                + "\", "
                + Boolean.toString(allowSystem)
                + ", "
                + sParam
                + "); throw $e;}",
            etype);
      }
    }

    if (buildAuthorityRegistryOnly) return;

    applicationClass.enhancedByteCode = ctClass.toBytecode();
    ctClass.detach();
  }
Example #13
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);
  }
  /** Generate Javassist Proxy Classes */
  private static <T> void generateProxyClass(
      Class<T> primaryInterface, String superClassName, String methodBody) throws Exception {
    String newClassName = superClassName.replaceAll("(.+)\\.(\\w+)", "$1.Hikari$2");

    CtClass superCt = classPool.getCtClass(superClassName);
    CtClass targetCt = classPool.makeClass(newClassName, superCt);
    targetCt.setModifiers(Modifier.FINAL);

    System.out.println("Generating " + newClassName);

    targetCt.setModifiers(Modifier.PUBLIC);

    // Make a set of method signatures we inherit implementation for, so we don't generate delegates
    // for these
    Set<String> superSigs = new HashSet<>();
    for (CtMethod method : superCt.getMethods()) {
      if ((method.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
        superSigs.add(method.getName() + method.getSignature());
      }
    }

    Set<String> methods = new HashSet<>();
    Set<Class<?>> interfaces = getAllInterfaces(primaryInterface);
    for (Class<?> intf : interfaces) {
      CtClass intfCt = classPool.getCtClass(intf.getName());
      targetCt.addInterface(intfCt);
      for (CtMethod intfMethod : intfCt.getDeclaredMethods()) {
        final String signature = intfMethod.getName() + intfMethod.getSignature();

        // don't generate delegates for methods we override
        if (superSigs.contains(signature)) {
          continue;
        }

        // Ignore already added methods that come from other interfaces
        if (methods.contains(signature)) {
          continue;
        }

        // Ignore default methods (only for Jre8 or later)
        if (isDefaultMethod(intf, intfCt, intfMethod)) {
          continue;
        }

        // Track what methods we've added
        methods.add(signature);

        // Clone the method we want to inject into
        CtMethod method = CtNewMethod.copy(intfMethod, targetCt, null);

        String modifiedBody = methodBody;

        // If the super-Proxy has concrete methods (non-abstract), transform the call into a simple
        // super.method() call
        CtMethod superMethod = superCt.getMethod(intfMethod.getName(), intfMethod.getSignature());
        if ((superMethod.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT) {
          modifiedBody = modifiedBody.replace("((cast) ", "");
          modifiedBody = modifiedBody.replace("delegate", "super");
          modifiedBody = modifiedBody.replace("super)", "super");
        }

        modifiedBody = modifiedBody.replace("cast", primaryInterface.getName());

        // Generate a method that simply invokes the same method on the delegate
        if (isThrowsSqlException(intfMethod)) {
          modifiedBody = modifiedBody.replace("method", method.getName());
        } else {
          modifiedBody =
              "{ return ((cast) delegate).method($$); }"
                  .replace("method", method.getName())
                  .replace("cast", primaryInterface.getName());
        }

        if (method.getReturnType() == CtClass.voidType) {
          modifiedBody = modifiedBody.replace("return", "");
        }

        method.setBody(modifiedBody);
        targetCt.addMethod(method);
      }
    }

    targetCt.writeFile("target/classes");
  }