Search in sources :

Example 66 with CtField

use of javassist.CtField in project hibernate-orm by hibernate.

the class PersistentAttributesHelper method inferTypeName.

/**
 * Consistent with hasAnnotation()
 */
private static String inferTypeName(CtClass ctClass, String attributeName) {
    AccessType classAccessType = getAccessTypeOrNull(ctClass);
    CtField field = findFieldOrNull(ctClass, attributeName);
    CtMethod getter = findGetterOrNull(ctClass, attributeName);
    if (classAccessType == AccessType.FIELD || (field != null && getAccessTypeOrNull(field) == AccessType.FIELD)) {
        return field == null ? null : inferFieldTypeName(field);
    }
    if (classAccessType == AccessType.PROPERTY || (getter != null && getAccessTypeOrNull(getter) == AccessType.PROPERTY)) {
        return getter == null ? null : inferMethodTypeName(getter);
    }
    String found = (getter == null ? null : inferMethodTypeName(getter));
    if (found == null && field != null) {
        return inferFieldTypeName(field);
    }
    return found;
}
Also used : CtField(javassist.CtField) AccessType(javax.persistence.AccessType) CtMethod(javassist.CtMethod)

Example 67 with CtField

use of javassist.CtField in project BroadleafCommerce by BroadleafCommerce.

the class ConditionalFieldAnnotationsClassTransformer method transform.

/**
 * Will return null if the Spring property value defined in {@link #propertyName} resolves to false, or if
 * an exception occurs while trying to determine the value for the property.
 *
 * @param loader
 * @param className
 * @param classBeingRedefined
 * @param protectionDomain
 * @param classfileBuffer
 * @return
 * @throws IllegalClassFormatException
 */
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
    // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done
    if (className == null) {
        return null;
    }
    String convertedClassName = className.replace('/', '.');
    ConditionalFieldAnnotationCopyTransformMemberDTO dto = manager.getTransformMember(convertedClassName);
    if (dto == null || dto.getTemplateNames() == null || dto.getTemplateNames().length < 1) {
        return null;
    }
    // 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 {
        String[] xformVals = dto.getTemplateNames();
        // Load the destination class and defrost it so it is eligible for modifications
        ClassPool classPool = ClassPool.getDefault();
        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);
            CtField[] fieldsToCopy = template.getDeclaredFields();
            // template annotations.  Otherwise, remove all annotations from the target.
            for (CtField field : fieldsToCopy) {
                ConstPool constPool = clazz.getClassFile().getConstPool();
                CtField fieldFromMainClass = clazz.getField(field.getName());
                AnnotationsAttribute copied = null;
                for (Object o : field.getFieldInfo().getAttributes()) {
                    if (o instanceof AnnotationsAttribute) {
                        AnnotationsAttribute templateAnnotations = (AnnotationsAttribute) o;
                        // have to make a copy of the annotations from the target
                        copied = (AnnotationsAttribute) templateAnnotations.copy(constPool, null);
                        break;
                    }
                }
                // add all the copied annotations into the target class's field.
                for (Object attribute : fieldFromMainClass.getFieldInfo().getAttributes()) {
                    if (attribute instanceof AnnotationsAttribute) {
                        Annotation[] annotations = null;
                        if (copied != null) {
                            // If we found annotations to copy, then use all of them
                            ArrayList<Annotation> annotationsList = new ArrayList<Annotation>();
                            for (Annotation annotation : copied.getAnnotations()) {
                                annotationsList.add(annotation);
                            }
                            annotations = new Annotation[annotationsList.size()];
                            int count = 0;
                            for (Annotation annotation : annotationsList) {
                                annotations[count] = annotation;
                                count++;
                            }
                            ((AnnotationsAttribute) attribute).setAnnotations(annotations);
                        } else {
                            // If no annotations were found on the template, then remove them entirely from the target.
                            ((AnnotationsAttribute) attribute).setAnnotations(new Annotation[] {});
                        }
                        break;
                    }
                }
            }
        }
        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) {
            try {
                clazz.detach();
            } catch (Exception e) {
            // do nothing
            }
        }
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) AnnotationsAttribute(javassist.bytecode.AnnotationsAttribute) ClassPool(javassist.ClassPool) ArrayList(java.util.ArrayList) LoaderClassPath(javassist.LoaderClassPath) Annotation(javassist.bytecode.annotation.Annotation) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) CtClass(javassist.CtClass) ByteArrayInputStream(java.io.ByteArrayInputStream) CtField(javassist.CtField) ConditionalFieldAnnotationCopyTransformMemberDTO(org.broadleafcommerce.common.weave.ConditionalFieldAnnotationCopyTransformMemberDTO)

