I have the following classes:
class Field<T> {
private final Class<T> type;
public Field(Class<T> type) {
this.type = type;
}
}
class Pick<V> {
private final V value;
private final Class<V> type;
public Pick(V value, Class<V> type) {
this.value = value;
this.type = type;
}
}
and the class the question is related to:
class PickField<T> extends Field<Pick<T>> {
public PickField(Class<Pick<T>> type) {
super(type);
}
}
Now this seems to be accepted by the compiler. Unfortunately I do not know/understand how I could create a new instance of PickField, e.g. for String picks.
This does - of course - not work:
new PickField<String>(Pick.class)
This is not allowed (I think I understand why):
new PickField<String>(Pick<String>.class)
So how to do it? Or does the whole approach somehow "smell"?
I think PickField should be parameterized with Pick instances only.
So doing this should be fine:
class PickField<T extends Pick<T>> extends Field<T> {
public PickField(Class<T> c) {
super(c);
}
}
Then, you could just instantiate it with:
PickField<SomeSpecificPick> instance = new PickField<>(SomeSpecificPick.class);
where SomeSpecificPick is defined as:
public class SomeSpecificPick extends Pick<SomeSpecificPick> {
public SomeSpecificPick(SomeSpecificPick value, Class<SomeSpecificPick> type) {
super(value, type);
}
}
More info (related with the topic):
Why is there no class literal for concrete parameterized types?
How to get a class instance of generics type T?
Erasure of Generic Types
There are various issues here.
Firstly as you point out, you cannot obtain the class of a parametrized type at compile time, since only one class is compiled for generic types, not one per given type parameter (e.g. the Pick<String>.class idiom does not compile, and doesn't actually make sense).
Again as you mention, parametrizing the PickField<String> constructor with Pick.class only will not compile again, as the signatures aren't matched.
You could use a runtime idiom to infer the right Pick<T> parameter, but that creates another problem: due to to type erasure, your type argument for T will be unknown at runtime.
As such, you can parametrize your constructor invocation by explicitly casting, as follows:
new PickField<String>(
(Class<Pick<String>>)new Pick<String>("", String.class).getClass()
);
... which will compile with an "unchecked cast" warning (Type safety: Unchecked cast from Class<capture#1-of ? extends Pick> to Class<Pick<String>>).
The real question is likely why do you need to know the value of type in your Pick class.
There is a way, but is not exactly a good one.
You need to create a method like this:
public static <I, O extends I> O toGeneric(I input) {
return (O) input;
}
Then, you create the object:
new PickField<String>(toGeneric(Pick.class));
Like I said, not really a good way, since you basically just lie to the compiler, but it works.
In order to pass generics information as an argument, Class<T> is not enough. You need some extra power to achive that. Please see this article, where it is explained what a super type token is.
In short, if you have the following class:
public abstract class TypeToken<T> {
protected final Type type;
protected TypeToken() {
Type superClass = getClass().getGenericSuperclass();
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() {
return this.type;
}
}
You could use it to store generics type information, such as Pick<String>.class (which is illegal). The trick is to use the superclass' generic type information, which is accessible via the Class.getGenericSuperclass() and ParameterizedType.getActualTypeArguments() methods.
I have slightly modified your Pick, Field and PickField classes, so that they use a super type token instead of a Class<t>. Please see the modified code:
class Field<T> {
private final TypeToken<T> type;
public Field(TypeToken<T> type) {
this.type = type;
}
}
class Pick<V> {
private final V value;
private final TypeToken<V> type;
public Pick(V value, TypeToken<V> type) {
this.value = value;
this.type = type;
}
}
class PickField<T> extends Field<Pick<T>> {
public PickField(TypeToken<Pick<T>> type) {
super(type);
}
}
And here is a sample usage:
TypeToken<Pick<String>> type = new TypeToken<Pick<String>>() {};
PickField<String> pickField = new PickField<>(type);
As TypeToken class is abstract, you need to subclass it (this explains the {} at the end of its declaration.
Related
I am trying to define a class which type could be a subtype of the given one if inferred but it doesn't seem to work with the default Java type inference mechanism and I do not understand why.
Here are some relevant pieces of code to illustrate the situation
public class ObjectChanged<T extends Something> implements TriggeringCondition<T> {
private final Class<? extends T> type;
private String featureName = null;
protected ObjectChanged(Class<? extends T> type) {
this.type = type;
}
public ObjectChanged<T> onFeature(String featureName) {
this.featureName = featureName;
return this;
}
public static <X extends Something> ObjectChanged<X> objectChanged(Class<? extends X> type) {
return new ObjectChanged<>(type);
}
}
Let's say I have one class called FastCar extending Car. I would like to build an object change for a FastCar, but to downcast it to TriggeringCondition<Car>.
If I write the following code it works as expected
TriggeringCondition<Car> test() {
return objectChanged(FastCar.class);
}
But then if I call the onFeature(String) method it doesn't compile anymore and complains that my triggering condition if of type FastCar, which is not compatible with Car.
If now I define the objectChanged function like this
public static <X extends Something, Y extends X> ObjectChanged<X> objectChanged(Class<Y> type, Class<X> baseType) {
return new ObjectChanged<>(type);
}
Then I can use this code which resolves the problem
TriggeringCondition<Car> test() {
return objectChanged(FastCar.class, Car.class).onFeature("something");
}
I also found out I can fix the previous build issue with this syntax, but it's quite ugly imo.
TriggeringCondition<Car> test() {
return ObjectChanged.<Car> objectChanged(FastCar.class).onFeature("test");
}
Is there a way to write the test method like this without needing an extra parameter ?
TriggeringCondition<Car> test() {
return objectChanged(FastCar.class).onFeature("test");
}
Is there a way to write the test method like this without needing an extra parameter ?
No.
If you don't want to use the type witness (<Car>), all you can do is to assign the objectChanged result to a variable, and then call onFeature on that variable.
TriggeringCondition<Car> test() {
TriggeringCondition<Car> tc = objectChanged(FastCar.class);
return tc.onFeature("test");
}
This is a problem which crops up a lot if you use Guava's Immutable*.Builders:
ImmutableList<String> list =
ImmutableList.<String>builder()
.add("foo")
.build();
The type witness is needed here, otherwise the type of the Builder is inferred to be ImmutableList.Builder<Object>, because the type of the polyexpression is determined before the .add(String) call.
It's annoying, but that's the nature of the beast.
One thing you could do is to define a static upcast method:
static <T extends Something> ObjectChanged<T> upcast(ObjectChanged<? extends T> oc) {
ObjectChanged<T> result = new ObjectChanged<>(oc.type);
return result.onFeature("test");
}
Now you can invoke something like:
TriggeringCondition<Car> test() {
return upcast(objectChanged(FastCar.class).onFeature("test"));
}
I have a generic type that implements a generic interface. Java compiler correctly infers the constraint in the type parameter of the type in all cases but fails to do so in one.
See getValue() method implementation in Generic class below:
package test.gen.company;
public class GenericProblem {
Generic<ISpecific> gen = new Generic<>();
//compiler has no problems here
ISpecific val = gen.getValue();
Generic<IMoreSpecific> gen2 = new Generic<>();
//both of these are OK
ISpecific val1 = gen2.getValue();
IMoreSpecific val2 = gen2.getValue();
//compiler won't allow this,
//correctly complains irrelevant is not within bounds
//Generic<Irrelevant> gen;
}
interface IGeneric<T>{
T getValue();
void setValue(T in);
}
interface ISpecific {}
interface IMoreSpecific extends ISpecific {}
interface Irrelevant{}
class ISpecificImplementer implements ISpecific {}
class Generic<T extends ISpecific> implements IGeneric<T> {
#Override
public T getValue() {
//error: required T, found ISpecificImplementer
return new ISpecificImplementer();
//Unchecked cast
//return (T) new ISpecificImplementer();
}
#Override
public void setValue(T in) {
//no complaints here, compiler knows T is ISpecific
wantSomeB(in);
}
private void wantSomeB(ISpecific in){
if (in == null) {
throw new RuntimeException("I'm completely meaningless");
}
}
}
The compiler sets the type of parameter in setValue(T in) to T extends ISpecific based on the type parameter of Generic but it cannot set the type of T in T getValue()
When I use a cast to T in getValue() it then complains about an unchecked cast.
Why is type inference working for the setter but not for the getter?
T in Generic<T extends ISpecific> is allowed to be any type extending ISpecific.
That means it could be ISpecificImplementer, or it could be some other matching type. The choice of T isn't up to the method to decide; it's up to whatever creates the Generic<T> instance.
Inside getValue(), you're trying to return an ISpecificImplementer. Now T might be ISpecificImplementer, or it might be some other type that is not compatible. So it requires a cast. And casting to a generic type generates a warning, because it is bypassing the type-safety that generics are intended to provide.
Suppose that SomeOtherType is another class implementing ISpecific.
If you instantiate a Generic<SomeOtherType> and call getValue(), you'll end up with a casting exception, because getValue() should return a SomeOtherType, but it will actually try and return a ISpecificImplementer. That's why there's a compile warning.
I am trying to create a generic class that represent the various parameters in our application. Parameters can be booleans, integers, decimals, date, longs, strings, etc. I've created the following class to represent that.
public class Parameter<T> {
private final String paramName;
private final Category category;
private final SubCategory subCategory;
private final T defaultValue;
private final Class<T> type;
public Parameter(String paramName, Category category, SubCategory subCategory, T defaultValue, Class<T> type) {
this.paramName = paramName;
this.category = category;
this.subCategory = subCategory;
this.defaultValue = defaultValue;
this.type = type;
}
public String getParamName() {
return paramName;
}
public Category getCategory() {
return category;
}
public SubCategory getSubCategory() {
return subCategory;
}
public T getDefaultValue() {
return defaultValue;
}
public Class<T> getType() {
return this.type;
}
}
This class is being wrapped by an Enum like so.
public enum Parameters {
HEARTBEAT_SERVICE_INTERVAL(new Parameter<Integer>("HeartbeatInterval", Category.SYSTEM, SubCategory.HEALTH_CHECK, 300000, Integer.class));
private Parameter<?> parameter;
Parameters(Parameter<?> parameter) {
this.parameter = parameter;
}
public Parameter<?> getParameter() {
return this.parameter;
}
}
I have a parameter service which takes the ENUM as an argument. I need to know the type of the generic T of parameter and do some logic depending on that. However I'm struggling to determine the type at runtime. The getParameter method of the parameter service needs to return a generic type because its going to return the value of the parameter if its found, otherwise use the default value on the Parameter class.
public <T> T getParameter(Parameters parameter, Class<T> clazz) {
// do something to figure out what type T is ????
}
EDIT:
The intended usage of the code is the following.
// get a String valued parameter
String text = parameterService.getParameterValue(Parameters.SOME_TEXT_PARAM);
// get a boolean valued parameter
Boolean isEnabled = parameterService.getParameterValue(SERVICE_ENABLED);
// etc
Because of type erasure, the only way to communicate the class, is to pass one as a parameter -- but you are already doing this:
public <T> T getParameter(Parameters parameter, Class<T> clazz)
At compile time, Java knows that T is clazz. At runtime, Java doesn't know this, but it doesn't matter.
The following works:
Object foo = new Foo();
#SuppressWarnings("unchecked")
public <T> T getFoo(Class<T> clazz) {
return (T) foo;
}
...
Foo f = getFoo(Foo.class);
... and is quite a common pattern. Essentially you're using the Class<T> parameter to bridge between compile time when generics are meaningful, and runtime when they are not.
It's your responsibility to ensure that the casts don't screw up at runtime, hence the #SuppressWarnings("unchecked"). The compiler can't do it for you: this would still compile if foo where declared as Object foo = new Bar().
It's not much of a leap from this to:
Map<String,Object> parameters;
...
#SuppressWarnings("unchecked")
public <T> T getParameter(String key, Class<T> clazz) {
return (T) parameters.get(key);
}
You can also use clazz.isInstance() to guard against runtime class cast exceptions:
#SuppressWarnings("unchecked")
public <T> T getParameter(String key, Class<T> clazz) {
Object o = parameters.get(key)
if(clazz.isInstance(o)) {
return (T) o;
} else {
return null; // or something better...
}
}
You could also do things like if(clazz.equals(Bar.class).
In some circumstances you might need to be a bit more sophisticated and use Class<? extends T> clazz -- don't worry about this too much until it hits you, unless you're writing library code, in which case you should have unit tests for
parameters.add("x", new SubclassOfFoo());
Foo foo = parameters.get("x", Foo.class);
Note, this whole approach only works for object types. You'll need to use Integer not int. In practice autoboxing makes this painless.
here codes are from the ibatis, the TypeReference would help.
make you Parameter class be abstract
using Parameter p = new Parameter(){}
you can get the type by calling p.getRawType();
/**
* References a generic type.
*
* #param <T> the referenced type
* #since 3.1.0
* #author Simone Tripodi
*/
public abstract class TypeReference<T> {
private final Type rawType;
protected TypeReference() {
rawType = getSuperclassTypeParameter(getClass());
}
Type getSuperclassTypeParameter(Class<?> clazz) {
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof Class) {
// try to climb up the hierarchy until meet something useful
if (TypeReference.class != genericSuperclass) {
return getSuperclassTypeParameter(clazz.getSuperclass());
}
throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
+ "Remove the extension or add a type parameter to it.");
}
Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
// TODO remove this when Reflector is fixed to return Types
if (rawType instanceof ParameterizedType) {
rawType = ((ParameterizedType) rawType).getRawType();
}
return rawType;
}
public final Type getRawType() {
return rawType;
}
#Override
public String toString() {
return rawType.toString();
}
}
Well, if its any type, then you essentially have an Object at runtime; you just need to ascertain your method for casting used variables. You'll need to pass a type token which can resolve the type at runtime. Since your Parameter has that, you can use it inside the parameter class:
public <R> R get() { //<R> R, so we can return any type, invalid types will CCE
//double cast unnecessary, but left here because it's simplified code
return (R) this.getType().cast(/* retrieved data */); //danger: removes type safety!
}
//Elsewheres, while losing safety, can be assigned direct:
int interval = Parameters.HEARTBEAT_SERVICE_INTERVAL.getParameter().get();
However, that's probably a far cry from what you want. Unfortunately you start to hit the realm of how you want to manually ensure that type safety, as you begin to hit the edge of what Java generics support. The way I handled it is through an #as method which would cast and check types/collections etc for me. You can see an example linked here. If done similarly here, it would look like:
int interval = Parameters.HEARTBEAT_SERVICE_INTERVAL.as(int.class); //int type token
I am trying to do something like this:
1. Approach
Type ty = entityType.getEntityClass(); // could be e.g. String.class
List<ty> list;
2. Approach
Class cl = entityType.getEntityClass(); // could be e.g. String.class
List<cl> list;
However, compiler simply says "no".
Is there any way to set the generic type <T> of e.g. a java.util.List dynamic only by having e.g. String.class or foo.getClass()?
...
What I am actually trying to do is initializing a List by a given parameter of type EntityTypeEnum or it's Class property value.
public enum EntityTypeEnum {
ARTICLE(Article.class),
ORDER(OrderHeader.class),
CUSTOMER(Customer.class),
CUSTOMER_SESSION(CustomerSession.class);
private final Class entityClass;
private EntityTypeEnum(final Class entityClass) {
this.entityClass = entityClass;
}
public Class getEntityClass() {
return entityClass;
}
}
Constructive criticism is welcome.
Thank you!
Add: (as a response of Andy's comment)
Class cl = String.class;
List<cl> list;
..is not working either!
List<String> list;
..works, of course.
So what is this difference between String and String.class?
Or is there a way to set the value like:
public enum EntityTypeEnum {
ARTICLE(Article)
..
You are misunderstanding what Java generics are capable of: you can't do something based upon the value of a variable, only with the type of the variable.
Basically, Java generics are just an elision of casts: the compiler automatically inserts casts for you, and checks that the types resulting from those casts match up.
You can do what you describe in your example though, sort of, just not using enums. One of the shortcomings of enums in Java is that all elements have the same type.
Instead of using a real enum, you can use something that roughly looks like an enum:
final class EntityTypeEnumIsh {
private EntityTypeEnumIsh() {}
static final EntityClassSupplier<Article> ARTICLE =
new EntityClassSupplier<>(Article.class);
static final EntityClassSupplier<OrderHeader> ORDER =
new EntityClassSupplier<>(OrderHeader.class);
// ...
final class EntityClassSupplier<T> {
private final Class<T> clazz;
EntityClassSupplier(Class<T> clazz) { this.clazz = clazz; }
Class<T> getEntityClass() { return clazz; }
}
}
You can now use these in a method as you describe:
<T> List<T> method(EntityClassSupplier<T> supplier) {
return new ArrayList<>();
}
and invoke like this:
List<Article> list = method(EntityTypeEnumIsh.ARTICLE);
Of course, you don't get all of the niceness of a "real" enum (like serialization, resistance to reflection attacks etc). But you get something else useful, so weigh it up for your use case.
It does not work because Generics are a compile-time concept but you try to use it as a runtime concept.
The difference is that for compile-time concepts, the compiler needs to be able to figure out the type based on the information it has on your code (i.e., without running or evaluating it).
This code here would be syntactically correct:
public enum EntityTypeEnum
{
ARTICLE(String.class), // just using some builtin types to demonstrate
ORDER(Integer.class),
CUSTOMER(Double.class),
CUSTOMER_SESSION(Short.class);
private final Class<?> entityClass;
private EntityTypeEnum(final Class<?> entityClass)
{
this.entityClass = entityClass;
}
public Class<?> getEntityClass()
{
return this.entityClass;
}
}
class Test
{
// here, T is the type parameter which is determined from the class type
public <T> List<T> createList(final Class<T> clazz)
{
return new ArrayList<T>();
}
// this is the demo code on how to use it
public void foo()
{
EntityTypeEnum t = EntityTypeEnum.ARTICLE;
List<?> list = createList(t.getEntityClass());
}
}
The problem is that this does not help you much. List is more or less the same as List. The compiler cannot narrow the type down to a specific contained object class, because it depends on the runtime.
For your case, if you have a common superclass for your elements, you could use this information to narrow down the type:
public enum EntityTypeEnum
{
ARTICLE(Article.class),
ORDER(OrderHeader.class),
CUSTOMER(Customer.class),
CUSTOMER_SESSION(CustomerSession.class);
private final Class<? extends CommonParent> entityClass;
private EntityTypeEnum(final Class<? extends CommonParent> entityClass)
{
this.entityClass = entityClass;
}
public Class<? extends CommonParent> getEntityClass()
{
return this.entityClass;
}
}
class Test
{
public <T extends CommonParent> List<T> createList(final Class<T> clazz)
{
return new ArrayList<T>();
}
public void foo()
{
EntityTypeEnum t = EntityTypeEnum.ARTICLE;
List<? extends CommonParent> list = createList(t.getEntityClass());
}
}
But if you have a common parent, there is no benefit of the above code over just writing:
List<CommonParent> list = new ArrayList<CommonParent>();
and skipping all that additional generic stuff...
This question already has answers here:
Get generic type of class at runtime
(30 answers)
Closed 7 years ago.
I'd like to find a hack to infer the actual generic instance of another instance's var in runtime, without:
Changing my needed method signature (adding the helper parameter Class<T>, the obvious way)
Having to instanceof all possible subtypes in a hardcoded way
MyInterface<? extends Number> myInterface = whateverReturnsWildcardDoubleInterface();
Class<?> type = inferInstanceType(myInterface);
assert type == Double.class;
/** This is the method that represents the code I am looking for with the conrete signature**/
public <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
return T.class; //Concrete T (can or cannot be the very Number)
}
Ideally, it should return Double when T is particular subtype Integer,Double.. and Number when T is Number
I checked reflection, several "TypeResolver"/"GenericResolver" libs (as the one in Spring or others in Github), but I cannot fin a way to hack it.
EDIT: I reached the conclusion that he only feasible way to do that would be some kind of very complex reflection through the stack trace up to the acutal line that passes the type in the very instantiation
EDIT2: I know it's stupid... but I solved it by simply adding a T getT() method to my interface, so I could return myInterface.getT().getClass()
Disclaimer: This solution is provided as a hack tailored to my understanding of your setup, i.e. one generic interface with a single type parameter, multiple classes, which are not themselves generic, directly implementing this one interface alone, and implementing no other generic interfaces, directly or indirectly.
Assuming that all of the above is true, there is a relatively straightforward way of hacking a solution: calling getClass().getGenericInterfaces() returns a Type object that provides the actual type with which your generic interface has been instantiated.
interface MyInterface<T extends Number> {
T getVal();
}
class DoubleImpl implements MyInterface<Double> {
public Double getVal() {return 42.42; }
}
...
public static void main (String[] args) throws java.lang.Exception {
MyInterface<? extends Number> x = new DoubleImpl();
Type[] ifs = x.getClass().getGenericInterfaces();
System.out.println(ifs.length);
for (Type c : ifs) {
System.out.println(c);
Type[] tps = ((ParameterizedType)c).getActualTypeArguments();
for (Object tp : tps) {
System.out.println("===="+tp); // <<== This produces class java.lang.Double
}
}
}
Demo.
As assylias pointed out, Java's erasure will make that information unavailable at runtime - and thus a need for a hack.
On the assumption that myInterface has a getter for T, as in, MyInterface.getValue():T (or the hack would be to add it) you could do something like this (ignoring the possibility that getValue() could return null):
public <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
return myInterface.getValue().getClass()
}
Below is the full implementation
public class Q34271256 {
public static interface MyInterface<T> {
T getValue();
}
public static class MyDoubleClass implements MyInterface<Double> {
private final Double value;
public MyDoubleClass(Double value) {
this.value = value;
}
#Override
public Double getValue() {
return value;
}
}
public static class MyIntegerClass implements MyInterface<Integer> {
private final Integer value;
public MyIntegerClass(Integer value) {
this.value = value;
}
#Override
public Integer getValue() {
return value;
}
}
#SuppressWarnings("unchecked")
public static <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
Number value = myInterface.getValue();
if (value == null) return null;
return (Class<T>)value.getClass();
}
public static void main(String...args) {
List<MyInterface<? extends Number>> list = Arrays.asList(
new MyDoubleClass(1.1),
new MyIntegerClass(5)
);
for (MyInterface<? extends Number> myInterface : list) {
Class<?> type = inferInstanceType(myInterface);
System.out.printf("%s inferred type is %s\n",
myInterface.getClass().getName(),
type.getName());
}
}
}
And the output should look something like this:
MyDoubleClass inferred type is java.lang.Double
MyIntegerClass inferred type is java.lang.Integer