in src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java [514:582]
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
// do not generate bytecode for final, native, private or synthetic methods
if ((access & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE | ACC_SYNTHETIC)) != 0) return null;
Object key = Map.entry(name, desc);
if (!visitedMethods.add(key)) return null;
boolean objectDelegate = objectDelegateMethods.contains(name + desc);
boolean closureDelegate = delegatedClosures.containsKey(name);
boolean wildcardDelegate = hasWildcard && !"<init>".equals(name);
if ((objectDelegate || closureDelegate || wildcardDelegate) && !Modifier.isStatic(access)) {
if (!GROOVYOBJECT_METHOD_NAMES.contains(name)
// GROOVY-8244, GROOVY-10717: replace if abstract or no abstract overload exists
&& (!Modifier.isAbstract(superClass.getModifiers()) || !isImplemented(superClass, name, desc)
|| ((objectDelegate || closureDelegate) && Arrays.stream(superClass.getMethods()).filter(m -> m.getName().equals(name)).mapToInt(Method::getModifiers).noneMatch(Modifier::isAbstract)))) {
if (closureDelegate || wildcardDelegate || !(objectDelegate && generateDelegateField)) {
delegatedClosures.put(name, Boolean.TRUE);
return makeDelegateToClosureCall(name, desc, signature, exceptions, access & ~ACC_ABSTRACT);
}
return makeDelegateCall(name, desc, signature, exceptions, access & ~ACC_ABSTRACT);
}
} else if ("getProxyTarget".equals(name) && "()Ljava/lang/Object;".equals(desc)) {
return createGetProxyTargetMethod(access, name, desc, signature, exceptions);
} else if ("<init>".equals(name) && (Modifier.isPublic(access) || Modifier.isProtected(access))) {
return createConstructor(access, name, desc, signature, exceptions);
} else if (Modifier.isAbstract(access) && !GROOVYOBJECT_METHOD_NAMES.contains(name) && !isImplemented(superClass, name, desc)) {
MethodVisitor mv = super.visitMethod(access & ~ACC_ABSTRACT, name, desc, signature, exceptions);
mv.visitCode();
if (emptyBody) {
Type returnType = Type.getReturnType(desc);
if (returnType == Type.VOID_TYPE) {
mv.visitInsn(RETURN);
} else {
int loadIns = getLoadInsn(returnType);
switch (loadIns) {
case ILOAD:
mv.visitInsn(ICONST_0);
break;
case LLOAD:
mv.visitInsn(LCONST_0);
break;
case FLOAD:
mv.visitInsn(FCONST_0);
break;
case DLOAD:
mv.visitInsn(DCONST_0);
break;
default:
mv.visitInsn(ACONST_NULL);
}
mv.visitInsn(getReturnInsn(returnType));
mv.visitMaxs(0, 0);
}
} else {
// for compatibility with the legacy proxy generator, we should throw an UnsupportedOperationException
// instead of an AbtractMethodException
mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "()V", false);
mv.visitInsn(ATHROW);
mv.visitMaxs(0, 0);
}
mv.visitEnd();
}
return null;
}