예제 #1
0
  public static CtClass makeInvocationClassNoCtors(
      AOPClassPool pool,
      boolean makeInnerClass,
      CtClass outerClass,
      String className,
      CtClass superInvocation)
      throws CannotCompileException, NotFoundException {
    CtClass untransformable = pool.get("org.jboss.aop.instrument.Untransformable");

    CtClass invocation;
    if (makeInnerClass) {
      // Strip away the package from classname
      String innerClassName = className.substring(className.lastIndexOf('.') + 1);
      defrostClassIfExists(pool, outerClass.getName() + "$" + innerClassName);

      // Only static nested classes are supported
      boolean classStatic = true;
      invocation = TransformerCommon.makeNestedClass(outerClass, innerClassName, classStatic);
      invocation.setSuperclass(superInvocation);
    } else {
      defrostClassIfExists(pool, className);
      invocation = TransformerCommon.makeClass(pool, className, superInvocation);
    }

    invocation.addInterface(untransformable);
    return invocation;
  }
예제 #2
0
  private static TemplateRenderer tryToCompile(String source, Map<String, String> expressions)
      throws NotFoundException, CannotCompileException, InstantiationException,
          IllegalAccessException {

    ClassPool cp = ClassPool.getDefault();
    CtClass sup = cp.get(Object.class.getCanonicalName());
    CtClass cls = cp.makeClass("RapidoidTemplate" + ID_GEN.incrementAndGet(), sup);

    cls.addInterface(cp.get(TemplateRenderer.class.getCanonicalName()));
    cls.addConstructor(CtNewConstructor.defaultConstructor(cls));

    for (Map.Entry<String, String> expr : expressions.entrySet()) {
      String fld =
          "private static final org.rapidoid.render.retriever.ValueRetriever %s = org.rapidoid.render.retriever.Retriever.of(%s);";

      String retrieverId = retrieverId(expr.getKey());
      String prop = expr.getValue();

      String field = U.frmt(fld, retrieverId, prop);

      cls.addField(CtField.make(field, cls));
    }

    CtClass[] params = {cp.get(RenderCtx.class.getCanonicalName())};
    CtClass clsVoid = cp.get(void.class.getCanonicalName());
    cls.addMethod(
        CtNewMethod.make(Modifier.PUBLIC, clsVoid, "render", params, new CtClass[0], source, cls));

    return (TemplateRenderer) cls.toClass().newInstance();
  }
예제 #3
0
  public static Getter generateGetter(OgnlContext context, String code) throws OgnlException {
    String className = NAME_FACTORY.getNewClassName();

    try {
      ClassPool pool = (ClassPool) pools.get(context.getClassResolver());
      EnhancedClassLoader loader = (EnhancedClassLoader) loaders.get(context.getClassResolver());
      CtClass newClass;
      CtClass ognlContextClass;
      CtClass objectClass;
      CtClass stringClass;
      CtMethod method;
      byte[] byteCode;
      Class compiledClass;

      if ((pool == null) || (loader == null)) {
        ClassLoader classLoader =
            new ContextClassLoader(OgnlContext.class.getClassLoader(), context);

        pool = ClassPool.getDefault();
        pool.insertClassPath(new LoaderClassPath(classLoader));
        pools.put(context.getClassResolver(), pool);

        loader = new EnhancedClassLoader(classLoader);
        loaders.put(context.getClassResolver(), loader);
      }

      newClass = pool.makeClass(className);
      ognlContextClass = pool.get(OgnlContext.class.getName());
      objectClass = pool.get(Object.class.getName());
      stringClass = pool.get(String.class.getName());

      newClass.addInterface(pool.get(Getter.class.getName()));
      method =
          new CtMethod(
              objectClass,
              "get",
              new CtClass[] {ognlContextClass, objectClass, stringClass},
              newClass);
      method.setBody("{" + code + "}");
      newClass.addMethod(method);
      byteCode = newClass.toBytecode();
      compiledClass = loader.defineClass(className, byteCode);
      return (Getter) compiledClass.newInstance();
    } catch (Throwable ex) {
      throw new OgnlException("Cannot create class", ex);
    }
  }
