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);
}
}
Related
I don't how to phrase this, so I'll drop an example
class AbstractUser<A extends AbstractAccount<? extends AbstractType>> {
// I want a method that has access to Type
// And returns the specific Type that extends AbstractType
protected <T extends AbstractType> T doSomething(T type) {
// do stuff
// and return the type specific type T
}
}
class AbstractAccount<T extends AbstractType> {
}
class AbstractType {
}
class Type extends AbstractType {
}
class Account extends AbstractAccount<Type> {
}
class AccountAdmin extends AbstractAccount<Type> {
}
class User extends AbstractUser<Account> {
}
What I want in this is that within User class I can do getType() and it returns the the specific type of AbstractAccount, in this case Account.
How do I do this without specifying any more templates? In other words, I want whatever type the ? in ? extends AbstractType is to be in that method
So if I do
final Account account = ...
final AccountAdmin admin = ...
final User user = ...
user.doSomething(account); // should work
user.doSomething(AccountAdmin); // should fail
You obviously can't create a method in AbstractUser like this:
public Class<A> getType() { return A.class; }
This is because of type erasure. The runtime does not know what A is.
So one workaround is to make this method abstract:
public abstract Class<A> getType();
Now, you can implement this method in subclasses:
class User extends AbstractUser<Account> {
public Class<Account> getType() { return Account.class; }
}
EDIT:
Now I realised you want the type that extends AbstractType, the workaround should still work. You just need to create another getType in AbstractAccount and make Account implement that method.
You can't really get around binding another type parameter in AbstractUser for this purpose:
class AbstractUser<T extends AbstractType, A extends AbstractAccount<T>> {
protected abstract T getType();
}
You need a way to reference the type of A's type parameter, and this serves that purpose.
As of Java 8 you could define a constructor which takes a Supplier returning instances of the appropriate type.
You said:
What I want in this is that within User class I can do getType() and it returns the the specific type of AbstractAccount, in this case Account.
And you want: doSomething(T type).
Thus I assume, you don't want a Class<T> but an instance of T to work with. As of your example this T should be Account.
According to this:
class AbstractUser<T extends AbstractType, A extends AbstractAccount<T>> {
private Supplier<T> accountSupplier;
public AbstractUser(Supplier<T> accountSupplier) {
this.accountSupplier = accountSupplier;
}
protected T getType() {
return accountSupplier.get();
}
}
Then class User would look as follows:
class User extends AbstractUser<Type, Account> {
public User() {
super(Account::new);
}
}
Please note that the class AbstractUser is still not declared abstract. If the only reason to have this class is providing different types of AbstractAccount by subclasses, then now we can do it without subclasses.
User user = new User(); can be rewritten as AbstractUser user = new AbstractUser(Type::new); (in this case AbstractUser is not the best name).
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.
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.
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.
I have run into a problem with generics in Java and I can't find a solution or example online of someone using generics in a similar fashion. I have a set of methods that are in the same request/response structure. For example, a user populates fields in the Request object, passes the object to a helper method, and they are returned a Response object. All of my request objects extend from a common Request super class (and similarly, Response objects from a Response super class). I would like my helper classes to also have a consistent structure so I have used an interface. Here is some code to illustrate...
Request super class:
public class SuperRequest {
// ...
}
Example Request subclass:
public class SubRequest extends SuperRequest {
// ...
}
Response super class:
public class SuperResponse {
// ...
}
Example response subclass:
public class SubResponse extends SuperResponse{
// ...
}
The interface:
public interface SomeInterface {
public <T extends SuperRequest, U extends SuperResponse> U someMethod(T request);
}
As you can see from the interface, I want to pass an object that is a child of SuperRequest and I want to return an object that is a child of SuperResponse. Here is my implementation:
public class SomeImplementation implements SomeInterface {
#Override
public SubResponse someMethod(SubRequest request) {
return null;
}
}
In Eclipse, I get compilation errors because the compiler tells me I have unimplemented methods and the #Override notation "does not override a supertype method".
Can anyone help me here? Is my syntax incorrect or is my understanding of generics a little off? Any help is greatly appreciated!
Try changing your interface and implementation to:
interface SomeInterface<T extends SuperRequest, U extends SuperResponse> {
public U someMethod(T request);
}
class SomeImplementation implements SomeInterface<SubRequest, SubResponse> {
#Override
public SubResponse someMethod(SubRequest request) {
return null;
}
}
As it stands, the implementation of SomeInterface must implement the parameterized method, i.e.:
public <T extends SuperRequest, U extends SuperResponse> U someMethod(T request);
It can't choose a particular Subclass to substitute for T and U.
The interface itself must be generic SomeInterface<T extends SuperRequest, U extends SuperResponse> and the subclass can then choose concrete implementations for T and U.
You have to declare the types as well when you implement the interface. Try this:
public class SomeImplementation implements SomeInterface<SubRequest,SubResponse> {
#Override
public SubResponse someMethod(SubRequest request) {
return null;
}
}