Java Generics - Cannot override a method with an extends generic - java

I have this method in a service AbstractClass:
public <E extends EntityFilter> Specification<T> getSpecifications(E entityFilter) {
return null;
}
Then I have an implementation for EntityFilter too:
public class UserEvaluationFilter implements EntityFilter {
#Getter
#Setter
private String evaluator;
}
And I want to override the AbstractClass in my serviceClass (which extends the controller AbstractClass) method like this:
#Override
public Specification<UserEvaluation> getSpecifications(UserEvaluationFilter filter) {
return doStuff();
}
The compiler says that this is not overriding any method of my AbstractClass.
What's wrong?

The method signature you have declared in the abstrct class says that the method should accept any subclass of EntityFilter as that parameter.
Actually, the type variable is redundant there: you may as well just declare it as:
public Specification<T> getSpecification(EntityFilter entityFilter)
What you're trying to do in your subclasses is to make the parameter type more specific than EntityFilter; but this is forbidden by the Liskov Subtitution Principle, which says that subclasses must be:
No more specific in the parameters they accept;
No more general in the values they return.
As such, the method you are trying to declare in the subclass doesn't actually override the method in the supertype, so it is forbidden.
To deal with this, you need to make the filter type a class-level type variable:
class AbstractClass<T, E extends EntityFilter> {
public Specification<T> getSpecifications(E entityFilter) {
return null;
}
}

Related

EnumSet as a parameter in generic Interface

I've a use case :
inteface A{
get(EnumSet<?> fetchModes);
}
class B implements A{
//Here FetchMode is an enum
get(EnumSet<FetchMode> fetchMode){
//Some logic here
}
}
But it's throwing compile time error :
Method get of class B has the same erasure as get(EnumSet fetchMode) of type A but doesn't override it.
I had read that Enums cannot be generic but is there any way to implement this usecase ?
(Basically want the EnumSet to be generic and different implementations can pass different Enums)
A method can override another if the argument types match exactly, but yours doesn't. Eventhough EnumSet<FetchMode> is a subtype of EnumSet<?>, they are not exactly the same. You are not overriding the super class method get(EnumSet<?> fetchModes); in your subclass, rather you are overloading it with a different parameter type. Both of these has the same signature due to erasure when you inspect or decompile the bytecode which is get(EnumSet fetchModes) and your compiler starts complaining.
This is covered in JLS ยง8.4.8.1:
A class cannot have two member methods with the same name and type
erasure
A naive attempt at fixing the problem is to change the parameter type such that it is compatible with that of the super class, overriding the method properly in your sub class.
#Override
public void get(EnumSet<?> fetchModes) {
}
Though this fixes the compiler error after a fashion, it is still not elegant since it allows your EnumSet to store any Object. But ideally you may want it to store only some subtype of Enum. This idiom supports that.
What you have to do is declare a generic interface with bounded type parameter and then implement it by overriding the method properly as shown below.
public interface A<E extends Enum<E>> {
void get(EnumSet<E> fetchModes);
}
public class B implements A<FetchMode> {
#Override
public void get(EnumSet<FetchMode> fetchModes) {
}
}
try this you have to make the generic type extends Enum:
public class B implements A<FetchMode> {
//Here FetchMode is an enum
public void get(EnumSet<FetchMode> fetchMode){
//Some logic here
}
}
}
interface A<T extends Enum<T>> {
void get(EnumSet<T> fetchModes);
}

Annotation Processor appears to break Java generics

