Thursday, June 28, 2007

Lies, Damned Lies, and XML

Various skeptics have tried (and failed) to argue that annotation-based dependency injection results in tighter coupling than other approaches. I would argue that reams of proprietary XML code couples you to a framework more than anything, but I digress.

If you're still on the fence, Kevin B. further debunks the myths in Coupling:

Furthermore, the idea of "coupling" implies that "the one cannot function without the other." But with Guice's annotations, this simply isn't the case. It's important to understand that these are only annotations. They are decoration; meta-information. They don't, and can't, actually do anything. They just sit there, innocuously, in case tools will wish to read them, and otherwise have no effect whatsoever. They do absolutely nothing to impede you from testing your code, or from using the classes with Spring.

If you produce 3rd party libraries and you want to help Guice users use your products, but you don't want a compile-time dependency on Guice yourself, provide a separate Guice integration package. This is like providing your users with example Spring XML, except it doesn't suck.

17 Comments:

Blogger Colin Sampaleanu said...

It's ironic that this blog entry is titled "Lies, Damn Lies and XML", when it points to a blog entry which says, with no basis in reality, that you can load classes annotated with Guice annotations, without guice.jar on the classpath.

I am on vacation now, so I'm not even going to get into anything else (e.g. the "sucks" comment) written in the entry...

Colin

1:07 PM  
Blogger Bob said...

In reply to, "no basis in reality," try it for yourself:

$ cat Foo.java
import com.google.inject.Inject;
import java.util.Arrays;
public class Foo {
@Inject
public static void main(String[] args) throws Exception {
System.out.println(
Arrays.asList(Foo.class.getMethod("main", String[].class).getAnnotations()));
}
}
$ javac -cp guice-1.0.jar Foo.java
$ java -cp . Foo
[]

If you want to completely strip @Inject away, simply include your own version of @Inject with compile time retention in the classpath and recompile.

Regarding my use of the word "sucks," :) :) :).

1:38 PM  
Blogger Colin Sampaleanu said...

Now go try this with older versions of Java 5...

1:42 PM  
Blogger Bob said...

Are you trying to say my example doesn't run on older JVMs?

Again, you can always compile your code with this in the classpath:

package com.google.inject;
@java.lang.annotation.Retention(
  java.lang.annotation.RetentionPolicy.SOURCE)
public @interface Inject {}

2:00 PM  
Blogger Colin Sampaleanu said...

Yes, this is exactly the same issue faced by people using the EJB 3/Java EE 5 annotations. At least the Java 5 (JDK 1.5) versions out at the time of release of Java EE 5 will throw an exception if you try to load a class with a Runtime retention annotation imported into it, even if that Annotation is never touched, if the Annotation is not on the classpath. This was supposed to be changed for Java 6 (JDK 1.6) or maybe a later version of Java 5, I don't remember which. Which version of Java are you doing your test with?

As for your suggestion of compiling the code with the @Inject annotation in it, with a fake version of @Inject on the classpath that has compile retention, I don't think this is very realistic. Somebody compiling against Guice is going to use the real Guice jar (with Runtime retention), and then they are going to ship their own code in binary format...

Colin

2:18 PM  
Blogger Bob said...

$ java -version
java version "1.5.0_07"

As for whether using a fake @Inject is realistic or not, I wouldn't bother myself. I also think the idea that writing even more framework-dependent code in XML somehow makes it easier to switch is even less realistic.

2:28 PM  
Blogger Nick said...

I've always thought that you needed the annotation definitions available to load classes. I know in early version of Java 1.5 that was the case, and while the spec doesn't seems to indicate the behavior one way or the other Ted Neward (JSR-175 member) has said:

"no part of JSR 175 was more hotly debated, or contested, than the requirement we made that annotations be present not only at compilation-time, but at run-time."

http://blogs.tedneward.com/2006/01/01/Annotation+Letdown+A+Response.aspx

It's possible that has changed, but I think its going a bit far to call it a lie.

4:23 PM  
Blogger Jesse Kuhnert said...

I'm not sure what the specs or Ted say but do know what the jvm actually does through some unfortunate class loading bugs I punished myself with a while back. ...

The annotation meta gets embedded in to the class byte code in either case so we have the class sitting there and the meta..

You can load that class in a class loader and one of two things will happen:

a) You have the annotation classes in the classloader hierarchy somewhere when you load said class. Everything works great. (isAnnotationPresent / etc)

b) You load this class without the original annotation class in the classpath. Class still loads great either way. If you somehow get the annotation classes in the classpath after the fact then calling isAnnotationPresent sadly won't work out for you. (this might be fixable after the fact as well but I never had to go that far)

What's really cool is that the meta handling stuff is really resilient and you can actually still get ~all~ of that meta information via lower level reflection routines such as getAnnotations() ...You just won't be able to check class equality is all.

That is my broken and small understanding of it.

