Referencja do metody w klasie generycznej.

0

Witam,
Szukam pomocy, gdyż mam problem z przerobieniem klasy na generyczną, a dokładniej referencją do niej metody.
Jako dodatek, ale nie jest to dla mnie wymagane fajnie by było, gdyby była możliwość przypisania referencji do metody na podstawie klasy, czyli :
Podajemy jako parametr klasa1 i jest tutaj np refleksja(tak to się chyba nazywa) MetodaKlasa1Metoda.
Chyba, że całkowicie inaczej powinienem to zrobić, bo się inaczej do tego zabieram.

Poniżej kod, jak to wygląda, a problem leży w implementacji generyka w klasie GetQueryUserDetailService

public abstract class GetQueryAbstractService<B, R> {

    @PersistenceContext
    protected EntityManager entityManager;

    protected abstract Class<B> getClazz();

    protected abstract Predicate getPredicate(Predicate predicate, CriteriaBuilder builder, Root r, List<SearchCriteria> params);

    protected abstract List<R> getDtos(CriteriaQuery<B> query);

    public List<R> execute(String search) {
        final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        final CriteriaQuery<B> query = builder.createQuery(getClazz());
        final Root r = query.from(getClazz());

        List<SearchCriteria> params = new ArrayList<>();
        if (search != null) {
            Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),");
            Matcher matcher = pattern.matcher(search + ",");
            while (matcher.find()) {
                params.add(new SearchCriteria(matcher.group(1), matcher.group(2), matcher.group(3)));
            }
        }

        Predicate predicate = builder.conjunction();
        predicate = getPredicate(predicate, builder, r, params);
        query.where(predicate);

        return getDtos(query);
    }
}
@Service
public class GetQueryUserDetailService extends GetQueryAbstractService<UserDetail, UserDetail.UserDetailDto> {

    @Override
    protected Class<UserDetail> getClazz() {
        return UserDetail.class;
    }

    @Override
    protected Predicate getPredicate(Predicate predicate, CriteriaBuilder builder, Root r, List<SearchCriteria> params) {
        UserSearchQueryCriteriaConsumer searchConsumer = new UserSearchQueryCriteriaConsumer(predicate, builder, r);
        params.forEach(searchConsumer);
        return searchConsumer.getPredicate();
    }

    @Override
    protected List<UserDetail.UserDetailDto> getDtos(CriteriaQuery<UserDetail> query) {
        return entityManager
                .createQuery(query)
                .getResultStream()
                .map(UserDetail::toUserDetailDto)
                .collect(Collectors.toList());
    }
}

Mam problem z : map(UserDetail::toUserDetailDto) , chyba że to nie działa, bo źle podaję genęryki.
Oczywiście, żeby kod był sprawny, to nie implementowałem powyżej wartości generycznych, żeby nie zrobić burdelu w kodzie.

Za pomoc/ wskazówki z góry dziękuje.

0

Tak linijka będzie działa, pod warunkiem że w UserDetail masz funkcje:

public class UserDetail {
    public UserDetailDto toUserDetailDto() {

albo jeśli jest statyczna

public class UserDetail {
    public static UserDetailDto toUserDetailDto(UserDetail ) {

Jeśli nie, to nie będzie działać. Najlepiej pokaż kod UserDetail.

0

Nie wiem czy to nie moja godzina, czy inny powód, ale za nic nie potrafię zrozumieć tego co napisałeś 😶

0

@QuantumComp:

TomRiddle napisał(a):

Najlepiej pokaż kod UserDetail.

0

Kurde, może faktycznie mogłem to napisać po rusku ,postaram się to inaczej opisać.

@TomRiddle ten kod działa, wraz z mapowaniem, tylko ja chcę to przerobić na klasę generyczną, czyli w tym przypadku by było:
.map(T::R)

@QuantumComp up

0

@Nowak Adam: aaa. tak się nie da.

1

Musisz albo wydzielić interfejs, albo przekazać Function<R,U> jako parametr.

1
Nowak Adam napisał(a):

Byłbyś w stanie napisać jakiś pseudo kod, czy coś, bo nie wiem, czy rozumiem. Mam po prostu stworzyć osobną klasę generyczną, której zadanie będzie tylko przekazanie R,U jako parametr? A wtedy tamtą funkcją przerobić, żeby przyjmowała od niej ten parametr ?

Tak na prawdę to zależy od tego co chcesz zrobić. Czy te parametry które chcesz przekazać tymi generykami mają zawsze tą samą metodę? Np wszystkie mają mapToDto()? Czy mają różne? np mapToDto, mapToCount(), mapToTable(), mapToView(), etc.

3
Nowak Adam napisał(a):

Właśnie wszędzie jest ta sam schemat czyli np : Klasa1 a tam toKlasa1Dto Klasa2 a tam toKlasa2Dto etc

No to masz dwie opcje.

Albo zrobić nowy interfejs generyczny (interface Klasa<R> { R map() }) , że każda z Twoich klas Klasa1, Klasa2 go będzie implementowała (tzn Klasa1 implements Klasa, Klasa2 implements Klasa, etc.)

Albo, możesz przekazać parametr do swojej klasy abstrakcyjnej.

1

Można też trochę inaczej podejść do tego co napisał @TomRiddle, czyli zrobić sobie interfejs Mapper<FROM,TO> z metodą TO map(FROM obj) i taki interfejs przekazywać jako dodatkowy parametr do GetQueryAbstractService. Jeżeli być skorzystał z jakiejś biblioteki do mapowania opartej o refleksje (nie powiem że to polecam) to dało by radę obejść się i bez tego parametru.

Alternatywnie możesz dołożyć extra metodę abstrakcyjną która wykona wspomniane tutaj mapowanie typu:

abstract DTO map(ENTITY entityt);

Dla masochistów: da radę to również zrobić refleksją, gdzie na podstawie klasy encji i docelowego DTO budujesz interfejs Function<A,R> - ale będzie to wolne i podatne na błędy.

PS. Pattern warto skompilować raz na poziomie klasy. O ile dobrze pamiętam skompilowane Patterny są thread-safe...

1 użytkowników online, w tym zalogowanych: 0, gości: 1