Background
I was trying to use Annotation Processors, to generate implementations of specific Factory interfaces. Those interfaces look the following:
public interface ViewFactory<T extends View> {
<S extends Presenter<T>> T create(S presenter);
}
and
public interface PresenterFactory<T extends View> {
<S extends Presenter<T>> S create();
}
The Annotation Processor is doing the correct thing and generates a factory for each matching class, that is annotated with an corresponding annotation.
The Problem
The output of the Annotation Processor is the following:
public final class TestViewImplFactory implements ViewFactory {
public final TestView create(TestPresenter presenter) {
return new TestViewImpl(presenter);
}
}
and the corresponding other class:
public final class TestPresenterImplFactory implements PresenterFactory {
public final TestPresenter create() {
return new TestPresenterImpl();
}
}
The TestViewImplFactory however cannot be compiled. The error message is:
"Class 'TestViewImplFactory' must be declared abstract or implement
abstract method create(S) in 'ViewFactory'"
Java says, the following is correct:
#Override
public View create(Presenter presenter) {
return new TestViewImpl(presenter);
}
which would not work at all, considering that the user wants to know, which View will be returned and which Presenter is required. I would have expected that:
either both of the autogenerated files are wrong
or both are correct
because they both are really similar. I expected the first to be true.
What am I missing here?
If I add the Generic type to the TestViewImplFactory like this:
public final class TestViewImplFactory implements ViewFactory<TestView> {
#Override
public <S extends Presenter<TestView>> TestView create(S presenter) {
return new TestViewImpl(presenter);
}
}
The problem arises, that the constructor Parameter (which is of the Type TestPresenter) is incorrect. Changing the S to a concrete TestPresenter will, again, make the class not compilable for the same reason as above.
So, I stumbled across an "solution" that can be compiled.
What basically has to be done, is to change the ViewFactory interface to the following:
public interface ViewFactory<T extends View, S extends Presenter<T>> {
T create(S presenter);
}
So the class definition has the same Generic type, as the method in the Question above.
After compilation (this time with generic type specification), the output looks like this:
public final class TestViewImplFactory implements ViewFactory<TestView, TestPresenter> {
public TestViewImplFactory() {
}
public final TestView create(TestPresenter presenter) {
return new TestViewImpl(presenter);
}
}
This can be compiled and runs successfully.
This however does not answer the original question. Why is the generic explicitly stated in the type definition correct, but inherited and specified in the method declaration wrong and not compilable?
To be concrete: Why can Java inherit one Generic automatically (within the PresenterFactory) and the other ones not (within the ViewFactory, at the method and at the type declaration)?
Why it is not working:
public interface PresenterFactory<T extends View> {
<S extends Presenter<T>> S create();
}
This signature causes the compiler to infer S at the location where create() is called. S will be what ever you assign create() to as in:
FancyPresenter fp = presenterFactory.create();
SomeOtherPresenter sop = presenterFactory.create();
This implies that:
public TestPresenter create(){...}
is not an implementation of:
<S extends Presenter<T>> S create();
but a method override. There is no implementation of the interface' method. It's not even possible to provide any implementation with a concrete S. It's similar with:
public interface ViewFactory<T extends View> {
<S extends Presenter<T>> T create(S presenter);
}
Here the generic is again inferred on method invocation. So an implementation must accept every subtype of Presenter<T>. The only valid implementation for this is:
public interface ViewFactory<T extends View> {
T create(Presenter<T> presenter);
}
But the return type is dependent on the parameter presenter. This might work if presenter provides you with a method to create an instance of T only.
Why does the other solution work:
Binding the method's generic via the type means that an implementation of the interface provides the concrete type. So for one object you don't need to provide multiple different bindings. No matter where you call the create() method of PresenterFactory<TestView, TestPresenter<TestView>> the return type's generic is bound to TestPresenter<TestView>. So there is a possible implementation for each subtype of PresenterFactory<...>.
I think the very first part of your problem statement should be addressed as I notice your annotation processor is implementing the raw ViewFactory type. I guess with type erasure, since it's generated code, it doesn't make a real difference in practice. But if the processor could generate implementations using the parameterized type, it would at least be easier to reason about the problem.
So, given a message signature <S extends Presenter<T>> T create(S presenter), you could have it generate:
public class TestViewImplFactory implements ViewFactory<TestView> {
#Override
public <S extends Presenter<TestView>> TestView create(S presenter) { ... }
}
Or more minimally:
public class TestViewImplFactory implements ViewFactory<TestView> {
#Override
public TestView create(Presenter presenter) { ... }
}
But then, with either of those, you cannot restrict the parameter to TestPresenter. You would have to change ViewFactory to something like
public interface ViewFactory<T extends View, U extends Presenter<T>>
and them implement ViewFactory<TestView, TestPresenter>. You kind of have to use the type parameters in the implementation to achieve the type restrictions you want.

Java Unchecked Overriding Return Type

