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