Exploiting Generics Metadata |
|

It is a common misconception that I hear when talking with clients that all information about generic types is erased from your Java class files. This is entirely untrue. All static generic information is maintained, and only generic information about individual instances is erased. So if I have a class Foo that implements List<String>, then I can determine that Foo implements the List interface parameterised by String at runtime. However, if I instantiate an instance of ArrayList<String> at runtime, I cannot take that instance and determine its concrete type parameter (I can determine that ArrayList requires type parameters). In this entry I'm going to show you a practical usage for some of the available generics metadata that simplifies the creation of strategy interfaces and implementations that differ by the type of object they process.
A pattern that I see occurring in many applications is the use of some kind of strategy interface with concrete implementations each of which handles a particular input type. For example, consider a simple scenario from the investment banking world. Any publicly traded company can issue Corporate Actions that bring about an actual change to their stock. A key example of this is a dividend payment which pays out a certain amount of cash, stock or property per shared to all shareholders. Within an investment bank, receiving notification of these events and calculating the resultant entitlements is very important in order to keep trading books up to date with the correct stock and cash values.
As a concrete example of this, consider BigBank which holds 1,200,000 IBM stock. IBM decides to issue a dividend paying $0.02 per share. As a result, BigBank needs to receive notification of the dividend action and, at the appropriate point in time, update their trading books to reflect the additional $24,000 of cash available.
The calculation of entitlement will differ greatly depending on which type of Corporate Action is being performed. For example, a merger will most likely result in the loss of stock in one company and the gain of stock in another.
If we think about how this might look in a Java application we could assume to see something like this (heavily simplified) example:
public class CorporateActionEventProcessor {
public void onCorporateActionEvent(CorporateActionEvent event) {
// do we have any stock for this security?
// if so calculate our entitlements
}
}
Notifications about events probably come in via a number of mechanisms from external parties and then get sent to this CorporateActionEventProcessor class. The CorporateActionEvent interface might be realised via a number of concrete classes:
public class DividendCorporateActionEvent implements CorporateActionEvent {
private PayoutType payoutType;
private BigDecimal ratioPerShare;
// ...
}
public class MergerCorporateActionEvent implements CorporateActionEvent {
private String currentIsin; // security we currently hold
private String newIsin; // security we get
private BigDecimal conversionRatio;
}
The process of calculating entitlements might be encapsulated by an interface such as this:
public interface EntitlementCalculator {
void calculateEntitlement(CorporateActionEvent event);
}
Along with this interface we are likely to see a number of implementations looking like this:
public class DividendEntitlementCalculator implements EntitlementCalculator {
public void calculateEntitlement(CorporateActionEvent event) {
if(event instanceof DividendCorporateActionEvent) {
DividendCorporateActionEvent dividendEvent = (DividendCorporateActionEvent)event;
// do some processing now
}
}
}
Our CorporateActionEventProcessor might then look something like this:
public class CorporateActionEventProcessor {
private Map<Class, EntitlementCalculator> entitlementCalculators = new HashMap<Class, EntitlementCalculator>();
public CorporateActionEventProcessor() {
this.entitlementCalculators.put(DividendCorporateActionEvent.class, new DividendEntitlementCalculator());
}
public void onCorporateActionEvent(CorporateActionEvent event) {
// do we have any stock for this security?
// if so calculate our entitlements
EntitlementCalculator entitlementCalculator = this.entitlementCalculators.get(event.getClass());
}
}
Here you can see we maintain a Map of CorporateActionEvent type to EntitlementCalculator implementation and we use this to locate the correct EntitlementCalculator for each CorporateActionEvent.
Looking back at this example the first glaring issue is that EntitlementCalculator.calculateEntitlement is typed to receive only CorporateActionEvent resulting in a type check and cast inside each implementation. We can easily fix this using generics:
public interface EntitlementCalculator<E extends CorporateActionEvent> {
void calculateEntitlement(E event);
}
public class DividendEntitlementCalculator implements EntitlementCalculator<DividendCorporateActionEvent> {
public void calculateEntitlement(DividendCorporateActionEvent event) {
}
}
As you can see we introduced a type parameter, E, which is bound to extend CorporateActionEvent. We then define that DividendEntitlementCalculator implements EntitlementCalculator<DividendCorporateActionEvent> resulting in E being replaced with DividendCorporateActionEvent as appropriate within the DividendEntitlementCalculator. removing the need to type check and cast.
The CorporateActionEventProcessor class continues to work as it is, however there is now some duplication and also the chance for errors. When registering a particular EntitlementCalculator we still have to specify the type it handles even though this is already specified in the class definition. Given this, it is possible to register an EntitlementCalculator for a type that it cannot possibly handle:
public CorporateActionEventProcessor() {
this.entitlementCalculators.put(MergerCorporateActionEvent.class, new DividendEntitlementCalculator());
}
Thankfully it is pretty easy to fix this by pulling the parameter type from the generic interface declaration and using this as the key type:
public void registerEntitlementCalculator(EntitlementCalculator calculator) {
this.entitlementCalculators.put(extractTypeParameter(calculator.getClass()), calculator);
}
We start by adding a registerEntitlementCalculator method which delegates to extractTypeParameter to find the type parameter for the EntitlementCalculator class.
private Class extractTypeParameter(Class<? extends EntitlementCalculator> calculatorType) {
Type[] genericInterfaces = calculatorType.getGenericInterfaces();
// find the generic interface declaration for EntitlementCalculator<E>
ParameterizedType genericInterface = null;
for (Type t : genericInterfaces) {
if (t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)t;
if (EntitlementCalculator.class.equals(pt.getRawType())) {
genericInterface = pt;
break;
}
}
}
if(genericInterface == null) {
throw new IllegalArgumentException("Type '" + calculatorType
+ "' does not implement EntitlementCalculator<E>.");
}
return (Class)genericInterface.getActualTypeArguments()[0];
}
Here we start by grabbing the Type[] representing the generic interfaces of the EntitlementCalculator type by calling Class.getGenericInterfaces(). This method differs greatly from Class.getInterfaces() which returns Class[]. Calling DividendEntitlementCalculator.class.getInterfaces() returns a single Class instance representing the EntitlementCalculator type. Calling DividendEntitlementCalculator.class.getGenericInterfaces() returns a single ParameterizedType instance representing the EntitlementCalculator type with a type argument of DividendCorporateActionEvent. Calling getGenericInterfaces() on a class with both generic and non-generic interfaces will return an array with both Class and ParameterizedType instances.
Next, we iterate over the Type[] and find the ParameterizedType instance whose "raw type" is EntitlementCalculator. From this we can extract the type argument for E using getTypeArguments() and returning the first array instance – which we know will always exist in this scenario.
Calling code can simply pass in the EntitlementCalculator implementations as required:
CorporateActionEventProcessor processor = createCorporateActionEventProcessor(); processor.registerEntitlementCalculator(new DividendEntitlementCalculator());
This is now a really nice API and be extended even further with something like Spring where you can use ListableBeanFactory.getBeansOfType() to locate all configured EntitlementCalculator implementations and automatically register them with the CorporateActionEventProcessor.
What's Next?
One interesting situation some of you may have noticed here is that it is entirely possible to have code like this:
EntitlementCalculator calculator = new DividendEntitlementCalculator(); calculator.calculateEntitlement(new MergerCorporateActionEvent());
This code will compile just fine but we know that the DividendEntitlementCalculator.calculateEntitlement method only accepts a DividendCorporateActionEvent object. So why does that compile? And, since it does compile what happens at runtime? Well, to answer the second question first – Java still ensure type safety by throwing ClassCastException at runtime. Why this works and to answer the question of why this example actually compiles I'll be writing another entry soon…
Further Reading
Generics in the Java Programming Language
Similar Posts
- A Bridge Too Far
- What's a FactoryBean?
- The Most Amazing Java Type Declaration Ever
- Transactions, Caching and AOP: understanding proxy usage in Spring
- Request-Reply JMS with Spring 2.0





