Lista/tablica klas dziedziczących po klasie abstrakcyjnej/interfejsie

0

Hej
Czy jest w ogóle jakiś sposób na wyciągnięcie listy/tablicy klas dziedziczących po klasie abstrakcyjnej lub interfejsie? Np. mamy klasę abstrakcyjną Osoba i mamy po niej klasy dziedziczące Nauczyciel, Uczeń, Dyrektor. I czy jest jakiś prosty sposób wyciągnięcia z klasy Osoba, które klasy po niej dziedziczą? Przejrzałem chyba większość metod, ale nie znalazłem, a na stacku coś chyba kiepsko wyszukuję, bo wyskakuje mi nie to co bym chciał

2

Zakładając pozytwyną interpretację, że odróżniasz klasę od obiektu, listę klas można uzyskać przez refleksję skanując cały JAR, idąc od córek (tzn matka nie wie, jakie ma córki)
Ale sądzę, że to nadmiar optymizmu.

5

W programowaniu obiektowym nie powinieneś potrzebować takiej wiedzy. Jeżeli potrzebujesz, to na 99.999% coś ostro zrąbałeś.

Wszystkie klasy w jakimś tam pakiecie możesz znaleźć tak:

 Reflections reflections = new Reflections("my.project.prefix");

 Set<Class<? extends Object>> allClasses = 
     reflections.getSubTypesOf(Object.class);
     

Pozostaje odfiltrować te, które nie spełniają warunków https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#isAssignableFrom-java.lang.Class-

3

Jeszcze możesz użyć sealed classy i wtedy zawolać

Osoba.class.getPermittedSubclasses()

Tylko wtedy musisz zadeklarować, które klasy mogą po niej dziedziczyć

abstract sealed class Osoba permits Nauczyciel, Uczeń, Dyrektor
3

Ale po co?

0

Widzę, że temat dosyć zaintrygował. Dzięki wielkie za wszelkie odpowiedzi i pomoc!

Riddle napisał(a):

Ale po co?

A no uczę się i testuję różne rozwiązania do różnych problemów. W tym przypadku jest to walidacja parametrów i wiem, że można to rozwiązać na parę sposobów, w tym zacząłem się zastanawiać czy jest może taka opcja. Szczerze to myślałem, że może jest wewnętrzny mechanizm w Javie, który zapisuje w pamięci wszystkie klasy dziedziczące po danej klasie i jest metoda w nadklasach, która zwraca te klasy. Fajnie, że jest to rozwiązanie z tą refleksją i sobie to potestuje z tym, że wiemy, że projektowo jest to kiepsko wydajne ze względu na skanowanie całej paczki.

1
kilroy napisał(a):

Widzę, że temat dosyć zaintrygował. Dzięki wielkie za wszelkie odpowiedzi i pomoc!

Riddle napisał(a):

Ale po co?

A no uczę się i testuję różne rozwiązania do różnych problemów. W tym przypadku jest to walidacja parametrów i wiem, że można to rozwiązać na parę sposobów, w tym zacząłem się zastanawiać czy jest może taka opcja. Szczerze to myślałem, że może jest wewnętrzny mechanizm w Javie, który zapisuje w pamięci wszystkie klasy dziedziczące po danej klasie i jest metoda w nadklasach, która zwraca te klasy. Fajnie, że jest to rozwiązanie z tą refleksją i sobie to potestuje z tym, że wiemy, że projektowo jest to kiepsko wydajne ze względu na skanowanie całej paczki.

To jest po prostu słabe technicznie rozwiązanie.

Kiedy ktoś dodaje nową klasę, to nie spodziewa się że coś innego zacznie wtedy działać inaczej.

Do walidacji używa się innych rozwiązań.

0
Riddle napisał(a):

Kiedy ktoś dodaje nową klasę, to nie spodziewa się że coś innego zacznie wtedy działać inaczej.

Rozumiem, też prawda.

Do walidacji używa się innych rozwiązań.

Tak, tak, oczywiście i tam tam parę znam i używam, ale jestem po prostu ciekaw kolejnych możliwości, rozszerzam moją wiedzę początkującego :) dzięki wielkie!

1
kilroy napisał(a):

Szczerze to myślałem, że może jest wewnętrzny mechanizm w Javie, który zapisuje w pamięci wszystkie klasy dziedziczące po danej klasie i jest metoda w nadklasach, która zwraca te klasy

