--- /dev/null
+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 {}
--- /dev/null
+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();
+ }
+*/
+}
--- /dev/null
+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; }
+}
--- /dev/null
+package de.scrum_master.app;
+
+public interface IEntityController<T> {
+ void setEntity(T entity);
+ T getEntity();
+}
--- /dev/null
+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());
+ }
+}
+
--- /dev/null
+/*******************************************************************************
+ * 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");
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+<!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>
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];
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 {
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
// 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);
// No annotation found
return false;
}
-
Method annotatedMethod = struct.method;
World world = struct.enclosingType.getWorld();
NameValuePair declareMixinPatternNameValuePair = getAnnotationElement(declareMixinAnnotation, VALUE);
// 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);
// 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);