protected void enhanceAttributesAccess(
      CtClass managedCtClass,
      IdentityHashMap<String, PersistentAttributeAccessMethods> attributeDescriptorMap) {
    final ConstPool constPool = managedCtClass.getClassFile().getConstPool();

    for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
      final MethodInfo methodInfo = (MethodInfo) oMethod;
      final String methodName = methodInfo.getName();

      // skip methods added by enhancement and abstract methods (methods without any code)
      if (methodName.startsWith("$$_hibernate_") || methodInfo.getCodeAttribute() == null) {
        continue;
      }

      try {
        final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
        while (itr.hasNext()) {
          final int index = itr.next();
          final int op = itr.byteAt(index);
          if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
            continue;
          }
          final String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
          final PersistentAttributeAccessMethods attributeMethods =
              attributeDescriptorMap.get(fieldName);

          // its not a field we have enhanced for interception, so skip it
          if (attributeMethods == null) {
            continue;
          }
          // System.out.printf( "Transforming access to field [%s] from method [%s]%n", fieldName,
          // methodName );
          log.debugf("Transforming access to field [%s] from method [%s]", fieldName, methodName);

          if (op == Opcode.GETFIELD) {
            final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getReader());
            itr.writeByte(Opcode.INVOKESPECIAL, index);
            itr.write16bit(methodIndex, index + 1);
          } else {
            final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getWriter());
            itr.writeByte(Opcode.INVOKESPECIAL, index);
            itr.write16bit(methodIndex, index + 1);
          }
        }
        methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
      } catch (BadBytecode bb) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new EnhancementException(msg, bb);
      }
    }
  }
  protected void enhanceAttributesAccess(Map<String, CtField> fieldsMap, CtClass managedCtClass)
      throws Exception {
    final ConstPool constPool = managedCtClass.getClassFile().getConstPool();
    final ClassPool classPool = managedCtClass.getClassPool();

    for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
      final MethodInfo methodInfo = (MethodInfo) oMethod;
      final String methodName = methodInfo.getName();

      // skip methods added by enhancement, and abstract methods (methods without any code)
      if (methodName.startsWith(DROOLS_PREFIX) || methodInfo.getCodeAttribute() == null) {
        continue;
      }

      try {
        final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
        while (itr.hasNext()) {
          final int index = itr.next();
          final int op = itr.byteAt(index);
          if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
            continue;
          }

          final String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
          CtField ctField = fieldsMap.get(fieldName);
          if (ctField == null) {
            continue;
          }

          // if we are in constructors, only need to intercept assignment statement for Reactive
          // Collection/List/... (regardless they may be final)
          if (methodInfo.isConstructor() && !(isCtFieldACollection(ctField))) {
            continue;
          }

          if (op == Opcode.PUTFIELD) {
            // addMethod is a safe add, if constant already present it return the existing value
            // without adding.
            final int methodIndex = addMethod(constPool, writeMethods.get(fieldName));
            itr.writeByte(Opcode.INVOKEVIRTUAL, index);
            itr.write16bit(methodIndex, index + 1);
          }
        }
        methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
      } catch (BadBytecode bb) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new Exception(msg, bb);
      }
    }
  }