Mike Dillon says:
Added on October 5th, 2006 at 5:47 pmIs there any plan to leverage this funcitonality in the Spring Framework? It would be awesome if Spring could use these APIs when running under JDK 5 to avoid injecting incompatible instances into a parameterized setter, only to be discovered at runtime with a ClassCastException.
For example, if Spring sees a setter of type List, it would automatically treat the elements of a as if they had instead of injecting a String into the List and causing a later ClassCastException. This would be especially helpful in leveraging JDK 5 enums as map keys and collection elements (currently the config gets littered with type="…").
Mike Dillon says:
Added on October 5th, 2006 at 5:49 pm[quote comment="437"]Is there any plan to leverage this funcitonality in the Spring Framework?…[/quote]
The previous comment lost some angle brackets. The "type List" above is a parameterized type of List with element type of Integer. I then refer to the "list" and "value" elements from the Spring config.
Rod Johnson (blog author) says:
Added on October 6th, 2006 at 9:54 amMatt, Spring 2.0 can use this information. The following text is quoted from the Spring 2.0 reference manual:
public class Foo { private Map accounts;
public void setAccounts(Map accounts) {
this.accounts = accounts;
}
}
When the 'accounts' property of the 'foo' bean is being prepared for injection, the generics information about the element type of the strongly-typed Map is actually available via reflection, and so Spring's type conversion infrastructure will actually recognize the various value elements as being of type Float and so the string values '9.99', '2.75', and '3.99' will be converted into an actual Float type.
Rod Johnson (blog author) says:
Added on October 6th, 2006 at 9:57 amAh, of course it didn't like the embedded XML… Please search the Reference Manual chapter on IoC for 3.3.3.4.2. Strongly-typed collection (Java5 only).
Rgds
Rod
Mike Dillon says:
Added on October 6th, 2006 at 7:28 pmThanks! That's great news.
I meant to ask if maybe Spring 2.0 did this, but didn't. We are still on 1.2.5 in our installation, but this is one more reason for me to consider moving to 2.0 sooner than later.
Francesco Iadanza says:
Added on August 6th, 2007 at 3:53 pmHi,
a question about generics and Spring:
is this kind of bean definition supported in Spring 2.0?
">
I mean, I created a generic bean class MyQueue and I want to specify the type "T" when creating a bean in Spring configuration
Thanks a lot
Francesco
Francesco Iadanza says:
Added on August 6th, 2007 at 3:55 pmHi,
a question about generics and Spring:
is this kind of bean definition supported in Spring 2.0?
" / >
I mean, I created a generic bean class MyQueue and I want to specify the type "T" when creating a bean in Spring configuration
Thanks a lot
Francesco
Francesco Iadanza says:
Added on August 7th, 2007 at 3:02 amI'm sorry, I missed the xml configuration.
a question about generics and Spring:
is this kind of bean definition supported in Spring 2.0?
<bean id="test" class="MyQueue<String>" />
I mean, I created a generic bean class MyQueue<T> and I want to specify the type "String" when creating a bean in Spring configuration
Thanks a lot
Francesco
Rob says:
Added on August 7th, 2007 at 3:25 amFrancesco,
There is no need to create that bean definition – you can simply use MyQueue without the type parameter – at runtime there is no such type as MyQueue when looking at an object instance. You can inject MyQueue into a MyQueue property.
Rob
Rob says:
Added on August 7th, 2007 at 3:27 amThat should have been:
Francesco,
There is no need to create that bean definition – you can simply use MyQueue without the type parameter – at runtime there is no such type as MyQueue<String> when looking at an object instance. You can inject MyQueue into a MyQueue<String> property.
Rob
Ramon Buckland says:
Added on September 21st, 2007 at 12:08 amHi Rob,
That is great. I was amazed to find this because I was trying to write exactly the same thing but
and I was able to drop in your extractTypeParameter() method over the top of mine. great!
was having a 20 minute battle with the reflection API and the generics interface. Your solution was spot on
it really makes it just "that" much bit tidier.
Peter says:
Added on February 9th, 2009 at 9:30 amI don't know if anyone is going to read this comment, but I can't seem to get this solution to work. I'm working on Java 6. The line with the return statement generates a ClassCastException. The function getActualTypeArguments returns an array with objects of type sun.reflect.generics.reflectiveObjects.TypeVariableImpl. It does implement the Type interface, but cannot be cast to type Class.
Twigathy says:
Added on August 11th, 2009 at 2:48 pmPeter, I also get that. Did you find a solution?
tanyue123 says:
Added on January 8th, 2012 at 10:05 pmHome Theater ProjectorJan 1, 2012 … The Top 10 Home Theater Projectors are broken into two resolution categories: 1080p and 720p. To help you find features important to you, …
Cheap 1080P ProjectorFeb 27, 2008 … Certainly many people are jumping on the 1080p bandwagon these days because the price of projectors is ridiculously cheap. But now that …
LCD Projector ScreenProjector Screens by Da-Lite Screens. Projector Screen specials that include free shipping. Over 3000 … Da-Lite Manual Model B Projector Screen 70" x 70" …
Conference ProjectorJan 1, 2012 … Below are the Popular Conference Room Projectors for both small and large rooms. The major difference between these two groups is the …
HID KitWelcome to HID Kits, the world's top retailer of HID lights & HID headlights. This week enjoy free shipping on all HID conversion kits, bulbs and ballasts within …
My Brodka says:
Added on January 6th, 2013 at 10:28 pmI recognize the spread and strength after being informed this. 1 year I was quite effortless got this information, and new now I get it. Good luck to you. and thank you.