Java nested self referential generic - java

I have a class which has a self referential generic parameter and a parameter which is of the same super class. The static function has identical bounds as the class.
public class Bar<T extends Bar<T, C>, C extends Bar<C, ?>> {
Bar() {
foo((T) null);
foo((C) null);//compile error
}
static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ?>> void foo(S_T t) {
}
}
This gives the following error.
Bound mismatch: The generic method foo(S_T) of type Bar<T,C> is not
applicable for the arguments (C). The inferred type C is not a valid
substitute for the bounded parameter <S_T extends Bar<S_T,S_C>>
I can't figure out why C can't be passed in to foo() since C is Bar<C,?> and the wildcard is a Bar because of the second parameter in the declaration says it extends Bar.
I know this is probably a bad idea and produces code which is hard to understand but I really wanna know why this doesn't compile.

The short answer is that Java type inference is actually pretty lame.
Java is not performing any intelligent inference on the wildcard ? in the declaration of Bar to infer that it is logically bounded by Bar< ?, ? > (nor that the ?s in that bound are themselves bounded, and so on). Once you put ? by itself, that's all Java knows. Although nothing is stopping you from putting that bound in on the wildcard in the declaration of Bar, even that does not help Java; Java won't ever assume that two separate ?s refer to the same type, even if deeper analysis would imply that they have to be. In other words, the compile error persists even with this code:
public class Bar<T extends Bar<T, C>, C extends Bar<C, ? extends Bar<?, ? extends Bar<?, ?>>>> {
Bar() {
foo((T) null);
foo((C) null);//compile error
}
static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ? extends Bar<?, ? extends Bar<?, ?>>>> void foo(S_T t) {
}
}

I'm not a crack with generics, but I think the problem is that you declare the type of foo() to be
<S_T extends Bar<S_T,S_C> > void foo(S_T)
and then call it in two different contexts that require a different static type for foo().
In the fist context S_T has type T and in the second context it has type C. But T and C are declared as Bar<T,?> and Bar<C,?>, which are incompatible types statically.
I would guess that the compiler figures out the type of foo() in the first call and then assumes correctly, that the type must remain the same throughout, which it doesn't.

Related

Why Java generics allows wildcard with higher upper bound than that of type parameter's?

This is an oversimplified version of the compiler behaviour I'm trying to understand:
class Scratch {
public static void main(String[] args) {
HouseCat<? extends Mammal> hcat = new Tabby();
//HouseCat<Mammal> won't work, compiler catches incorrect type parameter bound
HouseCat<CrazyHouseCat> crazyCat = new Tabby();
}
}
interface Mammal<T extends Mammal> extends Comparable<T>{
T cloneInstance();
}
interface Feline<T extends Feline> extends Mammal<T>{}
interface HouseCat <T extends HouseCat> extends Feline<T>{}
interface CrazyHouseCat<T extends CrazyHouseCat> extends HouseCat<T>{
void pushStuffOverTvStand();
}
class Tabby implements CrazyHouseCat<CrazyHouseCat>{
#Override
public CrazyHouseCat cloneInstance() {
return null;
}
#Override
public void pushStuffOverTvStand() {
}
#Override
public int compareTo(CrazyHouseCat o) {
return 0;
}
}
In the snippet above, HouseCat<? extends Mammal> is a reference with a wider range of types than that is allowed by the HouseCat interface, namely: HouseCat<T extends HouseCat>
If I were to try to do something like HouseCat<Long> the compiler would tell me that Long does not satisfy the type parameter's constraints. Well, so does not <? extends Mammal>, at least potentially.
The compiler would not let me create an instance that violates the type parameter T's constraints but I'm confused about its behaviour regarding the use of Mammal as the upper bound of the reference. There is an invalid type range between (HouseCat,Mammal] so why won't the compiler refuse this reference definition?
Clarification:
My question is not about the meaning of wildcard ?. I'm asking why the compiler is allowing a reference to a parameterised type instance be defined using a wider range of types than what is allowed by the parameterised type's definition. The mentioned questions do not address this specific case, they're about the meaning of a wildcard. My question is about the valid range of the wildcard, which the compiler does not seem be enforcing.
This looks like it answers your question. Basically HouseCat<? extends Mammal> allows to create a HouseCat<[insert type that extends Mammal here]>. All <? extends Mammal> does is act as a generic. In your example I don't see why you'd try to do it this way, but I hope this helps.

How to declare object of type class with multiple bounds

