Beside adding support for closures to Java 7, I propose adding support for runtime interface and abstract class reification. Well, I propose that someone who actually knows what they're talking about propose such a mechanism.
Background: Earlier today I was reading a blog about the worthlessness of constructors. Frankly, I didn't really get the point of the post, but the title was catchy. Jeremy mentioned something about dependency injection (DI), one of my favorite topics, having written at length about how crappy Spring is (it's really not, and I hope the Spring guys didn't take offense to it--like Jeremy, I tend to be hyperbolic in my praise and criticism).
The problem I've always had with DI frameworks, be it Spring or Guice, is they create this nasty dependency tree. If you don't want to use GlobalApplicationContext.getBean() or Injector.getInstance() then you'll need to inject all your dependencies at the root. It annoys the crap out of me, but I suppose there's just no way around it...
Except if the language had a mechanism to realize interfaces and abstract classes at runtime, either built-in or through some extension.
I want to be able to do something like this
interface MovieFinder {...}
...
MovieFinder mf = realize MovieFinder();
List<Movie> movies = mf.findAll("Scarlet Johansson");
...
and have the language realize the MovieFinder interface for me (at runtime). It could be a DBMovieFinder, or maybe a MockMovieFinder for testing purposes. "realize" is just like "new" except we let the runtime figure out what concrete implementation(s) reifies the interface or abstract class. The fundamental problem with all dependency injection tools is they are trying to do what language should be doing (instantiating objects that implement some interface).
As I mentioned earlier, I don't think the Java language should have this built-in, because it is a rather specific use case; but Java might have some sort of extension mechanism so that it appears built-in to the average programmer.
I'm sure there are many issues with such a mechanism, but I don't think I'm too off base. Gilad Bracha writes,
And apparently the creator of Guice agrees,
It's 2008, we've landed a man on the moon, and I'm still clunking around with DI tools!
It seems like realize could be implemented with Guice and some syntactic sugar... Perhaps something to try in Kijaro? https://kijaro.dev.java.net/
Posted by: Jesse Wilson | August 19, 2008 at 11:03 AM
thanks for the link, I'll have a look.
Posted by: tinou | August 19, 2008 at 11:44 AM
I posted some thoughts about how these issues are handled in Qi4j, which you might be interested in:
http://www.jroller.com/rickard/entry/qi4j_fixing_dependency_injection
Posted by: Rickard Öberg | August 19, 2008 at 07:34 PM
Seems to me, with the service provider build right into Java, I get 90% of the benefits of DI without having to pull it dependencies and rely on more frameworks I really want to (lord known, there are already too many on even the smallest Java project).
Tim Boudreau of NetBeans fame wrote a piece on this a few weeks ago:
http://weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html
Posted by: Casper Bang | August 20, 2008 at 04:19 AM
I am not sure I fully understand what the problem is. Is it that for each dependency you have, you also need to have it injected somewhere, to avoid GlobalApplicationContext.getBean() or Injector.getInstance() ?
Butterfly Container has a slightly different approach to this. You can have Butterfly Container adapt itself to your custom factory interface, like this:
public interface MyFactory{
Bean bean1();
Bean bean2();
Product product();
}
public class ClassThatNeedsObjects{
protected MyFactory myFactory = null;
public ClassThatNeedsObjects(MyFactory factory){
myFactory = factory;
}
public void atRunTime(){
Bean bean1 = myFactory.bean1();
Bean bean2 = myFactory.bean2();
Product product = myFactory.bean3();
}
}
The calls to the methods in the MyFactory interface are translated into beans in the container.
Notice how the atRunTime() method can actually obtain beans from the container, without ever dependending on the container's interface. It only knows the MyFactory interface, which is something
you write yourself.
The configuration of the container would look like this:
bean1 = * com.blabla.Bean("value1");
bean2 = * com.blabla.Bean("value2");
product = * com.blabla.Product();
classThatNeedsObjects = * com.blabla.ClassThatNeedsObjects(#product);
Posted by: Jakob Jenkov | August 20, 2008 at 06:08 AM
My thought was that we could reuse "import" instead of "realize" so we don't have to add a new keyword.
Posted by: Bob Lee | August 20, 2008 at 09:43 AM
Interesting idea! Never really thought about something like that. But there's one thing I don't get: How would the language know which concrete implementation of MovieFinder to "realize"?
Posted by: MartinJ | August 20, 2008 at 12:45 PM
Meh,
DI is great. Doing it in a configuration step e.g. through XML, annotations or a scripting language is not a property of DI, it's an implementation. In my book, this still qualifies as DI:
MyService myService = new MyService();
MyController myController = new MyController();
myController.setService(myService);
Posted by: fletch | August 21, 2008 at 04:12 AM
@MartinJ: One idea: it could work like/with class loaders. i.e., you'd have a thread local "object loader".
@fletch: I agree. I actually present the "DI by hand" approach in the beginning of my talk, and then I go into why you'd want to use a framework: http://crazybob.org/2007/06/introduction-to-guice-video-redux.html
Posted by: Bob Lee | August 21, 2008 at 09:48 AM
@casper: I'm not too familiar with SPI, but it sounds like a service locator approach, and seems heavyweight since it requires jars (is that correct?)
@MartinJ: i'll echo bob's thoughts. my first thought is some type of classloading/classpath approach, with override. the one nice thing about classloading/classpath is it'll force better module/component dependencies. for example
client-module: client code
service-interface-module: defines interfaces to your services
implementation-module: defines concrete implementation
mock/test-module: defines the mock/test implementations
if your modules aren't deployed correctly then you'll get ambiguous realizations/imports errors.
echo'ing gilad's thoughts, i wished java packages could be used for dependency management. right now packages fairly limited.
Posted by: tinou | August 21, 2008 at 11:06 AM
bit late but anyways...
@Bob & tinou: I'm still a bit unsure as to how that could work exactly. If I understand you correctly the "realized/imported" concrete implementation is known because it's part of some JAR on the classpath, right? So one would just swap in some other JAR-File to get a different implementation. What if you've got more than one implementation? Care to explain your ideas a bit more? I think it's a really interesting idea for the lanugage to provide such a mechanism...
Posted by: MartinJ | August 27, 2008 at 01:51 PM
Off-hand, I wonder how far someone could get just with properties files to specify implementations, like the way the security.provider class is set in java.security (with which I became way too familiar when I was writing code to run on Websphere).
Then a unit test, for instance, could override this implementation property in code.
Posted by: Reedo | May 19, 2009 at 11:06 AM