Posts mit dem Label Java werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Java werden angezeigt. Alle Posts anzeigen

Samstag, 15. Dezember 2007

Instantiating Generic Type Parameters with Factory Pattern

Some weeks ago a cowoker of mine asked me for help. He wanted to write a class with generic parameter type and create a new object of this generic type inside the class. I.E. he wanted to write something like this in Java:


public class WrongSyntax<T> {
public void someMethod() {
T object = new T(); //this line does not compile
}
}
There are some reasons why this code can't compile. Most evident reason is that T could be an interface and you can't instantiate an interface. And you have to be aware generics are boiling down to one rule : Generics are a double-check on compile time but at runtime the type parameter will be replaced by java.lang.Object and casts to the parameter type. This effect is called type erasure.

If you use java.lang.String as parameter type (and the compiler would not reject the marked line) this class would be replaced by:

public class WrongSyntax<T> {
public void someMethod() {
String object = (String) new Object();
}
}

You would get a ClassCastExcetion on runtime, therefore the compiler does not allow it.

Some days ago I read an article by Angelika Langer & Klaus Kreft regarding this problem in the German Java SPEKTRUM magazin. I'm afraid you won't find it online but there is an excellent english FAQ about Java Generics on Langer's site.

In this said article they discuss the problem of array and simple type instantiation for type parameters. Even though they brought up several solutions for arrays they came up with only one for simple types: Using reflection.


public class UsingReflection<T> {

public static <T> void createInstance(Class<T> clazz) {
T instance;
try {
instance = clazz.newInstance(); // does not work for every class
} catch (InstantiationException e) {
//...
} catch (IllegalAccessException e) {
//...
}

//...

}
}


While this will work for some classes it is obvious that it will not work for interfaces, abstract classes and classes without a default constructor.

Here are two examples that will pass the compiler but fail on runtime:



// throws java.lang.InstantiationException
new UsingReflection().createInstance(Serializable.class);

// throws java.lang.IllegalAccessException
new UsingReflection().createInstance(AbstractCollection.class);



To my mind there is a reason why instantiating type parameters is so difficult. In the first place generics are a double-check for programmers to avoid class cast exceptions. But there is more to it. Using generics brings you the benefit of decoupling an algorithm from the type it works on. But if you are trying to create a new instance of this type your generic code isn't indepent from this type anymore.

Fortunately there is a solution to the problem known from one of the most referenced books in software engineering - the GOF-Book. It's called Factory Pattern. And with generics the factory pattern is even more powerful. Your factories only need to implement the generic Factory interface


public interface Factory<T> {

public T create();

}


and your generic algorithm can trustfully rely on it.


public class UsingFactory<T> {

Factory<T> factory; // or maybe use Factory<? extends T> factory;

public UsingFactory(Factory<T> factory) {
this.factory = factory;
}

public void someMethod() {
T instance = factory.create();
//...
}

}


Object creation and object using are now decoupled, while the algorithm and the type it works on are decoupled too.

Now you can even implement a class GenericFactory<T> which uses reflection for instantiation. But you don't have to. You aren't forced to use a class with default constructor for T. But generics still work for you and the compiler will complain if the factory type parameter and the type parameter of your algorithm do not match.


// SimpleString creates Strings just like everybody does
Factory<String> simpleStringFactory = new SimpleStringFactory();

UsingFactory<String> useSimple = new UsingFactory<String>(simpleStringFactory);


// instantiates a factory that creates Strings via reflection
Factory<String> stringFactory = new GenericFactory<String>(String.class);

UsingFactory<String> useString = new UsingFactory<String>(stringFactory); // this works like expected

UsingFactory<Long> useLong = new UsingFactory<Long>(stringFactory); //type params do not match; does not compile

Freitag, 9. November 2007

My WJax Review

I just came back from W-Jax/SOACON yesterday where I've seen a lot of great talks. Three days of high quality input can really make you feel your synapses growing in your brain.

I learned a lot of things while staying in Munich. MVS (Most Valuable Speaker) for me was Gregor Hohpe who is a really cool guy. He is co-author of one of my favorite books (Patterns of EAI) and I was really excited to meet him in person.

He was the first one who made clear to me what SOA is really all about, something that all these SOA hype business people never were able to. You don't know how annoying these people are. These people make you feel like a second class citizen if you don't have WS-* everywhere and use some BPEL and BPM and BLA BLA BLA.

But thanks to Gregor, now I know that we are on the right track. More than that I know we can reach leading position if we abstract a little bit more here and do some looser coupling there, etc. Nothing to difficult, nothing to worry about, just utilizing more patterns and make things work.
I had a very nice discussion with Gregor and almost missed my flight from Munich back to Berlin.

Gregor Hohpe also was the one who encouraged the audience to write more blogs and articles about patterns and related topics. And this is exactly what I'm trying to do right now. ;-)

But I learned a lot more things on W-Jax. I attended some talks about OSGi which soon will be featured in every serious Java project. I swear. In 2009 you won't see any bigger Java project (open source or not) which isn't OSGi-enabled. I bet Peter Kriens would tell you the same.

And I attended some talks about the Java language, Groovy and Spring.

These guys from interface21 seem to be really busy these days. They just released Spring 2.5 and are working hard on Spring Webflow 2.0 and Spring Batch. I'm thinking about using Webflow as lifecycle controller in my project. As far as I know do they try to utilise Spring Webflow to manage the JSF lifecycle.

Groovy lead Dierk König showed off some really cool Groovy stuff. I have to admit I bought 3 books on Groovy & Grails and 2 Spring books approx one year ago and never had time to do more than a little Grails demo. Shame on me. I promise I will do more with Groovy. Hopefully my team leader at my dayjob will allow me to use it.

Angelika Langer showed some cool stuff she did with Java annotations. I use annotations on my project too, but it's astonishing what different things you are able to do with them at compile time and runtime. Someone should really write a book about annotation patterns.

By the way, does anybody know a good book about AOP patterns? Runtime annotation analysation with reflection seems to be a lot like AOP to me and I want to know more about that.

Powered By Blogger