I have an object of type Class<?> and I'm trying to call a method with the signature:
<T extends A & B> void foo(Class<T> clazz);
How can I declare the argument to satisfy the signature?
Example:
void bar(String type) throws Exception {
Class<?> clazz = Class.forName(type);
if(!clazz.isAssignableFrom(A.class)) throw new IllegalArgumentException("type="+type);
if(!clazz.isAssignableFrom(B.class)) throw new IllegalArgumentException("type="+type);
//We know clazz implements both A and B, how do we call foo?
foo(clazz.asSubclass(???));
}
<T extends A & B> void foo(Class<T> clazz) {
//Success
}
Edit: I resorted to refactor the foo method into <T extends A> ... and moved the .isAssignableFrom(B.class) inside it.
Edit: Let me preprend my answer with this (see below for more info): reflection and generics aren't a good fit as they operate at different times:
generics primarily are a compile time tool to help the compiler spot potential programming errors such as trying to add strings to a list of numbers
reflection primarily is a runtime tool to get information about your classes/objects at runtime (such as resolveClass()) and due to type erasure most generics information is lost at runtime
Original answer:
T extends A & B only works if B is an interface (A can be a class or an interface) and the parameter must match both, i.e. it must be a subclass of A and implement B (assuming A doesn't already implement B in which case the A & B part would be unnecessary).
As an example let's use Number and Comparable:
<T extends Number & Comparable<T>> void foo(Class<T> clazz);
We could now call foo(Long.class) because Long extends Number implements Comparable<Long>.
We couldn't call foo(AtomicInteger.class) because AtomicInteger extends Number but it doesn't implement Comparable<AtomicInteger>.
We also couldn't call foo(Number.class) because Number matches extends Number but doesn't implement Comparable<Number>.
In your case you'd need to define a variable Class<? extends A & B> but that is not supported so you'd need to use a generic type (defined on the calling method or the class) or a concrete type:
<T extends A & B> bar() {
Class<T> clazz = resolveClass(); //This would need the same generic type
foo( clazz );
}
or
class C extends A implements B {}
and
Class<C> clazz = resolveClass(); //This would need the same generic type
foo( clazz );
As you can imagine that can become quite complex and might not be feasible.
As a last ditch effort you could try to use raw types:
Class clazz = resolveClass(); //This would need the same generic type
foo( clazz );
This would produce a lot of warnings because it disables type checks so make sure your parameters are thoroughly checked. So if you need to do that it might hint at a design flaw so I'd suggest you think really hard about whether you need T extends A & B at all and what your code is doing.

Class of a generic Java type cannot be assigned to a variable whose Class type is upper bounded by a generic super type

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.

Java Generics Hell

I suspect this has been asked here (and answered) before, but I don't know how to name the problem. Why can I express the wildcards without problem only when I'm not passing the class itself?
It all boils down to this code. Everything works as expected except for the call to genericsHell(ShapeSaver.class):
interface Shape { }
interface Circle extends Shape { }
interface ShapeProcessor<T extends Shape> { }
class CircleDrawer implements ShapeProcessor<Circle> { }
class ShapeSaver<T extends Shape> implements ShapeProcessor<T> { }
class Test {
void genericsHeaven(ShapeProcessor<? extends Shape> a) {}
void genericsHell(Class<? extends ShapeProcessor<? extends Shape>> a) {}
void test() {
genericsHeaven(new CircleDrawer());
genericsHeaven(new ShapeSaver<Circle>());
genericsHell(CircleDrawer.class);
genericsHell(ShapeSaver.class); // ERROR: The method genericsHell is not applicable for the arguments (Class<ShapeSaver>)
}
}
The type of ShapeSaver.class is Class<ShapeSaver>. When feed it to genericsHell(), compiler needs to check if Class<ShapeSaver> is a subtype of Class<? extends ShapeProcessor<?>, which is reduces to whether ShapeSaver is a subtype of ShapeProcessor<?>. The subtype relation does not hold, the method call fails.
The same thing should be true for #Bohemian's solution. Here the subtype checking occurs at bound checking of T after T is inferred. It should fail too. This appears to be a compiler bug, which somehow misinterprets the rule that Raw is assignable to Raw<X> as if Raw is a subtype of Raw<X>. see also Enum.valueOf throws a warning for unknown type of class that extends Enum?
A simple solution to your problem is to declare
void genericsHell(Class<? extends ShapeProcessor> a)
indeed, ShapeSaver is a subtype of ShapeProcessor, and the call compiles.
That's not just a workaround. There's a good reason for it. Strictly speaking, for any Class<X>, X must be a raw type. For example, Class<List> is ok, Class<List<String>> is not. Because there is really no class that represents List<string>; there is only a class representing List.
Ignore the stern warning that you shall not use raw type. We must use raw types sometimes, given how Java type system is designed. Even Java's core APIs (Object.getClass()) use raw types.
You probably intended to do something like this
genericsHell(ShapeSaver<Circle>.class);
Unfortunately, that's not allowed. Java could have, but did not, introduce type literal along with generics. That created lots of problems for lots of libraries. java.lang.reflect.Type is a mess and unusable. Every library has to introduce their own representation of type system to solve the problem.
You can borrow one, e.g. from Guice, and you'll be able to
genericsHell( new TypeLiteral< ShapeSaver<Circle> >(){} )
------------------
(learn to skip the craps around ShaveSaver<Circle> when reading the code)
In the method body of genericsHell(), you'll have full type information, not just the class.
Typing the genericsHell method allows it to compile:
static <T extends ShapeProcessor<?>> void genericsHell(Class<T> a) {}
EDITED: This allows the compiler to specify from context, or by coding an explicit type, that the ShapeProcessor is not literally any ShapeProcessor, but the same type as the one passed as a parameter. If the call was explicitly typed, (which the compiler does under the covers) the code would look like this:
MyClass.<ShapeSaver>genericsHell(ShapeSaver.class);
Which interestingly, gives a type warning, but still compiles. The explicit type is not required however because sufficient type information is available from the parameter to infer the generic type.
Your question is missing some declarations, so I added them in to create a Short Self-Contained Correct Example - ie this code compiles as-is
static interface Shape { }
static interface Circle extends Shape { }
static interface ShapeProcessor<T extends Shape> { }
static class CircleDrawer implements ShapeProcessor<Circle> { }
static class ShapeSaver<T extends Shape> implements ShapeProcessor<T> { }
static void genericsHeaven(ShapeProcessor<? extends Shape> a) { }
// The change was made to this method signature:
static <T extends ShapeProcessor<?>> void genericsHell(Class<T> a) { }
static void test() {
genericsHeaven(new CircleDrawer());
genericsHeaven(new ShapeSaver<Circle>());
genericsHell(CircleDrawer.class);
genericsHell(ShapeSaver.class);
}

Overriding a method with Generic Parameters in Java?

I have an abstract Class Monitor.java which is subclassed by a Class EmailMonitor.java.
The method:
public abstract List<? extends MonitorAccount> performMonitor(List<? extends MonitorAccount> accounts)
is defined in Monitor.java and must be overridden in EmailMonitor.java.
I currently have the method overridden in EmailMonitor.java as follows:
#Override
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
//...unrelated logic
return emailAccounts;
}
However, this produces the compile time error:
Name clash: The method performMonitor(List<EmailAccount>) of type EmailMonitor has the same erasure as performMonitor(Lis<? extends MonitorAccount> emailAccounts) of type Monitor but does not override it
EmailAccount is a subclass of MonitorAccount, so (in my mind at least) overriding it in this way makes perfect sense. Seeing as the compiler is not happy with my logic though, How should I go about this correctly while still keeping my compile time checks to make sure that all calls to EmailMonitor.performMonitor() receive Lists of EmailAccount rather than some other type of MonitorAccount?
No, it's not overriding it properly. Overriding means you should be able to cope with any valid input to the base class. Consider what would happen if a client did this:
Monitor x = new EmailMonitor();
List<NonEmailAccount> nonEmailAccounts = ...;
x.performMonitor(nonEmailAccounts);
There's nothing in there which should give a compile-time error given your description - but it's clearly wrong.
It sounds to me like Monitor should be generic in the type of account it can monitor, so your EmailMonitor should extend Monitor<EmailAccount>. So:
public abtract class Monitor<T extends MonitorAccount>
{
...
public abstract List<? extends T> performMonitor(
List<? extends T> accounts);
}
public class EmailMonitor extends Monitor<EmailAccount>
{
#Override
public abstract List<? extends EmailAccount> performMonitor(
List<? extends EmailAccount> accounts)
{
// Code goes here
}
}
You might want to think carefully about the generics in the performMonitor call though - what's the return value meant to signify?
Here is my own solution. I suspect this is the same thing Jon Skeet was trying to get at... without the typo (see my comment in reply to his answer).
the Monitor.java class:
public abstract class Monitor <T extends MonitorAccount> {
...
public abstract List<T> performMonitor(List<T> accounts);
..
}
EmailMonitor.java
public class EmailMonitor extends Monitor<EmailAccount> {
...
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
..//logic...logic...logic
return emailAccounts;
}
...
}
In this configuration, EmailMonitor.performMonitor() will always check at compile time that it receives a list of EmailAccount rather than any of my other types FTPAccount, DBAccount, etc... It's much cleaner than the alternative, which would have been receiving/sending a raw list and then having to coerce it the required type resulting in potential runtime type casting exceptions.

Categories