Takiego mechanizmu być nie może (przynajmniej tak jak Java jest zbudowana) bo zawsze można dodac nową implementację istniejącego interfejsu. Dlatego trzeba przeszukać wszystkie załadowane Jary.
Z drugiej strony takie rozwiązanie niekoniecznie jest wolne jeśli wynik przeszukiwania będziesz trzymał w Cache'u. Tak właśnie działa Spring przy wyszukiwaniu adnotacji @Service

Drugim rozwiązaniem jest zakazanie implementacji interfejsu za pomocą sealed classes. Nikt nie będzie mógł tworzyć dodatkowych implementacji i wszystkie implementacje będą znane podczas kompilacji i nie będzie trzeba przeszukiwać Jara

0
KamilAdam napisał(a):

... jeśli wynik przeszukiwania będziesz trzymał w Cache'u. Tak właśnie działa Spring przy wyszukiwaniu adnotacji @Service

"Trochę" to uprościłeś ... to juz nie używają aspektów, code wearing i hw co jeszcze? To jak od jutra zostanę sprigowcem ...

Z drugiej strony takie rozwiązanie niekoniecznie jest wolne jeśli wynik przeszukiwania będziesz trzymał w Cache'u. Tak właśnie działa Spring przy wyszukiwaniu adnotacji @Service

Całe szczęście, że użytkownik apki webowej doświadcza jej już załadownej, z rozwiązanymi zależnościami, rozgrzanej, itd.

W "przypadku ogólnym", np desktop albo command line, najpierw przygasają żarówki we wsi, a potem już jest dobrze.

Riddle napisał(a):

Ale po co?

+1, 2, 5, ile chcesz.

piotrpo napisał(a):

W programowaniu obiektowym nie powinieneś potrzebować takiej wiedzy. Jeżeli potrzebujesz, to na 99.999% coś ostro zrąbałeś.

+1

@kilroy:
jeśli (wydaje ci się że ) potrzebujesz, tzn masz spieprzony projekt obiektowy na 200%

0
piotrpo napisał(a):

W programowaniu obiektowym nie powinieneś potrzebować takiej wiedzy. Jeżeli potrzebujesz, to na 99.999% coś ostro zrąbałeś.

Ale się uwzieliści :D
Czyli jak robisz system plaginów dziedziczących po interfejsie Plugin to to nie jest obiektowe. No fajnie. A ktoś ma pomysł jak to zrobić obiektowo? A może nie zawsze trzeba robić kod obiektowo?

0
piotrpo napisał(a):

W programowaniu obiektowym nie powinieneś potrzebować takiej wiedzy. Jeżeli potrzebujesz, to na 99.999% coś ostro zrąbałeś.

E?

Ja bym po prostu powiedział: "na 99% nie potrzebujesz takiej wiedzy". Nie ważne w jakim paradygmacie. Taki meta-programming to ma sens w bardzo, bardzo, bardzo wąskich rejonach.

KamilAdam napisał(a):
piotrpo napisał(a):

W programowaniu obiektowym nie powinieneś potrzebować takiej wiedzy. Jeżeli potrzebujesz, to na 99.999% coś ostro zrąbałeś.

Ale się uwzieliści :D
Czyli jak robisz system plaginów dziedziczących po interfejsie Plugin to to nie jest obiektowe. No fajnie. A ktoś ma pomysł jak to zrobić obiektowo?

No ja mam. Nie potrzebujesz tak czy tak znać klasy dokładnej żeby zrobić plugin.

A może nie zawsze trzeba robić kod obiektowo?

Możesz sobie wybrać paradygmat jaki chcesz. Ale to moim zdaniem błąd wybrać paradygmat, powiedzmy obiektowy, a potem doszukiwać się w projekcie niemożliwości użycia go.

0
KamilAdam napisał(a):
piotrpo napisał(a):

W programowaniu obiektowym nie powinieneś potrzebować takiej wiedzy. Jeżeli potrzebujesz, to na 99.999% coś ostro zrąbałeś.

Ale się uwzieliści :D
Czyli jak robisz system plaginów dziedziczących po interfejsie Plugin to to nie jest obiektowe. No fajnie. A ktoś ma pomysł jak to zrobić obiektowo?

No ja mam. Nie potrzebujesz tak czy tak znać klasy dokładnej żeby zrobić plugin.

To mie teraz zaciekawiłeś. Bo jak ja robiłem system pluginów jako junior to przeszukiwałem całego classPatha w Javie żeby znaleźć klasy implementujące interface Plugin (o szczegóły nie pytaj bo już nie mamiętam :D ). Zaletą było to że pluginów nie trzeba było w żaden sposób rejestrować. Po prostu dorzucało się nowego Jara do tomcata (to była naprawdę stara aplikacja). Jak zrobiłeś pluginy bez przeszukiwania ClassPatha? Czy rejestrujesz pluginy?

