public abstract class BaseDaoImpl<E extends AbstractEntity> implements BaseDao<E> {
.....
public BaseDaoImpl() throws DataAccessException {
logger = LoggerFactory.getLogger(E); <<-- error here.
}
In the above code I get a error in the call to getLogger(E).
E cannot be resolved to a variable
This makes sense, but getLogger(E.class) (or variants thereof) does not work either.
I don't want to pass the literal class in the constructor, so a solution like changing the the constructor header to:
public BaseDaoImpl(Class<E> clazz) ... is not an option.
How do I get the class type from E?
Note that the answers to: How to get class of generic type when there is no parameter of it?
do not help.
Without changing the constructor you can't learn anything about E at runtime that you didn't already know statically. That's because in Java, there just simply isn't any runtime effect of a generic parameter -- the compiler literally erases all references to E in the code it generates. So if you want code that can tell what class its type parameter is being instantiated with, you have to add in some kind of argument (e.g. a Class object) yourself. There's just no way around it.
It is possible by reflection as pointed out by #CorayThan . A simple way to do it is from method signature
interface BaseDao<E>
E find(long id);
class FooDao implements BaseDao<Foo>
Foo find(long id)
So type E can be found through
this.getClass().getDeclaredMethod("find", long.class).getReturnType();
However, it is a very good option to pass a Class in the constructor. Because the constructor is not meant to be called by user codes, the verbosity is not an issue here.
abstract class BaseDaoImpl<E>
BaseDaoImpl(Class<E> clazz)
class FooDao extends BaseBaoImpl<Foo>
FooDao()
super(Foo.class);
// usages:
BaseDao<Foo> fooDao = new FooDao(); // clean & simple API
Because generics are implemented in the Java language using type erasure, you cannot do anything that would require runtime type information. See this page for more info.
This works for me.
public abstract class BaseDaoImpl<E extends AbstractEntity> implements BaseDaoImpl<E> {
protected final Class<E> type;
public BaseDaoImpl() {
this.type = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public Class<E> getType() {
return type;
}
public BaseDaoImpl() throws DataAccessException {
logger = LoggerFactory.getLogger( getType() );
}
}
Already been answered.
Basically, you can't unless you use reflection.
I wouldn't recommend using reflection, but if you want to, you should be able to use:
GenericClass.class.getTypeParameters()
Related
Anyone knows how to use a class as a parameter that need to implement "Listener" in enums?
For example, I want to load some classes dynamically via EventType.MY_LISTENER.register();
public enum EventType {
GAME_START(GameStartListener.class);
private Class<?> clazz;
EventType(Class<?> clazz) {
this.clazz = clazz;
}
public void register() {
Main.registerListener(this.clazz);
}
}
"GameStartListener" is a class which implements "Listener", but I'm not really sure how to do this, because it shows me an syntax error at:
Main.registerListener(this.clazz);
"java: incompatible types: java.lang.Class cannot be converted to my.package.Listener"
Any help would be really appreciated.
Because Main.registerListener expects Listener type and you're passing actually Class<GameStartListener> (a type holding meta-data about your GameStartListener class) instead real GameStartListener object.
Here is my problem:
public interface Containter extends ModelElement{
List<? extends ModelElement> getChildren();
}
There are several classes implementing Containter, and I want to mock them:
public class MockMama {
public static <T extends Containter, Y extends ModelElement> T bornContainer(Class<T> clazz, Y ... children) {
T container = mock(clazz);
when(container.getChildren()).thenReturn(Arrays.asList(children));
return container;
}
}
But this doesn't work. Eclipse says "The method thenReturn(List) in the type OngoingStubbing> is not applicable for the arguments (List)". I've also tried to pass locally declared variable of type List<? extends ModelElement> to thenReturn but this didn't help either.
Any help is highly appreciated and welcomed :)
Your problem is that there's no guarantee that the type returned by getChildren() matches the type of the varargs argument to your bornContainer method. So the compiler is right to complain about this. Using an intermediate local variable is really turning the compiler error into a potential runtime problem.
It seems to me that your "Containter" should really be a generic class, because its behaviour depends on the type that's in the list that getChildren() returns. Have a look at my rewrite of your example. This has no compile errors or warnings.
public interface Containter<Z extends ModelElement> extends ModelElement{
List<Z> getChildren();
}
public class MockMama {
public static <Y extends ModelElement, T extends Containter<Y>> T bornContainer( Class<T> clazz, Y ... children) {
T container = mock(clazz);
when(container.getChildren()).thenReturn( Arrays.asList(children));
return container;
}
}
Hope this helps.
Usually in tests you can disregard unchecked or raw type warnings. So it is usually safe to annotate your test with a compiler directive such as #SupressWarning("unchecked") .
What is the difference between passing in generic parameter some generic class with and without his generic parameter?
Example:
Simple Generic class:
public class Foo<T> { /*...*/ }
Simple class that extend simple generic class setting the generic parameter to some irrelevant type:
public class FooFoo extends Foo<Type1> { /*...*/ }
Another generic class
public class Bar<T> extends FooFoo { /*...*/ }
Our base class that as generic parameter need something that extends class Foo
public class TestFooClass<T extends Foo<?>> { /*...*/ }
And the question what is the deference between this two parameters
public class BarTestOne extends TestFooClass<Bar> { /*...*/ }
public class BarTestTwo extends TestFooClass<Bar<?>> { /*...*/ }
Problem
Class<T> class = (Class<T>) ((Foo)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
In the first case code works in the second doesn't.
It looks like you are trying to determine the actual type that the TestFooClass is parameterized with?
In that context, the difference between using generic class with and without its generic parameter is that getActualTypeArguments()[0] will:
In the first case provide an instance of Class representing the raw type
In the second case provide an instance of ParameterizedType (thus one may get ClassCastException). If you call getRawType() on that ParameterizedType, you will get Class representing the raw type.
This:
BarTestOne one = new BarTestOne();
BarTestTwo two = new BarTestTwo();
Class<?> clazz1 = (Class<?>) ((ParameterizedType) one.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Class<?> clazz2 = (Class<?>) ((ParameterizedType) ((ParameterizedType) two.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).getRawType();
System.out.println(clazz1.equals(clazz2));
This will return true.
Alas, any deeper answer is beyond my knowledge of generics.
Bar means Bar<Object> and Bar<?> doesn't. For example, if you have a List, you can add to it, if you have a List<?> you can't, because the compiler doesn't know if your object is compatible with the "actual generic type" of the object.
As for the reflection code, I don't know. It says getClass(), which depends on the object you call it on; in this case the object is obviously this... From where is this code called?
I'd like to make a class that looks basically like this:
public class MyClass<T implements Serializable) {
void function() {
Class c = T.class;
}
}
Two errors:
- I cannot call T.class, even though I can do that with any other object type
- I cannot enforce that T implements Serializable in this way
How do I solve my two generics problems?
Cheers
Nik
You can't get the type.
Generics are implemented using something called type-erasure.
When a generic type is instantiated,
the compiler translates those types by
a technique called type erasure — a
process where the compiler removes all
information related to type parameters
and type arguments within a class or
method. Type erasure enables Java
applications that use generics to
maintain binary compatibility with
Java libraries and applications that
were created before generics.
The essence of this is that the type information is used by the compiler and discarded, hence not available at runtime.
With regards to the enforcing T implements Serializable, you just need the following:
public class MyClass<T extends Serializable>)
{
public void function(T obj)
{
...
}
}
This is simply referring to the is a relationship, so an class that implements Serializable, is a Serializable and can be passed to function.
you do this:
public class MyClass<T implements Serializable) {
void function(Class<T> tc) {
...
}
}
Basically, you have to pass in the class at run time in order to see it. You could also do something like this:
public class MyClass<T implements Serializable) {
Class<T> ct;
public MyClass(Class<T> ct){this.ct = ct;}
void function() {
... //you know what the class is here
}
}
It's kind of annoying, but not really that big of a hassle overall.
Something along these lines should do it.
private Class<T> dataType;
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
dataType = (Class<T>) paramType.getActualTypeArguments()[0];
} else if (type instanceof Class) {
dataType = (Class<T>) type;
}
You can't do T.class because java does not actually know which class T is at runtime.
All that information is lost at compilation.
To get the class object for T you can either call getClass() on an instance of T (if you have access to one) or require the user to pass the class object as an argument to function, like:
void function(Class<T> c)
This is not possible without tricks.
The Java Generics FAQ provides an idea for a workaround.
I have a generic type that is parameterized on some Enum, declared like this:
public class FlagsField<T extends Enum<T>> {
private EnumSet<T> _flagSet;
public FlagsField() {
_flagSet = EnumSet.<T>noneOf( /* what goes here? */ );
}
...
}
I want to initialize _flagsField in the constructor as above, but can't figure out for the life of me what the right parameter to the noneOf method is. It needs to be of type Class<T>. If this weren't a generic, you'd use MyFooEnumType.class here, but T.class is not valid.
Thanks!
You've run into type erasure. Your constructor is going to need to look like:
public FlagsField(Class<T> enumClass) {
_flagSet = EnumSet.<T>noneOf(enumClass);
}
You could use this trick in your constructor: (see Generic Data Access Objects, section "Preparing DAOs with lookup")
enumClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
But I believe this code only works when the class is sub-classed and an instance of the sub-class executes it.