I am working on a class that will have functionality similar to JTable's setDefaultRenderer method. I want to have Class-specific formatters which convert objects to strings suitable for displaying.
public interface Formatter<T> {
String format(T value);
}
private Map<Class<?>, Formatter<?>> formatters;
public <T> void addFormatter(Formatter<T> formatter) {
formatters.put(T.class, formatter);
}
That's the code I have right now, but Java doesn't accept T.class.
error: cannot select from a type variable
formatters.put(T.class, formatter);
^
1 error
Is there a way to write this without passing a separate Class<T> parameter? I'm trying to avoid that. It seems redundant.
No, it's impossible because of generic type erasure in Java. All information about a generic class is lost at runtime, the only solution is to explicitly pass around the class as a parameter.
Not a solution but a hack.
You can do it. But through dirty tricks and reflection. Look at below code for example. Courtesy here:
class ParameterizedTest<T> {
/**
* #return the type parameter to our generic base class
*/
#SuppressWarnings("unchecked")
protected final Class<T> determineTypeParameter() {
Class<?> specificClass = this.getClass();
Type genericSuperclass = specificClass.getGenericSuperclass();
while (!(genericSuperclass instanceof ParameterizedType) && specificClass != ParameterizedTest.class) {
specificClass = specificClass.getSuperclass();
genericSuperclass = specificClass.getGenericSuperclass();
}
final ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
final Type firstTypeParameter = parameterizedType.getActualTypeArguments()[0];
return (Class<T>) firstTypeParameter;
}
}
//change the type of PrameterizedTest<Integer> to Parameterized<String> or something to display different output
public class Test extends ParameterizedTest<Integer>{
public static void main(String... args){
Test test = new Test();
System.out.println(test.determineTypeParameter());
}
}
Here on the runtime, you get the Type Parameter. So instead in your class, you will have to define a Class object which gets the class as explained above. Then using Class.newInstance you get a new Object. But you will have to manually handle type cast and so on.
The question is: Is all this worth it??
No according to me as most of it can be avoided by using bounds in generic types and interfacing to the bound type. So you should be looking for alternative solution
In general it's not possible. In your case, though, it might be reasonable to have Formatter implement a Class<T> getFormatterTargetClass() method, which you could then use instead of T.class in your code.
Due to type-erasure T.class is not available at runtime, so you would have to pass in a separate parameter. In general, generic type-information is not available at runtime (unless you are using unbounded wildcards).
That's not possible in Java language. All the generic types are determited at compilation time, so you can't access class value in execution. So you need to pass the Class<T> parameter as well in order to be able to access it.
public Class MyGenericClassContainer<T>{
public T instance;
public Class<T> clazz;
public MyGenericClassContainer(Class<T> clazz){
intance = clazz.newInstance();
}
}
An instructive exercise is to ask yourself, "How would I do this without generics?" The answer to that is also the answer to your question.
A program with generics can be written into an equivalent program without generics, by removing generics and inserting casts in the right places, without changing anything else in the code. This transformation is called "type erasure". This means that if something cannot be written without generics, then it cannot be written with generics either.
Without generics, your code looks like this:
public interface Formatter {
String format(Object value);
}
private Map formatters;
public void addFormatter(Formatter formatter) {
formatters.put(?, formatter);
}
So, I ask you, how would you do it?
Related
I have this problem
a method which is cutting unwanted details from one class and returning collection of objects with wanted ones. the matter is I want this metod to be able to work with different classes ( which are based on one abstract, though), so I use generic type. the problem is that in one point I need to create an instance of , which is impossible. I looked for some way out, but it doesn't seem to work for my case.
So, code is following
private <T extends RestMandate> List<T> toRestMandate(List<CardMandate> mandates ) {
List<T> restMandates = new ArrayList<>(mandates == null ? 0
: mandates.size());
if (mandates != null) {
for (CardMandate mandate : mandates) {
restMandates.add(new T(mandate));
}
}
return restMandates;
}
RestMandate is base class, CardMandate were I take the info. Any ideas?
Since the generic type arguments are erased at runtime, there is no way you can refer to it like you are trying to do. The only way out is a type tag argument + reflective instantiation.
A better choice is to redesign your solution to solve this without relying on generics and type tags. Leverage dynamic method dispatch instead: add a method to RestMandate which will return the object converted to the desired type.
Because of Type Erasure, T becomes Object at runtime. You don't know its real type anymore.
You can still instantiate the object by reflection if you have its class. In order to do that, you must give the class to your method:
private <T extends RestMandate> List<T> toRestMandate(List<CardMandate> mandates, Class<T> clazz ) {
...
for (CardMandate mandate : mandates) {
/*
* I get the constructor which needs one CardMandate and call it.
* Note : I do not recommend this solution (no check at compile-time!).
* Like Marko Topolnik, I advise to redesign the solution.
*/
restMandates.add(clazz.getConstructor(CardMandate.class).newInstance(mandate));
}
...
}
To create an instance you require Class<T> object too
private <T extends RestMandate> List<T> toRestMandate(List<CardMandate> mandates, Class<T> clazz) {
//....
T newInst = clazz.newInstance();
//....
}
I am writing some generic DAO as follows
public class MyGenericDAO<T> {
Class<T> clazz;
public void doSome(){
for(int =0 ;i<14;i++){
//do something
}
}
}
Now i want to initialize clazz based on Type of T? .How can i do it?
For example if someone does MyGenericDAO<Xyz> = new MyGenericDAO<MyGenericDAO>() then type of T should be Xyz.
How can i do it?Is it possible without refelection?
It's not even possible with reflection, unfortunately. If you need it, you'll need to make a MyGenericDao constructor that takes a Class<T> argument:
public MyGenericDao(class<T> clazz) {
this.clazz = clazz;
}
Unfortunately, due to the type erasure the only way to initialize clazz to the type of T is passing the corresponding class in the constructor:
MyGenericDAO(Class<T> clazz) {
this.clazz = clazz;
}
Once of the reasons why java.lang.Class has been made generic is precisely to support this pattern. Since the T in Class<T> must correspond to the T in MyGenericDAO<T>, the compiler will be able to do the type checking for you.
Type arguments don't get to the runtime, so the calling code must pass a token to construct the Class<T> object at runtime. I name it token because there are many different objects you can pass to rebuild a Class<T> object at runtime, for example:
a String, to be used with Class.forName(name)
a Class<T> object
a type token, ie a subclass of a parameterized type whose arguments are neither type variables nor wildcard (bounded or not), for example a new List<String>(){} (I used new and the curly braces to underline that this expression returns an instance of an anonymous subclass)
With type tokens:
public class MyGenericDAO<T> {
#SuppressWarnings("unchecked")
public Class<T> getTypeParameter() throws Exception {
Type type = ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
return (Class<T>) type;
}
}
Note that there is an unchecked conversion when you cast the Type to a Class<T>. The calling code then looks like:
MyGenericDAO<Foo> dao = new MyGenericDAO<Foo>(){};
// Then if you want an instance
Foo foo = dao.getTypeParameter().newInstance();
Again, note the curly braces, since super type tokens only work when there is a real class generated at compile time. This approach only works if the client code honors the contract and uses an anonymous inner class every time a DAO object is needed (otherwise the magic of getTypeParameter() vanishes)
Consider the following code:
public class Generics {
C c; // initialized at runtime
public void testGenericsCall(Object o) {
c.myMethod(o);
}
}
class C<E> {
public void myMethod(E input) {
}
}
This is working, but I get warnings because the parametrized class C is used with a raw type. I cannot use a declaration like
C<String> c;
because the type of C is known only at runtime. I also cannot add a type parameter to the class Generics because I need to create objects of this class before knowing the type of C. The declaration
C<?> c;
or
C<? extends Object> c;
would be OK for the compiler, but then the method testGenericsCall does not compile ("actual argument java.lang.Object cannot be converted to capture#1 of ? by method invocation conversion")
What is the best way to deal with a situation like this?
EDIT: Note that when I actually (at runtime) create an instance of C, I know its type parameter, this part of the code is type-safe and working well. In the real code, I don't have a single "C" class, but a series of interrelated classes, and there the generics are definitely useful (even if in this simplified example this is not obvious - so please don't just tell me not to use generics :). I already have the compile-time type-safety, but not here, but between C and other classes (not shown here).
I see how in this case I cannot check the type parameter at compile time, that's why I tried to declare it C<?> c. Here I am just looking for the best way to bridge the generic and not-generic code without compiler warnings.
Because of type erasure, there's no way to use generics at runtime. You'll have to deal with your data type programmatically, by checking type or anything (reflection maybe).
You can do it. But through dirty tricks and reflection. Look at below code for example. Courtesy here:
class ParameterizedTest<T> {
/**
* #return the type parameter to our generic base class
*/
#SuppressWarnings("unchecked")
protected final Class<T> determineTypeParameter() {
Class<?> specificClass = this.getClass();
Type genericSuperclass = specificClass.getGenericSuperclass();
while (!(genericSuperclass instanceof ParameterizedType) && specificClass != ParameterizedTest.class) {
specificClass = specificClass.getSuperclass();
genericSuperclass = specificClass.getGenericSuperclass();
}
final ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
final Type firstTypeParameter = parameterizedType.getActualTypeArguments()[0];
return (Class<T>) firstTypeParameter;
}
}
//change the type of PrameterizedTest<Integer> to Parameterized<String> or something to display different output
public class Test extends ParameterizedTest<Integer>{
public static void main(String... args){
Test test = new Test();
System.out.println(test.determineTypeParameter());
}
}
Here on the runtime, you get the Type Parameter. So instead in your class, you will have to define a Class object which gets the class as explained above. Then using Class.newInstance you get a new Object. But you will have to manually handle type cast and so on.
The question is: Is all this worth it??
No according to me as most of it can be avoided by using bounds in generic types and interfacing to the bound type
This question already has answers here:
Get generic type of class at runtime
(30 answers)
Closed 4 years ago.
I have a small problem in java while using genericity. I have a class A :
public class A<T>
In a method of A, I need to get the type name of T.
Is there a way to find the string s using T ?
(If I create A<String> temp = new A<String>();, I want to be able to get java.lang.String at one point - I have to use genericity because one of my methods will have to return a List<T>).
This seems quite easy but I do not see how to do it.
You can't do this in general because of type erasure - an instance of A<String> doesn't know the type of T. If you need it, one way is to use a type literal:
public class A<T>
{
private final Class<T> clazz;
public A<T>(Class<T> clazz)
{
this.clazz = clazz;
}
// Use clazz in here
}
Then:
A<String> x = new A<String>(String.class);
It's ugly, but that's what type erasure does :(
An alternative is to use something like Guice's TypeLiteral. This works because the type argument used to specify a superclass isn't erased. So you can do:
A<String> a = new A<String>() {};
a now refers to a subclass of A<String>, so by getting a.getClass().getSuperClass() you can eventually get back to String. It's pretty horrible though.
You can get the name of the generics from the subclass. See this example.
We Define a parent class like this:
public class GetTypeParent<T> {
protected String getGenericName()
{
return ((Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0]).getTypeName();
}
}
We then define its child class in this way:
public class GetTypeChild extends GetTypeParent<Integer> {
public static void main(String[] args) {
GetTypeChild getTypeChild = new GetTypeChild();
System.out.println(getTypeChild.getGenericName());
}
}
You can see that in the main method, or in any instance method, I am capable to get the name of the generics type, in this case the main will print: java.lang.Integer.
Short answer: Impossible.
Slightly longer answer: Once your code is compiled, the type parameters is discarded.
Thus, Java cannot know what you set there.
You could, however, pass the class in question to your object and operate on it:
public class Example<T> {
private final Class<T> clazz;
public Example(Class<T> clazz){
this.clazz = clazz;
}
...
}
As is normally the case, Apache has a solution for this one with TypeUtils:
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/TypeUtils.html
A quick example from the above question:
TypeUtils.getTypeArguments(temp.getClass(), A.class).get(A.class.getTypeParameters()[0])
Disclaimer: I did not attempt building this first, but have used this utility in a similar fashion in the past.
Generics in Java are implemented by erasure, so no, you won't be able to get the name of the "type" which was used to create your generic collection at run-time. Also, why not just inspect the elements to know what type it belongs to?
If you're doing it in a subclass which has it's parent class defining the generic type, this is what worked for me:
// get generic type class name
String name = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].toString();
// then when you've got the name, you can make the Class<T> object
Class.forName(name.replace("class ", ""))
Reason why I couldn't do it with #getClass() instead of #toString() in the first snip is that I was always getting the "Class" class, which is useless to me.
I'd like to get the generic type of a collection, using reflection, at runtime.
Code (JAVA):
Field collectionObject = object.getClass().getDeclaredField(
collectionField.getName());
//here I compare to see if a collection
if (Collection.class.isAssignableFrom(collectionObject.getType())) {
// here I have to use the generic type of the collection
// to see if it's from a specific type - in this case Persistable
if (Persistable.class.isAssignableFrom(GENERIC_TYPE_COLLECTION.class)) {
}
}
Is there a way of getting the generic type of the collection in java at runtime? In my case I need the .class of the collection's generic type.
Thanks in advance!
Type erasure means that information about the generic type of an object simply isn't present at execution time.
(The link is to the relevant section of Angelika Langer's Java Generics FAQ which should answer virtually every question you could possibly ask about Java generics :)
However, you're not really interested in the type of an object - you're interested in the type of a field. I misread the question, and although the answer has been accepted I hope to make amends by fixing it now :)
If the field doesn't use a type parameter itself, it can be done. For example:
import java.lang.reflect.*;
import java.util.*;
public class Test
{
public List<String> names;
public static void main(String [] args)
throws Exception // Just for simplicity!
{
Field field = Test.class.getDeclaredField("names");
ParameterizedType type = (ParameterizedType) field.getGenericType();
// List
System.out.println(type.getRawType());
// Just String in this case
for (Type typeArgument : type.getActualTypeArguments())
{
System.out.println(" " + typeArgument);
}
}
}
If the field were in a class T with the field being List<T> then you'd have to know the type argument for the instance in order to know the type argument for the collection.
Translating this into your required code is somewhat tricky though - you really need to know the type argument at the point of the collection class. For instance, if someone declared:
public class StringCollection implements Collection<String>
and then had a field of type StringCollection, that field itself wouldn't have any type arguments. You'd then need to check getGenericSuperType and getGenericInterfaces recursively until you found what you wanted.
It's really not going to be easy to do that, even though it's possible. If I were you I'd try to change your design so that you don't need this.
You can absolutely do what you want. Type erasure means you can't inspect an instance of a collection for its generic type, but you can certainly inspect a field for its generic type.
class Thing {
List<Persistable> foo;
}
Field f = Thing.class.getDeclaredField("foo");
if( Collection.class.isAssignableFrom( f.getType() ) {
Type t = f.getGenericType();
if( t instanceof ParameterizedType ) {
Class genericType = (Class)((ParameterizedType)t).getActualTypeArguments()[0];
if( Persistable.class.isAssignableFrom( genericType ) )
return true;
}
}
There's a lot of things which can go wrong here, for example, if you have
Class Thing<T> {
List<T> foo;
}
then the above won't work.
You can get the generic type of the field you read the object from with Field.getGenericType. Note that the field may be a raw type, be a rare type (generic but with a generic argument that is raw), use the type of the instance, use wildcards, etc.
Copied from my post at: https://stackoverflow.com/questions/1004022/java-generic-class-determine-type/1005283#1005283
I've used a similar solution to what he explains here for a few projects and found it pretty useful.
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/
The jist of it is using the following to determine the type parameter at runtime:
public Class returnedClass {
ParameterizedType parameterizedType =
(ParameterizedType) getClass().getGenericSuperClass();
return (Class) parameterizedtype.getActualTypeArguments()[0];
}