Main | June 2004 »

May 31, 2004

The Ted Neward Challenge (AOP without the buzzwords)

After the AOP panel at the TSS Java Symposium had finished, Ted Neward threw out a challenge to some of the participants to come up with "an explanation of AOP without resorting to buzzwords." I've been mulling that around in my head for a few days now... What follows should be considered an early version of an attempt to explain what's at the heart of AOP (from my perspective), without resorting to any buzzwords. Following the conclusion of this paragraph, the following words and phrases are hereby banned for the rest of today's entry: scattering, tangling, crosscutting, modularity, encapsulation, abstraction, dominant decomposition, concern.

When you are writing a piece of software it's generally a good idea if you can design the program in such a way that each unique idea, concept, requirement, etc. addressed by the program has a direct and clear representation in the source code. For example, if I'm writing a banking application, the concept of a bank account probably has a direct representation in the program as a BankAccount class. If I'm writing a health service application, the concept of a patient probably has a direct representation in the program as a Patient class. One design concept maps onto one implementation construct.

Now think of a simple model-view-controller application. There's a simple, single design-level requirement that following any change in the state of a model class, any registered views are notified - but it's much harder to map this single design requirement into a single implementation construct. In a typical implementation, you'll find calls to notifyObservers() spread throughout the state-changing methods of the model classes. This implementation has deviated from the goal of 1-to-1 mapping, and instead has a 1-to-n concept:implementation ratio.

The concepts and requirements that a design captures are also the most likely units of change as the software evolves. Design elements that have a 1-to-1 mapping to an implementation are easy to add, remove, and maintain. Elements that have a 1-to-n concept:implementation ratio are much harder to add, remove and maintain since there are multiple places in the implementation to be updated, and it is important to update all of them, and to update them consistently.