Example 68 with CtField

use of javassist.CtField in project BroadleafCommerce by BroadleafCommerce.

the class DirectCopyClassTransformer method transform.

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
    // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done
    if (className == null) {
        return null;
    }
    // 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;
        Set<String> buildXFormVals = new HashSet<>();
        Boolean[] xformSkipOverlaps = null;
        Boolean[] xformRenameMethodOverlaps = null;
        if (!xformTemplates.isEmpty()) {
            if (xformTemplates.containsKey(xformKey)) {
                buildXFormVals.addAll(Arrays.asList(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<>();
            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);
                XFormParams params = reviewDirectCopyTransformAnnotations(clazz, mySkipOverlaps, myRenameMethodOverlaps, matchedPatterns);
                XFormParams conditionalParams = reviewConditionalDirectCopyTransforms(convertedClassName, matchedPatterns);
                if (conditionalParams != null && !conditionalParams.isEmpty()) {
                    params = combineXFormParams(params, conditionalParams);
                }
                if (params.getXformVals() != null && params.getXformVals().length > 0) {
                    buildXFormVals.addAll(Arrays.asList(params.getXformVals()));
                }
                xformSkipOverlaps = params.getXformSkipOverlaps();
                xformRenameMethodOverlaps = params.getXformRenameMethodOverlaps();
            }
        }
        if (buildXFormVals.size() > 0) {
            String[] xformVals = buildXFormVals.toArray(new String[buildXFormVals.size()]);
            logger.debug(String.format("[%s] - Transform - Copying into [%s] from [%s]", LifeCycleEvent.END, 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 != null && 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 != null && xformSkipOverlaps[index]) {
                                logger.debug(String.format("Skipping overlapped field [%s]", field.getName()));
                                continue;
                            }
                            clazz.removeField(ctField);
                        } 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());
                        // 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 != null && 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 != null && 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.debug(String.format("[%s] - Transform - Copying into [%s] from [%s]", LifeCycleEvent.END, 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) {
            try {
                clazz.detach();
            } catch (Exception e) {
            // do nothing
            }
        }
    }
    return null;
}
Also used : ConstPool(javassist.bytecode.ConstPool) ClassPool(javassist.ClassPool) ArrayList(java.util.ArrayList) NotFoundException(javassist.NotFoundException) CtField(javassist.CtField) HashSet(java.util.HashSet) ClassFile(javassist.bytecode.ClassFile) LoaderClassPath(javassist.LoaderClassPath) NotFoundException(javassist.NotFoundException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) CtConstructor(javassist.CtConstructor) CtClass(javassist.CtClass) ByteArrayInputStream(java.io.ByteArrayInputStream) CtMethod(javassist.CtMethod)

Example 69 with CtField

use of javassist.CtField in project javassist-maven-plugin by icon-Systemhaus-GmbH.

the class MethodCallClassTransformer method applyTransformations.

