return cached.toClass();
}
}
CtClass originalClass = classPool.get(intf.getName());
ClassFile originalClassFile = originalClass.getClassFile();
CtClass newClass = classPool.makeInterface(simplifiedName);
newClass.defrost();
ClassFile newClassFile = newClass.getClassFile();
//we'll be adding new constants to the class file (for generics and annotations)
ConstPool constPool = newClassFile.getConstPool();
//copy the annotations on the class
AnnotationsAttribute annotations = (AnnotationsAttribute) originalClassFile
.getAttribute(AnnotationsAttribute.visibleTag);
AnnotationsAttribute newAnnotations = copyAnnotations(annotations, constPool);
//add our @Simplified annotation to the new class
newAnnotations = addSimplifiedClassAnnotation(originalClass.getName(), newAnnotations, constPool);
newClassFile.addAttribute(newAnnotations);
//copy the generic signature of the class
SignatureAttribute signature = (SignatureAttribute) originalClassFile.getAttribute(SignatureAttribute.tag);
if (signature != null) {
newClassFile.addAttribute(new SignatureAttribute(constPool, signature.getSignature()));
}
//now copy over the methods
CtMethod[] methods = originalClass.getMethods();
for (CtMethod originalMethod : methods) {
//we are only simplifying interfaces here, but the CtClass.getMethods() also returns concrete methods
//inherited from Object. Let's just skip those - we don't need to worry about them...
if (!Modifier.isAbstract(originalMethod.getModifiers())) {
continue;
}
CtClass[] params = originalMethod.getParameterTypes();
//capture all the runtime visible method annotations on the original method
annotations = (AnnotationsAttribute) originalMethod.getMethodInfo().getAttribute(
AnnotationsAttribute.visibleTag);
//capture all the runtime visible parameter annotations on the original method
ParameterAnnotationsAttribute parameterAnnotations = (ParameterAnnotationsAttribute) originalMethod
.getMethodInfo().getAttribute(ParameterAnnotationsAttribute.visibleTag);
//capture the generic signature of the original method.
signature = (SignatureAttribute) originalMethod.getMethodInfo().getAttribute(
SignatureAttribute.tag);
boolean simplify = params.length > 0 && params[0].getName().equals(Subject.class.getName());
if (simplify) {
//generate new params, leaving out the first parameter (the subject)
CtClass[] simpleParams = new CtClass[params.length - 1];
System.arraycopy(params, 1, simpleParams, 0, params.length - 1);
params = simpleParams;
}
//generate the new method with possibly modified parameters
CtMethod newMethod = CtNewMethod.abstractMethod(originalMethod.getReturnType(),
originalMethod.getName(), params, originalMethod.getExceptionTypes(), newClass);
//copy over the method annotations
annotations = copyAnnotations(annotations, constPool);
if (simplify) {
//add the @SimplifiedMethod to the method annotations
annotations = addSimplifiedMethodAnnotation(annotations, constPool);
if (signature != null) {
//fun, we need to modify the signature, too, because we have left out the parameter
MethodSignature sig = MethodSignature.parse(signature.getSignature());
sig.paramTypes.remove(0);
signature = new SignatureAttribute(constPool, sig.toString());
}
//next, we need to copy the parameter annotations
parameterAnnotations = copyParameterAnnotations(parameterAnnotations, constPool, 1);
} else {
//just copy the sig and parameter annotations verbatim
if (signature != null) {
signature = new SignatureAttribute(constPool, signature.getSignature());
}
parameterAnnotations = copyParameterAnnotations(parameterAnnotations, constPool, 0);
}
if (parameterAnnotations != null) {
newMethod.getMethodInfo().addAttribute(parameterAnnotations);
}
if (signature != null) {
newMethod.getMethodInfo().addAttribute(signature);
}
if (annotations != null) {
newMethod.getMethodInfo().addAttribute(annotations);
}
//it is important to add the method directly to the classfile, not the class
//because otherwise the generics info wouldn't survive
newClassFile.addMethod(newMethod.getMethodInfo());
}
return newClass.toClass();
} catch (Exception e) {