예제 #4
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 handleCompositeField(
      CtClass managedCtClass, CtField persistentField, CtMethod fieldWriter)
      throws NotFoundException, CannotCompileException {
    if (!persistentField.hasAnnotation(Embedded.class)) {
      return;
    }

    // make sure to add the CompositeOwner interface
    managedCtClass.addInterface(classPool.get(CompositeOwner.class.getName()));

    if (enhancementContext.isCompositeClass(managedCtClass)) {
      // if a composite have a embedded field we need to implement the TRACKER_CHANGER_NAME method
      // as well
      MethodWriter.write(
          managedCtClass,
          ""
              + "public void %1$s(String name) {%n"
              + "  if (%2$s != null) { %2$s.callOwner(\".\" + name) ; }%n}",
          EnhancerConstants.TRACKER_CHANGER_NAME,
          EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME);
    }

    // cleanup previous owner
    fieldWriter.insertBefore(
        String.format(
            "" + "if (%1$s != null) { ((%2$s) %1$s).%3$s(\"%1$s\"); }%n",
            persistentField.getName(),
            CompositeTracker.class.getName(),
            EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER));

    // trigger track changes
    fieldWriter.insertAfter(
        String.format(
            "" + "((%2$s) %1$s).%4$s(\"%1$s\", (%3$s) this);%n" + "%5$s(\"%1$s\");",
            persistentField.getName(),
            CompositeTracker.class.getName(),
            CompositeOwner.class.getName(),
            EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER,
            EnhancerConstants.TRACKER_CHANGER_NAME));
  }
  @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;
  }