@Override
public void applyTransformations(final CtClass classToTransform) throws JavassistBuildException {
    if (null == classToTransform) {
        return;
    }
    try {
        classToTransform.instrument(new ExprEditor() {

            @Override
            public void edit(final MethodCall method) throws CannotCompileException {
                final String statement = getStatement(method.getClassName(), method.getMethodName());
                if (statement != null) {
                    try {
                        method.replace(statement);
                    } catch (final CannotCompileException e) {
                        throw new CannotCompileException(String.format("Compile statement '%1$s' FAILED with: %2$s", statement, e.getMessage()), e);
                    }
                }
            }
        });
        // insert internal introspection state field
        final CtField introspectedField = new CtField(CtClass.booleanType, ALREADY_INTROSPECTED_FIELD_NAME, classToTransform);
        introspectedField.setModifiers(AccessFlag.PUBLIC | AccessFlag.STATIC | AccessFlag.FINAL);
        classToTransform.addField(introspectedField, Initializer.constant(true));
    } catch (CannotCompileException e) {
        throw new JavassistBuildException(e);
    }
}
Also used : CtField(javassist.CtField) ExprEditor(javassist.expr.ExprEditor) JavassistBuildException(javassist.build.JavassistBuildException) CannotCompileException(javassist.CannotCompileException) MethodCall(javassist.expr.MethodCall)

Example 70 with CtField

use of javassist.CtField in project javassist-maven-plugin by icon-Systemhaus-GmbH.

the class TestJavassistTransformerExecuter method applyStamp_on_Class.

@Test
public void applyStamp_on_Class() throws CannotCompileException, NotFoundException {
    // given
    final String className = "test.TestClass";
    final CtClass candidateClass = mock("candidateClass", CtClass.class);
    final Capture<CtField> fieldCaptures = newInstance();
    // createStampField
    expect(candidateClass.isInterface()).andReturn(false);
    expect(candidateClass.getClassPool()).andReturn(classPool).anyTimes();
    expect(candidateClass.getClassFile2()).andReturn(new ClassFile(false, className, null));
    expect(candidateClass.isFrozen()).andReturn(false);
    expect(candidateClass.getName()).andReturn(className).anyTimes();
    candidateClass.addField(capture(fieldCaptures), anyObject(CtField.Initializer.class));
    replay(candidateClass, classPool);
    // when
    sut.applyStamp(candidateClass);
    // then
    verify(candidateClass, classPool);
    assertThat("generated stamp field starts with the constant prefix.", fieldCaptures.getValue().getName(), org.hamcrest.core.StringStartsWith.startsWith(JavassistTransformerExecutor.STAMP_FIELD_NAME));
    assertThat("generated stamp field must have the right modifiers.", fieldCaptures.getValue().getModifiers(), is(STATIC | FINAL | PRIVATE));
    assertThat("generated stamp field is a boolean.", fieldCaptures.getValue().getType(), is(booleanType));
}
Also used : CtClass(javassist.CtClass) ClassFile(javassist.bytecode.ClassFile) CtField(javassist.CtField) Test(org.junit.Test)

Aggregations

CtField (javassist.CtField)76 CtClass (javassist.CtClass)47 CtMethod (javassist.CtMethod)27 CannotCompileException (javassist.CannotCompileException)24 NotFoundException (javassist.NotFoundException)22 ClassPool (javassist.ClassPool)20 CtConstructor (javassist.CtConstructor)15 Test (org.junit.Test)12 ClassFile (javassist.bytecode.ClassFile)9 IOException (java.io.IOException)7 Method (java.lang.reflect.Method)7 ArrayList (java.util.ArrayList)6 AnnotationsAttribute (javassist.bytecode.AnnotationsAttribute)5 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)4 ConstPool (javassist.bytecode.ConstPool)4 SMethod (org.bimserver.shared.meta.SMethod)4 SParameter (org.bimserver.shared.meta.SParameter)4 InsertableMethod (com.github.stephanenicolas.afterburner.inserts.InsertableMethod)3 SimpleInsertableMethod (com.github.stephanenicolas.afterburner.inserts.SimpleInsertableMethod)3 ByteArrayInputStream (java.io.ByteArrayInputStream)3