Search in sources :

Example 1 with BadBytecode

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

the class PersistentAttributesEnhancer method enhanceAttributesAccess.

protected void enhanceAttributesAccess(CtClass managedCtClass, IdentityHashMap<String, PersistentAttributeAccessMethods> attributeDescriptorMap) {
    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("$$_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;
                }
                // only transform access to fields of the entity being enhanced
                if (!managedCtClass.getName().equals(constPool.getFieldrefClassName(itr.u16bitAt(index + 1)))) {
                    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.INVOKEVIRTUAL, index);
                    itr.write16bit(methodIndex, index + 1);
                } else {
                    final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getWriter());
                    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 EnhancementException(msg, bb);
        }
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) CodeIterator(javassist.bytecode.CodeIterator) ClassPool(javassist.ClassPool) EnhancementException(org.hibernate.bytecode.enhance.spi.EnhancementException) MethodInfo(javassist.bytecode.MethodInfo) BadBytecode(javassist.bytecode.BadBytecode)

Example 2 with BadBytecode

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

the class PersistentAttributesEnhancer method extendedEnhancement.

// --- //
/**
 * 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 aCtClass Class to enhance (not an entity class).
 */
public void extendedEnhancement(CtClass aCtClass) {
    final ConstPool constPool = aCtClass.getClassFile().getConstPool();
    final ClassPool classPool = aCtClass.getClassPool();
    for (Object oMethod : aCtClass.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 = classPool.getCtClass(fieldClassName);
                if (!enhancementContext.isEntityClass(targetCtClass) && !enhancementContext.isCompositeClass(targetCtClass)) {
                    continue;
                }
                if (targetCtClass == aCtClass || !enhancementContext.isPersistentField(targetCtClass.getField(fieldName)) || PersistentAttributesHelper.hasAnnotation(targetCtClass, fieldName, Id.class) || "this$0".equals(fieldName)) {
                    continue;
                }
                log.debugf("Extended enhancement: Transforming access to field [%s.%s] from method [%s#%s]", fieldClassName, fieldName, aCtClass.getName(), 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 extended enhancement in method [%s]", methodName);
            throw new EnhancementException(msg, bb);
        } catch (NotFoundException nfe) {
            final String msg = String.format("Unable to perform extended enhancement in method [%s]", methodName);
            throw new EnhancementException(msg, nfe);
        }
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) CtClass(javassist.CtClass) CodeIterator(javassist.bytecode.CodeIterator) ClassPool(javassist.ClassPool) EnhancementException(org.hibernate.bytecode.enhance.spi.EnhancementException) NotFoundException(javassist.NotFoundException) MethodInfo(javassist.bytecode.MethodInfo) BadBytecode(javassist.bytecode.BadBytecode)

Example 3 with BadBytecode

use of javassist.bytecode.BadBytecode in project fakereplace by fakereplace.

the class WeldClassTransformer method transform.

@Override
public boolean transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode {
    // Hack up the proxy factory so it stores the proxy ClassFile. We need this to regenerate proxies.
    if (file.getName().equals(ORG_JBOSS_WELD_BEAN_PROXY_PROXY_FACTORY)) {
        for (final MethodInfo method : (List<MethodInfo>) file.getMethods()) {
            if (method.getName().equals("createProxyClass")) {
                modifiedMethods.add(method);
                final VirtualToStaticManipulator virtualToStaticManipulator = new VirtualToStaticManipulator();
                virtualToStaticManipulator.replaceVirtualMethodInvokationWithStatic(ClassLoader.class.getName(), WELD_PROXY_CLASS_LOADING_DELEGATE, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;", loader);
                virtualToStaticManipulator.replaceVirtualMethodInvokationWithStatic("org.jboss.weld.util.bytecode.ClassFileUtils", WELD_PROXY_CLASS_LOADING_DELEGATE, "toClass", "(Lorg/jboss/classfilewriter/ClassFile;Ljava/lang/ClassLoader;Ljava/security/ProtectionDomain;)Ljava/lang/Class;", "(Lorg/jboss/classfilewriter/ClassFile;Ljava/lang/ClassLoader;Ljava/security/ProtectionDomain;)Ljava/lang/Class;", loader);
                virtualToStaticManipulator.transformClass(file, loader, true, modifiedMethods);
                return true;
            } else if (method.getName().equals("<init>")) {
                modifiedMethods.add(method);
                Integer beanArgument = null;
                int count = 1;
                for (final String paramType : DescriptorUtils.descriptorStringToParameterArray(method.getDescriptor())) {
                    if (paramType.equals("Ljavax/enterprise/inject/spi/Bean")) {
                        beanArgument = count;
                        break;
                    } else if (paramType.equals("D") || paramType.equals("J")) {
                        count += 2;
                    } else {
                        count++;
                    }
                }
                if (beanArgument == null) {
                    log.error("Constructor org.jboss.weld.bean.proxy.ProxyFactory.<init>" + method.getDescriptor() + " does not have a bean parameter, proxies produced by this factory will not be reloadable");
                    continue;
                }
                // similar to other tracked instances
                // but we need a strong ref
                Bytecode code = new Bytecode(file.getConstPool());
                code.addAload(0);
                code.addAload(beanArgument);
                code.addInvokestatic(WeldClassChangeAware.class.getName(), "addProxyFactory", "(Ljava/lang/Object;Ljava/lang/Object;)V");
                CodeIterator it = method.getCodeAttribute().iterator();
                it.skipConstructor();
                it.insert(code.get());
            }
        }
    }
    return false;
}
Also used : VirtualToStaticManipulator(org.fakereplace.manip.VirtualToStaticManipulator) CodeIterator(javassist.bytecode.CodeIterator) MethodInfo(javassist.bytecode.MethodInfo) List(java.util.List) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode)

Example 4 with BadBytecode

use of javassist.bytecode.BadBytecode in project fakereplace by fakereplace.

the class WildflyClassTransformer method transform.

@Override
public boolean transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode, DuplicateMemberException {
    if (!file.getName().equals("org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService")) {
        return false;
    }
    for (MethodInfo method : (List<MethodInfo>) file.getMethods()) {
        if (method.getName().equals("createServletConfig")) {
            CodeAttribute code = method.getCodeAttribute();
            code.setMaxStack(code.getMaxStack() + 1);
            CodeIterator it = code.iterator();
            modifiedMethods.add(method);
            while (it.hasNext()) {
                int pos = it.next();
                int inst = it.byteAt(pos);
                if (inst == CodeAttribute.ARETURN) {
                    Bytecode b = new Bytecode(method.getConstPool());
                    b.addGetstatic("org.fakereplace.integration.wildfly.autoupdate.WebUpdateHandlerWrapper", "INSTANCE", "Lio/undertow/server/HandlerWrapper;");
                    b.addInvokevirtual("io.undertow.servlet.api.DeploymentInfo", "addInnerHandlerChainWrapper", "(Lio/undertow/server/HandlerWrapper;)Lio/undertow/servlet/api/DeploymentInfo;");
                    it.insert(pos, b.get());
                }
            }
        }
    }
    return true;
}
Also used : CodeAttribute(javassist.bytecode.CodeAttribute) CodeIterator(javassist.bytecode.CodeIterator) MethodInfo(javassist.bytecode.MethodInfo) List(java.util.List) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode)