I have a project that has the following components:
public abstract class BaseThing {
public abstract <T extends BaseThing> ThingDoer<T, String> getThingDoer();
}
public class SomeThing extends BaseThing {
public ThingDoer<SomeThing, String> getThingDoer() {
return Things.getSomeThingDoer();
}
}
public class SomeOtherThing extends BaseThing {
public ThingDoer<SomeOtherThing, String> getThingDoer() {
return Things.getSomeOtherThingDoer();
}
}
public class Things {
public ThingDoer<SomeThing, String> getSomeThingDoer {
return getThingDoer(SomeThing.class);
}
public ThingDoer<SomeOtherThing, String> getSomeOtherThingDoer {
return getThingDoer(SomeOtherThing.class);
}
private <D extends ThingDoer<T, String> D getThingDoer(Class<T> clazz) {
//get ThingDoer
}
}
public class ThingDoer<T, V> {
public void do(T thing) {
//do thing
}
}
public class DoThing {
private BaseThing thing;
public void doIt() {
thing.getThingDoer().do(thing);
}
}
I'm getting a compiler warning in SomeThing.getThingDoer() that says:
Unchecked overriding: return type requires unchecked conversion.
Found ThingDoer<SomeThing, String>, required ThingDoer<T, String>
Everthing compiles fine, and while I didn't get a chance to test out DoThing.doIt() yet, I have no reason to believe that it won't work.
My question is, can this break and is there a better way to do this? I could make DoThing a base class, and have subclasses for both SomeThing and SomeOtherThing but that doesn't seem very elegant.
EDIT: I would like to avoid making BaseThing generic.
Let's look first at your BaseThing class that you don't want to make generic:
public abstract class BaseThing {
public abstract <T extends BaseThing> ThingDoer<T, String> getThingDoer();
}
This is not a generic class, but it contains a generic method. Frequently, generic methods like this are designed so that the type <T> is bound by the compiler based on some argument to the method. For example: public <T> Class<T> classOf(T object). But in your case, your method takes no arguments. That is also somewhat common, in cases where the implementation of the method returns something "universally" generic (my term) like this method from the Collections utility class: public <T> List<T> emptyList(). This method takes no arguments, but the type <T> will be inferred from the calling context; it works only because the implementation of emptyList() returns an object that is type-safe in all cases. Due to type erasure, the method doesn't ever actually know the type of T when it's called.
Now, back to your classes. When you create these subclasses of BaseThing:
public class SomeThing extends BaseThing {
public ThingDoer<SomeThing, String> getThingDoer() {
return Things.getSomeThingDoer();
}
}
public class SomeOtherThing extends BaseThing {
public ThingDoer<SomeOtherThing, String> getThingDoer() {
return Things.getSomeOtherThingDoer();
}
}
Here, you want to override the abstract method from the base class. Overriding the return type is allowed in Java as long as the return type is still valid in the context of the original method. For instance you can override a method that returns Number with a specific implementation that always returns Integer for that method, because Integer is a Number.
With generics, however, a List<Integer> is not a List<Number>. So while your abstract method is defined to return ThingDoer<T, String> (for some T extends BaseThing), your overloads that return ThingDoer<SomeThing, String> and ThingDoer<SomeOtherThing, String> are not generally compatible with some unknown T even though SomeThing and SomeOtherThing both extend from BaseThing.
The caller (from the abstract API) expects some unknown, unenforceable T that cannot be guaranteed to be satisfied by either of your concrete implementations. In fact, your concrete overloads are no longer generic (they return specific, statically-bound type parameters) and that conflicts with the definition in the abstract class.
EDIT:
The "correct" way (no warnings) to define the abstract method should be something like:
public abstract ThingDoer<? extends BaseThing, String> getThingDoer();
This makes it clear to the caller that it's getting a ThingDoer with its first type parameter bound to something that extends BaseThing (so it can use it as if it were a BaseThing) but the caller will not know the specific implementation when accessed by the abstract API.
EDIT #2 - Findings from our discussion in chat...
The OP's original example usage is:
BaseThing thing = /* ... */;
thing.getThingDoer().do(thing);
Notice how the same thing reference is passed back into a method in the object returned from that same thing's getThingDoer() method. The object returned by getThingDoer() needs to be tightly bound to the concrete implementation type of thing (according to the OP). To me, this smells like broken encapsulation.
Instead, I suggest exposing the logical operation as a part of the BaseThing API and encapsulating the delegation to the ThingDoer as an internal implementation detail. The resulting API would look something like:
thing.doTheThing();
And implemented somewhat like:
public class SomeThing extends BaseThing {
#Override public void doTheThing() {
Things.getSomeThingDoer().do(this);
}
}
public class SomeOtherThing extends BaseThing {
#Override public void doTheThing() {
Things.getSomeOtherThingDoer().do(this);
}
}

Passing generic subtype class information to superclass in Java

