dimanche 25 janvier 2015

How do I generate an accurate generics expression for a Java class field?

I am trying to reason about generics at runtime. There are several great libraries to do this (e.g., gentyref, ClassMate and Guava). However, their usage is a little over my head.


Specifically, I want to extract an expression which matches a particular field in the context of a subclass.


Here is an example using gentyref:



import com.googlecode.gentyref.GenericTypeReflector;

import java.lang.reflect.Field;
import java.lang.reflect.Type;

public class ExtractArguments {

public static class Thing<T> {
public T thing;
}

public static class NumberThing<N extends Number> extends Thing<N> { }

public static class IntegerThing extends NumberThing<Integer> { }

public static void main(final String... args) throws Exception {
final Field thing = Thing.class.getField("thing");

// naive type without context
Class<?> thingClass = thing.getType(); // Object
System.out.println("thing class = " + thingClass);
Type thingType = thing.getGenericType(); // T
System.out.println("thing type = " + thingType);
System.out.println();

// exact types without adding wildcard
Type exactThingType = GenericTypeReflector.getExactFieldType(thing, Thing.class);
System.out.println("exact thing type = " + exactThingType);
Type exactNumberType = GenericTypeReflector.getExactFieldType(thing, NumberThing.class);
System.out.println("exact number type = " + exactNumberType);
Type exactIntegerType = GenericTypeReflector.getExactFieldType(thing, IntegerThing.class);
System.out.println("exact integer type = " + exactIntegerType);
System.out.println();

// exact type with wildcard
final Type wildThingType = GenericTypeReflector.addWildcardParameters(Thing.class);
final Type betterThingType = GenericTypeReflector.getExactFieldType(thing, wildThingType);
System.out.println("better thing type = " + betterThingType);
final Type wildNumberType = GenericTypeReflector.addWildcardParameters(NumberThing.class);
final Type betterNumberType = GenericTypeReflector.getExactFieldType(thing, wildNumberType);
System.out.println("better number type = " + betterNumberType);
final Type wildIntegerType = GenericTypeReflector.addWildcardParameters(IntegerThing.class);
final Type betterIntegerType = GenericTypeReflector.getExactFieldType(thing, wildIntegerType);
System.out.println("better integer type = " + betterIntegerType);
System.out.println();

System.out.println("desired thing type = T");
System.out.println("desired number thing type = N extends Number");
System.out.println("desired integer thing type = Integer");
}

}


And here is the output:



thing class = class java.lang.Object
thing type = T

exact thing type = class java.lang.Object
exact number type = class java.lang.Object
exact integer type = class java.lang.Integer

better thing type = capture of ?
better number type = capture of ?
better integer type = class java.lang.Integer

desired thing type = T
desired number thing type = N extends Number
desired integer thing type = Integer


I know the betterThingType Type object (a gentyref-specific implementation) is more sophisticated than what is shown by toString() here. But I am guessing I need to invoke getExactFieldType again with a non-wildcard Type to get what I'm looking for.


My main requirement is that I need an expression which could become part of a code-generated source file that could be successfully compiled—or at least compiled with minimal modification. I am open to using whatever library is best for the job.






Aucun commentaire:

Enregistrer un commentaire