The most extreme concept:implementation ratio that you're ever likely to encounter in real software systems is that old chestnut, tracing. Take the simple, single design statement "when tracing is enabled, the entry and exit of every method should be recorded in a trace buffer." In one system I've studied, the concept:implementation ratio for that single requirement is well in excess of 1:100,000. Just think of all the implementation effort that has been expended creating and maintaining all those source code statements. When faced with such a situation, many programmers make a value judgement that the effort does not justify the return and instead opt for a different solution with a concept:implementation ratio of 1:0 (ie. they don't bother to add tracing at all).

A related example in that same system concerned a requirement to log failures - this had a concept:implementation ratio in excess of 1:8,000. But these are extreme examples, and you won't find too many situations where the ratios are this great. Much more common are situations with concept:implementation ratios in the order of 1:20 or 1:30. The model-view-controller requirement described previously could easily fall in this range. If you want an open-source example you can study for yourself, go and look at how the Eclipse JDT compiler handles progress notification (a single concept) during compilation.

Down at the other end of the spectrum, you'll find more subtle issues such as the requirement that a class implement a certain interface. We still want to retain a clear 1-to-1 mapping between the requirement and the implementation, but in many cases it is not explicit exactly which subset of the state and methods in a class are there in order to support the interface implementation. The requirement is addressed in one place, but the boundaries of the implementation are sort of fuzzy. A lot of programmers I know address this by simply grouping together in the source file the set of methods concerned with the interface implementation, and in very many situations that's a perfectly OK thing to do. All I'm attempting to do here is illustrate the diverse range of situations you can encounter when you start focusing on getting a clear 1-to-1 ratio between concept and implementation.

Now let's look at the flip side of the same coin. We want each design concept to map clearly to one implementation construct. We also want each implementation construct to map clearly to one and only one design concept. But we've already seen that some design concepts end up getting spread out through the implementation, and that means inevitably that there are some parts of the implementation which are dealing with multiple design concepts. This is the n-to-1 concept:implementation problem. Just think about the model-view-controller example one more time - the model classes are dealing with at least two design concepts: the notion of whatever it is they are modelling, and the requirement to notify any registered views whenever their state changes.

The n-to-1 problem presents just as many difficulties as the 1-to-n problem. It means for example that when a programmer is maintaining a class, he or she has to be aware of and correctly balance all of the design requirements that the class is trying to address. In some application domains this proved so painful that special frameworks were developed to handle commonly occuring cases of n-to-1 mappings. An example is enterprise application development, where it proved to be too much to ask programmers with business domain expertise to also manage and balance transaction, persistence, and security requirements within business domain classes. Classes that have logic and dependencies relating to multiple concepts in the design are harder to reuse, and harder to test (you want the model classes for example, but you've got to wire them into a different notification scheme).

So what we've really got in any non-trivial software application is not the ideal 1-to-1 mapping between concept and implementation, but an n:m mapping. No wonder software gets so hard to maintain, and so hard to understand, and so complex. And it's not your fault. The tools that object-oriented languages give us don't enable the clean mapping of every design concept into a single implementation construct (and we've seen several examples of that in this short article), and consequently neither do they allow each implementation construct to map cleanly onto a single design concept. This is the problem that aspect-oriented programming attempts to help us solve. It's about getting as close to a 1-to-1 mapping as we can. AOP addresses the problem by introducing a new construct known as an aspect that is able to capture in one place the implementation of design requirements, such as the view-notification requirement in MVC, which OOP cannot.

When you start to think of AOP in this way, I hope that you can see it as less of a bolt-on adjunct to existing software, and more as an integral part of the design and implementation of a software program. This is why AspectJ integrates the concepts of AOP directly in a programming language. Remember, we're after a 1-to-1 mapping between design concept and implementation, and whenever we deviate from that ratio in either direction we're in for trouble. AOP is about getting as close to 1-to-1 programming as we can.

Posted by adrian at 09:06 PM [permalink] | Comments (6)

May 28, 2004

Person owns Dog...

There's a famous OO problem involving people and dogs that I first learnt about in Meilir Page-Jones' excellent book "Fundamentals of Object-Oriented Design in UML." It involves a class Person, with an attribute numOfDogsOwned and a simple accessor method getNumDogsOwned(). The argument goes that this may not neccessarily be good design, since Person and Dog are distinct concepts, and dog ownership is not an essential property of being a person.

Page-Jones calls this mixed-role cohesion, and he explains the problem better than I can: "What if you wanted to reuse Person in an application that had no dogs? You could do so, but you'd have extra, useless baggage from the class, and you might get some pesky warnings about missing dogs from your compiler (or linker). And where should we stop with this design philosophy? Why not include these attributes in Person: numOfCarsOwned, numOfBoatsOwned, numOfCatsOwned, numOfFrogsOwned,... ?"

It's an interesting problem, because there's no perfect solution in OO - Page-Jones discusses the pros and cons of four possible solutions including just adding the members directly to Person, using a PersonDogOwnership relationship class, using an abstract mix-in class, and using aggregation. Mixed-role cohesion sounds like the kind of problem that inter-type declarations in AspectJ should be able to help us address, so here's the world's first (AFAIK) aspect-oriented solution to the person-owns-dog problem:

/** * not a dog in sight... */ public class Person { private String lastName; private Address address; ... public String getLastName() { return lastName; } ... }

Some of you will have heard me use my adverb/adjective analogy for aspects before, and that's exactly what we've got here. We want to create a dog-owning person, which we could do by creating a DogOwningPerson class (a bit like creating a new noun), but dog-owning isn't limited to people, maybe an Organisation can own dogs too? What we've got is a concept (a compound adjective, dog-owning) that stands in its own right independent of any one class, and that could be applied to many different classes. I'm thinking interface, and I'm thinking aspect...

/** * not a person in sight... */ public aspect DogOwnership { public interface IDogOwner {}; private int IDogOwner.numDogsOwned; public int IDogOwner.getNumDogsOwned() { return numDogsOwned; } }

This aspect represents in a single module the concept of dog ownership. It defines an IDogOwner interface (it doesn't have to be an inner-interface, but making it so helps to keep the whole thing together), and uses inter-type declarations to define a numDogsOwned attribute and a getNumDogsOwned() method on behalf of all dog owners.

We still haven't quite got to person-owns-dog - I wanted to keep the concept of dog ownership independent of any one kind of dog owner. If we have an application where we need person-owns-dog, we can write the following:

public aspect PersonOwnsDog { declare parents : Person implements DogOwnership.IDogOwner; }

I like this solution because Person and DogOwnership are independently reusable, and represent cohesive abstractions in their own right. The PersonOwnsDog aspect that binds the two together is also very clear and simple.

With these aspects in place, you could call the getNumDogsOwned method on a Person as follows:

Person person = new Person(); person.getNumDogsOwned();

this will compile happily and execute without any problems. If ever you build the application without the PersonOwnsDog aspect though, you'll get a compile-time error about missing dogs. If you don't want that to happen, you could code the client this way (and I probably would in this particular circumstance):

... if (person instanceof DogOwnership.IDogOwner) { ((DogOwnership.IDogOwner)person).getNumDogsOwned(); } ...

but it's just a matter of personal taste, the compiler doesn't require it.

Posted by adrian at 12:21 PM [permalink] | Comments (5)

May 27, 2004

Load-time weaving with AspectJ 1.2

After breathing a sigh of relief following the release of AspectJ 1.2, today I thought I'd discuss how to exploit one the new features in the 1.2 release - load-time weaving from the command-line. I'm going to use a variation on the same simple Boy/Girl/Teacher example that I discussed last week. Let's get the boring bit out of the way and show you the code for the basic application first:

In Kissable.aj: public interface Kissable { void kiss(); } In Boy.aj public class Boy implements Kissable { public void kiss() { System.out.println("wahay!"); } } In Girl.aj public class Girl { private Kissable k; public Girl(Kissable k) { this.k = k; k.kiss(); } } In Main.aj public class Main { public static void main(String[] args) { Girl g = new Girl(new Boy()); } }

I compiled this with the command:

ajc *.aj

You can run the application by typing "java Main", but I've chosen to add the new "aj" script that ships with AspectJ 1.2 to my path, and I'm going to use that to launch the application instead (it makes no difference at this stage). You will find the "aj" script in the doc/examples/ltw directory of your AspectJ installation.

aj Main
> wahay!

Time to introduce the Teacher. Here's a really simple variation:

In Teacher.aj: public aspect Teacher { after() returning : execution(* Kissable.kiss()) { System.out.println("Ahem..."); } }

I'm going to compile the Teacher aspect directly into an aspect library. Here's the command-line incantation to do it:

ajc Teacher.aj -outjar teacher.jar

At this point, I could run "aj Main" again and it would produce the same output as before, nothing has changed (we didn't link the Teacher with the rest of our application, we compiled it independently into a library).

Finally, we get to set a new environment variable that the "aj" script looks for: ASPECTPATH. (ASPECTPATH is to aspect libraries as CLASSPATH is to class libraries).

set ASPECTPATH=teacher.jar

Now if I run the application again:

aj Main
> wahay!
> Ahem...

you'll see that AspectJ has linked the application classes with the aspect library as they were loaded. It's as simple as that...

Posted by adrian at 04:05 PM [permalink] | Comments (3)

May 25, 2004

AspectJ 1.2 and AJDT 1.1.10 released

AspectJ 1.2

A good day for AspectJ today. We released AspectJ 1.2, which is the culmination of months of hard work by the project team and I'm very proud of what we've been able to achieve. Full details of the release content are in the README, and you can download it from the AspectJ project home page.

Edited highlights of AspectJ 1.2 include:

  • Much faster compilation and weave times (approx. twice as fast in many cases) than 1.1.1.
  • Support for a new option -XlazyTjp which generates code that runs faster and uses less memory in some common cases.
  • Faster incremental compilation, coupled with incremental support for binary resources.
  • The return of ajdoc, which generates javadoc-like html containing information about aspects and shows cross-cutting structure (e.g. "advised-by" hyperlinks for methods).
  • Better out-of-the-box support for load-time weaving, including a sample command-line script you can use straightaway, and also a class loader and adapter implementation if you need to integrate AspectJ's load-time weaving into an existing server.
  • Much improved error messages (with source context information for weaver messages restored).
  • New lint warnings help catch common mistakes and advise on changes to serializability.
  • The new -Xreweavable option allows class files to be woven more than once.
  • A new -inpath option allows both jar files and directories to be specified as input to the weaver.

AspectJ 1.2 Install Screen

AJDT 1.1.10

Eclipse released 3.0 M9 on Friday. Time to the first AJDT bug report saying that AJDT doesn't work on M9? About 20 seconds. We released AJDT 1.1.10 this morning that both works on M9, and also includes the AspectJ 1.2 compiler. There's a lot of energy being poured into AJDT improvements at the moment, so look out for more releases from the project coming soon :- release early, release often.

A huge thank-you to all of the AspectJ and AJDT users and developers who have helped us to reach this significant milestone. We're not done yet by a long-chalk, so look out for more exciting things from these projects over the coming weeks and months.

Posted by adrian at 07:13 PM [permalink] | Comments (1)

May 21, 2004

Sun reveal what they really think of AOP

Sun have decided to host an AOP panel at JavaOne. The panel discussion's title, abstract, and participants tell you a lot about Sun's views on AOP at the moment.

Update: 25th May. Simon Phipps posted a comment here to say that he is chairing the discussion, rather than taking part. He maintains an open mind on AOP, so apologies Simon for calling you a 'leading doubter.' I doesn't look like I'll be at JavaOne, but next time we're in town together I'll buy you a beer and attempt to persuade you of the virtues of AOP :)

Let's start by looking at the participants in the panel: from Sun's side we have James Gosling (CTO), Graham Hamilton (Distinguished Engineer), and Simon Phipps (Chief Technology Evangelist). The fact that the panel is happening, and that Sun have placed such prominent panelists on it, indicates to me that Sun are taking AOP seriously. If you thought AOP was inconsequential, you wouldn't feature the panel at all, and you certainly wouldn't put such high-profile people on it. The non-Sun panelists are Gregor Kiczales and Cedric Beust.

Now consider the title of the panel and the abstract. The panel discussion goes under the banner of "Aspect Oriented Programming: Great New Thing or Great Leap Backwards?" The abstract is pretty small, so let me just quote it here in its entirety:

"Aspect-Oriented Programming (AOP) technology is receiving a great deal of attention within the object-oriented programming community. Although it provides a great deal of power, it also potentially greatly disrupts program semantics. This session hosts a lively debate between some leading proponents and some leading doubters of AOP."

Since Gregor and Cedric are proponents of AOP, that must mean that James Gosling, Graham Hamilton, and Simon Phipps are "leading doubters." Presumably from the title they therefore believe that AOP is a "Great Leap Backwards," and that it "greatly disrupts program semantics." Quite leading words and phrases.

So there you go. I think it's pretty clear what line Sun will be taking during the panel discussion. I'll leave you with my quiz for the day:

Sun are clearly taking AOP seriously, do you think they view it as:

(a) an opportunity?, or
(b) a threat?

answers on a postcard please...

Posted by adrian at 11:01 AM [permalink] | Comments (10)

May 20, 2004

Effective AspectJ - Understanding type checking for pointcuts and advice

I'll get back onto the Spring theme very soon, but thought I'd mix things up a little today and touch on a different topic.

An AspectJ user raised a bug this morning about AspectJ's type checking, which turned out to be 'working as designed' (*). The rules that AspectJ follows seem completely natural to me now, but I remember a time when the treatment of formal parameters in advice and pointcuts wasn't quite so obvious. Perhaps you could argue that I'm too close to the code, but I think the more significant shift was that I changed the words I say in my head when I read a pointcut definition. Now it's a struggle for me to remember how I could ever think it was any other way. So, the aim of today's post is to help you understand how pointcut and advice parameters work, by looking at a couple of code examples.

Consider the following pointcut and advice definitions:

pointcut accountOperation(Account acc) : execution(public * *(..)) && this(acc); after(CurrentAccount cAcc) returning : accountOperation(acc) { ... }

Assuming that CurrentAccount is a subclass of Account then this should be fine, right? The after advice takes a CurrentAccount, the pointcut needs an Account, and CurrentAccount is an Account.

But it's not fine at all - if you try to compile this code you'll get an incompatible type error. I've led you up the garden path by using misleading language to describe the situation. The thing is, that unlike method parameters (or advice parameters) which are passed into the method/advice body, pointcut parameters go the other way. Pointcut parameters are not a definition of what the pointcut needs to be passed to it, but instead a declaration of the context information that a pointcut provides at a join point it matches. Although pointcut parameters is a correct term for them (in the sense that they parameterize the pointcut), I stopped calling the formals in a pointcut declaration the parameter list (because to my mind at least that has a connotation of values being passed in), and started to call them instead the 'provides' list. Ever since I made that switch, I've found the type matching rules completely natural and intuitive.

Here's how to read the definitions given above using our new terminology: the accountOperation pointcut provides an object of type Account at each join point it matches, and the after advice requires an object of type CurrentAccount. Since the object provided by the pointcut could be any type of Account, and not just a CurrentAccount, this is a type error as the advice is not guaranteed to get an instance of the type it needs.

In contrast, the example below is perfectly well-formed:

pointcut currentAccountOperation(CurrentAccount acc) : execution(public * *(..)) && this(acc); after(Account acc) : currentAccountOperation(acc) { ... }

The currentAccountOperation pointcut provides a value of type CurrentAccount, and the after advice requires an object of type Account. Since a CurrentAccount is an Account everything works just fine.

* The actual bug report was in a slightly different area, and had to do with the return type of around advice not being compatible with the expected return value from a call join point:

double around() : call(int foo()) { return (proceed() * Math.PI); }

Can you see the subtle type error here?

Posted by adrian at 04:10 PM [permalink] | Comments (3)

May 19, 2004

What the teacher said (using AspectJ with Spring part II)

Yesterday I introduced a simple example of a Teacher aspect responding to a playground kiss. Today's objective is to make the teacher's response configurable as a bean property using Spring.

First let's update the Teacher aspect to have a response property. I'm going to use setter-injection for reasons that will become apparent later:

public aspect Teacher { private String response; public void setResponse(String response) { this.response = response; } /** * There are many things that can be kissed, and many possible kissers, * but here we're just interested in Girls kissing Boys. */ pointcut aGirlKissingABoy() : call(* Kissable.kiss()) && this(Girl) && target(Boy); /** * Now we get to decide what the teacher's reaction is to the kiss... */ after() returning : aGirlKissingABoy() { System.out.println(response); } }

Now the tricky bit - how do we convince Spring to configure the Teacher aspect? Spring usually both instantiates and configures bean objects, but aspects in AspectJ are implicitly constructed on point of first reference - so it doesn't work for Spring to simply call the default constructor of Teacher. This is also the reason that we can't use constructor-injection: AspectJ will actually give a compile-time error if you attempt to define a non-zero argument constructor in an aspect. I've played round with various permutations to address this configuration problem, and I don't claim to have arrived at the ideal solution yet, but the following works quite nicely.

<beans> <bean id="girl" class="Girl"> <property name="kissable"><ref bean="boy"/></property> </bean> <bean id="boy" class="Boy"> </bean> <bean id="teacher" class="Teacher" factoryMethod="aspectOf"> <property name="response"><value>we'll have none of that please...</value></property> </bean> <bean id="aspectFactory" class="org.aspectj.springframework.beans.factory.config.AspectBootstrapBean"> <property name="aspects"> <list> <ref bean="teacher"/> </list> </property> </bean> </beans>

Notice that the teacher bean is configured almost exactly like any other bean, except that instead of letting Spring use a default constructor to create an instance of the bean, we ask it to use a factory method instead. In this case the factory method is aspectOf, which is defined by AspectJ on every singleton aspect and returns the aspect instance as created by the AspectJ runtime. I added an second bean into the mix too, the "aspectFactory" bean. Note that the class of this bean refers to a framework class I wrote to aid in the bootstrap process. This bean is configured like any other bean, and has an "aspects" property that should be passed a list of all the (aspect) beans to be used in the program. This has the consequence that loading the aspectFactory bean causes Spring to create and configure all of the aspects we will need.

Here's the updated main program that puts it all together:

public class Main { public static void main(String[] args) throws Exception { XmlBeanFactory beanFactory = new XmlBeanFactory(new FileInputStream("beans.xml")); beanFactory.getBean("aspectFactory"); // causes init and config of all aspects Girl g = (Girl) beanFactory.getBean("girl"); g.kiss(); } }

If you run this program you get the output:

we'll have none of that please...

confirming that Spring has indeed configured the teacher aspect correctly. Aspects configured in this way support all of the various property types that Spring offers (references to other beans, lists, maps, constant values, etc.).

There's lots more to talk about - in future posts I'll discuss what happens when you want two Teachers to show up at the same time, the issues surrounding aspect instantiation models other than the default (perthis, pertarget, ...), how to (dynamically) configure pointcut expressions as bean properties, using the Spring configuration to enable and disable aspects, and of course how AspectJ fits in with Spring's own AOP framework.

All of this is new territory, so if you've suggestions for how you'd like to see things work, just let me know...

Ok, I confess, I cheated a little bit. The "factoryMethod" attribute doesn't yet exist in Spring's DTD, but I've been talking a lot with Rod Johnson about all this and it will be coming in the Spring 1.0.3 release. Until then, there's a variation you can use that works with Spring today, but is a little more verbose. It entails a change to the config file I showed you, and it looks like this:

<beans> <bean id="girl" class="Girl"> <property name="kissable"><ref bean="boy"/></property> </bean> <bean id="boy" class="Boy"> </bean> <bean id="teacher" class="org.aspectj.springframework.beans.factory.config.AspectFactoryBean"> <property name="staticMethod"><value>amc.Teacher.aspectOf</value></property> <property name="aspectProperties"> <map> <entry key="response"> <value>we'll have less of that please...</value> </entry> </map> </property> </bean> <bean id="aspectFactory" class="org.aspectj.springframework.beans.factory.config.AspectBootstrapBean"> <property name="aspects"> <list> <ref bean="teacher"/> </list> </property> </bean> </beans>

For the curious, AspectFactoryBean is a little helper class I wrote that extends Spring's MethodInvokingFactoryBean to also configure the bean that it creates.

Posted by adrian at 10:53 PM [permalink] | Comments (2)

May 18, 2004

Using AspectJ with Spring - part 1

This is the first of what I envisage will be several entries exploring how AspectJ and Spring can be used together. Today I'm just going to introduce a very simple example that I can build on in later posts, and that shows an aspect working seamlessly (if unsurprisingly) in a Spring application. The example takes its inspiration directly from Aslak's pico container talk at TSS.

From a Spring perspective (the AspectJ pieces of this example could equally well be used with pico, nano, or HiveMind), the example hinges around a Girl kissing a Boy, and the question of how our Girl finds her prince charming.

Some things in life can be kissed:

public interface Kissable { void kiss(); }

Girls, now they'll kiss anything...

public class Girl { private Kissable k; public void setKissable(Kissable toKiss) { this.k = toKiss; } public void kiss() { k.kiss(); } }

Boys are just one of the many things that can be kissed:

public class Boy implements Kissable { public void kiss() { System.out.println("wahay!"); } }

We can wire the application up with Spring to create a Girl bean and a Boy bean, and help them get it together.

<beans> <bean id="girl" class="Girl"> <property name="kissable"><ref bean="boy"/></property> </bean> <bean id="boy" class="Boy"> </bean> </beans>

Finally we need a minimal "main" to fire up the container and run the application:

public class Main { public static void main(String[] args) throws Exception { XmlBeanFactory beanFactory = new XmlBeanFactory(new FileInputStream("beans.xml")); Girl g = (Girl) beanFactory.getBean("girl"); g.kiss(); } }

If you run this stunning program, you get the output


as the girl kisses the boy. So far, not an aspect in site.

Finally, it's time to add an aspect into the mix. Let's move the scene to a school playground and see what happens when a Teacher observes a girl and boy kissing:

public aspect Teacher { /** * There are many things that can be kissed, and many possible kissers, * but here we're just interested in Girls kissing Boys. */ pointcut aGirlKissingABoy() : call(* Kissable.kiss()) && this(Girl) && target(Boy); /** * Now we get to decide what the teacher's reaction is to the kiss... */ after() returning : aGirlKissingABoy() { System.out.println("Let's keep that behaviour for after school hours shall we?"); } }

Run the program again, and now you'll see the output:

Let's keep that behaviour for after school hours shall we?

In tomorrow's installment, I'll get into the issue of how we could use Spring to make the Teacher's response a configurable property on a "teacher" bean (i.e. how to use Spring to configure aspects).

I think the Teacher aspect is a very clear and direct implementation. Given a system with several different Kissable classes, and several different clients that call them, how would you code this in straight OO? Do you have a solution that is non-intrusive on the Girl and Boy classes (after all, they really don't care what the teacher thinks)? What if I tell you that my next requirement will be for the teacher to react when a Girl kisses a Frog too?

Posted by adrian at 02:25 PM [permalink] | Comments (1)

May 17, 2004

Maven AspectJ 3.0 plugin released

Thought I'd stick to a nice non-controversial post today ;).

Carlos Sanchez has released version 3.0 of the Maven AspectJ plugin. It integrates the AspectJ 1.2 release candidate and promises "major improvements" over the previous version.

Thanks Carlos :).

Posted by adrian at 04:32 PM [permalink] | Comments (0)

May 15, 2004

EJB 3.0 - What's wrong with @Inject?

The TSS Symposium gave us all a first glance of what's coming in EJB 3.0 (see Dion's write-up). The new spec has prompted a lot of debate, but I want to comment here on only one small part of it. It struck me as soon as I saw it on the slides, but I couldn't immediately put my finger on why I disliked it so: I'm talking about the use of the @Inject annotation to indicate a setter-method that the container will call to provide a bean with a reference to another bean, or to a service it depends on. Here's an example from the TSS article:

@Session public class MyBean { private DataSource customerDB; @Inject private void setCustomerDB(DataSource customerDB) { this.customerDB = customerDB; } public void foo() { ... Connection c = customerDB.getConnection(); ... } }

There are two separate issues raised here - why do I need the @Inject annotation at all, and if I do need an annotation, is @Inject the right one? Like it or not, annotations are coming. A prominent J2EE specification such as EJB should guide us in their correct usage, and not set a bad example. This morning it fully dawned on me why I think @Inject is a bad example, and it's based on the same reasoning we give for how we think annotations will be best used in conjunction with an aspect-oriented language like AspectJ.

The clue is in the name: "JSR 175: A metadata facility for the Java Programming Language." Annotations are supposed to be metadata - they are supposed to provide information about the language element being annotated: a good annotation describes some property of the thing it is annotating. If classes and data members are nouns, and methods are verbs, then annotations are like adjectives and adverbs, describing the classes, fields, and methods respectively. But "inject" isn't an adverb or adjective - it's a verb. "Inject" doesn't describe any property of the set-method, instead it sounds more like a compiler or run-time directive. That's not a good way to encourage people to think about annotations, though I'm sure we'll see many such abuses in time. The smallest possible change that would make me happier is to add two characters, "ed." That would give us the annotation @Injected, which does at least describe a property of the dependency (it's an injected dependency).

While I'm on the soap-box though, let me also say that the annotation @Injected still sounds a bit mechanistic to me, something that captures the intent more accurately, something a little closer to the intended semantics would be even better. My suggestion of the day is "@ContainerProvided," this annotation tells us that we expect a container to provide a value for us. A final suggestion: is this really a property of the setter-method, or of the data member itself? In the example above, it's the value of the customerDB field that is container provided - the setter method is just the means of achieving that end. Here's how the EJB would look if these suggestions were adopted:

@Session public class MyBean { @ContainerProvided private DataSource customerDB; private void setCustomerDB(DataSource customerDB) { this.customerDB = customerDB; } public void foo() { ... Connection c = customerDB.getConnection(); ... } }

I think it's better anyway - what do you think?

Some footnotes on the discussion:

1) One reason to put the @ContainerProvided annotation on the setter-method rather than the field is that this allows for 'virtual' fields, where there is no customerDB data member in the class, and the setter method performs some calculation based on the passed value without ever storing it. These (relatively rare) cases could be handled by annotating a set-method directly still.

2) A nice feature that follows from annotating the field directly rather than the setter-method, is that both constructor and setter dependency injection could be supported (and even direct field setting), giving more flexibility in different situations.

3) I didn't discuss the issue of whether the annotation is needed at all or not. Spring, pico, nano, and HiveMind all seem to get along fine without annotations. The only thing I can think of that the annotation really buys you here is the ability for a compile time/deploy time/runtime check to say "hey, you asked for this value to be container provided, but I can't find an appropriate setter method, nor a constructor parameter, and neither is the field visible for me to set it directly." That check might be useful if say, you're trying to get the container to provide you with a SessionContext and you misspell the setSesionContext method name - in EJB 3.0 I could see that failing silently without the annotation in place (interfaces used to solve that problem for us, but they're sooooo EJB 2.1 you know).

Posted by adrian at 02:51 PM [permalink] | Comments (8)

May 14, 2004

AJDT 1.1.9 Released

Andy (Clement) has uploaded version 1.1.9 of AJDT, which bundles the AspectJ 1.2rc2 compiler we released yesterday. You can get AJDT 1.1.9 from the AJDT project page, but there's an even nicer way to upgrade if you've already got 1.1.8 installed:

Go to the preferences page from the windows menu, and if you haven't already done so check the "automatically find new updates and notify me" option in the Install/Update->Automatic Updates panel.

update panel

When you click OK, Eclipse will start looking for updates immediately (it will also do this every time you start Eclipse from now on). Since you installed 1.1.8 previously, Eclipse knows about the AJDT update site, and finds the new version:

new updates available

Click on "Yes" to review and install the updates, and voila... Eclipse takes you to the install screen for AJDT 1.1.9.

AJDT install screen Hope you enjoy it!

Posted by adrian at 11:53 AM [permalink] | Comments (1)

May 13, 2004

Integrating AspectJ and AOP Alliance based aspects

I was taking part in the AOP panel discussion at last weeks TSS symposium, and listening to Rod Johnson and Bob Lee describe how dynaop and Spring can share aspects since they both implement the AOP Alliance interfaces. Sounds like both projects have some great aspects already written, and with more to come the obvious question crossed my mind: can I use aspects written to the AOP Alliance interfaces from within AspectJ?

A few hours later and I had a solution that lets you use the expressive power of AspectJ's pointcut language to invoke advice (interceptors) written to the AOP Alliance interfaces, and to freely mix and match AspectJ and AOP Alliance advice in the same program, even applying at the same join points. Here's how it looks...

First a little background, the AOP Alliance have basically defined a set of interfaces that define method interception and constructor interception implemented advice, and a join point interface hierarchy that provides access to the (java.lang.)Method or Constructor being advised, the currently executing object ('this'), and the call parameters. Unlike in AspectJ, the Joinpoint interface in the aopalliance.jar also contains the proceed() method that is to be called by an interceptor if and when it decides to allow computation at the join point to proceed.

Here's how a simple method interceptor looks written to the AOP Alliance interfaces:

public class MyMethodInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation jp) throws Throwable { System.out.println("About to invoke: " + jp.getMethod().getName()); Object ret = jp.proceed(); System.out.println("Completed invocation of: " + jp.getMethod().getName()); return ret; } }