Esempio n. 3
0
  private void addOutputArg(List<String> args, Object object) {
    if (!(object instanceof String))
      throw new IllegalArgumentException("Only a single output file can be specified");

    String value = (String) object;
    args.add("-o");
    if (value.endsWith(".vcf")) {
      args.add(value);
      try {
        ConstPool constPool = annotatedWalker.getClassFile().getConstPool();
        AnnotationsAttribute att =
            new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
        Annotation ann = new Annotation(Output.class.getName(), constPool);
        att.addAnnotation(ann);

        CtClass writerClass = pool.get(VCFWriter.class.getName());
        CtField field = new CtField(writerClass, "out", annotatedWalker);
        field.setModifiers(Modifier.PUBLIC);
        field.getFieldInfo().addAttribute(att);
        annotatedWalker.addField(field);
      } catch (NotFoundException e) {
        throw new RuntimeException(e);
      } catch (CannotCompileException e) {
        throw new RuntimeException(e);
      }
    } else throw new IllegalArgumentException("Only VCF files are supported as output files");
  }
  private void autoInjectProperty(ModelClass modelClass) {

    // 连接数据库,自动获取所有信息,然后添加属性
    CtClass ctClass = modelClass.originClass;
    String entitySimpleName = ctClass.getSimpleName();
    List<String> skipFields = modelClass.notMappingColumns();

    try {
      DBType dbType = ServiceFramwork.injector.getInstance(DBType.class);
      DBInfo dbInfo = ServiceFramwork.injector.getInstance(DBInfo.class);

      Map<String, String> columns = dbInfo.tableColumns.get(entitySimpleName);
      if (columns == null) return;
      for (String columnName : columns.keySet()) {
        String fieldName = columnName;
        String fieldType = columns.get(columnName);
        if (skipFields.contains(fieldName)) continue;
        if (fieldName.equals("discriminator")) continue;

        // 对定义过的属性略过
        boolean pass = true;
        try {
          ctClass.getField(fieldName);
        } catch (Exception e) {
          pass = false;
        }
        if (pass) continue;

        ConstPool constPool = ctClass.getClassFile().getConstPool();
        AnnotationsAttribute attr =
            new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
        CtField ctField =
            CtField.make(
                " private " + dbType.typeToJava(fieldType).v2() + " " + fieldName + " ;", ctClass);

        Tuple<Class, Map> tuple = dbType.dateType(fieldType, constPool);
        if (tuple != null) {
          createAnnotation(attr, tuple.v1(), tuple.v2());
        }

        if (fieldName.equals("id")) {
          createAnnotation(attr, javax.persistence.Id.class, map());
          createAnnotation(attr, javax.persistence.GeneratedValue.class, map());
        } else {
          createAnnotation(
              attr, Column.class, map("nullable", new BooleanMemberValue(true, constPool)));
        }

        if (attr.getAnnotations().length > 0) {
          ctField.getFieldInfo().addAttribute(attr);
        }

        ctClass.addField(ctField);
      }

    } catch (Exception e) {
      e.printStackTrace();
    }
    ctClass.defrost();
  }
  @Override
  public void describeTo(StringBuilder stringBuilder) {
    ClosureUtil.SourceInfo sourceInfo = ClosureUtil.getSourceInfo(invoker.getClosure());
    if (sourceInfo == null) {
      ClassPool pool = ClassPool.getDefault();
      try {
        CtClass ctClass = pool.get(invoker.getClosure().getClass().getName());
        CtMethod ctMethod = ctClass.getDeclaredMethod("doCall");
        int lineNumber = ctMethod.getMethodInfo().getLineNumber(0);

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

        if (lineNumber != -1 && sourceFile != null) {
          stringBuilder
              .append("closure at line ")
              .append(lineNumber)
              .append(" of ")
              .append(sourceFile);
        } else {
          stringBuilder.append("closure ").append(invoker.getClosure().getClass().getName());
        }
      } catch (NotFoundException e) {
        stringBuilder.append(invoker.getClosure().getClass().getName());
      }
    } else {
      stringBuilder
          .append("closure at line ")
          .append(sourceInfo.getLineNumber())
          .append(" of ")
          .append(sourceInfo.getUri());
    }
  }
Esempio n. 6
0
  private static void inheritAnnotations(final CtClass theClass, final CtMethod theMethod)
      throws NotFoundException {
    if (hasMethod(theClass, theMethod)) {
      CtMethod aOtherMethod = theClass.getMethod(theMethod.getName(), theMethod.getSignature());
      // method we're probably overriding or implementing in the case of an abstract method.

      AnnotationsAttribute annotationsAttribute =
          (AnnotationsAttribute)
              aOtherMethod.getMethodInfo().getAttribute(AnnotationsAttribute.visibleTag);

      if (annotationsAttribute != null) {
        ConstPool cp = theClass.getClassFile().getConstPool();
        AnnotationsAttribute attr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);

        for (Object obj : annotationsAttribute.getAnnotations()) {

          Annotation a = (Annotation) obj;

          Annotation theAnnotation = new Annotation(a.getTypeName(), cp);

          if (a.getMemberNames() != null) {
            for (Object aName : a.getMemberNames()) {
              theAnnotation.addMemberValue(aName.toString(), a.getMemberValue(aName.toString()));
            }
          }

          attr.setAnnotation(theAnnotation);
        }
        theMethod.getMethodInfo().addAttribute(attr);
      }
    }
  }
 private void findAndRemoveMethod(CtClass ctClass, String methodName) throws NotFoundException {
   try {
     CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
     ctClass.getClassFile().getMethods().remove(ctMethod.getMethodInfo());
   } catch (Exception e) {
   }
 }
  private void findAndRemoveMethod(CtClass ctClass, CtField ctField, String className) {

    try {
      CtMethod ctMethod =
          ctClass.getDeclaredMethod(
              ctField.getName(), new CtClass[] {ctClass.getClassPool().get(className)});
      ctClass.getClassFile().getMethods().remove(ctMethod.getMethodInfo());
    } catch (Exception e) {
    }
  }
