Java:How to override this generic method?
Solution 1
My solution was to not override this at all but to create a service class that does the needed logic and leave repository untouched.
Solution 2
For one method to override another it must apply to at least all valid parameters of the overridden method. Your base method is generic public <S extends T> List<S> save(Iterable<S> entities)
. So it will accept any type S
that extends T
. However your override is more restrictive because it will only accept collections of MyType
, therefore it is not a valid override.
If you had your base class defined with T
, and the method accepted just T
, and the derived class locked down T
to MyType
you should be OK.
To give a better answer we need to see the class declarations for the two classes. I would suggest the following:
class MyClass<T>{
public List<T> save(Iterable<T> entities);
}
class OtherClass extends MyClass<MyType>{
public List<MyType> save(Iterable<MyType> entities);
}
EDIT:
If you don't have control over the base class (which it seems that you don't), you are stuck with the public <S extends MyType> List<S> save(Iterable<S> structures)
signature. This is because the overridden method is genericized and so the overridding method must also be
Solution 3
Depends on how you have defined , the following works
public class TestGenerics2<T> {
public <S extends T> List<S> save(Iterable<S> entities) {
return new ArrayList<S>();
}
}
public class TestGenerics3 extends TestGenerics2<Number> {
@Override
public <S extends Number> List<S> save(Iterable<S> entities) {
return super.save(entities);
}
}
Solution 4
Here's an example that compiles and that shows how to use it:
abstract class A<T> {
abstract public <S extends T> List<S> save(Iterable<S> entities);
}
class B extends A<List<Integer>> {
@Override
public <S extends List<Integer>> List<S> save(Iterable<S> entities) {
return null;
}
}
class C {
public void useIt() {
B b = new B();
Iterable<ArrayList<Integer>> it = new ArrayList<ArrayList<Integer>>();
b.save(it);
}
}
Class A
defines the method with the original signature. class B
implements it and chooses List<Integer>
for type parameter T
. And finally, class C
uses this method with an Iterable
whore generic type is a subclass of List<Integer>
.
Solution 5
Since
public <S extends T> List<S> save(Iterable<S> entities)
is given, your override must be for
public <S extends MyType> List<S> save(Iterable<S> structures)
and your implementation must respect that S might be a real subtype of MyType.
Your approach
public List<MyType> save(Iterable<MyType> structures)
is not a correct override:
- since Java >=1.5 allows covariant return types and
List<MyType>
is a subtype ofList<S extends MyType>
, this is ok, but - Java only allows invariant parameter types, but
Iterable<MyType>
is a subtype ofIterable<S extends MyType>
, hence your compiler error message.
beginner_
Updated on June 05, 2022Comments
-
beginner_ almost 2 years
public <S extends T> List<S> save(Iterable<S> entities) { //... }
If I use following method to override
@Override public List<MyType> save(Iterable<MyType> structures) { List<MyType> result = new ArrayList<>(); //... return result; }
I get following error:
method does not override or implement a method from a supertype name clash: save(Iterable<MyType>) in MyTypeRepositoryImpl and <S>save(Iterable<S>) in SimpleJpaRepository have the same erasure, yet neither overrides the other where S,T are type-variables: S extends T declared in method <S>save(Iterable<S>) T extends Object declared in class SimpleJpaRepository
How can I solve this? I don't need the method to be generic and in fact it should not be. What I mean is that
@Override public <S extends MyType> List<S> save(Iterable<S> structures) { List<S> result = new ArrayList<>(); //... return result; }
Will not work as the method can create a new Object of MyType which is not "compatible" to List.
How can I make this work?
EDIT:
For clarification. I'm trying to override the different save() methods of Spring data SimpleJpaRepository (which is extented by QuerydslJpaRepository)
Class defintions:
public class MyTypeRepositoryImpl extends QueryDslJpaRepository<MyType, Long> implements MyTypeRepository @NoRepositoryBean public interface MyTypeRepository extends JpaRepository<MyType, Long>, QueryDslPredicateExecutor<MyType>
And this (from Spring Data)
public class QueryDslJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements QueryDslPredicateExecutor<T>
EDIT 2:
The method calls save(MyType entity) for each element and that method contains following logic:
- entity has a field which is unique
- get that fields value and check if entity with that value already exists
- if yes, use that entity (call to entityManager.merge) -> does not work returns MyType not S
- if no create a new one -> here new object is created. Does not work with generic type
For 4. I can just set id = null and use the passed in object. That does not work for 3.
So I'm very puzzled why this method has this signature. It makes it unusable for me and i don't get why I would save a subclass of T using Ts DAO. the save methods are the only ones with . All others just use T. I could just cast to S to make it compile but that seems ugly too...as any other type than T would lead to an exception.
-
beginner_ over 11 yearsI'm not declaring the method I override. It's an existing class from Spring Data. See edit.
-
beginner_ over 11 yearsI get that. But I do not need the <S extends T>. T is a fixed Type, eg. always the same type, and T is a final class. Besides that depending on input I'm creating a new Object of MyType in the method. Mytype newObject = new MyType(args); That does not work with S.
-
Andreas Dolk over 11 yearsConfused. If a final class is used for
T
then you won't find a class forS
which makes the method quite unusable (for this case) -
DaveFar over 11 yearsIC, adopted my answer accordingly.
-
beginner_ over 11 yearsDoesn't T fulfill S? I'm confused now too. :O
-
beginner_ over 11 yearsSorry. I was wrong. I wanted the class to be final but it is an Entity and the can't be final.
-
asgs over 6 yearsNo offence, but this is not a solution to your problem you have stated in the question, hence not the "best" answer either. what you've ended up doing is a work around