Annotation Processor appears to break Java generics - java

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.

Related

Java generics, Interface and Class inheritance

Consider the abstract class:
public abstract class Animal { ...}
and the interface:
public interface Canine<T extends Animal> {...}
I've defined the concrete classes:
public class Dog extends Animal implements Canine<Dog> {...}
public class Wolf extends Animal implements Canine<Wolf> {...}
I'd like to build a repository class that accesses the database of animals and returns them. I've defined it in the following way:
public interface Repository {
Option<Dog> findById(String id, Class<Dog> type);
Option<Wolf> findById(String id, Class<Wolf> type);
(note: Option is taken from the vavr library)
This repository is used in the following class:
public abstract AbstractFinderClass<T extends Animal & Canine<T>> {
private Class<T> animalType;
public AbstractFinderClass(Class<T> animalType) {
this.animalType = animalType;
}
public Option<T> findMyAnimal(String id) {
return repository.findById(id, this.animalType);
}
}
which in turn is implemented in concrete form with:
public class DogFinder extends AbstractFinderClass<Dog> {
public DogFinder() {
super(Dog.class);
}
}
Now, the line return repository.findById(id, this.animalType) causes two errors:
on the second parameter, this.animalType is of type Class<T> while the expected type is Class<Dog>, and these are apparently incompatible;
the return type is expected to be Option<T> while instead I get Option<Dog>
I am afraid I am missing some "little" detail, as I would expect Dog and T to be compatible.
Could you help me in fixing the problem?
The first problem is that you're having an unnecessary type parameter for DogFinder. It's a dog finder, so a type parameter for what it finds is superfluous (the unconventionally named type parameter Dog could perhaps have indicated a problem). It should be:
class DogFinder extends AbstractFinderClass<Dog> {
public DogFinder() {
super(Dog.class);
}
}
Second, your Repository type has methods that are bound to specific types. This makes little sense because you want it to be generic. So you can use just one method, (optionally) making the repository itself generic (in the process solving the signature clash problem):
interface Repository<T extends Animal> {
Option<T> findById(String id, Class<T> type);
}
Third, unless we're missing context, I believe your Canine type doesn't need to be generic (unless things must be convoluted):
interface Canine {
}
If you need a dedicated canine finder, you can simply change your repository class, like so:
abstract class CanineFinderClass<T extends Animal & Canine>
implements Repository<T> {...}
As a side note, the DogFinder repository is redundant unless it offers special dog methods, like findAllPuppies(). Otherwise, making AbstractFinderClass concrete should be enough as the type is generic (just an example):
class AnimalFinderClass<T extends Animal> implements Repository<T> {
Repository<T> repository;
private Class<T> animalType;
public AbstractFinderClass(Class<T> animalType) {
this.animalType = animalType;
}
public Option<T> findMyAnimal(String id) {
return repository.findById(id, this.animalType);
}
}

Need to understand the syntax class Builder<T extends Builder<T>>

I am following examples in "Effective Java" and came across the following code:
abstract static class Builder<T extends Builder<T>>
and its implementation:
public static class Builder extends Pizza.Builder<Builder>
Why is this declared T extends Builder<T> and not T extends Builder. Is it really needed to add the template <T>? What is the impact if I just use Builder<T extends Builder>?
It is called as "generic type". That declaration means T can be any type that is subclass of Builder<T>.
The goal of implementing Generics is finding bugs in compile-time other than in run-time. Finding bugs in compile-time can save time for debugging java program, because compile-time bugs are much easier to find and fix.
What is the impact if we just use Builder<T extends Builder>?
It transforms into raw type. And type safety goes off.
Builder<T extends Builder<T>> means that,
The class T passed in must implement the Builder interface / extend Builder class, and the generic parameter of Builder must be T itself.
I have some examples to show that actually the difference is not that big. I think the OP wants to know the difference between T extends Builder<T> and T extends Builder.
public abstract class Builder2<T extends Builder2> {
//doesn't compile either, because String is not a subtype of Builder2
static class WrongHouseBuilder extends Builder2<String> {}
//all ok
static class RawHouseBuilder extends Builder2 {}
static class HouseBuilder1 extends Builder2<RawHouseBuilder> {}
static class HouseBuilder2 extends Builder2<HouseBuilder1> {}
static class HouseBuilder3 extends Builder2<HouseBuilder2> {}}
Now with Builder<T>:
public abstract class Builder<T extends Builder<T>> {
//all ok
static class RawCarBuilder extends Builder {}
static class CarBuilder extends Builder<CarBuilder> {}
//ok as well, T doesn't have to be CarBuilder2
static class CarBuilder2 extends Builder<CarBuilder> {}
//doesn't compile because CarBuilder2 is not a subtype of Builder<CarBuilder2>
static class CarBuilder3 extends Builder<CarBuilder2> {}}
Of cause with T extends Builder<T>, you have more protection, but not that much.
UPDATE
Just to clarify, we should not use raw type. #Radiodef has provided an interesting example in the comment. And a quote from that answer to help you understand it:
In simpler terms, when a raw type is used, the constructors, instance methods and non-static fields are also erased.
Minor: It looks more natural to me to use Builder as an interface, not an abstract class. This is a sort of recursive type declaration. It is used for type safety to prevent nasty things like the following happens:
public abstract Builder<T extends Builder<T>> {
T build();
}
public class Entity extends Builder<String>{ // does not compile
#Override
public String build() {
return null;
}
}
public class Entity extends Builder<Entity>{ //ok
#Override
public Entity build() {
return null;
}
}
Anyway more naturally looking version (from my point of view) is:
public interface Buildable<T extends Buildable<T>> {
T build();
}
public final class Entity implements Buildable<Entity>{
//other methods
#Override
public Entity build() {
//implementation
}
}
I see that the question is about the <T> part in Builder<T>. Without this <T>, you simply get a raw type, and your IDE might complain.
But in my answer, I'd like to explain what's the purpose of T extends Builder<T>, because other answers do not seem to cover it (maybe you know this already).
T extends Builder<T> serves the purpose of returning appropriate Builder.this in all the Builder methods (except build() method, of course).
I usually use it with a protected abstract method like T thisInstance().
Example:
abstract class NamedBuilder<T extends NamedBuilder<T>> {
private String name;
T name(String name) {
this.name = name;
return thisInstance();
}
protected abstract T thisInstance();
}
final class MoreSpecificBuilder extends NamedBuilder<MoreSpecificBuilder> {
#Override
protected MoreSpecificBuilder thisInstance() {
return this;
}
}
Thanks to such approach, you do not have to redefine name() method in all the NamedBuilder subclasses to return the specific subclass.
Without such constraint type parameter T, you would have:
abstract class NamedBuilder {
NamedBuilder name(String name);
}
and you would need to override all such methods in subclasses like that:
final class MoreSpecificBuilder extends NamedBuilder {
#Override
MoreSpecificBuilder name(String name) {
super.name(name);
return this;
}
}
EDIT: Without the constraint extends Builder<T> on type parameter T:
abstract class NamedBuilder<T> {
// ...
}
this would work fine, although such design would be less intuitive and more error-prone.
Without such constraint, compiler would accept anything as T (e.g. String), so the constraint acts simply as a compile-time check for the implementors of NamedBuilder.

Java Generics - Cannot override a method with an extends generic

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;
}
}

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);
}
}

