Search in sources :

Example 16 with CtClass

use of javassist.CtClass in project gwt-test-utils by gwt-test-utils.

the class GwtTranslator method onLoad.

public void onLoad(ClassPool pool, String className) throws NotFoundException {
    CtClass classToLoad = pool.get(className);
    patchClass(classToLoad);
}
Also used : CtClass(javassist.CtClass)

Example 17 with CtClass

use of javassist.CtClass in project gwt-test-utils by gwt-test-utils.

the class AutomaticPatcher method getPatchMethods.

private Set<CtMethod> getPatchMethods(Set<CtClass> patchClasses) {
    Set<CtMethod> result = new HashSet<CtMethod>();
    // add all @PatchMethod found in a temporary map
    Map<String, List<CtMethod>> temp = new HashMap<String, List<CtMethod>>();
    for (CtClass patchClass : patchClasses) {
        for (CtMethod ctMethod : patchClass.getDeclaredMethods()) {
            if (ctMethod.hasAnnotation(PatchMethod.class)) {
                if (!Modifier.isStatic(ctMethod.getModifiers())) {
                    throw new GwtTestPatchException("@" + PatchMethod.class.getName() + " has to be static : '" + ctMethod.getLongName() + "'");
                }
                String nameAndSignature = ctMethod.getName() + Descriptor.toString(ctMethod.getSignature());
                List<CtMethod> correspondingMethods = temp.get(nameAndSignature);
                if (correspondingMethods == null) {
                    correspondingMethods = new ArrayList<CtMethod>();
                    temp.put(nameAndSignature, correspondingMethods);
                }
                correspondingMethods.add(ctMethod);
            }
        }
    }
    // override=true
    for (Map.Entry<String, List<CtMethod>> entry : temp.entrySet()) {
        CtMethod methodToUse = getMethodToUse(entry.getValue(), PatchMethod.class);
        methodToUse.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
        result.add(methodToUse);
    }
    return result;
}
Also used : GwtTestPatchException(com.googlecode.gwt.test.exceptions.GwtTestPatchException) CtClass(javassist.CtClass) PatchMethod(com.googlecode.gwt.test.patchers.PatchMethod) CtMethod(javassist.CtMethod)

Example 18 with CtClass

use of javassist.CtClass in project gwt-test-utils by gwt-test-utils.

the class JavassistUtils method getInvisibleAnnotationStringValue.