0
KamilAdam napisał(a):

No ja mam. Nie potrzebujesz tak czy tak znać klasy dokładnej żeby zrobić plugin.

To mie teraz zaciekawiłeś. Bo jak ja robiłem system pluginów jako junior to przeszukiwałem całego classPatha w Javie żeby znaleźć klasy implementujące interface Plugin (o szczegóły nie pytaj bo już nie mamiętam :D ). Zaletą było to że pluginów nie trzeba było w żaden sposób rejestrować. Po prostu dorzucało się nowego Jara do tomcata (to była naprawdę stara aplikacja). Jak zrobiłeś pluginy bez przeszukiwania ClassPatha? Czy rejestrujesz pluginy?

Skanowanie w tym przypadku miało innych charakter, niż powyżej, bardziej "fizyczny" niż "logiczny.""

A w dodatku (jakby) pluginy do "centrali" mogą się zgłaszać przez mechanizm "services", chyba od Javy 5 albo 6, własnoręczne skanowanie jest zbędne.
https://www.baeldung.com/java-spi

Riddle napisał(a):

No ja mam. Nie potrzebujesz tak czy tak znać klasy dokładnej żeby zrobić plugin.

+1

2
KamilAdam napisał(a):

To mie teraz zaciekawiłeś. Bo jak ja robiłem system pluginów jako junior to przeszukiwałem całego classPatha w Javie żeby znaleźć klasy implementujące interface Plugin (o szczegóły nie pytaj bo już nie mamiętam :D ). Zaletą było to że pluginów nie trzeba było w żaden sposób rejestrować. Po prostu dorzucało się nowego Jara do tomcata (to była naprawdę stara aplikacja). Jak zrobiłeś pluginy bez przeszukiwania ClassPatha? Czy rejestrujesz pluginy?

Ale Ty teraz nie mówisz o programowaniu pluginów, tylko o ich automatycznym ładowaniu/dodawaniu/rejestrowaniu.

A zauważ że takie coś jak "automatyczne robienie czegokolwiek" zahacza o metaprogramming.

Odpowiadając na Twoje pytanie, ja robiłem explicit rejestrowanie, i podoba mi się to. Że jak ja nie zarejestruje jawnie pluginu, to po prostu się nie doda. Uważam to za dużo lepsze podejście, explicit jest lepsze niż implicit.

0

@KamilAdam może się nie zrozumieliśmy.

Rozumiem że wymaganie jest takie, że masz włożyć jar'a, i ma działać. Spoko.

Tylko czemu nie zaprogramować tego normalnie, bez żadnych refleksji i bez żadnego automatycznego znajdowania dzieci klasy?

0
Riddle napisał(a):

Tylko czemu nie zaprogramować tego normalnie, bez żadnych refleksji i bez żadnego automatycznego znajdowania dzieci klasy?

Bo byłem juniorem i nie umiałem. Architekt też nie umiał i techniczny kierownik też nie umiał :D

0
KamilAdam napisał(a):
Riddle napisał(a):

Tylko czemu nie zaprogramować tego normalnie, bez żadnych refleksji i bez żadnego automatycznego znajdowania dzieci klasy?

Bo byłem juniorem i nie umiałem. Architekt też nie umiał i techniczny kierownik też nie umiał :D

Ale to jest proste. Zwykle używanie zwykłych klas javowych, bez żadnych refleksji i metaprogramingu i żadnej automagii.

0
Riddle napisał(a):
KamilAdam napisał(a):
Riddle napisał(a):

Tylko czemu nie zaprogramować tego normalnie, bez żadnych refleksji i bez żadnego automatycznego znajdowania dzieci klasy?

Bo byłem juniorem i nie umiałem. Architekt też nie umiał i techniczny kierownik też nie umiał :D

Ale to jest proste. Zwykle używanie zwykłych klas javowych, bez żadnych refleksji i metaprogramingu i żadnej automagii.

No to jakbyś to zrobił? Dla wyjaśnienia hostoryjka działania

  1. Aplikacjia działa normalnie na tomcacie
  2. Dorzucamy nowego Jara z pluginem
  3. Resetujemy aplikację
  4. Mamy zainstalowane nowe pluginy
1
KamilAdam napisał(a):
Riddle napisał(a):
KamilAdam napisał(a):
Riddle napisał(a):

Tylko czemu nie zaprogramować tego normalnie, bez żadnych refleksji i bez żadnego automatycznego znajdowania dzieci klasy?

