I have an enum that stores some metadata for a database table:
static enum DataTable implements TableMetaData {
HISTORIES ("h", Hx.class, HxColumn.HPI_ID),
:
:
private final String e_alias;
private final Class<? extends Row> e_tbl;
private final ColumnMetaData e_idCol;
DataTable(String al,
Class <? extends Row> c1,
ColumnMetaData id)
{...}
#Override public Class<? extends Row> modelClass() { return this.e_tbl; }
:
:
}
The field of interest is e_tbl which stores the model object class corresponding to the database table. All the model object classes in this project implement a Row interface. I'd like to be able to access this field in order to generate instances of this class.
My problem is that I'm using an unchecked cast that I don't know is safe and I haven't been able to figure out how to perform a runtime check to be sure that the model object matches. Here's the code in which the cast occurs:
static final <E extends Row> List<E> doQuery (
final List<JdbcValue> pars,
final String sql,
final TableMetaData dm
)
{
List<E> result = new ArrayList<E>();
#SuppressWarnings("unchecked")
Class<E> cls = (Class<E>) dm.modelClass();
:
:
}
I believe that this is a dangerous cast. The query is intended to generate E instances and those instances will be made using the model class that is contained in the supplied enum constant. The problem is I can't know that E matches the stored class token in the enum. This is a situation in which Class.asSubclass() does not seem to be able to help me.
The problem is that I have a field that is <? extends Row> and I need to make it compatible with <E extends Row>.
One solution would be to refactor the method to that it requires a Class<E> cls parameter rather than the enum. This would provide at least some compile-time assurance that the class token was appropriate for the type of the result list being generated. However this still does not enable me to use the data in the enum; I'd still have to cast it before the method call.
Is there a check I can use?
==================================================
UPDATED 12/6/14
It seems to me that this is a problem without a good, clean solution.
Enums do not support generic type parameters (they can't).
Having incompatible type information at compile-time will happen every time you try to store parameterized types in an enum constant.
Using a parameterized type-safe singleton pattern, as suggested, would enable the compiler to check type safety but the API I have is permeated by these enum classes and I don't feel that I can refactor them into regular classes.
To limit the damage, I wonder if the following reasoning is accurate:
Data associated with enum constants is static and final; here it is also all immutable.
I fully control the data that goes into the enum constants, so I know at run-time that the e_tbl field will always be a Class object of some type that extends Row.
These assumptions admit two approaches that I think have the same flaws. In the enum class, the accessor method is rewritten to:
#Override public <E extends Row> Class<E> modelclass() {
#SuppressWarning("unchecked")
Class<E> cls = (Class<E>) this.e_tbl;
return this.e_tbl; }
I can store the data to the enum to a field that uses a raw type. The raw type interoperates with the generic accessor method and so it compiles but a warning is generated.
I can store the data to the enum to a field that uses a <? extends Row> wildcard type. This won't compile with the generic accessor method (<E> extends Row>) so I have to use an unchecked cast. A warning is still generated.
Since I know that the enum data always extends Row, I think this is probably ok. What I can't do is guarantee that the enum data being retrieved is appropriate for the List type being generated. But I don't think there is any way to control for this aside from documenting that the API user must send the correct TableMetaData constant for the query being returned or the results will be "undefined."
Since enums won't work with generic types, I don't think there is a better solution.
One thing you could do:
Turn TableMetaData into TableMetaData<E> and define the class in terms of E
Get rid of the enum (because they don't support type parameters) and write one class
per enum entry
So the interface looks roughly like
class Histories implements TableMetaData<SpecialRowType> {
Class<SpecialRowType> modelClass();
}
Which should finally allow you to cast use it.
static final <E extends Row> List<E> doQuery (
final List<JdbcValue> pars,
final String sql,
final TableMetaData<E> dm
)
{
List<E> result = new ArrayList<E>();
// type safe, because E refers to the same thing.
Class<E> cls = dm.modelClass();
:
}
Now the compiler can be sure that the ? extends Row class is the same as the E extends Row class, which do have a common ancestor but that doesn't mean that you can cast them to each other.
Related
I have a method that needs to accept a Enum class. These enums implement an interface. Now I need access to both Enum methods like ordinal(), name(), etc and my interface methods. What I've tried:
public <T extends ConfigFeature, Enum> void showEnabledFeatures(Class<T> enumType, long mask) {
List<T> list = Arrays.asList(enumType.getEnumConstants());
list.forEach(item -> {
// My interface's method, works fine
item.getMask();
// Enum method doesn't work:
// item.ordinal();
});
}
Reversing the order reverses the working:
public <T extends Enum, ConfigFeature> void showEnabledFeatures(Class<T> enumType, long mask) {
List<T> list = Arrays.asList(enumType.getEnumConstants());
list.forEach(item -> {
// My interface's method, doesn't work now
// item.getMask();
// Enum method now works:
item.ordinal();
});
}
Is there a way to get access to both methods from interface and Enum?
You are using the wrong syntax to say that T must implement this interface AND is an enum.
This:
<T extends ConfigFeature, Enum>
is not constraining T to Enum, but actually creating a new generic parameter called Enum.
Similarly,
<T extends Enum, ConfigFeature>
is not constraining T to ConfigFeature. You are declaring a new generic parameter called ConfigFeature.
The correct syntax is to use &:
<T extends Enum<T> & ConfigFeature>
Note that the order is actually important here! Enum can only come first.
According to here, only the first constraint can be a class, and then the ones after it must all be interfaces:
TypeParameter:
{TypeParameterModifier} Identifier [TypeBound]
TypeParameterModifier:
Annotation
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}
AdditionalBound:
& InterfaceType
Your syntax is wrong; you need:
public <T extends Enum<T> & ConfigFeature>
That syntax that you used creates two generic type parameters one called T and one called Enum (where Enum isn't bounded and T is bounded to extend ConfigFeature).
Note that, to avoid any generics warnings about the use of raw types, you also have to provide a type parameter to the Enum bound. An enum called X always extends Enum<X>, so you can use T extends Enum<T>, and the full text of the method local generic declaration becomes <T extends Enum<T> & ConfigFeature>
Replace the , in your second example with &. You can use & to declare multiple bounds as long as they’re interfaces from the second type onwards. If you use a comma it’s a separate type parameter, not a bound.
Just to add to existing answers, instead of using Mutliple Bounds as described in other answers, you can define interface that combines interface you want with return method for enum, like:
public interface ConfigFeatureEnumI <T extends Enum<T>> extends ConfigFeatureI{
#SuppressWarnings("unchecked")
default public T asEnum() {
return (T) this;
}
}
You can implement asEnum() in enum used, or just use default method if Java 8 is available as I show here.
public enum ConfigEnum implements ConfigFeatureEnumI<ConfigEnum>{//...
Then showEnabledFeatures can look like:
public <T extends ConfigFeatureEnumI<?>> void showEnabledFeatures(Class<T> enumType, long mask) {
List<T> list = Arrays.asList(enumType.getEnumConstants());
list.forEach(item -> {
// Interface method works:
item.getMask();
// Enum method works via asEnum():
item.asEnum().ordinal();
});
}
While adding new Interfaces is not ideal, it can be easier to use for programmers who do not know Java generics that well or never used Multiple bounds (I use generics a lot, but never needed such feature , so I was a bit off when I did see it).
I ran into a below statement which expects aforementioned parameter type while reviewing oracle entitlement server API.
FunctionEntry functionEntry = ...;
functionEntry.setParameterTypes(List<Class<? extends DataType>>);
I am having a hard time to understand what it is asking for. I only understand "? extends DataType". What type of parameter I need to pass into setParameterTypes method?
It asks for a list of specific Class objects. In this case a list of Class objects which represent classes which extends from the DataType class. When you extends from this class like:
public class MySpecialDataType extends DataType
{
}
public class AnotherDataTypeToUse extends DataType
{
}
you can use the expressions MySpecialDataType.class and AnotherDataTypeToUse.class (something called "class literal") to get objects which can be assigned to Class<? extends DataType> variables.
Class<MySpecialDataType> clazzOne = MySpecialDataType.class;
Class<AnotherDataTypeToUse> clazzTwo = AnotherDataTypeToUse.class;
Class<? extends DataType> baseClazz = clazzOne; // works
baseClazz = clazzTwo; // also works
List<Class<? extends DataType>> clazzes = new ArrayList<Class<? extends DataType>>();
clazzes.add(clazzOne);
clazzes.add(clazzTwo);
functionEntry.setParameterTypes(clazzes);
You might want to look at Arrays.asList() for the argument of setParameterTypes().
A List<Class<?>> is a list of Class objects e.g.
Arrays.asList(String.class, Boolean.class, Pattern.class)`
A List<Class<? extends T>> is a list that can only contain the Class objects of T and its subclasses e.g. List<Class<? extends CharSequence>> could be
Arrays.asList(String.class, StringBuffer.class, StringBuilder.class, CharSequence.class)`
The statement defines the type of each parameter that the FunctionEntry takes. Although, the way you typed it is not syntactically correct. The definition of setParameterTypes is
setParameterTypes(java.util.List<java.lang.Class<? extends DataType>> parameters)
So it is expecting a list of classes corresponding to the parameter types of the function you are defining, with the added requirement that the types must be subclasses of DataType. For example, the classes OpssBoolean, OpssInteger and OpssDouble are subclasses of DataType in the Oracle API. So if you wanted to define a function in this API that takes an OpssBoolean as 1st parameter, an OpssInteger as 2nd parameter, and an OpssDouble as 3rd parameter, you define it this way:
List<java.lang.Class<? extends DataType>> parameterTypes = Arrays.asList(
OpssBoolean.class, OpssInteger.class, OpssDouble.class
);
functionEntry.setParameterTypes(parameterTypes);
It returns a list of input parameters.
Lets say, this function takes a variable number of input parameters, it will return the TYPES of minimum required inputs.
For example, logical functions AND and OR can take an unbound number of input parameters but require minimum 2 OpssBoolean type parameters. So this method will return {OpssBoolean.class,OpssBoolean.class} for AND or OR functions.
Its asking that objects within List should extend DataType class
It is asking you to pass a List<MyDataType> where
public class MyDataType extends DataType
{
/* your data type stuff */
}
See here for details on DataType: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
I use Java 8. In my design a have a few simple classes which model value parameters such as FloatParameter or EnumParameter<E>. A have a common generic super class of these classes (GenericParameter<T>) which implements parameter name and its default value. The sub classes implement other attributes specific to them such as range in case of FloatParameter.
Moreover, I want to work with the types of the parameters regardless of their specific type. But I still want to bound the types in the way that they are sub types of GenericParameter<T>. In order to do that, I created a method such as process(Class<? extends GenericParameter<?>> paramType).
Now, the problem is that the EnumParameter.class cannot be assigned to a variable of type Class<? extends GenericParameter<?>> while FloatParameter.class can be.
Further I list the code for the classes to make it more clear and reproducible:
public class GenericParameter<T> {
protected String name;
protected T defaultValue;
}
public class FloatGenericParameter extends GenericParameter<Float> {
...
}
public class TypedGenericParameter<T> extends GenericParameter<T> {
...
}
Class<? extends GenericParameter<?>> fgpc = FloatGenericParameter.class; // ok
Class<? extends GenericParameter<?>> tgpc = TypedGenericParameter.class; // error: incompatible types: Class<TypedGenericParameter> cannot be converted to Class<? extends GenericParameter<?>>
Class<? extends GenericParameter> tgpc2 = TypedGenericParameter.class; // warning: [rawtypes] found raw type: GenericParameter
Finally, when using a non-generic base class, there is no problem:
public class Parameter {
....
}
public class FloatParameter extends Parameter {
...
}
public class TypedParameter<T> extends Parameter {
...
}
Class<? extends Parameter> fpc = FloatParameter.class; // ok
Class<? extends Parameter> tpc = TypedParameter.class; // ok
Please, do you have any suggestions?
I can go with process(Class<?> paramType) as a workaround or do casts, but I wanted to benefit from the static type checking by the compiler.
EDIT:
I would like to use the cast when registering factories that produce GUI components for each parameter type. The code looks like:
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() { ... })
In such case, the compiler would check the added parameter type at compile time. Also the code would be more self-explaining.
EDIT 2:
Currently, I am using the suggested approach to introduce a type parameter for the addParameterComponentFactory method. The signature looks like this:
public static <P extends GenericParameter<?>> addParameterComponentFactory(Class<P> clazz, ParameterComponentFactory pcf)
With this definition I am able to specify TypedParameter.class (EnumParameter.class - also one type param) as well as I obtain the static type checking.
Let's start with the core bits of your API. You have a generic Parameter<T>
type that represents some named parameter with a value of type T. You have
specialized GUI components designed to edit or display specific types of
parameters, and you want to be able to register factories to create these
components.
class Parameter<T> {
String name;
T defaultValue;
}
class ParameterComponent<P extends Parameter> {
void setParameter(final P p) {}
}
interface ParameterComponentFactory<P extends Parameter> {
ParameterComponent<P> newComponent();
}
class FloatParameter extends Parameter<Float> {}
class FloatParameterComponent extends ParameterComponent<FloatParameter> {}
class EnumParameter extends Parameter<Enum> {}
class EnumParameterComponent extends ParameterComponent<EnumParameter> {}
If I understand you correctly, you're running into trouble figuring out how to
declare a method that statically enforces a relationship between some
Parameter type and a factory for GUI components specialized for that type.
For example, you want to be able to write this:
addComponentFactory(EnumParameter.class, EnumParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, FloatParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, EnumParameterComponent::new); // ERROR!
The problem is related to the rules of generic subtyping, and you can work around them by employing a type variable instead of an embedded wildcard. This should give you the type checking you want, without the need for
nasty casting:
static <P extends Parameter> void addComponentFactory(
final Class<P> parameterType,
final ParameterComponentFactory<? extends P> factory) { ... }
Explanation[1]
Explain the difference between introducing a new type P extends Parameter<?> used in Class<P> and stating
directly Class<? extends Parameter<?>>
This is complicated, so bear with me. Let's talk a bit about wildcards, raw
types, and conversions. Consider the following:
// Scenario 1(a)
GenericParameter raw = /* some value */;
GenericParameter<?> wc = raw;
// Scenario 1(b)
Class raw = GenericParameter.class;
Class<?> wc = raw;
// Scenario 2
Class<GenericParameter> classOfRaw = GenericParameter.class;
Class<GenericParameter<?>> classOfWC = classOfRaw;
Scenarios 1(a) and 1(b) both compile for the same reason: because a raw type
G may undergo an unchecked conversion
to any parameterized type of the form G<T_1, ..., T_n>.
Scenario 2 does NOT compile. But why?
In Scenario 2, neither side in the second assignment is a raw type. For the
assignment to be valid,
there must be either an identity conversion or a widening conversion
from the right-hand type to the left-hand type. For widening conversions on
reference types, the left-hand type must be a supertype of the right-hand type.
When these types are generic, the rules of generic subtyping
apply. Specifically, the type arguments on the left-hand side must
contain
the type arguments on the right-hand side.
An assignment from Class<String> to Class<? extends Object> is valid.
Class<String> is a generic subtype of Class<? extends Object> because
? extends Object contains String. In Scenario 2, for the second
assignment to be valid, GenericParameter<?> would have to contain
GenericParameter, but it doesn't. T is not a subtype of T<?>;
T is a supertype of T<?>. Thus, by the generic subtyping rules,
Class<T> is not a subtype of Class<T<?>>, and the assignment is not
valid.
So why does the following work?
public static <P extends GenericParameter<?>> addParameterComponentFactory(
Class<P> clazz,
ParameterComponentFactory pcf)
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() {})
In the call above, type inference on P is driven entirely by the
Class<P> argument. You are passing a Class<EnumParameter>, so P
in this case gets bound to the raw type EnumParameter. For the constraint
P extends GenericParameter<?> to be satisfied, GenericParameter<?>
must be assignable from EnumParameter, and it is assignable via an
unchecked conversion, just like in Scenarios 1(a) and 1(b).
[1] This explanation is blatant plagarism
an amalgamation of other excellent Stack Overflow answers, mostly by
radiodef.
Say I have a parent interface/class like so
interface Parent<T> {}
And a number of implementing interfaces that fix the generic type.
interface Child extends Parent<Type> {}
Can I use reflection to get the instance of Class representing T if I have the Class object for Child. Something like this:
<T, I extends Parent<T>> I create(Class<I> type) {
Class<T> tType = ...
...
}
Currently I'm having tType be passed in as a parameter, but I'd like to simplify things if I can.
Yes, despite what the others have said, this info is available if you have access to the subclass' Class object. You need to use getGenericSuperclass along with getActualTypeArguments.
ParameterizedType superClass = (ParameterizedType)childClass.getGenericSuperclass();
System.out.println(superClass.getActualTypeArguments()[0]);
In your example, the "actual" type argument should return the Class for Type.
If you need to do anything non-trivial with generic types at runtime, consider Guava's TypeToken. It can answer your question (and many more!) while addressing some of the nuanced concerns raised by commenters:
private interface Parent<T> {}
private interface Intermediate<U, V> extends Parent<V> {}
private interface Child<Z> extends Comparable<Double>, Intermediate<Z, Iterable<String>> {}
public void exploreGuavaTypeTokens() {
final TypeToken<? super Child> token = TypeToken.of(Child.class).getSupertype(Parent.class);
final TypeToken<?> resolved = token.resolveType(Parent.class.getTypeParameters()[0]);
System.out.println(resolved); // "java.lang.Iterable<java.lang.String>"
final Class<?> raw = resolved.getRawType();
System.out.println(raw); // "interface java.lang.Iterable"
}
I don't think so. Read about type erasure: the generic types are used only for compile-time checking, and then discarded. They're not stored in the compiled class files so they're not available at runtime.
This is an example which I made up to be a simplification of my real code, so I apologize if it is a little contrived. What I would like to do is to effectively get two type parameters out of a single nested type argument. I'm pretty sure this is impossible, but I thought I'd give it a shot.
//Not legal java code
public class Foo<C extends Collection<T>> { //where T is another type parameter
private C coll;
public Foo(C coll) {
this.coll = coll;
}
public void add(T elem){
this.coll.add(elem);
}
//UPDATED TO ADD GETTER
/**
* I may need to retrieve the collection again, or pass it
* on to another function that needs the specific C type
*/
public C getColl(){
return coll;
}
}
...
List<String> strings = new ArrayList<String>();
Foo<List<String>> foo = new Foo<List<String>>(strings);
foo.add("hello");
I know that I could do it by adding another type parameter:
public class Foo<C extends Collection<T>,T>
but then I have to add the redundant:
Foo<List<String>,String> foo = new Foo<List<String>,String>(strings);
And in my real world case, my generics can sometimes be specified in the implements clause like
public class Bar implements Baz<String>
Having to specify that second type parameter is even more painful then, because it feels like it throws the implementation details in my face. Having to say
Foo<Bar,String>
when there is a relationship between String and Bar already, just seems inelegant. I get that its Java, so that goes with the territory, but just curious if there was a solution for this.
It's not possible and I don't think it's ideal anyway because there is nothing in your existing class that requires invariance.
Foo<T,C extends Collection<T>>
could more generally be
Foo<T,C extends Collection<? super T>>
if the only reason to have T is to allow mutation of the collection.
Note, if you're concerned about having to specify two type parameters frequently, you can create a shallow subclass:
class DerivedFoo<T> extends Foo<Collection<T>,T>
and you can use factory methods to avoid having to double-specify at creation time
public static <T> Foo<Collection<T>,T> fromCollection(Collection<T> c)
You can also abstract the interface into an interface to get the benefits of concise types that you get with DerivedFoo above.
Why wouldn't you just use T as your only type parameter, as in:
public class Foo<T> { //where T is another type parameter
private Collection<T> coll;
public Foo(Collection<T> coll) {
this.coll = coll;
}
public void add(T elem){
this.coll.add(elem);
}
Prior to Java7, constructors don't do type inference, the workaround is to have a static factory method. That's no longer necessary. In Java 7 you can
Foo<List<String>,String> foo = new Foo<>(strings);
Regarding T and C, if we have 2 type parameters with constraints between them, there got to be some degree of redundancy. In your example, since one parameter C totally dictates the another parameter T, the redundancy seems unbearable. I don't see a solution.
But you probably can feel better if the type parameters are reordered
Foo<String,Bar> foo = new Foo<>(bar);
so we declare String first; then further provide a Baz<String> which is Bar