I've written an AspectJ library aspect AOPAllianceAdapter that lets you invoke such interceptors as regular AspectJ advice. First I'll show you how it looks to use the aspect, and then we can dive into the details.

public aspect MyAOPAllianceAdapter extends AOPAllianceAdapter { private MethodInterceptor myMethodInterceptor = null; /** * provide definition of getMethodInterceptor from super-aspect */ protected MethodInterceptor getMethodInterceptor() { if (myMethodInterceptor == null) myMethodInterceptor = new MyMethodInterceptor(); return myMethodInterceptor; } /** * provide definition of targetJoinPoint pointcut from super-aspect */ pointcut targetJoinPoint() : within(*); }

The aspect you see above will invoke the method interceptor at each execution join point matched by the targetJoinPoint pointcut definition. That's all there is to it. You can also override the getConstructorInterceptor method if you want to use an AOP Alliance constructor interceptor instead or in addition.

For the curious, here's the definition of the library aspect - the only tricky part is building the closure so that when an AOP Alliance interceptor calls proceed() on a join point AspectJ will do the right thing.

public abstract aspect AOPAllianceAdapter { /** * sub-aspects override this method to tell the adapter which interceptor to drive. */ protected abstract MethodInterceptor getMethodInterceptor(); /* * constructor interceptors are less often used, so we provide a default implementation */ protected ConstructorInterceptor getConstructorInterceptor() { return null; } /** * sub-aspects define this pointcut to determine the join points at which the interceptor(s) will be * invoked. */ protected abstract pointcut targetJoinPoint; // method interceptors should only be triggered at method-execution join points, and // constructor interceptors at constructor-execution join points pointcut methodExecution() : execution(* *(..)); pointcut constructorExecution() : execution(new(..)); /** * invoke method interceptor at target execution join points */ Object around() : targetJoinPoint() && methodExecution() { MethodInvocationClosure mic = new MethodInvocationClosure(thisJoinPoint) { public Object execute() { return proceed(); } } MethodInterceptor mInt = getMethodInterceptor(); if (mInt != null) { try { return mInt.invoke(mic); } catch(Throwable t) { throw new SoftException(t); } } else { return proceed(); } } /** * invoke constructor interceptor at target execution join points */ Object around() : targetJoinPoint() && constructorExecution() { ... similar to above definition } }

The helper class MethodInvocationClosure implements the AOP Alliance MethodInvocation interface. It defines the proceed() method from the interface to call execute (since proceed() has a special meaning inside AspectJ's around advice). An anonymous subclass of the closure is created inside the around advice, that proceeds (AspectJ proceed) when the execute method is invoked (i.e., when the AOP Alliance adapter wants to proceed at the join point).

I'll post the code and test cases for this somewhere publicly available - probably in the AspectJ samples 'sandbox' in CVS - so that you can try this out for yourself.

Posted by adrian at 04:27 PM [permalink] | Comments (1)