Bug 77076 - Weaving into jar fails if some of the referred classes are unavailable
Summary: Weaving into jar fails if some of the referred classes are unavailable
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.2.1 M1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 1.5.0 M4   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-10-26 23:43 EDT by Ramnivas Laddad CLA
Modified: 2005-09-25 20:07 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ramnivas Laddad CLA 2004-10-26 23:43:59 EDT
I am trying to profile JDBC access in a Spring-based application.
Since all the JDBC interaction is performed through Spring classes,
I need to weave into spring.jar. However, many of the classes 
referred by spring.jar aren't available to me (I am not using 
the functionality implemented by many of the classes). When I 
try to weave into spring.jar I get errors complaining that it 
can't find types for those classes.

I expected that ajc would ignore unknown classes unless weaving
would be affected by content/API of those classes.

Using jar files that refer to foreign classes that one may
never have/need is a common scenario. For example, spring.jar
refers to Velocity, Struts, JDO, Hibernate, Quartz classes;
I am unlikely to use all of these referred frameworks in an
application. This bug/limitation prevents using AspectJ with
such jars.

To reproduce the bug in a controlled environment, I created
the following aspect which should make the weaving process
a pass-thru filter (no join point is matched by the pointcut)

class TemporaryClass {
}

public aspect NoWeaveAspect {
    before() : call(* TemporaryClass.*(..)) && within(org.spring..*) {
    }
}

Weaving this aspect with spring.jar should result in logically
identical jar file. However, when I compile using the following
command (or equivalent ant task), I get the following errors:

C:\work\aop\bugs\injar-with-nonexisting-classes>ajc -version
AspectJ Compiler 1.2.1rc1 built on Friday Oct 22, 2004 at 13:31:47 GMT

C:\work\aop\bugs\injar-with-nonexisting-classes>ajc -injars spring.jar -outjar s
pring-woven.jar NoWeaveAspect.java
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.quartz.xml.JobSchedulingDataProcessor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.quartz.StatefulJob
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.quartz.SimpleTrigger
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe freemarker.cache.TemplateLoader
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.quartz.CronTrigger
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.quartz.JobDetail
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.quartz.Job
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.quartz.impl.jdbcjobstore.JobStoreCMT
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.struts.action.PlugIn
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.velocity.tools.generic.NumberTool
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.struts.action.Action
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.struts.tiles.TilesRequestProcessor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.struts.action.RequestProcessor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.velocity.runtime.resource.loader.ResourceLoader
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.velocity.runtime.log.LogSystem
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe javax.faces.el.VariableResolver
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.velocity.tools.generic.DateTool
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.commons.attributes.AttributeRepositoryClass
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.cglib.proxy.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.commons.pool.PoolableObjectFactory
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.cglib.proxy.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.cglib.proxy.Dispatcher
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInvocation
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.cglib.proxy.CallbackFilter
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.cglib.proxy.NoOp
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.hibernate.transaction.TransactionManagerLookup
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.hibernate.connection.ConnectionProvider
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.hibernate.UserType
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.apache.ojb.broker.accesslayer.ConnectionFactoryManagedImpl
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.cglib.proxy.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe net.sf.cglib.proxy.CallbackFilter
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)
C:\work\aop\bugs\injar-with-nonexisting-classes\spring.jar [error] can't find ty
pe org.aopalliance.intercept.MethodInterceptor
(no source information available)

41 errors
Comment 1 Andrew Clement CLA 2004-10-27 11:44:21 EDT
In order to fully identify some join points and determine if there is a match,
ajc effectively needs the classpath when weaving that was used when the code was
compiled.  Without it, things like full hierarchy analysis can't be done.

However, I take your point and have been thinking about what we can do.  It is
possible that in the case where we can't do full static analysis because you
haven't supplied all the types, we might be able to simply insert more dynamic
tests (of course, we'll tell you that we are doing it because you didn't supply
all the types).

In the short term, we could even at least tell you what we were trying to do
when we couldn't resolve the type, so you could then decide whether to worry
about it or simply ignore it.
Comment 2 Adrian Colyer CLA 2005-03-23 08:51:23 EST
this is a common problem. scheduling for investigation in m4.
Comment 3 Alexandre Vasseur CLA 2005-03-23 09:26:33 EST
the wished behavior (important for LTW as well) is:

- type resolution must be as lazy as possible (f.e. getMethod called on a bcel
class mirror should not trigger new type resolution, unless method params and
returned values are actually queried etc, same with annotation, same with fields
etc) Actually it is usually possible to have a string mirror for a method
signature: void foo(bar.Baz) => method name = "foo", parameter[0] =
mirror.getName = "bar.Baz", mirror.get() => trigger type resolution

as a consequence of that:
- if pointcut can be match without loading further types mirror, then it should
not warn
- if a pointcut does not further types mirror to do the match and those cannot
be found, then its better to have a warning (and the pointcut expression /
location) so that the user can narrow its pointcut

(mainly: "+" in type patterns, method argument, method return value, annotation,
 field type, exception throwned)
Comment 4 Adrian Colyer CLA 2005-09-24 05:36:46 EDT
I've made a big dent in this long-standing problem. The only message that the compiler produces now 
when compiling your example against spring.jar is XLint:adviceDidNotApply. I also tested with a similar 
example against struts.jar that weaved into the Action class (which refers to javax.servlet types not on 
the classpath). This now works too - though in that case the compiler puts out warning messages 
indicating that certain types could not be found and that this may have affected pointcut matching at 
the call / execution join point in question. The example in question is 

before() : execution(* Action.*(..))

when the supertypes of some struts types can't be found, we don't know for certain that those missing 
types don't themselves descend from Action (and hence might cause some methods in the type being 
analysed to match). But it's a likely bet that they don't, hence the warning rather than an error.

For those interested in such things, the solution involves the following:

* a new subtype of ResolvedType, MissingResolvedTypeWithKnownSignature. We create one of these 
when we can't resolve a type for which we know the signature. Instead of putting out the "can't find 
type" error straight away, we now only do so if a question is asked of the missing type that can't be 
answered solely based on signature.

* In join point signature matching, switching to using a lazy iterator that only creates join point 
signatures when absolutely needed, rather than building all the signatures of a join point up front.

* Every time we created a LazyClassGen, we looked to see if it implemented Serializable (so that lint 
warnings could be issued on operations affecting serializability). This requires chasing all supertypes of 
any given type looking for Serializable - which always caused a type not found if any parent type was 
not present. Now we tolerate a missing type in this situation and just assume that it did not implement 
Serializable - the only side effect is that some serializability warnings will not be issued that may have 
been had the type been present and it implemented Serializable and we performed some munging that 
affected it's serializability. 

* A similar parent-chasing scenario happens during preparation for weaving when we try to work out if 
a type exposed to the weaver and implementing an interface is the topmost implementor of that 
interface. This logic also now tolerates missing types, and assumes in this case that the sub-type in 
question is the topmost (it is certainly the topmost exposed to the weaver, which is all that matters 
here).

* Finally, the can't find type messages themselves are much improved to give more information about 
why we were trying to find the type in the first place.

Fix commited in tree and should be available for download in next published aspectj build.
Comment 5 Ramnivas Laddad CLA 2005-09-25 20:07:09 EDT
Wonderful! Thank you very much.