Problem at JUnit test with generics - java

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();
}
}

Related

How can I use generics to provide a "universal getter method"?

This question is more theoretical (what I want to do is more complicated but this is the part I'm stuck on), so apologies for the contrived example which may not make much sense.
Say I have some class that has methods that return its value in different forms:
public class MyObject {
public String getAsString() {...}
public int getAsInt() {...}
// and so on
}
I'm trying to create a single method to allow me to specify which MyObject method to call via its parameters. Something like:
public <T> T getValue(MyObject obj, Class<T> c) {
if (c == String.class) {
return obj.getAsString();
} else if (c == Integer.class) {
return obj.getAsInt();
} // and so on
}
So then I would like to call this method like this, assuming obj is a MyObject:
String s = getValue(obj, String.class);
int i = getValue(obj, Integer.class);
// and so on
I'm getting the compile error "Type mismatch: cannot convert from String to T" (and likewise for Integer) in the getValue method. Clearly I'm just not understanding generics fully, but I thought this was the general idea behind generics - here I'm specifying (or trying to specify, at least) the real type of T via the parameter c. What am I doing wrong?
If you want to to create a single method with really safe casts - then I would suggest to setup a mapping between the expected type and its respective getter.
Given the MyObject class definition as:
public class MyObject {
public int getIntValue() {
return 42;
}
public String getStringValue() {
return "Answer";
}
}
So that the "accessor" class could look as follows (it can be generalized further if needed):
public class MyObjectAccessor {
private final Map<Class<?>, Function<MyObject, ?>> registry = new HashMap<>();
public Accessor() {
registerGetter(Integer.class, MyObject::getIntValue);
registerGetter(String.class, MyObject::getStringValue);
}
private <T> void registerGetter(Class<T> type, Function<MyObject, T> getter) {
registry.put(type, getter);
}
#SuppressWarnings("unchecked")
public <T> Optional<T> getValue(MyObject obj, Class<T> type) {
return (Optional<T>) ofNullable(registry.get(type)).map(getter -> getter.apply(obj));
}
}
This would allow you to make the behavior much more predictable with a control over the unexpected/missing mapping.
(Here it returns an Optional back, but you can also throw an exception or provide a default value or do something else)
Please note that the cast inside getValue is actually a safe checked cast (even though it was marked with #SuppressWarnings) as the "safety" proof here is a little bit beyond current javac's capability of static code analysys.
First of all, if getAsString and getAsInt are not doing any conversion (such as would be the case if all your values were stored as strings), you probably can reduce your method to this:
public <T> T getValue(MyObject obj) {
return (T) obj.value;
}
This will have an unchecked cast warning, but that's not worse than leaving the typing decision to your caller (so I'd just #SuppressWarnings("unchecked") it). If your caller uses the wrong target type, they will get a ClassCastException at runtime, which I assume goes well with your current contract. But you can keep c.cast(obj.getAsX()) if you want the exception to be raised in your own method.
With the above, your callers would just use:
String s = getValue(obj);
int i = getValue(obj);
If, however, you are actually converting data in getAs... methods, then you will need to cast in your generic getter after dispatching to the correct getAsX method, at least as ProGu suggested (i.e., return c.cast(obj.getAsX()) in each branch).

How to check generic method parameter to avoid ClassCastException?

Java uses type erasure wherever applicable, but, of course, when invoking methods the parameter types must match.
How to avoid a ClassCastException when I cannot ensure the type at compile time? Example:
class KeyedHashSet<K,E> // implements Set<E>
{ final Map<K,E> map = new HashMap<>();
final Function<E,K> keyExtractor; // extracts intrusive key from value
public KeyedHashSet(Function<E,K> keyExtractor)
{ this.keyExtractor = keyExtractor; }
public boolean contains(Object o)
{ if (o != null)
try
{ #SuppressWarnings("unchecked") // <- BAD
K key = keyExtractor.apply((E)o);
E elem = map.get(key);
return elem != null && elem.equals(o);
} catch (ClassCastException ex) // <- EVIL!!!
{}
return false;
}
// more methods
}
The method Set.contains takes an arbitrary object as parameter. But I cannot extract the key required for my hash lookup from an arbitrary object. This only works for objects of type E.
In fact I am not interested in the key when the object is not of type E because in this case I am sure that the collection does not contain the object.
But the above work around with catching the ClassCastException has several drawbacks:
First of all, one should not throw an exception when this is a normal program path.
Secondly, I might catch a ClassCastException thrown from deep inside the keyExtractor implementation, which is not intended.
Is it possible to check the type of o against the parameter of keyExtractor before the call to .apply and without unreasonable runtime overhead?
Note: I know that the above design requires E to have an immutable key. But this is no big deal and happens quite often.
How could a ClassCastException happen after Erasure?
After erasure is applied it can be hard to determine if an unchecked cast will trigger a ClassCastException. After all, the types are reduced to Object; why would casting to Object throw a casting exception? One cause for this error is generic code that calls non-generic implementations, where the types are explicitly stated. Take this example:
class Test<K> {
public void foo(Object o) {
bar((K) o);
}
public void bar(K k) {
System.out.println(k);
}
public static void main(String[] args) {
Test<Integer> test = new Test<>();
test.foo("hello");
}
}
The above example will still print "hello" correctly even though the generic type argument was an Integer. After erasure the method bar only requires an object:
public bar(Ljava/lang/Object;)V
If we extend Test and override bar where the type is explicit, then we will produce an error.
class TestInteger extends Test<Integer> {
#Override
public void bar(Integer k) {
super.bar(k);
}
public static void main(String[] args) {
Test<Integer> test = new TestInteger();
test.foo("hello");
}
}
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at TestInteger.bar(TestInteger.java:17)
at Test.foo(TestInteger.java:9)
at TestInteger.foo(TestInteger.java:17)
at TestInteger.main(TestInteger.java:24)
In this child class, the method being overridden has a different signature than the method produced by Test<K>. The compiler creates a new overloaded method, called a synthetic or bridge method, in order to call bar as written in TestInteger. This bridge method is where the ClassCastException happens. It will look like bellow:
public void bar(Object k) {
bar((Integer) k); //java.lang.String cannot be cast to java.lang.Integer
}
public void bar(Integer k) {
System.out.println(k);
}
In your example, somewhere within the call to keyExtractor.apply((E)o) there lies a signature which relies on the explicit type causing the casting exception.
Is it possible to check the type before casting?
Yes it is possible, but you will have to provide your KeyedHashSet class with extra data. You cannot directly get the Class object associated with a type parameter.
One way is to inject a Class type into your container and call isInstance:
This method is the dynamic equivalent of the Java language instanceof operator. The method returns true if the specified Object argument is non-null and can be cast to the reference type represented by this Class object without raising a ClassCastException. It returns false otherwise.
public class Test<K> {
final Class<K> clazz;
Test(Class<K> clazz) { this.clazz = clazz; }
public void foo(Object o) {
if (clazz.isInstance(o)) {
bar((K) o);
}
}
...
Test<Integer> test = new Test<>(Integer.class);
test.foo("string");
You could also use some validation strategy where the instance check is performed:
public class Test<K> {
final Function<Object, Boolean> validator;
Test(Function<Object, Boolean> validator) { this.validator = validator; }
public void foo(Object o) {
if (validator.apply(o)) {
bar((K) o);
}
}
...
Test<Integer> test = new Test<>(k -> k instanceof Integer);
test.foo("string");
Another option could be to move the type checking inside the Function<E,K> keyExtractor instance and have the type parameters become Function<Object,K> keyExtractor, returning null if the type was incorrect.
It would also be theoretically possible to reflectively examine method signatures for keyExtractor and get a Class instance, but it is not guaranteed that it's implementation will explicitly define the type parameters either.
Will checking instanceof slow down my application?
The execution time of isInstance is actually quite fast. There's an interesting article which experimentally compares the speeds of a try-catch with unsafe cast to an isInstance solution. In the results of the experiment, the solution which explicitly checks for the type is only marginally slower than the unsafe solution.
Given that the performance penalty is so low I would opt to go the safe route and add class checking to your contains method. If you keep the try-catch solution as is, you may end up masking future bugs caused by the implementation of keyExtractor.apply, map.get, elem.equals, etc.

Combining Java generics and reflection to avoid casting

I have some code like this:
Object doMethod(Method m, Object... args) throws Exception {
Object obj = m.getDeclaringClass().getConstructor().newInstance();
return m.invoke(obj, args);
}
The code I use is a little more complex, but that's the idea of it. To invoke doMethod I do something like this:
Method m = MyClass.class.getMethod("myMethod", String.class);
String result = (String)doMethod(m, "Hello");
This works just fine for me (variable number of arguments and all). The thing that irks me is the necessary cast to String in the caller. Since myMethod declares that it returns a String, I'd like doMethod to be smart enough to change its return type to also be String. Is there some way of using Java generics to accomplish something like this?
String result = doMethod(m, "Hello");
int result2 = doMethod(m2, "other", "args");
Sure,
#SuppressWarnings("unchecked")
<T> T doMethod(Method m, Class<T> returnType, Object Args ...) {
Object obj = m.getDeclaringClass().getConstructor().newInstance();
return (T) m.invoke(obj, args);
}
String result = doMethod(m, m.getReturnType(), "Hello");
One is idly curious about the architecture that calls for such a thing to be done, but that's well out of scope :)
If you don't like that you can also leave off the binding of returnType and the compiler will automatically cast it to whatever you're assigning the return type to. e.g., this is legal:
#SuppressWarnings("unchecked")
<T> T doMethod(Method m, Object Args ...) {
Object obj = m.getDeclaringClass().getConstructor().newInstance();
return (T) m.invoke(obj, args);
}
The cast will be to whatever you are attempting to assign it to, but I think most people would consider it suspect.
I wish that Method had been parameterized to capture the return type. You could always do that yourself by wrapping Method with your own MethodEx... Doing so would allow you to provide some pretty nice facades too...
public class MethodEx<T> {
private final Method _method;
private final Class<T> _returnType;
public MethodEx(Method method, Class<T> returnType) {
_method = method;
_returnType = returnType;
}
public T invoke(Object object, Object... args) throws InvocationTargetException {
try {
return _returnType.cast(_method.invoke(object, args));
}
// good opportunity to hide/wrap other exceptions if your
// usecases don't really encounter them
}
}
This is just a starting point -- you can have factory methods on MethodEx that does a lot of up-front validation to make sure method is public, etc.
Finally, if you are caching the Method instances etc and dealing with dynamically loaded classes, this would also be a good opportunity to defensively introduce weak references (to the method and the return type) so you don't have to be as careful about pegging entire classloaders throughout your code.
You could try
public <T> T doMethod(Method m, Class<T> clazz, Object... args);
Although it moves the cast to the routine itself. In general what you're trying to do doesn't sound like good practice. Reflection itself incurs some performance overhead, but perhaps that not of concern?

Get Values from Enum Known Only At Runtime

I need to get all the values from an enum, whose type will only be known at runtime. I've come up with the following, but would like to know if anyone knows a better way:
enum TestEnum {
FOO,
BAR
}
Enum[] getValuesForEnum(Class type) {
try {
Method m = type.getMethod("values");
return (Enum[])m.invoke(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Class testEnum = Class.forName("TestEnum");
getValuesForEnum(testEnum);
Thanks!
Use the available API instead:
T[] getValuesForEnum(Class<T> type) {
return type.getEnumConstants();
}
From the Javadoc:
Returns the elements of this enum class or null if this Class object does not represent an enum type.
Note that I have turned your method into generic to make it typesafe. This way you need no downcasts to get the actual enum values from the returned array. (Of course, this makes the method so trivial that you can omit it and call type.getEnumConstants() directly :-)
Here's a variant of Kevin Stembridge's answer that preserves the type (avoiding downcasts), whilst still guarding against being called with a non-enum type:
static <E extends Enum<E>> E[] getValuesForEnum(Class<E> clazz) {
return clazz.getEnumConstants();
}
I use type.getEnumConstants().
I think this works:
Enum<?>[] getValuesForEnum(Class<Enum<?>> enumType) {
return enumType.getEnumConstants();
}

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

Categories