Bo byłem juniorem i nie umiałem. Architekt też nie umiał i techniczny kierownik też nie umiał :D

Ale to jest proste. Zwykle używanie zwykłych klas javowych, bez żadnych refleksji i metaprogramingu i żadnej automagii.

No to jakbyś to zrobił? Dla wyjaśnienia hostoryjka działania

  1. Aplikacjia działa normalnie na tomcacie
  2. Dorzucamy nowego Jara z pluginem
  3. Resetujemy aplikację
  4. Mamy zainstalowane nowe pluginy

No wystawić Plugins.add(Plugin) z głównej aplikacji, i kod z .jara zawoła Plugin.add(this) dodając się. A jak nie chcesz, to możesz nawet te Plugins wsadzić do jescze osobnego jara.

0
Riddle napisał(a):

@KamilAdam może się nie zrozumieliśmy.

Rozumiem że wymaganie jest takie, że masz włożyć jar'a, i ma działać. Spoko.

Wasza dyskusja, (skądinąd dawno nie ma nic wspólnego z pierwotnym pytanie) warto aby dopowiedzieć:
a) włożyć w umówione miejsce i podnieść proces "main" (SPI powyzej)
b) uruchomić podczas runtime (OSGI??? nigdy nie poznałem tego std, zawsze sobie obiecywałem "później" Kochajmy kontenerowe standardy, tak szybko umierają)

1

A to nie jest tak, że np. takie serwery aplikacyjne tak sobie doczytywały "dynamicznie" dajmy na to różne sterowniki jdbc? Zresztą nawet to oryginalne, dziwne sprawdzanie odpowiedniego sterownika Class.forName("") było oparte o refleksje, a zakładam, że nawiązywanie połączenia też musi dość ostro rzeźbić refleksjami.

2
piotrpo napisał(a):

A to nie jest tak, że np. takie serwery aplikacyjne tak sobie doczytywały "dynamicznie" dajmy na to różne sterowniki jdbc? Zresztą nawet to oryginalne, dziwne sprawdzanie odpowiedniego sterownika Class.forName("") było oparte o refleksje, a zakładam, że nawiązywanie połączenia też misi dość ostro rzeźbić refleksjami.

Sterowniki JDBC od "miliona lat" zgłaszają swoje istnienie do "centrali w Moskwie" w konwencji SPI (którą podałem wyżej)
Otwórz sobie winzipem któryś jar, i zajrzyj do META-INF/services

Piękne, standardowe, przypuszczam, że szybkie, bo wsadzone gdzieś w fabryczne loadery. No thirty-party software.
OBIEKTOWE

0

Co do pierwotnego pytania - nie da się tego zrobić standardowymi metodami, które zadziałają we wszystkich przypadkach z jednego powodu - ładowanie klas w JVM jest lazy.
Można próbować castować classloadery do takich które mają indeks wszystkich zasobów na classpath i listować / ładować / filtrować wszystko po kolei (albo użyć gotowych bibliotek które robią to samo, Guava chyba ma coś takiego, Spring też to robi) - trzeba pamiętać że to będzie duży overhead jeśli takie skanowanie odbywać się będzie na początku życia aplikacji.

Można też podejść do tego w taki sposób, że indeks klas które Cię interesują budujesz podczas kompilacji za pomocą Annotation Processor API - taki skaner w czasie kompilacji może zrzucić nazwy klas które spełniają Twoje kryteria do pliku na classpath, potem możesz w runtime łatwo te klasy załadować za pomocą Class.forName() - taki własny odpowiednik Javowego Service Provider Interface ale trochę bardziej dynamiczny.

0

@damianem:

Co do pierwotnego pytania - nie da się tego zrobić standardowymi metodami, które zadziałają we wszystkich przypadkach z jednego powodu - ładowanie klas w JVM jest lazy.

ciekawe, to musi generować wiele problemów gdy ktoś mocno używa refleksji

0

@damianem:

Zadałeś mi na wieczór ciekawe pytanie ... wynika z niego, że SPI jest eager (tzn nie jest lazy)

Owszem, rozumiem, to nie jest do wszystkiego, wymaga zapaczkowanego JAR (choć sądzę, ze podczas uruchamiania żywego projekty w Idea by działało), lepiej pasuje "na granicy projektów": niż "wewnątrz projektu"

Kierunek Annotation Procesor zasługuje na pozytywne wyróżnienie - choć znów wymaga zaplanowana, opanowania, dania znów jakiś metadanych choć w innej formie - jeśli nasz OP myśli o chaotycznie klepanych klasach, to nie jest "od ręki", podobnie jak SPI.

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