Introduction

Orthodox is a library that makes it easier to work with the Java type system at runtime.

Prior to the release of Java 5, the Java library had 1 class that provided access to type information at runtime - java.lang.Class. However, with the introduction of generics in Java 5, this has been extended to include:

Dealing with all these classes, and working with them at runtime, is overly complex, and so reduces the power of generics.

Imagine a class com.example.Bean has a method getList() that returns an object of type java.util.List. You want to know what type of object that list will contain. Is it a list of Objects? A list of Strings? Something else?

If we look at the source code, we might see:

List< ? extends CharSequence > getList() { /* ... */ }

But how do we get access to that information at runtime? You might think it's impossible, due to type erasure, but the information is actually there, it's just that it's hard to get to because of all those different ways of representing a type.

Here's roughly how it's done using the Java standard library:

Method method = com.example.Bean.class.getMethod("getList", new Class[0] );

Type type = method.getGenericReturnType();
ParameterizedType pType = (ParameterizedType)type; /* We can only do this because we know it's a parameterized list, it wouldn't work if getList() returned a non-generic class */

Type argument = pType.getActualTypeArguments()[0]; /* This relies on "pType" being a List, and not a sub-class */
WildcardType wType = (WildcardType)argument; /* Only works because it's a wildcard - if the return type was "List<String>" then the argument would be a "Class" instead */

Type upperBound = wType.getUpperBounds()[0];
Class charSeq = (Class)upperBound; /* Also unsafe. The "upperBound" could actually be a ParameterizedType like "Comparable<CharSequence>" */

And here's how it's done using orthodox:

Method method = com.example.Bean.class.getMethod("getList", new Class[0] );

TypeInfo type = typeInfo( method.getGenericReturnType() );

TypeInfo asList = type.as( List.class ); /* This allows us to handle anything that sub-classes list */

TypeInfo param = asList.getGenericParameters()[0];
Class charSeq = param.asClass();

Or even more simply, because orthodox recognises that implementations of iterable have a component type, just like arrays, you can do:

Method method = com.example.Bean.class.getMethod("getList", new Class[0] );
TypeInfo type = typeInfo( method.getGenericReturnType() );
Class charSeq = type.getComponentType().asClass();

Contents