I've long used an idiom in Java for using the class information of a (non-abstract) class in the methods of its (generally abstract) ancestor class(es) (unfortunately I can't find the name of this pattern):
public abstract class Abstract<T extends Abstract<T>> {
private final Class<T> subClass;
protected Abstract(Class<T> subClass) {
this.subClass = subClass;
}
protected T getSomethingElseWithSameType() {
....
}
}
An example of a subclass thereof:
public class NonGeneric extends Abstract<NonGeneric> {
public NonGeneric() {
super(NonGeneric.class);
}
}
However, I'm having trouble defining a subclass of Abstract which has its own generic parameters:
public class Generic<T> extends Abstract<Generic<T>> {
public Generic() {
super(Generic.class);
}
}
This example is not compilable; likewise, it is not possible to specify the generic types using e.g. Generic<T>.class or even to use a wildcard like Generic<?>.
I also tried replacing the declaration of generic type T in the superclass to ? extends T, but that isn't compilable either.
Is there any way I can get this pattern to work with generic base classes?
The "pattern" (idiom) of passing an instance of Class<T> (typically to the constructor) is using Class Literals as Runtime-Type Tokens, and is used to keep a runtime reference to the generic type, which is otherwise erased.
The solution is firstly to change the token class bound to:
Class<? extends T>
and then to put a similar requirement on your generic subclass as you did with your super class; have the concrete class pass a type token, but you can type it properly as a parameter:
These classes compile without casts or warnings:
public abstract class Abstract<T extends Abstract<T>> {
private final Class<? extends T> subClass;
protected Abstract(Class<? extends T> subClass) {
this.subClass = subClass;
}
}
public class NonGeneric extends Abstract<NonGeneric> {
public NonGeneric() {
super(NonGeneric.class);
}
}
public class Generic<T> extends Abstract<Generic<T>> {
public Generic(Class<? extends Generic<T>> clazz) {
super(clazz);
}
}
And finally at the concrete class, if you declare the usage as its own class, it doesn't require a cast anywhere:
public class IntegerGeneric extends Generic<Integer> {
public IntegerGeneric() {
super(IntegerGeneric.class);
}
}
I haven't figured out how to create an instance of Generic (anonymous or not) without a cast:
// can someone fill in the parameters without a cast?
new Generic<Integer>(???); // typed direct instance
new Generic<Integer>(???) { }; // anonymous
I don't think it's possible, but I welcome being shown otherwise.
The major problem you have got here is, there is no class literal for concrete parameterized type. And that makes sense, since parameterized types don't have any runtime type information. So, you can only have class literal with raw types, in this case Generic.class.
Reference:
Java Generics FAQs
Why is there no class literal for concrete parameterized types? :
Well, that's fine, but Generic.class gives you a Class<Generic> which is not compatible with Class<Generic<T>>. A workaround is to find a way to convert it to Class<Generic<T>>, but that too you can't do directly. You would have to add an intermediate cast to Class<?>, which represents the family of all the instantiation of Class. And then downcast to Class<Generic<T>>, which will remove the compiler error, though you will an unchecked cast warning. You can annotate the constructor with #SuppressWarnings("unchecked") to remove the warning.
class Generic<T> extends Abstract<Generic<T>> {
public Generic() {
super((Class<Generic<T>>)(Class<?>)Generic.class);
}
}
There is no need in Class<T> subClass argument. Change:
protected Abstract(Class<T> subClass) {
this.subClass = subClass;
}
to:
protected Abstract(Class subClass) {
this.subClass = subClass;
}
and everything will compile.

Java generics: Generic parameter defined at method level vs interface level

I'm having the following issue to do with generics. I have the following:
InterfaceA as:
public interface InterfaceA {
public <T extends DTOInterface> Object methodName (T dto) {}
}
DTOInterface is just an empty interface.
Then my implementation would be:
public class ImplementationA implements InterfaceA {
public Object methodName(DTOImplementation dto) {
return null;
}
}
DTOImplementation is just a class implementing DTOInterface.
This is failing because the method in ImplementationA is not recognized as a valid implementation of the method in InterfaceA.
However, if I define the parameter at interface level i.e.
public interface InterfaceA **<T extends DTOInterface>** {
public Object methodName (T dto) {}
}
And then define the implementation as:
public class ImplementationA implements **InterfaceA<DTOImplementation>** {
public Object methodName(DTOImplementation dto) {
return null;
}
}
It does work. The method is recognized as a valid implementation.
Does anyone know why this is happening?
The first declaration says that in order to implement InterfaceA, the subclass needs to provide a method methodName that works for any type T that extends DTOInterface of the method caller's choice. In other words, T is a parameter that the caller of methodName gets to choose; the class that implements InterfaceA doesn't get to choose it. So when you provide an implementation that attempts to choose a particular value of T for methodName and only implement that, the compiler rejects your program.
The second declaration, on the other hand, is an interface that allows the implementor to provide a particular value for T and only implement its methods for that particular choice. ImplementationA choose to implement InterfaceA only for one particular subtype of DTOInterface (namely, DTOImplementation) and provides a method only for that choice of T. That's perfectly fine.
Your interface definition has a generic method
public <T extends DTOInterface> Object methodName (T dto) {}
This method states that it takes any type T that extends DTOInterface. If you want to implement the interface you need to provide the exact same method in the implementation.
You cannot restrict the method in an implementation because what would happen if you did this:
AnotherDTOImplementation adi = new AnotherDTOImplementation();
InterfaceA obj = new ImplementationA();
ojb.methodName(adi);
This obviously breaks type safety.
In your second example you have a generic interface. This means that when you implement the interface you either have to declare the generic type of specify the implementation as a generic class.
This means that ImplementationA is of type InterfaceA<DTOImplementation> which in turn means that you have type safety.

Categories

Resources