|
|
@@ -0,0 +1,229 @@ |
|
|
|
/******************************************************************************* |
|
|
|
* Copyright (c) 2008 Contributors |
|
|
|
* All rights reserved. This program and the accompanying materials |
|
|
|
* are made available under the terms of the Eclipse Public License v1.0 |
|
|
|
* which accompanies this distribution, and is available at |
|
|
|
* http://www.eclipse.org/legal/epl-v10.html |
|
|
|
* |
|
|
|
* Contributors: |
|
|
|
* Andy Clement - initial API and implementation |
|
|
|
*******************************************************************************/ |
|
|
|
package org.aspectj.systemtest.ajc169; |
|
|
|
|
|
|
|
import java.io.File; |
|
|
|
import org.aspectj.apache.bcel.classfile.Method; |
|
|
|
import java.lang.reflect.Modifier; |
|
|
|
|
|
|
|
import junit.framework.Test; |
|
|
|
|
|
|
|
import org.aspectj.apache.bcel.classfile.Field; |
|
|
|
import org.aspectj.apache.bcel.classfile.JavaClass; |
|
|
|
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; |
|
|
|
import org.aspectj.apache.bcel.util.ClassPath; |
|
|
|
import org.aspectj.apache.bcel.util.SyntheticRepository; |
|
|
|
import org.aspectj.testing.XMLBasedAjcTestCase; |
|
|
|
|
|
|
|
/** |
|
|
|
* What would a completely transparent weave be? Is there a minimal subset that makes sense? What is the roadmap to get there? What |
|
|
|
* needs testing |
|
|
|
* |
|
|
|
* --- 'Transparent' here is meaning that the resultant bytecode is more representative of the original declarations, so that it |
|
|
|
* looks like the intertype declaration and associated constructs have been seamless added to the affected targets. |
|
|
|
* |
|
|
|
* |
|
|
|
* Fully transparent weaving, what would we like to have: - ITDs appear exactly as declared: 'private int A.i' will create 'private |
|
|
|
* int i' in A |
|
|
|
* |
|
|
|
* - What is the benefit? - although this isn't really in keeping with the AspectJ definition of what an ITD represents, having the |
|
|
|
* end result look like the declaration does make it easier for users simply looking at the resultant class file or attempting |
|
|
|
* reflection to access what they just ITD'd in place |
|
|
|
* |
|
|
|
* |
|
|
|
* testing For transparent weaving of ITD fields - annotations on new fields - AJDT model - AjType support - what happens to it? - |
|
|
|
* advice on within() how does that get affected? - visibility - accessors created when required? - handling clashes with existing |
|
|
|
* fields - handling clashes with other aspects - generic declarations - interface declarations - initializers - static and |
|
|
|
* non-static - accessibility from advice, for read and write |
|
|
|
* |
|
|
|
* Design<br> |
|
|
|
* The intention will be 'new code' uses the new style whilst old code continues to cause the old code to be built. Whether the code |
|
|
|
* wants to use the old or new naming should be apparent from the |
|
|
|
* |
|
|
|
* @author Andy Clement |
|
|
|
*/ |
|
|
|
public class TransparentWeavingTests extends org.aspectj.testing.XMLBasedAjcTestCase { |
|
|
|
|
|
|
|
// Simple private ITD onto a target |
|
|
|
public void testSimplePrivate() throws Exception { |
|
|
|
runTest("one - private"); |
|
|
|
checkForField("OnePrivate", Modifier.PRIVATE, "x"); |
|
|
|
} |
|
|
|
|
|
|
|
// Default visibility ITD field |
|
|
|
public void testSimpleDefault() throws Exception { |
|
|
|
runTest("one - default"); |
|
|
|
checkForField("OneDefault", 0, "x"); |
|
|
|
} |
|
|
|
|
|
|
|
// annotated private ITD |
|
|
|
public void testSimplePrivateAnnotated() throws Exception { |
|
|
|
runTest("one - private - annotated"); |
|
|
|
Field f = checkForField("OnePrivateAnnotated", Modifier.PRIVATE, "x"); |
|
|
|
AnnotationGen[] annos = f.getAnnotations(); |
|
|
|
assertTrue(annos.length > 0); // 0==Anno 1==ajcITD |
|
|
|
assertEquals("LAnno;", annos[0].getTypeSignature()); |
|
|
|
} |
|
|
|
|
|
|
|
// annotated default ITD |
|
|
|
public void testSimpleDefaultAnnotated() throws Exception { |
|
|
|
runTest("one - default - annotated"); |
|
|
|
Field f = checkForField("OneDefaultAnnotated", 0, "x"); |
|
|
|
AnnotationGen[] annos = f.getAnnotations(); |
|
|
|
assertTrue(annos.length > 0); // 0==Anno 1==ajcITD |
|
|
|
assertEquals("LAnno;", annos[0].getTypeSignature()); |
|
|
|
} |
|
|
|
|
|
|
|
// Simple private ITD with getter/setter usage |
|
|
|
public void testSimplePrivateWithAccessors() throws Exception { |
|
|
|
runTest("one - private - accessors"); |
|
|
|
} |
|
|
|
|
|
|
|
// check initializer runs OK |
|
|
|
public void testSimplePrivateInitializer() throws Exception { |
|
|
|
runTest("one - private - initializer"); |
|
|
|
} |
|
|
|
|
|
|
|
public void testDeclareAtOnPrivateItd() throws Exception { |
|
|
|
runTest("declare at on private itd"); |
|
|
|
Field f = checkForField("OneDeclareAt", Modifier.PRIVATE, "x"); |
|
|
|
AnnotationGen[] annos = f.getAnnotations(); |
|
|
|
assertTrue(annos.length > 0); // 1==Anno 0==ajcITD |
|
|
|
assertEquals("LAnno;", annos[1].getTypeSignature()); |
|
|
|
} |
|
|
|
|
|
|
|
// declare @field on a field that already has one |
|
|
|
public void testDeclareAtTwo() throws Exception { |
|
|
|
runTest("declare at two"); |
|
|
|
Field f = checkForField("DeclareAtTwo", Modifier.PRIVATE, "x"); |
|
|
|
AnnotationGen[] annos = f.getAnnotations(); |
|
|
|
assertTrue(annos.length > 2); // 1==Anno 0==ajcITD |
|
|
|
assertEquals("LAnno;", annos[0].getTypeSignature()); |
|
|
|
assertEquals("LAnno2;", annos[2].getTypeSignature()); |
|
|
|
} |
|
|
|
|
|
|
|
public void testTwoItdsOnTarget() throws Exception { |
|
|
|
runTest("two itds on target"); |
|
|
|
// Aspect X gets the field, aspect Y gets a mangled one |
|
|
|
checkForField("TwoItdsOnTarget", Modifier.PRIVATE, "x"); |
|
|
|
checkForField("TwoItdsOnTarget", Modifier.PUBLIC, "ajc$interField$Y$x"); |
|
|
|
} |
|
|
|
|
|
|
|
public void testTwoItdsOnTargetThatAlreadyHasIt() throws Exception { |
|
|
|
runTest("two itds on target that already has it"); |
|
|
|
// Aspect X gets the field, aspect Y gets a mangled one |
|
|
|
checkForField("TwoItdsOnTargetHasAlready", Modifier.PUBLIC, "ajc$interField$X$x"); |
|
|
|
checkForField("TwoItdsOnTargetHasAlready", Modifier.PUBLIC, "ajc$interField$Y$x"); |
|
|
|
} |
|
|
|
|
|
|
|
public void testInteractingOldAndNew() throws Exception { |
|
|
|
runTest("interacting old and new"); |
|
|
|
int SYNTHETIC = 0x00001000; // 4096 |
|
|
|
checkForField("InteractingOldAndNew", Modifier.PRIVATE, "i"); |
|
|
|
checkForField("InteractingOldAndNew", Modifier.PUBLIC, "ajc$interField$Y$i"); |
|
|
|
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC | Modifier.STATIC, "main"); |
|
|
|
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC, "ajc$get$i"); |
|
|
|
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC, "ajc$set$i"); |
|
|
|
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC, "getI1"); |
|
|
|
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC, "getI2"); |
|
|
|
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC, "setI1"); |
|
|
|
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC, "setI2"); |
|
|
|
} |
|
|
|
|
|
|
|
public void testPrivateGenerics() throws Exception { |
|
|
|
runTest("generics - private"); |
|
|
|
Field f = checkForField("Generics", Modifier.PRIVATE, "listOfString"); |
|
|
|
assertEquals("Ljava/util/List<Ljava/lang/String;>;", f.getGenericSignature()); |
|
|
|
f = checkForField("Generics", Modifier.PRIVATE, "thing"); |
|
|
|
assertEquals("TX;", f.getGenericSignature()); |
|
|
|
} |
|
|
|
|
|
|
|
// --- |
|
|
|
|
|
|
|
private Field checkForField(String clazzname, int modifiers, String name) throws Exception { |
|
|
|
JavaClass jc = getClassFrom(ajc.getSandboxDirectory(), clazzname); |
|
|
|
Field[] fs = jc.getFields(); |
|
|
|
StringBuffer fields = new StringBuffer(); |
|
|
|
for (Field f : fs) { |
|
|
|
fields.append(f.getName()).append(" "); |
|
|
|
if (f.getName().equals(name)) { |
|
|
|
if (f.getModifiers() != modifiers) { |
|
|
|
fail("Found field " + name + " in " + clazzname + " but modifiers were wrong, they were " + f.getModifiers()); |
|
|
|
} |
|
|
|
return f; |
|
|
|
} |
|
|
|
} |
|
|
|
fail("Did not find field " + name + " in class " + clazzname + ". Found fields: " + fields.toString()); |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
private Method checkForMethod(String clazzname, int modifiers, String name) throws Exception { |
|
|
|
JavaClass jc = getClassFrom(ajc.getSandboxDirectory(), clazzname); |
|
|
|
Method[] fs = jc.getMethods(); |
|
|
|
StringBuffer methods = new StringBuffer(); |
|
|
|
methods.append("\n"); |
|
|
|
for (Method f : fs) { |
|
|
|
methods.append(f.getName()).append("\n"); |
|
|
|
if (f.getName().equals(name)) { |
|
|
|
if (f.getModifiers() != modifiers) { |
|
|
|
fail("Found method " + name + " in " + clazzname + " but modifiers were wrong, they were " + f.getModifiers()); |
|
|
|
} |
|
|
|
return f; |
|
|
|
} |
|
|
|
System.out.println(f.getGenericSignature()); |
|
|
|
} |
|
|
|
fail("Did not find method " + name + " in class " + clazzname + ". Found methods: " + methods.toString()); |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
// public itd onto a target that already has a field of that name |
|
|
|
// just to check what goes wrong and who checks it |
|
|
|
public void testPublicClash() throws Exception { |
|
|
|
runTest("two"); |
|
|
|
} |
|
|
|
|
|
|
|
public void testPrivateClash() throws Exception { |
|
|
|
runTest("three"); |
|
|
|
|
|
|
|
JavaClass jc = getClassFrom(ajc.getSandboxDirectory(), "Three"); |
|
|
|
Field[] fs = jc.getFields(); |
|
|
|
for (Field f : fs) { |
|
|
|
System.out.println(f); |
|
|
|
} |
|
|
|
|
|
|
|
// public int ajc$interField$X$xPrivate [RuntimeVisibleAnnotations] |
|
|
|
// public Integer ajc$interField$$yDefault [RuntimeVisibleAnnotations] |
|
|
|
// public String zPublic [RuntimeVisibleAnnotations] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// -- |
|
|
|
|
|
|
|
public SyntheticRepository createRepos(File cpentry) { |
|
|
|
ClassPath cp = new ClassPath(cpentry + File.pathSeparator + System.getProperty("java.class.path")); |
|
|
|
return SyntheticRepository.getInstance(cp); |
|
|
|
} |
|
|
|
|
|
|
|
protected JavaClass getClassFrom(File where, String clazzname) throws ClassNotFoundException { |
|
|
|
SyntheticRepository repos = createRepos(where); |
|
|
|
return repos.loadClass(clazzname); |
|
|
|
} |
|
|
|
|
|
|
|
public static Test suite() { |
|
|
|
return XMLBasedAjcTestCase.loadSuite(TransparentWeavingTests.class); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected File getSpecFile() { |
|
|
|
return new File("../tests/src/org/aspectj/systemtest/ajc169/transparentweaving.xml"); |
|
|
|
} |
|
|
|
|
|
|
|
} |