Whether things are lies or whatever I have no idea and don't want to be involved in - just wanted the technical facts to be asserted.

5:25 PM  
Blogger Bob said...

Yeah, shame on you, Colin, for calling Kevin a liar. :)

What's important is that annotations do not tightly couple you to the framework. They're just metadata which doesn't get in the way of your using the classes in other contexts. Whether you need annotation classes in the classpath or not is immaterial in my humble opinion.

5:41 PM  
Blogger Kevin Bourrillion said...

The fact that Bob's sample code didn't work on java 1.5.0_01 is an interesting phenomenon called a "bug" which the JRE had at the time. I don't see how that's relevant to anything.

Colin, if I were on vacation right now, I think I'd spend my time doing something a little more relaxing! :-)

6:26 PM  
Blogger Davide Baroncelli said...

Even if we have fairly complex systems based on Spring, I didn't ever seem "reams" of XML configuration.

More than that: Spring XML config does not suck.

I guess it's hard to accept, but I can assure you it's true: there is a large community of persons thinking that Spring XML config is a viable, practical and manageable way of working. Repeating "Spring XML sucks" or "Spring API sucks" does not add a single grain of value to the work you're doing, and is frankly irritating for people like me: when Guice will have done what Spring has done for the jee world you will maybe be right, speaking in those terms. Up until that moment, I think you should show more respect for it.

Spring XML does not suck. Not more than Guice's lame flowing constructs, or annotations which explicitly mention dependencies in my view. I guess it's all a matter of taste, period.

2:37 AM  
Blogger Robbie Vanbrabant said...

Bob has a point. XML is being overused.

But I'd also say that the Spring Framework is one of the best frameworks on the planet. A lot of people see DI as "yeah, whatever" these days. It's supposed to be there. Spring's value add is in all the rest. The API abstractions. The industry support. The community. The standard.

But for pure DI, as a technology and from a usability perspective, nothing beats Guice. And that's why I always consider it, and will probably use it more often.

Keep up the good work guys.

Robbie

3:03 AM  
Blogger Bob said...

Immanuel, I do think Spring sucks. Why do you think Guice looks nothing like it? A "large community of persons" also liked EJB 1/2 and Struts 1, but that didn't make them right.

If Spring is up to your standards, then by all means, use it. Frankly, I don't have time to dissect Spring's flaws for you. I'm too busy supporting Guice users, and I know better than to waste time trying to teach people who aren't willing to learn.

Contrary to Spring's philosophies, I think very few design decisions are "a matter of taste." Some ways of doing things are provably better than others, and one way of doing something is almost always better than two. Otherwise, you end up with the Perl of frameworks.

Incidentally, this post was about annotations vs. XML, not Guice vs. Spring. In case you didn't notice, Spring supports annotations now, albeit not as well as Guice.

Robbie, thanks for using Guice!

10:06 AM  
Anonymous Anonymous said...

Bob,

Let's assume for the moment that you are correct and coupling is not one of the drawbacks of using Guice.

In that case, what do believe are the drawbacks of Guice in particular and using annotation for configuration in general? Or, have we finally reached configuration nirvana?

Chris

10:14 AM  
Blogger Bob said...

First off, let me say that I hope no one takes my frankness too personally. I obviously don't think Spring sucks entirely--I just think it sucks compared to Guice. Big surprise! :)

Chris, that's an awesome question! In the short term, Guice itself could benefit from more tool support (it's on the way!).

Long term, I think it sucks that we need a DI framework at all. Not all languages do. Technically, we're working around deficiencies in the Java language. That said, I think Java's other qualities more than make up for these deficiencies, at least compared to other viable languages. Tools like Guice can be good enough but not panaceas by any stretch of the immagination. Check out Gilad Bracha's post Constructors Considered Harmful.

Finally, annotations aren't always a good replacement for XML. Please take this post in the context in which Guice applies them.

1:15 PM  
Blogger Bob said...

Also, in retrospect, "Annotation Myth Busters" would have been a better title for this post. :)

1:23 PM  
Blogger Dhanji R. Prasanna said...

Why is it that people feel so slighted when you point out a conclusion. I thought the scientific method is about refutation not "being irritated." Assuming that we consider ourselves scientists.

I do consider myself that (more so than an engineer). An engineer is worried about standardization and norms. A scientist is worried about the problem. period. We borrow from each other where necessary (JSRs are engineering standards, academia/researchers produce new design constructs).

Tomorrow, guice could be overrun by some Java7 driven feature. Why is that a bad thing?

For instance, it is impossible to dispute that HiveMind is a more sophisticated IoC container than spring AND guice (service-schemas? filter chains?), that doesnt necessarily make it the best choice (it lacks a measure of typesafety). Im not sure I understand all the static or why we need to take sides irreconcilably.

Dhanji.

6:39 PM  

Post a Comment

<< Home