Relates to #68. Signed-off-by: Alexander Kriegisch <Alexander@Kriegisch.name>tags/V1_9_8
import java.lang.invoke.ConstantBootstraps; | |||||
import java.util.concurrent.Callable; | |||||
public class Application { | |||||
public static void main(String[] args) throws Exception { | |||||
Callable<?> first = new CondyCallable(); | |||||
Callable<?> second = new CondyCallable(); | |||||
if (!(first.call() == second.call())) | |||||
throw new RuntimeException("Non-identical ConstantDynamic values (should never happen)"); | |||||
} | |||||
/** | |||||
* Class {@link CondyCallable} dispatches to this constructor via {@link ConstantBootstraps#invoke} | |||||
* in order to initialise a dynamic constant value. The constructor should be executed exactly once, | |||||
* no matter how many times {@link CondyCallable#call} is called. | |||||
*/ | |||||
public Application() { | |||||
System.out.println("Sample instance created"); | |||||
} | |||||
} |
import org.objectweb.asm.ClassWriter; | |||||
import org.objectweb.asm.ConstantDynamic; | |||||
import org.objectweb.asm.Handle; | |||||
import org.objectweb.asm.MethodVisitor; | |||||
import org.objectweb.asm.Opcodes; | |||||
import java.io.FileOutputStream; | |||||
import java.io.IOException; | |||||
/** | |||||
* This class was created by ASM-ifying a class generated by Byte Buddy. | |||||
* Its purpose it to create a class <tt>CondyCallable</tt> making use of | |||||
* dynamic class-file constants, a Java 11 feature introduced by JEP 309. | |||||
* | |||||
* @see https://openjdk.java.net/jeps/309 | |||||
*/ | |||||
public class Generator implements Opcodes { | |||||
private static final String CLASS_FILE = "CondyCallable.class"; | |||||
public static void main(String[] args) throws IOException { | |||||
try (FileOutputStream fos = new FileOutputStream(CLASS_FILE)) { | |||||
fos.write(getClassBytes()); | |||||
} | |||||
System.out.println(CLASS_FILE + " generated successfully"); | |||||
} | |||||
private static byte[] getClassBytes() { | |||||
ClassWriter classWriter = new ClassWriter(0); | |||||
classWriter.visit(V11, ACC_PUBLIC | ACC_SUPER, "CondyCallable", null, "java/lang/Object", new String[] { "java/util/concurrent/Callable" }); | |||||
createDefaultConstructor(classWriter); | |||||
createMethod_call(classWriter); | |||||
classWriter.visitEnd(); | |||||
return classWriter.toByteArray(); | |||||
} | |||||
private static void createDefaultConstructor(ClassWriter classWriter) { | |||||
MethodVisitor methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); | |||||
methodVisitor.visitCode(); | |||||
methodVisitor.visitVarInsn(ALOAD, 0); | |||||
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); | |||||
methodVisitor.visitInsn(RETURN); | |||||
methodVisitor.visitMaxs(1, 1); | |||||
methodVisitor.visitEnd(); | |||||
} | |||||
private static void createMethod_call(ClassWriter classWriter) { | |||||
MethodVisitor methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "call", "()Ljava/lang/Object;", null, new String[] { "java/lang/Exception" }); | |||||
methodVisitor.visitCode(); | |||||
methodVisitor.visitLdcInsn( | |||||
// Create constant-dynamic instruction | |||||
new ConstantDynamic( | |||||
// Dummy name | |||||
"_", | |||||
// Constant type | |||||
"LApplication;", | |||||
// Bootstrap method: ConstantBootstraps::invoke, dispatching to an existing method/constructor | |||||
new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/ConstantBootstraps", "invoke", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;", false), | |||||
// Bootstrap method arguments: here we simply dispatch to the constructor of class Application | |||||
new Handle(Opcodes.H_NEWINVOKESPECIAL, "Application", "<init>", "()V", false)) | |||||
); | |||||
methodVisitor.visitInsn(ARETURN); | |||||
methodVisitor.visitMaxs(1, 1); | |||||
methodVisitor.visitEnd(); | |||||
} | |||||
} |
public aspect MyAspect { | |||||
before() : execution(*.new(..)) && !within(MyAspect) { | |||||
System.out.println(thisJoinPoint); | |||||
} | |||||
} |
if (LangUtil.is9VMOrGreater()) { | if (LangUtil.is9VMOrGreater()) { | ||||
suite.addTest(CompileWithReleaseTests.suite()); | suite.addTest(CompileWithReleaseTests.suite()); | ||||
} | } | ||||
if (LangUtil.is11VMOrGreater()) { | |||||
suite.addTest(Bugs198Java11Tests.suite()); | |||||
} | |||||
if (LangUtil.is17VMOrGreater()) { | if (LangUtil.is17VMOrGreater()) { | ||||
suite.addTest(SanityTestsJava17.suite()); | suite.addTest(SanityTestsJava17.suite()); | ||||
suite.addTest(Ajc198TestsJava.suite()); | suite.addTest(Ajc198TestsJava.suite()); |
/******************************************************************************* | |||||
* Copyright (c) 2021 Contributors | |||||
* All rights reserved. This program and the accompanying materials | |||||
* are made available under the terms of the Eclipse Public License v 2.0 | |||||
* which accompanies this distribution, and is available at | |||||
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt | |||||
*******************************************************************************/ | |||||
package org.aspectj.systemtest.ajc198; | |||||
import junit.framework.Test; | |||||
import org.aspectj.testing.XMLBasedAjcTestCase; | |||||
import org.aspectj.testing.XMLBasedAjcTestCaseForJava11OrLater; | |||||
/** | |||||
* @author Alexander Kriegisch | |||||
*/ | |||||
public class Bugs198Java11Tests extends XMLBasedAjcTestCaseForJava11OrLater { | |||||
public void testGitHub_68() { | |||||
runTest("correctly weave code using constant-dynamic"); | |||||
} | |||||
public static Test suite() { | |||||
return XMLBasedAjcTestCase.loadSuite(Bugs198Java11Tests.class); | |||||
} | |||||
@Override | |||||
protected java.net.URL getSpecFile() { | |||||
return getClassResource("ajc198.xml"); | |||||
} | |||||
} |
<suite> | <suite> | ||||
<!-- https://github.com/eclipse/org.aspectj/issues/68 --> | |||||
<ajc-test dir="bugs198/github_68" vm="11" title="correctly weave code using constant-dynamic"> | |||||
<compile files="Application.java MyAspect.aj" options="-11" inpath="condy.jar"/> | |||||
<run class="Application"> | |||||
<stdout> | |||||
<line text="execution(CondyCallable())" /> | |||||
<line text="execution(CondyCallable())" /> | |||||
<line text="execution(Application())" /> | |||||
<line text="Sample instance created" /> | |||||
</stdout> | |||||
</run> | |||||
</ajc-test> | |||||
<!-- https://github.com/eclipse/org.aspectj/issues/105 --> | <!-- https://github.com/eclipse/org.aspectj/issues/105 --> | ||||
<ajc-test dir="bugs198/github_105" vm="8" title="ITD annotation with mandatory parameter via aspectpath"> | <ajc-test dir="bugs198/github_105" vm="8" title="ITD annotation with mandatory parameter via aspectpath"> | ||||
<compile files="FooAnnotation.java BarAnnotation.java FooAspect.aj" options="-8" outjar="aspect.jar"/> | <compile files="FooAnnotation.java BarAnnotation.java FooAspect.aj" options="-8" outjar="aspect.jar"/> |