예제 #8
0
  private boolean addSerializeMethods(CtClass cc, boolean callSuper)
      throws NotFoundException, CannotCompileException {
    CtField[] fields = cc.getDeclaredFields();
    int size = 0;
    StringBuffer sb = new StringBuffer();
    sb.append(callSuper ? "{$2=super.pack($1, $2);$1.extend($2" : "{$1.extend($2");
    for (int i = 0; i < fields.length; i++) {
      CtField f = fields[i];
      if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) {
        CtClass type = f.getType();
        if (type.isPrimitive()) {
          if (type == CtClass.booleanType || type == CtClass.byteType) {
            size += 1;
          } else if (type == CtClass.charType || type == CtClass.shortType) {
            size += 2;
          } else if (type == CtClass.longType || type == CtClass.doubleType) {
            size += 8;
          } else {
            size += 4;
          }
        } else if (type.getName().equals("java.lang.String")) {
          sb.append("+org.nachodb.impl.Bytes#sizeof(");
          sb.append(f.getName());
          sb.append(",$3)");
        } else {
          return false;
        }
      }
    }
    cc.addInterface(serializable);

    CtMethod m = new CtMethod(pack, cc, null);
    sb.append('+');
    sb.append(size);
    sb.append(");");
    for (int i = 0; i < fields.length; i++) {
      CtField f = fields[i];
      if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) {
        CtClass type = f.getType();
        String name = f.getName();
        if (type == CtClass.booleanType) {
          sb.append("$1.arr[$2++]=(byte)(");
          sb.append(name);
          sb.append("?1:0);");
        } else if (type == CtClass.charType) {
          sb.append("org.nachodb.impl.Bytes#pack2($1.arr,$2,(short)");
          sb.append(name);
          sb.append(");$2+=2;");
        } else if (type == CtClass.byteType) {
          sb.append("$1.arr[$2++]=");
          sb.append(name);
          sb.append(";");
        } else if (type == CtClass.shortType) {
          sb.append("org.nachodb.impl.Bytes#pack2($1.arr,$2,");
          sb.append(name);
          sb.append(");$2+=2;");
        } else if (type == CtClass.intType) {
          sb.append("org.nachodb.impl.Bytes#pack4($1.arr,$2,");
          sb.append(name);
          sb.append(");$2+=4;");
        } else if (type == CtClass.longType) {
          sb.append("org.nachodb.impl.Bytes#pack8($1.arr,$2,");
          sb.append(name);
          sb.append(");$2+=8;");
        } else if (type == CtClass.doubleType) {
          sb.append("org.nachodb.impl.Bytes#packF8($1.arr,$2,");
          sb.append(name);
          sb.append(");$2+=8;");
        } else if (type == CtClass.floatType) {
          sb.append("org.nachodb.impl.Bytes#packF4($1.arr,$2,");
          sb.append(name);
          sb.append(");$2+=4;");
        } else {
          sb.append("$2=org.nachodb.impl.Bytes#packStr($1.arr,$2,");
          sb.append(name);
          sb.append(",$3);");
        }
      }
    }
    sb.append("return $2;}");
    m.setBody(sb.toString());
    cc.addMethod(m);

    m = new CtMethod(unpack, cc, null);
    sb = new StringBuffer();
    sb.append(callSuper ? "{$2=super.unpack($1, $2);" : "{");
    for (int i = 0; i < fields.length; i++) {
      CtField f = fields[i];
      if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) {
        CtClass type = f.getType();
        String name = f.getName();
        sb.append(name);
        sb.append('=');
        if (type == CtClass.booleanType) {
          sb.append("$1[$2++]!=0;");
        } else if (type == CtClass.charType) {
          sb.append("(char)org.nachodb.impl.Bytes#unpack2($1,$2);$2+=2;");
        } else if (type == CtClass.byteType) {
          sb.append("$1[$2++];");
        } else if (type == CtClass.shortType) {
          sb.append("org.nachodb.impl.Bytes#unpack2($1,$2);$2+=2;");
        } else if (type == CtClass.intType) {
          sb.append("org.nachodb.impl.Bytes#unpack4($1,$2);$2+=4;");
        } else if (type == CtClass.longType) {
          sb.append("org.nachodb.impl.Bytes#unpack8($1,$2);$2+=8;");
        } else if (type == CtClass.doubleType) {
          sb.append("org.nachodb.impl.Bytes#unpackF8($1,$2);$2+=8;");
        } else if (type == CtClass.floatType) {
          sb.append("org.nachodb.impl.Bytes#unpackF4($1,$2);$2+=4;");
        } else {
          sb.append(
              "org.nachodb.impl.Bytes#unpackStr($1,$2,$3);$2+=org.nachodb.impl.Bytes#sizeof($1,$2);");
        }
      }
    }
    sb.append("return $2;}");
    m.setBody(sb.toString());
    cc.addMethod(m);
    return true;
  }
  public byte[] injectReactive(String classname) throws Exception {
    init();

    CtClass droolsPojo = cp.get(classname);
    if (collectReactiveFields(droolsPojo).size() == 0) {
      LOG.info(
          "Skipped bytecode injection in class "
              + droolsPojo.getName()
              + " because no fields candidated for reactivity.");
      return droolsPojo.toBytecode();
    }

    droolsPojo.addInterface(cp.get(ReactiveObject.class.getName()));

    CtField ltsCtField =
        new CtField(cp.get(Collection.class.getName()), DROOLS_LIST_OF_TUPLES, droolsPojo);
    ltsCtField.setModifiers(Modifier.PRIVATE);
    ClassType listOfTuple =
        new SignatureAttribute.ClassType(
            Collection.class.getName(),
            new TypeArgument[] {
              new TypeArgument(new SignatureAttribute.ClassType(Tuple.class.getName()))
            });
    ltsCtField.setGenericSignature(listOfTuple.encode());
    // Do not use the Initializer.byNew... as those method always pass at least 1 parameter which is
    // "this".
    droolsPojo.addField(ltsCtField, Initializer.byExpr("new java.util.HashSet();"));

    final CtMethod getLeftTuplesCtMethod =
        CtNewMethod.make(
            "public java.util.Collection getLeftTuples() {\n"
                + "    return this.$$_drools_lts != null ? this.$$_drools_lts : java.util.Collections.emptyList();\n"
                + "}",
            droolsPojo);
    MethodSignature getLeftTuplesSignature = new MethodSignature(null, null, listOfTuple, null);
    getLeftTuplesCtMethod.setGenericSignature(getLeftTuplesSignature.encode());
    droolsPojo.addMethod(getLeftTuplesCtMethod);

    final CtMethod addLeftTupleCtMethod =
        CtNewMethod.make(
            "public void addLeftTuple("
                + Tuple.class.getName()
                + " leftTuple) {\n"
                + "    if ($$_drools_lts == null) {\n"
                + "        $$_drools_lts = new java.util.HashSet();\n"
                + "    }\n"
                + "    $$_drools_lts.add(leftTuple);\n"
                + "}",
            droolsPojo);
    droolsPojo.addMethod(addLeftTupleCtMethod);

    final CtMethod removeLeftTupleCtMethod =
        CtNewMethod.make(
            "public void removeLeftTuple("
                + Tuple.class.getName()
                + " leftTuple) {\n"
                + "    $$_drools_lts.remove(leftTuple);\n"
                + "}",
            droolsPojo);
    droolsPojo.addMethod(removeLeftTupleCtMethod);

    Map<String, CtField> fieldsMap = collectReactiveFields(droolsPojo);
    for (CtField f : fieldsMap.values()) {
      LOG.debug("Preparing field writer method for field: {}.", f);
      writeMethods.put(f.getName(), makeWriter(droolsPojo, f));
    }

    enhanceAttributesAccess(fieldsMap, droolsPojo);

    // first call CtClass.toClass() before the original class is loaded, it will persist the
    // bytecode instrumentation changes in the classloader.
    return droolsPojo.toBytecode();
  }