Bound mismatch with Java Generics "nesting"

I'm having difficulty using generics for a redesign/refactoring I'm doing on an existing design.
public interface DataDto {
// some data here
}
public interface SetDto<MyDataDto extends DataDto> {
List<MyDataDto> getData();
}
public interface Results<MySetDto extends SetDto<DataDto>> {
MySetDto getResults();
}
public interface MyProblemInterface<MyDataDto extends DataDto,
MySetDto extends SetDto<MyDataDto>,
MyResults extends Results<MySetDto>> {
// some stuff here
}
My problem is that I get the following error for MyProblemInterface:
Bound mismatch: The type MySetDto is not a valid substitute for the
bounded parameter <MySetDto extends SetDto<DataDto>> of the type
Results<MySetDto>
I admit my experience with generics is somewhat limited, but basically I'm trying to enforce that all three of the types in MyProblemInterface are the same "type". For example, if I have ADataDto, BDataDto, ASetDto<ADataDto>, BSetDto<BDataDto>, AResults<ASetDto>, BResults<BSetDto>, I want to ensure a class can't implement MyProblemInterface in a manner like AMyProblemInterface<ADataDto, ASetDto, BResults>. I would think that since MySetDto extends SetDto<MyDataDto> just fine, I could continue to take that further, but I'm apparently wrong.
Thank you for any help.
You want too much from Java generics.
It would be simpler to declare your interface as following:
public interface MyProblemInterface<MyDataDto extends DataDto>
And then force method to use SetDto<MyDataDto> and Results<MySetDto>.
By using generics in class/interface declaration you specify some kind of variety which is determined later in definition. But in your case you said that SetDto and Results will always have MyDataDto as parameter, so there is no variety.
Shouldn't it be something like this instead, and you add the actual classes only when implementing the interfaces.
Updated the code, because I forgot to add the right Results definition. This should work.
public interface DataDto {
// some data here
}
public interface SetDto<T extends DataDto> {
List<T> getData();
}
public interface Results<T extends SetDto<? extends DataDto>> {
T getResults();
}
public interface MyProblemInterface<T extends DataDto, E extends SetDto<T>, K extends Results<E>> {
// some stuff here
}

Categories

Resources