Search in sources :

Example 41 with ClassFile

use of javassist.bytecode.ClassFile in project tutorials by eugenp.

the class JavasisstUnitTest method givenTableOfInstructions_whenAddNewInstruction_thenShouldConstructProperSequence.

@Test
public void givenTableOfInstructions_whenAddNewInstruction_thenShouldConstructProperSequence() throws NotFoundException, BadBytecode, CannotCompileException, IllegalAccessException, InstantiationException {
    // given
    ClassFile cf = ClassPool.getDefault().get("com.baeldung.javasisst.ThreeDimensionalPoint").getClassFile();
    // when
    FieldInfo f = new FieldInfo(cf.getConstPool(), "id", "I");
    f.setAccessFlags(AccessFlag.PUBLIC);
    cf.addField(f);
    ClassPool classPool = ClassPool.getDefault();
    Field[] fields = classPool.makeClass(cf).toClass().getFields();
    List<String> fieldsList = Stream.of(fields).map(Field::getName).collect(Collectors.toList());
    assertTrue(fieldsList.contains("id"));
}
Also used : Field(java.lang.reflect.Field) ClassFile(javassist.bytecode.ClassFile) ClassPool(javassist.ClassPool) FieldInfo(javassist.bytecode.FieldInfo) Test(org.junit.Test)

Example 42 with ClassFile

use of javassist.bytecode.ClassFile in project hibernate-orm by hibernate.

the class ClassFileArchiveEntryHandler method handleEntry.

@Override
public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
    // Ultimately we'd like to leverage Jandex here as long term we want to move to
    // using Jandex for annotation processing.  But even then, Jandex atm does not have
    // any facility for passing a stream and conditionally indexing it into an Index or
    // returning existing ClassInfo objects.
    // 
    // So not sure we can ever not do this unconditional input stream read :(
    final ClassFile classFile = toClassFile(entry);
    final ClassDescriptor classDescriptor = toClassDescriptor(classFile, entry);
    if (classDescriptor.getCategorization() == ClassDescriptor.Categorization.OTHER) {
        return;
    }
    resultCollector.handleClass(classDescriptor, context.isRootUrl());
}
Also used : ClassFile(javassist.bytecode.ClassFile)

Example 43 with ClassFile

use of javassist.bytecode.ClassFile 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 44 with ClassFile

use of javassist.bytecode.ClassFile in project BroadleafCommerce by BroadleafCommerce.

the class QueryConfigurationClassTransformer method transform.

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
    if (className == null || isExecuted) {
        return null;
    }
    String convertedClassName = className.replace('/', '.');
    if (managedClassNames.contains(convertedClassName)) {
        try {
            ClassFile classFile = new ClassFile(new DataInputStream(new ByteArrayInputStream(classfileBuffer)));
            if (isExecuted) {
                return null;
            }
            ConstPool constantPool = classFile.getConstPool();
            ClassPool pool = ClassPool.getDefault();
            pool.importPackage("javax.persistence");
            pool.importPackage("java.lang");
            List<?> attributes = classFile.getAttributes();
            Iterator<?> itr = attributes.iterator();
            while (itr.hasNext()) {
                Object object = itr.next();
                processClassLevelAnnotations(constantPool, pool, object);
            }
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            DataOutputStream os = new DataOutputStream(bos);
            classFile.write(os);
            os.close();
            isExecuted = true;
            return bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalClassFormatException("Unable to convert " + convertedClassName + " to a SingleTable inheritance strategy: " + e.getMessage());
        }
    } else {
        return null;
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) ClassFile(javassist.bytecode.ClassFile) DataOutputStream(java.io.DataOutputStream) ClassPool(javassist.ClassPool) ByteArrayOutputStream(java.io.ByteArrayOutputStream) DataInputStream(java.io.DataInputStream) NotFoundException(javassist.NotFoundException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) ByteArrayInputStream(java.io.ByteArrayInputStream) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException)

Example 45 with ClassFile

use of javassist.bytecode.ClassFile 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

ClassFile (javassist.bytecode.ClassFile)51 DataInputStream (java.io.DataInputStream)15 ClassPool (javassist.ClassPool)15 DataOutputStream (java.io.DataOutputStream)14 CtClass (javassist.CtClass)14 AnnotationsAttribute (javassist.bytecode.AnnotationsAttribute)14 ConstPool (javassist.bytecode.ConstPool)13 ByteArrayOutputStream (java.io.ByteArrayOutputStream)12 ByteArrayInputStream (java.io.ByteArrayInputStream)11 IOException (java.io.IOException)11 MethodInfo (javassist.bytecode.MethodInfo)11 CtField (javassist.CtField)10 NotFoundException (javassist.NotFoundException)9 Annotation (javassist.bytecode.annotation.Annotation)9 Test (org.junit.Test)9 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)8 HashSet (java.util.HashSet)7 CtMethod (javassist.CtMethod)7 FieldInfo (javassist.bytecode.FieldInfo)7 Bytecode (javassist.bytecode.Bytecode)5