예제 #10
0
  /**
   * Given a bean-style interface, generate an instance of the interface by implementing getters and
   * setters for each property. It will also add implementations to support the {@link
   * SupportsRdfId} interface and generate simple, default equals, toString and hashCode methods.
   *
   * <p>If there are other non-bean style (getter and/or setter's for properties) methods on the
   * interface, this will likely fail to generate the instance.
   *
   * @param theInterface the interface to build an instance of
   * @param <T> the type of the interface
   * @return New dynamically generated bytecode of a class that implements the given interface.
   * @throws Exception if there is an error while generating the bytecode of the new class.
   */
  public static synchronized <T> Class<T> generateInstanceClass(Class<T> theInterface)
      throws Exception {
    processedMethods.clear();

    // TODO: can we use some sort of template language for this?

    ClassPool aPool = ClassPool.getDefault();

    aPool.appendClassPath(new LoaderClassPath(theInterface.getClassLoader()));

    CtClass aInterface = aPool.get(theInterface.getName());
    CtClass aSupportsRdfIdInterface = aPool.get(SupportsRdfId.class.getName());
    CtClass aEmpireGeneratedInterface = aPool.get(EmpireGenerated.class.getName());

    if (!Arrays.asList(aInterface.getInterfaces()).contains(aSupportsRdfIdInterface)
        && !SupportsRdfId.class.isAssignableFrom(theInterface)) {
      throw new IllegalArgumentException(
          "Class '"
              + theInterface.getName()
              + "' does not implement SupportsRdfId, cannot generate Empire suitable implementation.");
    }

    String aName = aInterface.getPackageName() + ".impl." + aInterface.getSimpleName() + "Impl";
    CtClass aClass = null;

    try {
      //  i had a good reason for doing this, but i dont remember what it is.  when i do, i'll
      // explain it here =)

      aClass = aPool.get(aName);
      return (Class<T>) BeanReflectUtil.loadClass(aName);
    } catch (NotFoundException e) {
      aClass =
          aPool.makeClass(
              aInterface.getPackageName() + ".impl." + aInterface.getSimpleName() + "Impl");
    } catch (ClassNotFoundException e) {
      throw new Exception("Previously created class cannot be loaded.", e);
    }

    if (aClass.isFrozen()) {
      aClass.defrost();
    }

    if (aInterface.isInterface()) {
      aClass.addInterface(aInterface);
    } else {
      aClass.setSuperclass(aInterface);
    }

    aClass.addInterface(aSupportsRdfIdInterface);
    aClass.addInterface(aEmpireGeneratedInterface);

    CtField aInterfaceField =
        new CtField(aPool.get(Class.class.getName()), "mInterfaceClass", aClass);
    aClass.addField(
        aInterfaceField, CtField.Initializer.byExpr(theInterface.getName() + ".class;"));

    CtField aAllTriplesField = new CtField(aPool.get(Graph.class.getName()), "mAllTriples", aClass);
    aClass.addField(
        aAllTriplesField, CtField.Initializer.byExpr("new com.clarkparsia.openrdf.ExtGraph();"));

    CtField aInstanceTriplesField =
        new CtField(aPool.get(Graph.class.getName()), "mInstanceTriples", aClass);
    aClass.addField(
        aInstanceTriplesField,
        CtField.Initializer.byExpr("new com.clarkparsia.openrdf.ExtGraph();"));

    aClass.addConstructor(CtNewConstructor.defaultConstructor(aClass));

    generateMethods(theInterface, aPool, aClass);
    generateMethodsForSuperInterfaces(theInterface, aPool, aClass);

    CtField aIdField = new CtField(aPool.get(SupportsRdfId.class.getName()), "supportsId", aClass);
    aClass.addField(
        aIdField,
        CtField.Initializer.byExpr("new com.clarkparsia.empire.annotation.SupportsRdfIdImpl();"));

    if (!hasMethod(aClass, "getRdfId")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public com.clarkparsia.empire.SupportsRdfId.RdfKey getRdfId() { return supportsId.getRdfId(); } ",
              aClass));
    }

    if (!hasMethod(aClass, "setRdfId")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public void setRdfId(com.clarkparsia.empire.SupportsRdfId.RdfKey theURI) { supportsId.setRdfId(theURI); } ",
              aClass));
    }

    if (!hasMethod(aClass, "getAllTriples")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public org.openrdf.model.Graph getAllTriples() { return mAllTriples; } ", aClass));
    }

    if (!hasMethod(aClass, "setAllTriples")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public void setAllTriples(org.openrdf.model.Graph theGraph) { mAllTriples = theGraph; } ",
              aClass));
    }

    if (!hasMethod(aClass, "getInstanceTriples")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public org.openrdf.model.Graph getInstanceTriples() { return mInstanceTriples; } ",
              aClass));
    }

    if (!hasMethod(aClass, "setInstanceTriples")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public void setInstanceTriples(org.openrdf.model.Graph theGraph) { mInstanceTriples = theGraph; } ",
              aClass));
    }

    String equalsMethodBody =
        "public boolean equals(Object theObj) {\n"
            + "  if (theObj == this) return true;\n"
            + "  if (!(theObj instanceof com.clarkparsia.empire.SupportsRdfId)) return false;\n"
            + "  if (!(mInterfaceClass.isAssignableFrom(theObj.getClass()))) return false;\n"
            + "  return getRdfId().equals( ((com.clarkparsia.empire.SupportsRdfId) theObj).getRdfId()) && super.equals(theObj);\n"
            + "}\n";

    aClass.addMethod(CtNewMethod.make(equalsMethodBody, aClass));

    if (theInterface.isInterface()) {
      aClass.addMethod(
          CtNewMethod.make(
              "public String toString() { return getRdfId() != null ? getRdfId().toString() : super.toString(); } ",
              aClass));
      aClass.addMethod(
          CtNewMethod.make(
              "public int hashCode() { return getRdfId() != null ? getRdfId().hashCode() : 0; } ",
              aClass));
    }

    aClass.freeze();

    Class<T> aResult = (Class<T>) aClass.toClass();

    try {
      // make sure this is a valid class, that is, we can create instances of it!
      aResult.newInstance();
    } catch (Exception ex) {
      // TODO: log this?
      throw ex;
    }

    return aResult;
  }
  /** 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");
  }
예제 #12
0
  // 用javassit得到动态代理
  public T createJavassistBytecodeDynamicProxy(
      LoadBalancer loadBalance, ConcurrentMap<String, T> map, Class ifaces) {
    try {
      ClassPool mPool = new ClassPool(true);
      CtClass mCtc = mPool.makeClass(ifaces.getName() + "JavaassistProxy");
      mCtc.addInterface(mPool.get(ifaces.getName()));
      mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));

      mCtc.addField(CtField.make("public " + loadBalance.getClass().getName() + " sub;", mCtc));
      mCtc.addField(CtField.make("public " + map.getClass().getName() + " map;", mCtc));
      //            mCtc.addField(CtField.make("public " + ArrayList.class.getName() + " list;",
      // mCtc));

      mCtc.addMethod(
          CtNewMethod.make(
              "public Object getRealClient() { return (Object)sub.select(new "
                  + ArrayList.class.getName()
                  + "(map.values())); }",
              mCtc));

      // 获取接口的方法
      for (Method method : ifaces.getMethods()) {
        Class returnType = method.getReturnType();
        String modifiers = "public";
        if (Modifier.PUBLIC == method.getModifiers()) {
          modifiers = "public";
        } else if (Modifier.PROTECTED == method.getModifiers()) {
          modifiers = "protected";
        } else if (Modifier.PRIVATE == method.getModifiers()) {
          modifiers = "private";
        }
        Class<?>[] parameter = method.getParameterTypes();

        String params = "";
        String ps = "";
        for (Class param : parameter) {
          params += param.getName() + " " + param.getName() + ",";
          ps += param.getName() + ",";
        }
        if (params.equals("")) {
          params = "";
          ps = "";
        } else {
          params = params.substring(0, params.length());
          ps = ps.substring(0, ps.length());
        }

        mCtc.addMethod(
            CtNewMethod.make(
                modifiers
                    + " void "
                    + method.getName()
                    + "(String a,String b){ Object t=this.getRealClient(); return (("
                    + ifaces.getName()
                    + ")t)."
                    + method.getName()
                    + "(a,b) ;}",
                mCtc));
        //                mCtc.addMethod(CtNewMethod.make("public int count() { return
        // delegate.count(); }", mCtc));
      }

      Class<?> pc = mCtc.toClass();

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

      T bytecodeProxy = (T) pc.newInstance();
      Field filed = bytecodeProxy.getClass().getField("sub");
      filed.set(bytecodeProxy, loadBalance);

      Field filed1 = bytecodeProxy.getClass().getField("map");
      filed1.set(bytecodeProxy, map);

      return bytecodeProxy;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }