2012-10-24 16 views
8
public <S extends T> List<S> save(Iterable<S> entities) { 
     //... 
} 

jeśli mogę użyć następującą metodę, aby zastąpićJava: Jak zastąpić tę ogólną metodę?

@Override 
public List<MyType> save(Iterable<MyType> structures) { 
    List<MyType> result = new ArrayList<>(); 
    //... 
    return result; 
} 

dostaję następujący błąd:

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 

Jak mogę rozwiązać ten problem? Nie potrzebuję tej metody, aby była ogólna i tak naprawdę nie powinna być. Chodzi mi o to, że

@Override 
public <S extends MyType> List<S> save(Iterable<S> structures) { 
    List<S> result = new ArrayList<>(); 
    //... 
    return result; 
} 

nie będzie działać zgodnie z metodą można utworzyć nowy obiekt z MyType który nie jest „kompatybilna” do listy.

Jak mogę to ułatwić?

EDYTOWANIE:

W celu wyjaśnienia. Próbuję zastępują różne save() metody danych wiosennym SimpleJpaRepository (który jest oporny przez QuerydslJpaRepository)

defintions Klasa:

public class MyTypeRepositoryImpl 
    extends QueryDslJpaRepository<MyType, Long> 
    implements MyTypeRepository 

@NoRepositoryBean 
public interface MyTypeRepository 
    extends JpaRepository<MyType, Long>, 
    QueryDslPredicateExecutor<MyType> 

I (od wiosny Danych)

public class QueryDslJpaRepository<T, ID extends Serializable> 
extends SimpleJpaRepository<T, ID> 
implements QueryDslPredicateExecutor<T> 

EDYCJA 2:

Metoda wywołuje zapis (element MyType) dla każdego elementu i ta metoda zawiera następującą logikę:

  1. jednostka ma pole, które jest unikalne
  2. get że pola wartości i sprawdzić, czy podmiot z tej wartości już istnieje
  3. jeśli tak, należy ten podmiot (wezwanie do EntityManager.merge) -> nie działa powraca MyType nie S
  4. jeśli nie utworzysz nowego -> tutaj tworzony jest nowy obiekt. Nie działa z typowym typem:

Dla 4. Mogę ustawić id = null i użyć przekazanego obiektu. To nie działa dla 3.

Więc jestem bardzo zdziwiony, dlaczego ta metoda ma ten podpis. To czyni go bezużytecznym dla mnie i nie rozumiem dlaczego zapisałbym podklasę T używając Ts DAO. metody zapisu są jedynymi, z którymi. Wszyscy inni po prostu używają T. Mogłem po prostu rzucić na S, aby go skompilować, ale to też wydaje się brzydkie ... jak każdy inny typ niż T, prowadziłby do wyjątku.

+0

W jaki sposób deklarowane są klasy zawierające? – assylias

+0

co masz na myśli, mówiąc, że nie jest "zgodny" z listą? Wygląda na to, że z oryginalnego parametru '' klasa jest stworzona tak, aby można jej było używać, wykonując coś w rodzaju 'implementuje InterfaceName ' bez konieczności mieszania się z podklasą –

+0

Od komentarzy do innych odpowiedzi i faktu, że jesteś rozszerzając klasę, nad którą nie masz kontroli, wierzę, że jesteś zmuszony do użycia 'public List save (Iterable struktur)'. Dzieje się tak dlatego, że zastąpiona metoda jest generyczna, a więc musi być również metoda overridding. –

Odpowiedz

0

Moje rozwiązanie było nie zastąpi to w ogóle, ale do stworzenia klasy usług, które wykonuje niezbędną logikę i pozostawić nietknięte repozytorium.

+1

Bez urazy, ale nie jest to rozwiązanie twojego problemu, które zadeklarowałeś w pytaniu, stąd też nie jest to "najlepsza" odpowiedź. to, co skończyłoście, to praca – asgs

8

Dla jednej metody nadpisania innej musi ona dotyczyć co najmniej wszystkich poprawnych parametrów metody nadpisanej. Twoja podstawowa metoda jest generyczna public <S extends T> List<S> save(Iterable<S> entities). Tak więc akceptuje każdy typ S, który rozszerza się o T. Jednak przesłonięcie jest bardziej restrykcyjne, ponieważ akceptuje tylko kolekcje o wartości MyType, dlatego nie jest poprawnym przesłonięciem.

Jeśli miał swoją klasę podstawową definicją z T, a metoda przyjęta tylko T, a klasa pochodna zablokowana T do MyType powinno być OK.

Aby dać lepszą odpowiedź, musimy zobaczyć deklaracje klas dla dwóch klas. Proponuję następujące:

class MyClass<T>{ 
    public List<T> save(Iterable<T> entities); 
} 

class OtherClass extends MyClass<MyType>{ 
    public List<MyType> save(Iterable<MyType> entities); 
} 

EDIT:

Jeśli nie masz kontroli nad klasie bazowej (co wydaje się, że nie), utkniesz z podpisem public <S extends MyType> List<S> save(Iterable<S> structures). To dlatego, że metoda zastąpiona jest genericized i dlatego metoda overridding musi być również

1

Od

public <S extends T> List<S> save(Iterable<S> entities) 

zostanie podany Twój korekcja musi być dla

public <S extends MyType> List<S> save(Iterable<S> structures) 

i implementacja musi respektować, że S może być prawdziwym podtypem MyType.

Twoje podejście

public List<MyType> save(Iterable<MyType> structures) 

nie jest prawidłowa korekcja:

  • od Java> = 1.5 pozwala covariant rodzajów powrotów i List<MyType> jest podtypem List<S extends MyType>, to jest ok, ale
  • Java zezwala tylko na niezmienne typy parametrów, ale Iterable<MyType> jest podtypem Iterable<S extends MyType>, stąd komunikat o błędzie kompilatora.
+0

Nie deklaruję metody, którą przesłoniłem. To istniejąca klasa z Spring Data. Zobacz edycję. –

+0

IC, przyjęła moją odpowiedź odpowiednio. – DaveFar

2

Oto przykład, który kompiluje i pokazuje, jak z niego korzystać:

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

Klasa A definiuje metodę z oryginalnym podpisem. klasa B implementuje ją i wybiera List<Integer> dla parametru typu T. I wreszcie, klasa C używa tej metody z typem ogólnej kurwy Iterable jest podklasą List<Integer>.

+0

Rozumiem. Ale nie potrzebuję . T jest ustalonym typem, np. zawsze ten sam typ, a T jest klasą końcową.Poza tym, w zależności od danych wejściowych, tworzę nowy obiekt MyType w metodzie. Mytype newObject = new MyType (args); To nie działa z S. –

+0

Confused. Jeśli do 'T' używana jest klasa końcowa, to nie znajdziesz klasy dla' S', która czyni metodę zupełnie bezużyteczną (dla tego przypadku) –

+0

Czy T nie spełnia S? Teraz też jestem zdezorientowany. : O –

3

Zależy jak zdefiniowano następujące prace

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); 
    } 
} 
Powiązane problemy