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);
}
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;
}
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;
}
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);
}
}
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);
}
}
}
Aggregations