Fix #252 make instrumentation works on JDK11 for the inner class which has access to the private constructor of the host classtags/rel_3_25_0_ga
@@ -636,8 +636,22 @@ public class MemberCodeGen extends CodeGen { | |||
throw new CompileError("no such constructor: " + targetClass.getName()); | |||
if (declClass != thisClass && AccessFlag.isPrivate(acc)) { | |||
desc = getAccessibleConstructor(desc, declClass, minfo); | |||
bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter | |||
boolean isNested = false; | |||
if (declClass.getClassFile().getMajorVersion() >= ClassFile.JAVA_11) { | |||
try { | |||
CtClass[] nestedClasses = declClass.getNestedClasses(); | |||
for (int i = 0; i < nestedClasses.length; i++) { | |||
if (thisClass == nestedClasses[i]) { | |||
isNested = true; | |||
break; | |||
} | |||
} | |||
} catch (NotFoundException ignored) { } | |||
} | |||
if (!isNested) { | |||
desc = getAccessibleConstructor(desc, declClass, minfo); | |||
bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter | |||
} | |||
} | |||
} | |||
else if (AccessFlag.isPrivate(acc)) |
@@ -14,6 +14,7 @@ import javassist.bytecode.NestMembersAttribute; | |||
import javassist.expr.ExprEditor; | |||
import javassist.expr.Handler; | |||
import javassist.expr.MethodCall; | |||
import javassist.expr.NewExpr; | |||
@SuppressWarnings({"rawtypes","unchecked","unused"}) | |||
public class JvstTest5 extends JvstTestRoot { | |||
@@ -469,6 +470,26 @@ public class JvstTest5 extends JvstTestRoot { | |||
assertEquals(2, invoke(obj, "run")); | |||
} | |||
public void testNestPrivateConstructor() throws Exception { | |||
CtClass cc = sloader.get("test5.NestHost3$Builder"); | |||
cc.instrument(new ExprEditor() { | |||
public void edit(NewExpr e) throws CannotCompileException { | |||
String code = "$_ = $proceed($$);"; | |||
e.replace(code); | |||
} | |||
}); | |||
cc.writeFile(); | |||
try { | |||
Class<?> nestHost3Class = cloader.loadClass("test5.NestHost3"); | |||
Object builder = nestHost3Class.getDeclaredMethod("builder").invoke(nestHost3Class); | |||
Class<?> nestHost3BuilderClass = cloader.loadClass("test5.NestHost3$Builder"); | |||
nestHost3BuilderClass.getDeclaredMethod("build").invoke(builder); | |||
} catch (Exception ex) { | |||
ex.printStackTrace(); | |||
fail("it should be able to access the private constructor of the nest host"); | |||
} | |||
} | |||
public void testSwitchCaseWithStringConstant2() throws Exception { | |||
CtClass cc = sloader.makeClass("test5.SwitchCase2"); | |||
cc.addMethod(CtNewMethod.make( |
@@ -0,0 +1,19 @@ | |||
package test5; | |||
public class NestHost3 { | |||
private NestHost3(Builder builder) { | |||
} | |||
public static Builder builder() { | |||
return new Builder(); | |||
} | |||
public static final class Builder { | |||
public Builder() { | |||
} | |||
public NestHost3 build() { | |||
return new NestHost3(this); | |||
} | |||
} | |||
} |