Esempio n. 9
0
  private void addVCFArg(List<String> args, Object object) {
    List<String> vcfs = new ArrayList<String>();
    if (object instanceof String) {
      vcfs.addAll(Arrays.asList(((String) object).split(",")));
    } else if (object instanceof List) {
      vcfs.add((String) object);
    }

    int count = 1;
    for (String vcf : vcfs) {
      args.add("--vcf" + count);
      args.add(vcf);
      try {
        ConstPool constPool = annotatedWalker.getClassFile().getConstPool();
        AnnotationsAttribute att =
            new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
        Annotation ann = new Annotation(Input.class.getName(), constPool);

        MemberValue fullName = new StringMemberValue("vcf" + count, constPool);
        ann.addMemberValue("fullName", fullName);
        att.addAnnotation(ann);

        RodBinding<VariantContext> dummy =
            new RodBinding<VariantContext>(VariantContext.class, "vcf", vcf, "VCF", null);
        CtClass rodClass = pool.get(dummy.getClass().getName());

        // If there are multiple vcfs, we number each one - vcf1, vcf2, ...
        // if there is only one, we just call it "vcf"
        CtField field =
            new CtField(rodClass, vcfs.size() > 1 ? "vcf" + count : "vcf", annotatedWalker);
        field.setModifiers(Modifier.PUBLIC);
        field.getFieldInfo().addAttribute(att);

        SignatureAttribute sig =
            new SignatureAttribute(
                constPool,
                "Lorg/broadinstitute/sting/commandline/RodBinding<Lorg/broadinstitute/sting/utils/variantcontext/VariantContext;>;;");
        field.getFieldInfo().addAttribute(sig);

        annotatedWalker.addField(field);

        if (config.containsKey("out")) {
          VCFHeaderInitializer vcfInit = new VCFHeaderInitializer(this);
          this.injections.get("initializers").add(vcfInit);
        }
      } catch (CannotCompileException e) {
        throw new RuntimeException(e);

      } catch (NotFoundException e) {
        throw new RuntimeException(e);
      }
      ++count;
    }
  }
