[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Understanding generic types in args(..) construction

Hello Fernando,

On 2-nov-08, at 02:27, Fernando Rubbo wrote:
There exists a formal description saying how args(..) and after(..) returning (..) must works?

The best description is probably: http://www.eclipse.org/aspectj/doc/released/adk15notebook/generics-inAspectJ5.html#d0e2512

It is not a complete description, and I can't directly say whether the implementation adheres to the specification in this case. However, it seems logical to me that:

1) AspectJ should employ the unerased version of signatures (which, as you point, is available) to determine args() matching

2) args() should have matching behavior closely related to "casting conversion" in Java: http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.5

* if the corresponding cast is statically known to be correct (identity/widening conversion), args() should directly match
* if the corresponding cast is legal, but not known to be correct (narrowing conversion), args() should match with a runtime check in so far this is possible; if the cast is completely or partially uncheckable, it should assume the uncheckable parts hold, but emit an unchecked-match warning
* if the corresponding cast is forbidden, args() should not match


Using these guidelines, I would expect the following for your cases:

class C{
   void m(List<Integer> e){}
}

args(List<Integer>): Should match (it does)
args(ArrayList<Integer>): Should runtime check (it does give a spurious warning however!)
args(List<Number>): Should not match (but it does!)
args(ArrayList<Number>): Should not match (it does not)
args(List<? extends Number>): Should match (it does)
args(ArrayList<? extends Number>): Should runtime check (it does not match!)


Whatever interpretation of the specification though, you have discovered a severe bug because args(List<Number>) matches a List<Integer>, without any warning, while the corresponding cast between these types is simply forbidden.

(You can see the cast is forbidden because there is no subtype relation in either direction between these types. Officially, the JLS forbids casts between types with (supertypes with) the same erasure but disjoint type arguments.)

By allowing this conversion, you break Java Generics soundness (without warnings), so if the specification intended to allow this (which I don't think it did), it should be fixed as well. To illustrate the safety problem, the following is a complete example to produce a ClassCastException:

import java.util.*;

public aspect Demo {
	
	public void m(List<Integer> e) {
		for(Integer i: e)
			System.out.println(i);
	}
	
	before(List<Number> e): execution(* Demo.*(..)) && args(e) {
		e.add(3.14f);
	}

	public static void main(String[] args) {
		List<Integer> e = new LinkedList<Integer>(Arrays.asList(1,2));
		Demo.aspectOf().m(e);
	}

}

Best regards,
Bruno De Fraine

--
Bruno De Fraine
Vrije Universiteit Brussel
Faculty of Applied Sciences, DINF - SSEL
Room 4K208, Pleinlaan 2, B-1050 Brussels
tel: +32 (0)2 629 29 75
fax: +32 (0)2 629 28 70
e-mail: Bruno.De.Fraine@xxxxxxxxx