Example 5 with BadBytecode

use of javassist.bytecode.BadBytecode in project fakereplace by fakereplace.

the class MethodReplacementTransformer method generateFakeConstructorBytecode.

/**
 * creates a class with a fake constructor that can be used by the reflection
 * api
 * <p>
 * Constructors are not invoked through the proxy class, instead we have to
 * do a lot more bytecode re-writing at the actual invocation sites
 */
private static String generateFakeConstructorBytecode(MethodInfo mInfo, ClassLoader loader) throws BadBytecode {
    String proxyName = ProxyDefinitionStore.getProxyName();
    ClassFile proxy = new ClassFile(false, proxyName, "java.lang.Object");
    proxy.setVersionToJava5();
    proxy.setAccessFlags(AccessFlag.PUBLIC);
    // add our new annotations directly onto the new proxy method. This way
    // they will just work without registering them with the
    // AnnotationDataStore
    String[] types = DescriptorUtils.descriptorStringToParameterArray(mInfo.getDescriptor());
    // as this method is never called the bytecode just returns
    Bytecode b = new Bytecode(proxy.getConstPool());
    b.add(Opcode.ALOAD_0);
    b.addInvokespecial("java.lang.Object", "<init>", "()V");
    b.add(Opcode.RETURN);
    MethodInfo method = new MethodInfo(proxy.getConstPool(), mInfo.getName(), mInfo.getDescriptor());
    method.setAccessFlags(mInfo.getAccessFlags());
    method.setCodeAttribute(b.toCodeAttribute());
    method.getCodeAttribute().computeMaxStack();
    method.getCodeAttribute().setMaxLocals(types.length + 1);
    copyMethodAttributes(mInfo, method);
    try {
        proxy.addMethod(method);
    } catch (DuplicateMemberException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    try {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(bytes);
        proxy.write(dos);
        ProxyDefinitionStore.saveProxyDefinition(loader, proxyName, bytes.toByteArray());
        return proxyName;
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
Also used : DuplicateMemberException(javassist.bytecode.DuplicateMemberException) ClassFile(javassist.bytecode.ClassFile) DataOutputStream(java.io.DataOutputStream) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode) MethodInfo(javassist.bytecode.MethodInfo) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException)

Aggregations

BadBytecode (javassist.bytecode.BadBytecode)24 Bytecode (javassist.bytecode.Bytecode)21 MethodInfo (javassist.bytecode.MethodInfo)16 CodeIterator (javassist.bytecode.CodeIterator)12 CodeAttribute (javassist.bytecode.CodeAttribute)8 List (java.util.List)6 NotFoundException (javassist.NotFoundException)6 IOException (java.io.IOException)5 CtClass (javassist.CtClass)5 DuplicateMemberException (javassist.bytecode.DuplicateMemberException)5 ClassFile (javassist.bytecode.ClassFile)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3 DataOutputStream (java.io.DataOutputStream)3 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)3 CannotCompileException (javassist.CannotCompileException)3 ClassPool (javassist.ClassPool)3 CompileError (javassist.compiler.CompileError)3 Javac (javassist.compiler.Javac)3 Method (java.lang.reflect.Method)2 HashSet (java.util.HashSet)2