@@ -0,0 +1,10 @@ | |||
package de.scrum_master.app; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.TYPE) | |||
public @interface EntityController {} |
@@ -0,0 +1,16 @@ | |||
package de.scrum_master.app; | |||
import org.aspectj.lang.annotation.Aspect; | |||
import org.aspectj.lang.annotation.*; | |||
@Aspect | |||
public class EntityControllerAspect { | |||
@DeclareParents(value = "@EntityController *", defaultImpl = EntityMongoController.class) | |||
private IEntityController iEntityController; | |||
/* | |||
@DeclareMixin("@EntityController *") | |||
private IEntityController createEntityControllerInstance() { | |||
return new EntityMongoController(); | |||
} | |||
*/ | |||
} |
@@ -0,0 +1,8 @@ | |||
package de.scrum_master.app; | |||
public class EntityMongoController<T> implements IEntityController<T> { | |||
private T entity; | |||
public void setEntity(T entity) { this.entity = entity; } | |||
public T getEntity() { return entity; } | |||
} |
@@ -0,0 +1,6 @@ | |||
package de.scrum_master.app; | |||
public interface IEntityController<T> { | |||
void setEntity(T entity); | |||
T getEntity(); | |||
} |
@@ -0,0 +1,37 @@ | |||
package de.scrum_master.app; | |||
import java.lang.reflect.Method; | |||
@EntityController | |||
public class MyAnnotatedController<T> { | |||
public void doSomething() { | |||
System.out.println("Doing something"); | |||
} | |||
public static void main(String[] args) { | |||
// Use class type directly so as to call its method | |||
MyAnnotatedController<String> annotatedTextController = new MyAnnotatedController<>(); | |||
annotatedTextController.doSomething(); | |||
// Print all declared methods (should also show interface methods introduced via ITD) | |||
for (Method method : annotatedTextController.getClass().getDeclaredMethods()) { | |||
if (!method.getName().startsWith("ajc$")) | |||
System.out.println(method); | |||
} | |||
// Prove that class type is compatible with interface type | |||
//IEntityController<String> entityTextController = annotatedTextController; | |||
//entityTextController.setEntity("foo"); | |||
// Would not work here because generic interface type is type-safe: | |||
// entityNumberController.setEntity(123); | |||
//System.out.println("Entity value = " + entityTextController.getEntity()); | |||
// Create another object and directly assign it to interface type | |||
//IEntityController<Integer> entityNumberController = new MyAnnotatedController<>(); | |||
//entityNumberController.setEntity(123); | |||
// Would not work here because generic interface type is type-safe: | |||
// entityNumberController.setEntity("foo"); | |||
//System.out.println("Entity value = " + entityNumberController.getEntity()); | |||
} | |||
} | |||
@@ -0,0 +1,39 @@ | |||
/******************************************************************************* | |||
* Copyright (c) 2014 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.ajc183; | |||
import java.io.File; | |||
import junit.framework.Test; | |||
import org.aspectj.testing.XMLBasedAjcTestCase; | |||
/** | |||
* @author Andy Clement | |||
*/ | |||
public class Ajc183Tests extends org.aspectj.testing.XMLBasedAjcTestCase { | |||
public void testAnnoStyleDecp_442425() { | |||
runTest("anno style decp"); | |||
} | |||
// --- | |||
public static Test suite() { | |||
return XMLBasedAjcTestCase.loadSuite(Ajc183Tests.class); | |||
} | |||
@Override | |||
protected File getSpecFile() { | |||
return getClassResource("ajc183.xml"); | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
/******************************************************************************* | |||
* Copyright (c) 2014 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.ajc183; | |||
import junit.framework.Test; | |||
import junit.framework.TestSuite; | |||
import org.aspectj.systemtest.apt.AptTests; | |||
public class AllTestsAspectJ183 { | |||
public static Test suite() { | |||
TestSuite suite = new TestSuite("AspectJ 1.8.3 tests"); | |||
// $JUnit-BEGIN$ | |||
suite.addTest(Ajc183Tests.suite()); | |||
suite.addTest(AptTests.suite()); | |||
// $JUnit-END$ | |||
return suite; | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd"[]> | |||
<suite> | |||
<ajc-test dir="bugs183/442425" title="anno style decp"> | |||
<compile options="-1.8" files="EntityController.java IEntityController.java MyAnnotatedController.java EntityControllerAspect.java EntityMongoController.java"> | |||
<message kind="error" line="23" text="Type mismatch: cannot convert from MyAnnotatedController<String> to IEntityController<String>"/> | |||
<message kind="error" line="30" text="Cannot infer type arguments for MyAnnotatedController<>"/> | |||
</compile> | |||
<!-- | |||
<run class="de.scrum_master.app.MyAnnotatedController"> | |||
<stdout> | |||
<line text="Doing something"/> | |||
<line text="public static void de.scrum_master.app.MyAnnotatedController.main(java.lang.String[])"/> | |||
<line text="public void de.scrum_master.app.MyAnnotatedController.doSomething()"/> | |||
<line text="public java.lang.Object de.scrum_master.app.MyAnnotatedController.getEntity()"/> | |||
<line text="public void de.scrum_master.app.MyAnnotatedController.setEntity(java.lang.Object)"/> | |||
<line text="Entity value = foo"/> | |||
<line text="Entity value = 123"/> | |||
</stdout> | |||
</run> | |||
--> | |||
</ajc-test> | |||
</suite> |
@@ -726,6 +726,9 @@ public class AtAjAttributes { | |||
TypePattern typePattern = parseTypePattern(decpPattern, struct); | |||
ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve( | |||
struct.enclosingType.getWorld()); | |||
if (fieldType.isParameterizedOrRawType()) { | |||
fieldType = fieldType.getGenericType(); | |||
} | |||
if (fieldType.isInterface()) { | |||
TypePattern parent = parseTypePattern(fieldType.getName(), struct); | |||
FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; | |||
@@ -772,9 +775,7 @@ public class AtAjAttributes { | |||
hasNoCtorOrANoArgOne = false; | |||
if (resolvedMember.getParameterTypes().length == 0) { | |||
if (defaultVisibilityImpl) { // default | |||
// visibility | |||
// implementation | |||
if (defaultVisibilityImpl) { // default visibility implementation | |||
if (resolvedMember.isPublic() || resolvedMember.isDefault()) { | |||
hasNoCtorOrANoArgOne = true; | |||
} else { | |||
@@ -819,11 +820,6 @@ public class AtAjAttributes { | |||
Iterator<ResolvedMember> methodIterator = fieldType.getMethodsIncludingIntertypeDeclarations(false, true); | |||
while (methodIterator.hasNext()) { | |||
ResolvedMember method = methodIterator.next(); | |||
// ResolvedMember[] methods = fieldType.getMethodsWithoutIterator(true, false, false).toArray( | |||
// new ResolvedMember[0]); | |||
// for (int i = 0; i < methods.length; i++) { | |||
// ResolvedMember method = methods[i]; | |||
if (method.isAbstract()) { | |||
// moved to be detected at weave time if the target | |||
// doesnt implement the methods | |||
@@ -849,22 +845,19 @@ public class AtAjAttributes { | |||
// So here we create a modified method with an | |||
// alternative declaring type so that we lookup | |||
// the right field. See pr164016. | |||
MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType, | |||
defaultImplClassName, typePattern); | |||
MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType, defaultImplClassName, typePattern); | |||
mdtm.setFieldType(fieldType); | |||
mdtm.setSourceLocation(struct.enclosingType.getSourceLocation()); | |||
struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm)); | |||
} | |||
} | |||
// successfull so far, we thus need a bcel type munger to | |||
// have | |||
// successful so far, we thus need a bcel type munger to have | |||
// a field hosting the mixin in the target type | |||
if (hasAtLeastOneMethod && defaultImplClassName != null) { | |||
ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, fieldType, struct.enclosingType); | |||
struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger( | |||
fieldHost, struct.enclosingType, typePattern))); | |||
} | |||
return true; | |||
} else { | |||
reportError("@DeclareParents: can only be used on a field whose type is an interface", struct); | |||
@@ -915,7 +908,6 @@ public class AtAjAttributes { | |||
// No annotation found | |||
return false; | |||
} | |||
Method annotatedMethod = struct.method; | |||
World world = struct.enclosingType.getWorld(); | |||
NameValuePair declareMixinPatternNameValuePair = getAnnotationElement(declareMixinAnnotation, VALUE); | |||
@@ -926,7 +918,9 @@ public class AtAjAttributes { | |||
// Return value of the annotated method is the interface or class that the mixin delegate should have | |||
ResolvedType methodReturnType = UnresolvedType.forSignature(annotatedMethod.getReturnType().getSignature()).resolve(world); | |||
if (methodReturnType.isParameterizedOrRawType()) { | |||
methodReturnType = methodReturnType.getGenericType(); | |||
} | |||
if (methodReturnType.isPrimitiveType()) { | |||
reportError(getMethodForMessage(struct) + ": factory methods for a mixin cannot return void or a primitive type", | |||
struct); | |||
@@ -942,7 +936,7 @@ public class AtAjAttributes { | |||
// supplied as a list in the 'Class[] interfaces' value in the annotation value | |||
// supplied as just the interface return value of the annotated method | |||
// supplied as just the class return value of the annotated method | |||
NameValuePair interfaceListSpecified = getAnnotationElement(declareMixinAnnotation, "interfaces"); | |||
NameValuePair interfaceListSpecified = getAnnotationElement(declareMixinAnnotation, "interfaces"); | |||
List<TypePattern> newParents = new ArrayList<TypePattern>(1); | |||
List<ResolvedType> newInterfaceTypes = new ArrayList<ResolvedType>(1); |