/**
     * 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.visibleTag);
    if (attr == null) {
        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;
}
Also used : CtClass(javassist.CtClass) AnnotationsAttribute(javassist.bytecode.AnnotationsAttribute)

Example 19 with CtClass

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

the class PersistentAttributesEnhancer method handleBiDirectionalAssociation.

private void handleBiDirectionalAssociation(CtClass managedCtClass, CtField persistentField, CtMethod fieldWriter) throws NotFoundException, CannotCompileException {
    if (!PersistentAttributesHelper.isPossibleBiDirectionalAssociation(persistentField)) {
        return;
    }
    final CtClass targetEntity = PersistentAttributesHelper.getTargetEntityClass(managedCtClass, persistentField);
    if (targetEntity == null) {
        log.infof("Could not find type of bi-directional association for field [%s#%s]", managedCtClass.getName(), persistentField.getName());
        return;
    }
    final String mappedBy = PersistentAttributesHelper.getMappedBy(persistentField, targetEntity, enhancementContext);
    if (mappedBy == null || mappedBy.isEmpty()) {
        log.infof("Could not find bi-directional association for field [%s#%s]", managedCtClass.getName(), persistentField.getName());
        return;
    }
    // create a temporary getter and setter on the target entity to be able to compile our code
    final String mappedByGetterName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + mappedBy;
    final String mappedBySetterName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + mappedBy;
    CtMethod getter;
    CtMethod setter;
    boolean tmpTargetMethods = false;
    try {
        getter = targetEntity.getDeclaredMethod(mappedByGetterName);
        setter = targetEntity.getDeclaredMethod(mappedByGetterName);
    } catch (NotFoundException nfe) {
        getter = MethodWriter.addGetter(targetEntity, mappedBy, mappedByGetterName);
        setter = MethodWriter.addSetter(targetEntity, mappedBy, mappedBySetterName);
        tmpTargetMethods = true;
    }
    // code fragments to check loaded state. We don't want to trigger lazy loading in association management code
    String currentAssociationLoaded = String.format("%s.isPropertyInitialized(this.%s, \"%s\")", Hibernate.class.getName(), persistentField.getName(), mappedBy);
    String targetElementLoaded = String.format("%s.isPropertyInitialized(target, \"%s\")", Hibernate.class.getName(), mappedBy);
    String newAssociationLoaded = String.format("%s.isPropertyInitialized($1, \"%s\")", Hibernate.class.getName(), mappedBy);
    if (PersistentAttributesHelper.hasAnnotation(persistentField, OneToOne.class)) {
        // only unset when $1 != null to avoid recursion
        fieldWriter.insertBefore(String.format("  if (this.%1$s != null && %2$s && $1 != null) { this.%1$s.%3$s(null); }%n", persistentField.getName(), currentAssociationLoaded, mappedBySetterName));
        fieldWriter.insertAfter(String.format("  if ($1 != null && %s && $1.%s() != this) { $1.%s(this); }%n", newAssociationLoaded, mappedByGetterName, mappedBySetterName));
    }
    if (PersistentAttributesHelper.hasAnnotation(persistentField, OneToMany.class)) {
        boolean isMap = PersistentAttributesHelper.isAssignable(persistentField.getType(), Map.class.getName());
        String toArrayMethod = isMap ? "values().toArray()" : "toArray()";
        // only remove elements not in the new collection or else we would loose those elements
        // don't use iterator to avoid ConcurrentModException
        fieldWriter.insertBefore(String.format("  if (this.%3$s != null && %1$s) {%n" + "    Object[] array = this.%3$s.%2$s;%n" + "    for (int i = 0; i < array.length; i++) {%n" + "      %4$s target = (%4$s) array[i];%n" + "      if ($1 == null || !$1.contains(target)) { target.%5$s(null); }%n" + "    }%n" + "  }%n", currentAssociationLoaded, toArrayMethod, persistentField.getName(), targetEntity.getName(), mappedBySetterName));
        fieldWriter.insertAfter(String.format("  if ($1 != null && %1$s) {%n" + "    Object[] array = $1.%2$s;%n" + "    for (int i = 0; i < array.length; i++) {%n" + "      %4$s target = (%4$s) array[i];%n" + "      if (%3$s && target.%5$s() != this) { target.%6$s(this); }%n" + "    }%n" + "  }%n", newAssociationLoaded, toArrayMethod, targetElementLoaded, targetEntity.getName(), mappedByGetterName, mappedBySetterName));
    }
    if (PersistentAttributesHelper.hasAnnotation(persistentField, ManyToOne.class)) {
        fieldWriter.insertBefore(String.format("  if (this.%2$s != null && %1$s && this.%2$s.%3$s() != null) { this.%2$s.%3$s().remove(this); }%n", currentAssociationLoaded, persistentField.getName(), mappedByGetterName));
        // check .contains(this) to avoid double inserts (but preventing duplicates)
        fieldWriter.insertAfter(String.format("  if ($1 != null && %s) {%n" + "    java.util.Collection c = $1.%s();%n" + "    if (c != null && !c.contains(this)) { c.add(this); }%n" + "  }%n", newAssociationLoaded, mappedByGetterName));
    }
    if (PersistentAttributesHelper.hasAnnotation(persistentField, ManyToMany.class)) {
        if (PersistentAttributesHelper.isAssignable(persistentField.getType(), Map.class.getName()) || PersistentAttributesHelper.isAssignable(targetEntity.getField(mappedBy).getType(), Map.class.getName())) {
            log.infof("Bi-directional association for field [%s#%s] not managed: @ManyToMany in java.util.Map attribute not supported ", managedCtClass.getName(), persistentField.getName());
            return;
        }
        fieldWriter.insertBefore(String.format("  if (this.%2$s != null && %1$s) {%n" + "    Object[] array = this.%2$s.toArray();%n" + "    for (int i = 0; i < array.length; i++) {%n" + "      %3$s target = (%3$s) array[i];%n" + "      if ($1 == null || !$1.contains(target)) { target.%4$s().remove(this); }%n" + "    }%n" + "  }%n", currentAssociationLoaded, persistentField.getName(), targetEntity.getName(), mappedByGetterName));
        fieldWriter.insertAfter(String.format("  if ($1 != null && %s) {%n" + "    Object[] array = $1.toArray();%n" + "    for (int i = 0; i < array.length; i++) {%n" + "      %s target = (%s) array[i];%n" + "	   if (%s) {%n" + "        java.util.Collection c = target.%s();%n" + "        if (c != this && c != null) { c.add(this); }%n" + "      }%n" + "    }%n" + "  }%n", newAssociationLoaded, targetEntity.getName(), targetEntity.getName(), targetElementLoaded, mappedByGetterName));
    }
    if (tmpTargetMethods) {
        targetEntity.removeMethod(getter);
        targetEntity.removeMethod(setter);
    }
}
Also used : CtClass(javassist.CtClass) Hibernate(org.hibernate.Hibernate) NotFoundException(javassist.NotFoundException) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) CtMethod(javassist.CtMethod)

Example 20 with CtClass

use of javassist.CtClass 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)

Aggregations

CtClass (javassist.CtClass)121 CtMethod (javassist.CtMethod)46 ClassPool (javassist.ClassPool)37 NotFoundException (javassist.NotFoundException)35 Test (org.junit.Test)32 CannotCompileException (javassist.CannotCompileException)23 CtField (javassist.CtField)20 IOException (java.io.IOException)11 CtConstructor (javassist.CtConstructor)8 Method (java.lang.reflect.Method)7 ArrayList (java.util.ArrayList)6 CtMethodJavaWriter (com.github.stephanenicolas.afterburner.inserts.CtMethodJavaWriter)4 FileNotFoundException (java.io.FileNotFoundException)4 LoaderClassPath (javassist.LoaderClassPath)4 AnnotationsAttribute (javassist.bytecode.AnnotationsAttribute)4 CodeAttribute (javassist.bytecode.CodeAttribute)4 ConstPool (javassist.bytecode.ConstPool)4 GwtTestPatchException (com.googlecode.gwt.test.exceptions.GwtTestPatchException)3 PinpointException (com.navercorp.pinpoint.exception.PinpointException)3 NamedClassPool (com.navercorp.pinpoint.profiler.instrument.classpool.NamedClassPool)3