Java Generics limitations or wrong usage? - java

I have a class representing a pair of two values of the same type (type which can be any of a specific set of types ):
public class Pair<E extends AClass>{
private E var1;
private E var2;
}
This class is used by a framework, so it needs a no-argument constructor in which I have to instantiate the 2 variables (var1, var2):
public class Pair<E extends AClass>{
private E var1;
private E var2;
public Pair(){
var1 = invoke constructor of type E;
var2 = invoke constructor of type E
}
}
There are obviously a number of problems here:
In order to instantiate the variables I should somehow know its exact type and invoke that specific type's constructor; in the best case this means to have a pretty large if else statement in the constructor, something like:
public Pair(){
if(var1 instanceof SpecificType1){
var1 = new SpecificType1();
var2 = new SpecificType2();
}
}
Even if I do as above, I will have some problems because var1 is declared of type E and I will get a type mismatch error when trying to instantiate SpecficType1 and to assign the resulted object to var1/var2. In order to make it work, I have to cast to E :
var1 = (E)new SpecificType1();
But this destroys the compile time type checking as I'm trying to cast a specific type to a generic type.
Is this a limitation of the Generics in java or is this scenario a bad one for using Generics ?

In order to instantiate the variables I should somehow know its exact type and invoke that specific type's constructor; in the best case this means to have a pretty large if else statement in the constructor, something like:
You'll run into problems before that.
if(var1 instanceof SpecificType1){
var1 = new SpecificType1();
var2 = new SpecificType2();
}
var1 is null at this point, so var1 instanceof T is false for all T.
One limitation of Java generics is that generic type parameters are erased so there's no way that you can reflect on the type parameter from a zero-argument constructor.
The caller has to provide some context to tell you how to initialize var1 and var2, and the typical way to provide that context is via constructor arguments.
Your best option is probably to let var1 and var2 start off null and then delay initialization until such time as you can get the context you need.
Perhaps
void init(Class<E> type) {
if (type.isAssignableFrom(ConcreteType1.class)) {
var1 = type.cast(new ConcreteType1(...));
var2 = type.cast(new ConcreteType1(...));
} else { /* other branches */ }
}
This isn't perfect since you still can't distinguish E extends List<String> from E extends List<Number> but it may be good enough for your case, and the .cast method will give you a type-safe cast to E.
Alternatively, Guava, Guice, and related libraries provide things like the Supplier<E> interface which may come in handy in an init method.

You cannot instantiate a generic type - What will happen if for example the generic type is SomeAbstractClass? What will be instantiated? (this is not the reason, it is just intuition)
However, you can use java reflection API to instantiate the object - but you will need the specific class object for it.
A more elegant alternative is using the abstract factory design pattern, and pass a factory object to your pair, and use it to construct the needed object.
Code sample:
public class Pair<S> {
public final S var1;
public final S var2;
public Pair(Factory<S> builder) {
var1 = builder.build();
var2 = builder.build();
}
}
public interface Factory<S> {
public S build();
}
public class IntegerBuilder implements Factory<Integer> {
private int element = 5;
public Integer build() {
return new Integer(element++);
}
}

If a framework were to instantiate it, it would do it as a raw type, something equivalent to new Pair() with no type parameters.
I guess you have to create simple one-liner classes like:
class SpecificType1Pair extends Pair<SpecificType1> {}
and pass them to the framework instead. You can get the actual type parameter as getClass().getGenericSuperclass()).getActualTypeArguments()[0]. You class pair would look like this:
public abstract class Pair<E extends AClass> {
private E var1;
private E var2;
public Pair() {
ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass();
#SuppressWarnings("unchecked")
Class<E> clazz = (Class<E>) superclass.getActualTypeArguments()[0];
try {
var1 = clazz.newInstance();
var2 = clazz.newInstance();
} catch (InstantiationException e) {
handle(e);
} catch (IllegalAccessException e) {
handle(e);
}
}
}

Related

Creating a List using the concrete type's Class

