I am reflectively getting classes and their declared classes, and I want to pass them into a function that takes classes, but it has generics on it.
// classes to pass into function
ClassPath.from(MyParent.class.getClassLoader())
.getTopLevelClasses()
.forEach(classInfo -> {
// checks...
Class<?> clazz = classInfo.load();
for (Class<?> declaredClass : clazz.getDeclaredClasses()) {
genericFunction(clazz, declaredClass); // the problem
}
});
// the function to pass into
<E extends Extendable<? extends Parent<E>>> void genericFunction(Class<? extends Parent<E>> parentClass, Extendable<E> extendableClass);
// classes used in generic function
public class MyParent extends Parent<MyExtendable> {
protected class MyExtendable extends Extendable<MyParent> {
}
}
public abstract class Parent<E extends Extendable<? extends Parent<E>>> {
}
public abstract class Extendable<E extends Parent<? extends Extendable<E>>> {
}
The problem is that I have no idea how to cast or reflective run that genericFunction() with the Class<?> objects.
I can assume that the classes that ClassPath finds are compatible (e.g: they all properly extend Parent and Extendable in inner classes.)
I can change my (likely) messy and overcomplicated generics on the function and classes.
Suppose we have three classes - AbstractMessage, AbstractEngine, and AbstractAction. These three classes all reference each other in a generic fashion so each Engine has a corresponding message and action and you can refer to them directly in the code.
public class MyMessage<M extends AbstractMessage<M,E,A>, E extends AbstractEngine<M,E,A>, A extends AbstractAction<M,E,A>> {
This is working fine, but when I attempt to enforce behavior at the highest level I run into some problems. My AbstractAction class has an applyTo method defined thusly:
protected abstract M applyTo(E engine, Object guarantee);
and my AbstractEngine class has this
private final M apply(A action) {
return action.apply(this, this.guarantee);
}
And it is on this line that it balks - complaining that:
The method applyTo(E, Object) in the type AbstractAction<M,E,A> is not
applicable for the arguments (AbstractEngine<M,E,A>, Object)
Now the reason for this is clear - the E in question might be some OTHER AbstractEngine and there's no way to know if the subclass we're calling this from is actually an E.
My question is, how can I say for certainty that if you're going to class MyEngine extends AbstractEngine<M...,E...,A...> that MyEngine is MUST be an E? And to have this certainty baked into AbstractEngine?
Here is a small example that illustrates the problem.
class EngineExample {
static abstract class AbEng<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
final M func(A act) {
return act.apply(this); // compile error here
}
}
static abstract class AbMes<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
}
static abstract class AbAct<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
abstract void apply(E e);
}
static class RealEng extends AbEng<RealAct, RealMes, RealEng> {
}
static class RealMes extends AbMes<RealAct, RealMes, RealEng> {
}
static class RealAct extends AbAct<RealAct, RealMes, RealEng> {
void apply(RealEng eng) {
System.out.println("applied!");
}
}
}
Use loosest valid parameter type
The simplest solution, is to not actually enforce that this isInstanceOf E. The rules of abstraction already guarantee that this is a safe operation, so it will just work if you change the parameter to just allow any Engine.
abstract Action<E> {
public void apply(Engine<?> e, Object o) {
e.doSomething(o);
}
}
or
abstract Action<E> {
<T extends Engine<?>> public T apply(T e, Object o) {
return e.doSomething(o);
}
}
Use a type-safe wrapper
Another solution is to create another class that binds these 3 together, and move the interaction calls to the wrapper.
abstract System<A extends Action, M extends Message, E extends Engine> {
abstract void apply(A action, E engine) {
engine.render(action.apply())
}
}
Or have the wrapper class take an instance of these 3 and use the passed in versions. This basically is the "allow anything close enough" solution, and adding another class to manage how they can and can't talk to each other.
Pre-cast check
You can also make a reference cast on construction to throw an error if the cast setup is invalid.
private final E dis = (E) this;
This really just moves the problem from from always on compile time, to sometimes on run time, so in general, not a safe/stable solution.
This next solution is a bit specific to your case (using info from our discussion). Basically, you want to define a method in an abstract class that class A and B can inherit, but A and B should not be interchangeable using their base class.
Just use polymophism and use generics just as a type segregator
Here is a modification of the MVCe that uses polymorphism instead, using generics only as a kind of type-category-exclusive-locking mechanism. Basically, Type is a semantic interface to say whether semantically, it makes sense for these classes to talk to each other. (A Physics Engine and Light Engine may share some functionality, but it would make no sense to let them be interchangeable.)
class test {
public static void main(String[] rawrs) {
RealEng re = new RealEng();
RealAct ra = new RealAct();
MockAct ma = new MockAct();
ra.apply(re);
// Remove all code related to Type interface if next line should compile
ma.apply(re); // compile error here
}
static interface Type {
}
static interface Real extends Type {
};
static interface Mock extends Type {
};
static abstract class AbEng<T extends Type> {
final void func(AbAct<T> act) {
act.apply(this); // compile error here
}
}
static abstract class AbMes<T extends Type> {
}
static abstract class AbAct<T extends Type> {
abstract void apply(AbEng<T> e);
}
static class RealEng extends AbEng<Real> {
}
static class RealMes extends AbMes<Real> {
}
static class RealAct extends AbAct<Real> {
#Override
void apply(AbEng<Real> eng) {
System.out.println("applied!");
}
}
static class MockAct extends AbAct<Mock> {
#Override
void apply(AbEng<Mock> eng) {
System.out.println("applied!");
}
}
}
Recursive type-parameters in Java generics are often troublesome.
The problem here is that paradoxically there in no way that you can guaranteed that this makes reference to an instance of E; the only thing that we known about this is that it also extends Engine<M, A, E> but not that is actually E.
Obvious solution is to add a cast ((E)this) and that might be an acceptable solution but you must make clear in the contract (thru javadoc or other documentations) that Engine extending classes must assign E to themselves.
Another solution simply change those method signatures to be a bit more flexible and instead E accept any engine that extends Engine<M, A, E>.
protected abstract M applyTo(AbstractEngine<M, A, E> engine, Object guarantee);
Also consider to reduce the number of type-parameters whenever possible. For example does Engine need to make reference to its own type? Does it have any method that accepts or returns and engine that must be of the same type/class?
EDIT
If you want to keep the E type parameter in applyTo another option is to create a field typed E in AbstractEngine that would be the one passed to the apply to. This field in fact would make reference to this but once it has been "casted" safely at construction.:
public class AbstractEngine<M extends ..., A extends ..., E extends ...> {
private final E engine;
protected AbstractEngine(final E engine) {
this.engine = Objects.requiresNonNull(engine);
}
}
public class MyEngine extends AbstractEngine<MyMessage, MyAction, MyEngine> {
public MyEngine() {
super(this);
}
}
The reason this works is that when we are declaring MyEngine then the compiler does know that MyEngine is E and so the "cast" is safe one. Then the code in AbstractEngine can use the casted value safely thereafter.
The obvious inconvenience is the extra field making reference to this, that although is a bit of memory waste in practice is probably negligible.
Here we are adding the possibility that an engine could designate a surrogate engine to be used in their apply method calls. Perhaps that might be useful... but if you really want to make it impossible to use a third engine here, then you can change the code in the AbstractEngine constructor to compare the passed engine with this and fail at runtime if they are not the same.
protected AbstractEngine(final E engine) {
if (engine != this) {
throw new IllegalArgumentException();
}
this.engine = engine;
}
Unfortunately this cannot be check at compilation time... the second best thing you can do is to make it part of your code tests to verify that all AbstractEngine extending classes are compliant so it would fail at build-time.
I have a base abstract class PipelineStage which has the following definition:
public abstract class PipelineStage<I, O> implements Runnable {
...
public abstract O step(I input);
...
}
I then have numerous concrete pipeline stages with definitions such as:
public class ConcreteStage extends PipelineStage<InputContextClass, OutputContextClass> {
...
#Override
public OutputContextClass step(InputContextClass input) {
input.someMethod();
...
return new OutputContextClass();
}
...
}
However, this has led to a rigid design in which either:
The context classes are very tightly coupled to which stages they are used in.
Every stage needs to have two full interfaces defined, defining all the properties of the input and output classes.
I wanted to improve this design by having generic interfaces that specify properties of the context classes, the ConcreteStage would then specify what interfaces it's input and output context classes must extend.
However, I can't figure out how to do this in a way the compiler likes.
For example:
public class ConcreteStage extends PipelineStage<I extends Interface1 & Interface2,
O extends Interface2 & Interface3> {
...
#Override
public O step(I input) {
input.someMethodFromInterface1();
input.someMethodFromInterface2();
...
// OutputContextClass extends Interface2 & Interface3
return new OutputContextClass();
}
...
}
However, this doesn't compile, showing that class I needs to be imported.
A wildcard also doesn't work, saying No wildcard expected.
Does anyone have any suggestions on how to implement this in a neat, flexible way? Many thanks in advance!
You need to put the type variable declarations on the class, not the superclass:
public static class ConcreteStage<
I extends Interface1 & Interface2, O extends Interface2 & Interface3>
extends PipelineStage<I, O> {
You can also make an interface uniting input interfaces together interface InputInterface12 extends InputInterface1, InputInterface2 {} and then class ConcreteStage extends PipelineStage<InputInterface12, OutputInterface12> {...}.
Is there any way using Java generics to express a type hierarchy like the following?
class A { ... }
class B extends A { ... }
interface Wraps<T> {
T getWrapped();
}
class WrapsA implements Wraps<A> {
A getWrapped();
}
class WrapsB extends WrapsA /* implements Wraps<B> */ {
B getWrapped();
}
I understand that as written Java's type system will reject this code, but is there any way I can specify the type parameters or inheritance hierarchy that will get this working?
EDIT: I realized that the real issue I'm having is I'm trying to enforce type safety in my API for a method like
<T extends A> T unwrap(Wraps<T> wrapper, Class<T> wrappedClass);
I'm not able to call it with unwrap(wrapsB, B.class). Is this something that Java will handle?
You can just use
class WrapsB extends WrapsA {
B getWrapped();
}
Since you're allowed to return subclasses in overriden methods (it's possible from Java SE6, as far as I remember)
Check out self-bounded types.
interface Wraps<T, W extends Wraps<T, W>> { ... }
abstract class AbstractWrapsA< T extends A, W extends AbstractWrapsA< T, W > implements Wraps< T, W > { ... }
class WrapsA extends AbstractWrapsA< A, WrapsA > {}
class WrapsB extends AbstractWrapsA< B, WrapsB > { ... }
EDIT: Actually to satisfy the OP's need we can dispense with self-bounded types and just migrate the guts of WrapsA to an abstract class. We still do not have that WrapsB both is-a WrapsA and is-a Wraps<B>.
I don't know why I can't find an answer to this online.
I have classes that implement multiple methods and I would like to write methods to expect them. I don't know how to do it though or if it's even possible.
E.g:
public void yellAtPet(<? extends Pet implements YellableAt> arg) {
arg.yellAt("Don't go there!");
arg.pet("Good Boy");
}
Extends is used for both interfaces and parent classes.
If you want to inforce multiple extends you needs something like:
<T extends ClassA & InterfaceB>
To enforce this on a method, generify the class:
public class MyClass<T extends something & somethingelse>{
public void doSomething(T arg)
{
//call methods defined by either interface
}
}
This should work fine as a generic method, without making your entire class generic:
public <T extends Pet & YellableAt> void yellAtPet(T arg) {
arg.yellAt("Don't go there!");
arg.pet("Good Boy");
}