Esempio n. 10
0
  /**
   * Retrieve the String value of an annotation which is not available at runtime.
   *
   * @param clazz The annotated class
   * @param annotation The annotation which is not visible at runtime
   * @param name The name of the String property of the annotation to retrieve
   * @return The String value of the annotation or null if the annotation or its property is not
   *     present
   */
  public static String getInvisibleAnnotationStringValue(
      Class<?> clazz, Class<? extends Annotation> annotation, String name) {
    CtClass ctClass = GwtClassPool.getCtClass(clazz);
    ctClass.defrost();

    AnnotationsAttribute attr =
        (AnnotationsAttribute)
            ctClass.getClassFile().getAttribute(AnnotationsAttribute.invisibleTag);
    if (attr == null) {
      return null;
    }
    javassist.bytecode.annotation.Annotation an = attr.getAnnotation(annotation.getName());

    ctClass.freeze();

    return an != null ? ((StringMemberValue) an.getMemberValue(name)).getValue() : null;
  }
    protected void writeOutChanges() {
      log.info("writing injection changes back [" + classFileLocation.getAbsolutePath() + "]");
      long timeStamp = classFileLocation.lastModified();
      ClassFile classFile = ctClass.getClassFile();
      classFile.compact();
      try {
        DataOutputStream out =
            new DataOutputStream(new BufferedOutputStream(new FileOutputStream(classFileLocation)));
        try {

          classFile.write(out);
          out.flush();
          if (!classFileLocation.setLastModified(System.currentTimeMillis())) {
            log.info("Unable to manually update class file timestamp");
          }
        } finally {
          out.close();
          classFileLocation.setLastModified(timeStamp);
        }
      } catch (IOException e) {
        throw new InjectionException("Unable to write out modified class file", e);
      }
    }
  public byte[] transform(String className) {
    if (transformer.filterClassName(className)) {
      try {
        CtClass classToTransform = classPool.get(className);
        if (!classToTransform.isFrozen() && transformer.filterCtClass(classToTransform)) {
          transformer.applyTransformations(classPool, classToTransform);
          classToTransform.getClassFile().compact();
          classToTransform.rebuildClassFile();

          try (ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
              DataOutputStream out = new DataOutputStream(new BufferedOutputStream(baos))) {
            classToTransform.toBytecode(out);
            out.flush();
            return baos.toByteArray();
          } catch (IOException | CannotCompileException e) {
            throw new IllegalStateException(e);
          }
        }
      } catch (NotFoundException e) {
        throw new IllegalStateException(e);
      }
    }
    return null;
  }
  @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;
  }
 public CtClassAnnotation(CtClass ctClass, Class<? extends java.lang.annotation.Annotation> type) {
   this.classFile = ctClass.getClassFile();
   init(classFile.getConstPool(), type);
 }
  /**
   * Replace access to fields of entities (for example, entity.field) with a call to the enhanced
   * getter / setter (in this example, entity.$$_hibernate_read_field()). It's assumed that the
   * target entity is enhanced as well.
   *
   * @param managedCtClass Class to enhance
   */
  public void enhanceFieldAccess(CtClass managedCtClass) {
    final ConstPool constPool = managedCtClass.getClassFile().getConstPool();

    for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
      final MethodInfo methodInfo = (MethodInfo) oMethod;
      final String methodName = methodInfo.getName();

      // skip methods added by enhancement and abstract methods (methods without any code)
      if (methodName.startsWith("$$_hibernate_") || methodInfo.getCodeAttribute() == null) {
        continue;
      }

      try {
        final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
        while (itr.hasNext()) {
          int index = itr.next();
          int op = itr.byteAt(index);
          if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
            continue;
          }
          String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
          String fieldClassName =
              constPool.getClassInfo(constPool.getFieldrefClass(itr.u16bitAt(index + 1)));
          CtClass targetCtClass = this.classPool.getCtClass(fieldClassName);

          if (!enhancementContext.isEntityClass(targetCtClass)
              && !enhancementContext.isCompositeClass(targetCtClass)) {
            continue;
          }
          if (targetCtClass == managedCtClass
              || !enhancementContext.isPersistentField(targetCtClass.getField(fieldName))
              || "this$0".equals(fieldName)) {
            continue;
          }

          log.debugf("Transforming access to field [%s] from method [%s]", fieldName, methodName);

          if (op == Opcode.GETFIELD) {
            int fieldReaderMethodIndex =
                constPool.addMethodrefInfo(
                    constPool.addClassInfo(fieldClassName),
                    EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName,
                    "()" + constPool.getFieldrefType(itr.u16bitAt(index + 1)));
            itr.writeByte(Opcode.INVOKEVIRTUAL, index);
            itr.write16bit(fieldReaderMethodIndex, index + 1);
          } else {
            int fieldWriterMethodIndex =
                constPool.addMethodrefInfo(
                    constPool.addClassInfo(fieldClassName),
                    EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName,
                    "(" + constPool.getFieldrefType(itr.u16bitAt(index + 1)) + ")V");
            itr.writeByte(Opcode.INVOKEVIRTUAL, index);
            itr.write16bit(fieldWriterMethodIndex, index + 1);
          }
        }
        methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
      } catch (BadBytecode bb) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new EnhancementException(msg, bb);
      } catch (NotFoundException nfe) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new EnhancementException(msg, nfe);
      }
    }
  }