I can understand the example of instantiating a List object using a generic type. My current homework assignment involves creating an Appender for Log4j that stores the logs in a list. One of the requirements is that the user could specify a concrete implementation of List for the constructor and I have done this by just accepting a List that they have created.
Is there a way to make it so that they can provide the Class<T> implementing List that they want to be using and my constructor will instantiate a new instance of it?
If I understand your question, then yes; the simplest method I can think of, would be a constructor that takes a Collection. For example, ArrayList(Collection).
List<SomeType> copyList = new ArrayList<>(original);
Or perhaps, you wanted something that returns a List<T> given an item T. Something like Collections.singletonList(T)
SomeType t = // ...
List<SomeType> al = Collections.singletonList(t);
Class<T> will let you call newInstance(), which will return you a T. If you then combine this with wildcard generics you could in theory specify a Class<? extends List<LoggingEvent>> and create any type that implements the List<LoggingEvent> interface.
However here is the first problem: you cannot use a parameterized type with the class literal (i.e. LinkedList<LoggingEvent>.class will not compile). Therefore you have to relax your method/constructor parameter to only bound the wildcard on the raw type of List, like this: Class<? extends List>.
So now when you create the List you will have to cast it to the correct generic type. That will mean you need to do unchecked conversion using #SuppressWarnings("unchecked"). In this case this is safe to do as you will never try and use that raw type as any other generic type other than List<LoggingEvent>. †
The final implementation would look something like:
class LogStore {
private List<LogLine> loggingEvents = null;
public LogStore(Class<? extends List> clazz) {
try {
#SuppressWarnings("unchecked")
List<LogLine> logStoreList = clazz.newInstance();
this.loggingEvents = logStoreList;
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
† In this case this may be safe to do so if you provide the user with a set of prompts to let them choose a standard List<LoggingEvent> implementation, but if they are going to use this as an API and you have no control over which Class<? extends List> they pass in then you have two choices: either let the api fail at runtime in unpredictable places, or try and check the type argument for list. However, even if you do check the type argument you cannot check for all eventualities and the API may still break (e.g. if the user passes the class for a read-only List<LoggingEvent>).
For example, even something as simple as this will cause a (to the API user strange, possibly untraceable) runtime exception:
new LogStore(IntList.class);
// Used with IntList defined as ...
public class IntList extends ArrayList<Integer> {
#Override public Integer remove(int index) { return super.remove(index); }
}
If you choose to do the latter of the two options you will want to do something like this to check it really is a List<LoggingEvent>:
public LogStore(Class<? extends List> clazz) {
assertListTypeArgsValid(clazz);
// ... the rest of the above method implementation ...
}
private void assertListOk(Class<? extends List> clazz) {
boolean verified = false;
for (Type intr : clazz.getGenericInterfaces()) {
if (!(intr instanceof ParameterizedType)) continue;
ParameterizedType pIntr = (ParameterizedType)intr;
if (pIntr.getRawType().getTypeName() != "java.util.List") continue;
Type[] typeArgs = pIntr.getActualTypeArguments();
if (typeArgs.length != 1) break;
Class<?> tac = (Class<?>)typeArgs[0];
verified = tac.isAssignableFrom(LoggingEvent.class);
if (!verified) throw new IllegalArgumentException("clazz must be a List<LoggingEvent>, and is a: "
+ pIntr.getTypeName());
break;
}
if (!verified) throw new IllegalArgumentException("clazz must be a List<LoggingEvent>");
}

Is there an easier way to retrieve hard-coded type parameters in subclass implementations?

Given the following interface:
public interface GenericInterface<T> {
T getValue();
void setValue(T newVal);
}
And the following impl:
public class FixedImpl implements GenericInterface<String> {
String value;
public FixedImpl(String value) {
this.value = value;
}
#Override
public String getValue() {
return value;
}
#Override
public void setValue(String newVal) {
value = newVal;
}
}
I want to be able to determine that in the case of FixedImpl, String.class is the value for GenericInterface.T by interrogating FixedImpl.class.
My current idea:
Find a method name in GenericInterface that returns a <T> - in this case, there's "getValue".
Go through all the methods declared in FixedImpl.class with the same name, and collect all the different return types.
The return type farthest from Object is my value for GenericInterface.T.
But there's a couple of issues with this process:
It will only work for generic types containing a method that returns <T>. You can't safely do the same trick using setValue(T), because method overloading by parameter / arity is possible to do in Java source. It only works for T getValue() because overloading by return value isn't (unless I'm mistaken).
It might have weird interactions with Java 8 default methods, or a generic method implementation in a (still generic) possibly abstract superclass.
It's kinda kludgey.
Can anybody point me to an easier / more surefire way to get the same information? I can't seem to find one, but I thought I'd ask the superior intellects of the toobs :)
NB: If you're wondering why I'd need this, it's because I want to programatically construct mocks of container classes with similar hard-coded type parameters, but POJO values rather than simple Strings.
EDIT: I eventually worked out the following solution (before seeing #stony-zhang's):
public static <G> List<Class> getConcreteTypes(Class<? extends G> implClass, Class<G> genericClass) {
List<Class> concreteTypes = new ArrayList<Class>();
for (Type type : implClass.getGenericInterfaces()) {
if (!(type instanceof ParameterizedTypeImpl)) continue;
ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) type;
if (parameterizedType.getRawType() != genericClass) continue;
for (Object arg : parameterizedType.getActualTypeArguments()) {
if (!(arg instanceof Class))
throw new IllegalArgumentException("Class " + implClass + " not concrete for generic type " + genericClass);
concreteTypes.add((Class) arg);
}
}
return concreteTypes;
}
You can get the the class of T by the following way, in the interface add a method getMessageClass(), and in the FixedImpl add the implemented method,
#SuppressWarnings("rawtypes")
public Class getMessageClass() {
int index =0; //In the case, you only have a generic type, so index is 0 to get the first one.
Type genType = getClass().getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
throw new RuntimeException("Index outof bounds");
}
if (!(params[index] instanceof Class)) {
return Object.class;
}
return (Class) params[index];
}
In you case, if you have multiple subclass, to use it, create one abstract class to implement the interface GenericInterface, and then the all subclass extends from the new abstract class,
public class abstract abstractImpl<T> implements implements GenericInterface<T> {
#SuppressWarnings("rawtypes")
#Override
public Class getMessageClass() {
...............
}
}
Remember type erasure. At runtime, there is no type information about your generics anymore, unless you specify it yourself. And this is what you should do. Add this to your interface:
Class<T> getTypeOfT();
And add this to your FixedImpl:
#Override
public Class<String> getTypeOfT()
{
return String.class;
}
That way, you can always call getTypeOfT() on your GenericInterface<T> implementations and find out what type you are dealing with.
I don't think that you will be able to get reliable result because of Type Erasure:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.
Your approach of of using the types of objects returned may at first seem alright, but beyond the issues you have pointed out there is no way (at runtime) to know if The return type farthest from Object is my value for GenericInterface.T.
My suggestion would be to use some kind of configuration XML which could be generated at build time based on the java source (using a build tool such as Ant), which would in turn be used to create Mock objects, or you could simply generate the tests based off the source at buildtime.
If you don't mind changing your runtime code for the purposes of testing, Jan Doereenhaus' answer suggests a simple hard-coded mechanism for retrieving the type
EDIT:
Consider the scenario:
public class FixedImpl implements GenericInterface<SomeClass> {
#Override
public SomeClass getValue() {
return new SomeClass();
}
}
public class FixedImpl2 extends FixedImpl {
#Override
public SomeClass getValue()
{
return new SomeSubClass();
}
}
From this example, you can see that the sub class of FixedImpl is able to return a subclass of T (which is further down the inheritance hierarchy from Object)

Creating generic method names in generic class?

Currently, I have something like this:-
public class MyHolder<T> {
private T value;
public MyHolder(T t) {
this.value = t;
}
public T getValue() {
return first;
}
public void setValue(T t) {
this.first = t;
}
}
With this, I can use it like this:-
MyBean bean = new MyBean();
MyHolder<MyBean> obj = new MyHolder<MyBean>(bean);
obj.getValue(); // returns bean
Instead of calling the getter/setter to be getValue() and setValue(..), is it possible to "generify" that too?
Essentially, it would be nice to have it getMyBean() and setMyBean(..), depending on the type passed in. Granted this is a very simple example, however if I create a generic holder class that takes N generic properties, then it would be nice to call it something meaningful instead of getValue1() or getValue2(), and so on.
Thanks.
No. There is no such feature in Java. I can't even imagine how it would look syntactically... void set<T>();? And how would the getter / setter for for instance MyHolder<? extends Number> look?
No, it's not possible unless you use some kind of source code generator to have the MyHolder class generated based on your input.
But on the other hand, even if you had this possibility, how it would be different from using a Map<String, T>? So the invocation would read:
MyBean bean = new MyBean();
MyHolder<MyBean> obj = new MyHolder<MyBean>(bean);
obj.get('value');
No, not possible. Java generics are based on type erasure, i.e. it's mostly syntactic sugar provided by the compiler. That means each generic class is actually implemented by a "raw type" where are type parameters are Object and which already contains all the methods. So it's fundamentally not possible to have different methods depending on type parameters.

Instantiating generics type in java

I would like to create an object of Generics Type in java. Please suggest how can I achieve the same.
Note: This may seem a trivial Generics Problem. But I bet.. it isn't. :)
suppose I have the class declaration as:
public class Abc<T> {
public T getInstanceOfT() {
// I want to create an instance of T and return the same.
}
}
public class Abc<T> {
public T getInstanceOfT(Class<T> aClass) {
return aClass.newInstance();
}
}
You'll have to add exception handling.
You have to pass the actual type at runtime, since it is not part of the byte code after compilation, so there is no way to know it without explicitly providing it.
In the code you posted, it's impossible to create an instance of T since you don't know what type that is:
public class Abc<T>
{
public T getInstanceOfT()
{
// There is no way to create an instance of T here
// since we don't know its type
}
}
Of course it is possible if you have a reference to Class<T> and T has a default constructor, just call newInstance() on the Class object.
If you subclass Abc<T> you can even work around the type erasure problem and won't have to pass any Class<T> references around:
import java.lang.reflect.ParameterizedType;
public class Abc<T>
{
T getInstanceOfT()
{
ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
Class<T> type = (Class<T>) superClass.getActualTypeArguments()[0];
try
{
return type.newInstance();
}
catch (Exception e)
{
// Oops, no default constructor
throw new RuntimeException(e);
}
}
public static void main(String[] args)
{
String instance = new SubClass().getInstanceOfT();
System.out.println(instance.getClass());
}
}
class SubClass
extends Abc<String>
{
}
What you wrote doesn't make any sense, generics in Java are meant to add the functionality of parametric polymorphism to objects.
What does it mean? It means that you want to keep some type variables of your classes undecided, to be able to use your classes with many different types.
But your type variable T is an attribute that is resolved at run-time, the Java compiler will compile your class proving type safety without trying to know what kind of object is T so it's impossible for it to let your use a type variable in a static method. The type is associated to a run-time instance of the object while public void static main(..) is associated to the class definition and at that scope T doesn't mean anything.
If you want to use a type variable inside a static method you have to declare the method as generic (this because, as explained type variables of a template class are related to its run-time instance), not the class:
class SandBox
{
public static <T> void myMethod()
{
T foobar;
}
}
this works, but of course not with main method since there's no way to call it in a generic way.
EDIT: The problem is that because of type erasure just one generic class is compiled and passed to JVM. Type checker just checks if code is safe, then since it proved it every kind of generic information is discarded.
To instantiate T you need to know the type of T, but it can be many types at the same time, so one solution with requires just the minimum amount of reflection is to use Class<T> to instantiate new objects:
public class SandBox<T>
{
Class<T> reference;
SandBox(Class<T> classRef)
{
reference = classRef;
}
public T getNewInstance()
{
try
{
return reference.newInstance();
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public static void main(String[] args)
{
SandBox<String> t = new SandBox<String>(String.class);
System.out.println(t.getNewInstance().getClass().getName());
}
}
Of course this implies that the type you want to instantiate:
is not a primitive type
it has a default constructor
To operate with different kind of constructors you have to dig deeper into reflection.
You need to get the type information statically. Try this:
public class Abc<T> {
private Class<T> clazz;
public Abc(Class<T> clazz) {
this.clazz = clazz;
}
public T getInstanceOfT()
throws throws InstantiationException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException,
NoSuchMethodException,
SecurityException {
return clazz.getDeclaredConstructor().newInstance();
}
}
Use it as such:
Abc<String> abc = new Abc<String>(String.class);
abc.getInstanceOfT();
Depending on your needs, you may want to use Class<? extends T> instead.
The only way to get it to work is to use Reified Generics. And this is not supported in Java (yet? it was planned for Java 7, but has been postponed). In C# for example it is supported assuming that T has a default constructor. You can even get the runtime type by typeof(T) and get the constructors by Type.GetConstructor(). I don't do C# so the syntax may be invalid, but it roughly look like this:
public class Foo<T> where T:new() {
public void foo() {
T t = new T();
}
}
The best "workaround" for this in Java is to pass a Class<T> as method argument instead as several answers already pointed out.
First of all, you can't access the type parameter T in the static main method, only on non-static class members (in this case).
Second, you can't instantiate T because Java implements generics with Type Erasure. Almost all the generic information is erased at compile time.
Basically, you can't do this:
T member = new T();
Here's a nice tutorial on generics.
You don't seem to understand how Generics work.
You may want to look at http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html
Basically what you could do is something like
public class Abc<T>
{
T someGenericThing;
public Abc(){}
public T getSomeGenericThing()
{
return someGenericThing;
}
public static void main(String[] args)
{
// create an instance of "Abc of String"
Abc<String> stringAbc = new Abc<String>();
String test = stringAbc.getSomeGenericThing();
}
}
I was implementing the same using the following approach.
public class Abc<T>
{
T myvar;
public T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException
{
return clazz.newInstance();
}
}
I was trying to find a better way to achieve the same.
Isn't it possible?
Type Erasure Workaround
Inspired by #martin's answer, I wrote a helper class that allows me to workaround the type erasure problem. Using this class (and a little ugly trick) I'm able to create a new instance out of a template type:
public abstract class C_TestClass<T > {
T createTemplateInstance() {
return C_GenericsHelper.createTemplateInstance( this, 0 );
}
public static void main( String[] args ) {
ArrayList<String > list =
new C_TestClass<ArrayList<String > >(){}.createTemplateInstance();
}
}
The ugly trick here is to make the class abstract so the user of the class is forced to subtype it. Here I'm subclassing it by appending {} after the call to the constructor. This defines a new anonymous class and creates an instance of it.
Once the generic class is subtyped with concrete template types, I'm able to retrieve the template types.
public class C_GenericsHelper {
/**
* #param object instance of a class that is a subclass of a generic class
* #param index index of the generic type that should be instantiated
* #return new instance of T (created by calling the default constructor)
* #throws RuntimeException if T has no accessible default constructor
*/
#SuppressWarnings( "unchecked" )
public static <T> T createTemplateInstance( Object object, int index ) {
ParameterizedType superClass =
(ParameterizedType )object.getClass().getGenericSuperclass();
Type type = superClass.getActualTypeArguments()[ index ];
Class<T > instanceType;
if( type instanceof ParameterizedType ) {
instanceType = (Class<T > )( (ParameterizedType )type ).getRawType();
}
else {
instanceType = (Class<T > )type;
}
try {
return instanceType.newInstance();
}
catch( Exception e ) {
throw new RuntimeException( e );
}
}
}
There are hacky ways around this when you really have to do it.
Here's an example of a transform method that I find very useful; and provides one way to determine the concrete class of a generic.
This method accepts a collection of objects as input, and returns an array where each element is the result of calling a field getter on each object in the input collection. For example, say you have a List<People> and you want a String[] containing everyone's last name.
The type of the field value returned by the getter is specified by the generic E, and I need to instantiate an array of type E[] to store the return value.
The method itself is a bit ugly, but the code you write that uses it can be so much cleaner.
Note that this technique only works when somewhere in the input arguments there is an object whose type matches the return type, and you can deterministically figure it out. If the concrete classes of your input parameters (or their sub-objects) can tell you nothing about the generics, then this technique won't work.
public <E> E[] array (Collection c) {
if (c == null) return null;
if (c.isEmpty()) return (E[]) EMPTY_OBJECT_ARRAY;
final List<E> collect = (List<E>) CollectionUtils.collect(c, this);
final Class<E> elementType = (Class<E>) ReflectionUtil.getterType(c.iterator().next(), field);
return collect.toArray((E[]) Array.newInstance(elementType, collect.size()));
}
Full code is here: https://github.com/cobbzilla/cobbzilla-utils/blob/master/src/main/java/org/cobbzilla/util/collection/FieldTransformer.java#L28
It looks like you are trying to create the class that serves as the entry point to your application as a generic, and that won't work... The JVM won't know what type it is supposed to be using when it's instantiated as you start the application.
However, if this were the more general case, then something like would be what you're looking for:
public MyGeneric<MyChoiceOfType> getMeAGenericObject(){
return new MyGeneric<MyChoiceOfType>();
}
or perhaps:
MyGeneric<String> objMyObject = new MyGeneric<String>();
Abc<String> abcInstance = new Abc<String> ();
..for example

Problem at JUnit test with generics

In my utility method:
public static <T> T getField(Object obj, Class c, String fieldName) {
try {
Field field = c.getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(obj);
} catch (Exception e) {
e.printStackTrace();
fail();
return null;
}
}
The line
return (T) field.get(obj);
gives the warning "Type safety: Unchecked cast from Object to T";
but I cannot perform instanceof check against type parameter T,
so what am I suppose to do here?
The annotation #SuppressWarnings will stop the compiler reporting this warning. I don't think there's any way you can get away from the compiler warning when using reflection like this. Something like the following:
Field field = c.getDeclaredField(fieldName);
field.setAccessible(true);
#SuppressWarnings(value="unchecked")
T t = (T) field.get(obj);
return t;
You can easily solve this problem by adding an additional parameter to your method which will specify the type of the filed, the method will then look as follows:
public static <T> T getField(Class<T> fieldType, Object obj, Class<?> c,
String fieldName)
{
try {
Field field = c.getDeclaredField(fieldName);
field.setAccessible(true);
Object value = field.get(obj);
return fieldType.cast(value);
} catch (Exception e) {
e.printStackTrace();
fail();
return null;
}
}
And here's how you can use it: getField(String.class, new G(), G.class, "s") where G is defined as:
public class G {
String s = "abc";
}
A 2nd improvement is to eliminate the c parameter of getFiled(). c can be obtained inside the method by invoking obj.getClass(). The only caveat is that this will give you the dynamic type of the object so you mat want to loop over all of C's superclasses until you find the field you're looking for, or until you arrive at Object (You will also need to use c.getFields() and look for the field in the resulting array).
I think that these changes will make your method easier to use and less prone to errors so it's worth the effort.
Generics are there to provide type safety in places where you didn't previously have any in Java. So it used to be that if you had a list full of Strings you had to do:
String myString = (String)myList.get(0);
but now you can retrieve it without casting it:
String myString = myList.get(0); //Compiler won't complain
When you generify using the variable T, you are saying T is a placeholder for a specific type, which will be defined on the instance of the class at instantiation time. For instance:
public class ArrayList<T> {
public ArrayList<T> {
....
}
}
allows you to instantiate the list with:
ArrayList<String> myList = new ArrayList<String>();
Now every function on ArrayList will return a String, and the compiler knows this so it doesn't require a cast. Each of those functions was defined much like yours above:
public T get(int index);
public void set(int index, T object);
at compile time they become:
public String get(int index);
public void set(int index, String object);
In your case, however, you seem to be trying to use T as a wildcard, which is different from a placeholder for a specific type. You might call this method three times for three different fields, each of which has a different return type, right? This means that, when you instantiate this class, you cannot pick a single type for T.
In general, look at your method signatures and ask yourself "will a single type be substituted for T for each instance of this class"?
public static <T> T getField(Object obj, Class c, String fieldName)
If the answer is "no", that means this is not a good fit for Generics. Since each call will return a different type, you have to cast the results from the call. If you cast it inside this function, you're losing any benefits Generics would provide, and might as well save yourself the headaches.
If I've misunderstood your design, and T does refer to a single type, then simply annotating the call with #SuppressWarnings(value="unchecked") will do the trick. But if I've understood correctly, fixing this error will just lead you to a long road of confusion unless you grok what I've written above.
Good luck!
As suggested above, you can specify the expected type of the field and call the cast method.
Also. you don't need to pass argument object's class. You can find out what it is by calling obj.getClass()
This simplifies your code to
public static <T> T getField(Object obj, Class<T> fieldClass, String fieldName) {
try {
Class<?> declaringClass = obj.getClass();
Field field = declaringClass.getDeclaredField(fieldName);
field.setAccessible(true);
return fieldClass.cast(field.get(obj));
}
catch (Exception e) {
throw new AssertionFailedError();
}
}

Categories