Methoden Methoden einer Klasse auf Grundlage eines Strings aufrufen

Naryxus

Aktives Mitglied
Hallo,

ich habe ein eher exotisches Problem. Ich möchte eine Art dynamisches Filtersystem für bestimmte Klassen erstellen.
Hintergrund ist das variable Zusammenstellen von Empfängergruppen für Nachrichten ("Alle Benutzer, die männlich sind", "Alle Benutzer, die weiblich sind und ein bestimmtes Alter haben", "Alle Benutzer, die 'Max' mit Vornamen heißen und zu einem bestimmten Zeitpunkt in einem bestimmten Raum sind", ...).
Dabei liegen die Daten über die Benutzer in verschiedenen Datenbanktabellen vor und werden über Hibernate auf die entsprechenden Klassen gemappt.

Mein bisheriger Ansatz war eine Art Beschreibungssprache zu entwickeln, mit der man die verschiedenen Klassen mit ihren Attributen als Adressat auswählen kann und mit einem bestimmten Vergleichswert vergleichen kann. Das hat grundlegend auch akzeptabel funktioniert.
Das Problem war hier nur die Erweiterbarkeit. Ich musste in meinem Parser natürlich einen großen switch-case-Block schreiben, um die entsprechenden Getter-Methoden der gewünschten Klasse aufzurufen, je nach dem, welches Attribut gefordert ist. Und dies müsste für alle weiteren Attribute und deren Änderungen erneut überarbeitet werden.

Ich habe nun zwei weitere Ansätze ausgearbeitet:
Zum einen wäre eine gewinnbringende Erweiterung schon mal, wenn es eine Möglichkeit gäbe, die Getter-Methoden über einen String aufzurufen (hier dann auch gleich meine Frage).
Und zum anderen ein Interface zu erstellen, das eine Methode beinhaltet, die einen String als Parameter erhält (den Namen eines Attributs) und den Wert des Attributs dann liefern soll. Dieser Ansatz bedeutet aber, dass die Autoren der entsprechenden Klassen, die mit der Datenbank gemappt werden, sich selbständig um die Implementierung dieser Methode kümmern müssen, deshalb möchte ich erst einmal von dem Ansatz absehen.

Nun zurück zu meiner Frage:
Gibt es irgendwie eine Möglichkeit, eine Methode oder ein Attribut auf Basis eines Strings aufzurufen? Ich kenne das von dem PHP-Framework "cakePHP", dort kann ich eine Variable mit einem String ($this->set('myVar', 42)) erstellen und in einer anderen Klasse dann tatsächlich auf die Variable $myVar zugreifen.

Oder habt ihr gegebenenfalls eine andere neue Idee für mich, wie ich das Problem möglichst effizient lösen könnte?

Grüße,
Naryxus
 

mrBrown

Super-Moderator
Mitarbeiter
Wenn ich dich richtig verstehe, willst du nur eine Liste filtern, nach übergebenen Parametern?

Reflections wäre da eine der Möglichkeiten - ist aber auch immer Fehlerquelle und sollte man imho meiden, wenn es geht.

Eine bessere Variante ist uU Nutzung von Predicates, als Lambda-Expression geschrieben, ist das auch kaum mehr, als das ganze als String ausgedrückt und dürfte ähnlich leicht zu erweitern sein. Hat aber im Gegensatz zu Reflections direkt Typsicherheit.
Wenn man zwingend das ganze aus Strings konvertieren muss, kann man da gut mit Enums und/oder Factorys arbeiten
 

Naryxus

Aktives Mitglied
Ja gibt es, das Stichwort hier heißt Reflection:
https://docs.oracle.com/javase/tutorial/reflect/

Ja, habe ich eben auch schon gefunden. Ich werde da gleich mal ein paar Beispiele austesten. Danke!

Wenn ich dich richtig verstehe, willst du nur eine Liste filtern, nach übergebenen Parametern?

Der Einfachheit halber sag ich erstmal unter Vorbehalt ja. Ein wenig komplizierter wird es leider schon werden, da die verschiedenen Klassen (Datenbanktabellen) über Fremdschlüssel miteinander in Beziehung stehen.

Eine bessere Variante ist uU Nutzung von Predicates, als Lambda-Expression geschrieben, ist das auch kaum mehr, als das ganze als String ausgedrückt und dürfte ähnlich leicht zu erweitern sein. Hat aber im Gegensatz zu Reflections direkt Typsicherheit.

Mit Predicates habe ich schon gearbeitet und die sind auch schon mit in den Parser eingeflossen. Das Problem ist hierbei, dass der Benutzer (der die Liste filtern möchte), sein Vorhaben über einen String der Form "User.gender = male" über ein Input-Feld ausdrückt und das muss über einen Parser dann erstmal auf Syntax und Semantik gecheckt werden (gibt es die Klasse? gibt es die Methode? Ist die Vergleichsrelation für das Attribut zulässig? ...). Und im Anschluss muss dann auf Grundlage dessen das Predicate erstellt werden (und die richtige Getter-Methode des Attributs der Klasse aufgerufen werden).


Wenn man zwingend das ganze aus Strings konvertieren muss, kann man da gut mit Enums und/oder Factorys arbeiten

Mit Factorys möchte ich erstmal nicht arbeiten, da ich vermutlich auch hier wieder das Problem der Erweiterbarkeit sehe. Da muss ich dann zwar nicht mehr meinen Parser ändern, wenn die Daten geändert werden, aber die Factory.
Wie meinst du das denn mit den Enums?


Viele Grüße und vielen vielen Dank für eure Antworten!
 

mrBrown

Super-Moderator
Mitarbeiter
Der Einfachheit halber sag ich erstmal unter Vorbehalt ja. Ein wenig komplizierter wird es leider schon werden, da die verschiedenen Klassen (Datenbanktabellen) über Fremdschlüssel miteinander in Beziehung stehen.

Das Model, mit dem dann in der Anwendung gearbeitet wird, sollte im Idealfall keine Fremdschlüssel, sondern nur noch die damit referenzierten Objekte enthalten ;)

Mit Predicates habe ich schon gearbeitet und die sind auch schon mit in den Parser eingeflossen. Das Problem ist hierbei, dass der Benutzer (der die Liste filtern möchte), sein Vorhaben über einen String der Form "User.gender = male" über ein Input-Feld ausdrückt und das muss über einen Parser dann erstmal auf Syntax und Semantik gecheckt werden (gibt es die Klasse? gibt es die Methode? Ist die Vergleichsrelation für das Attribut zulässig? ...). Und im Anschluss muss dann auf Grundlage dessen das Predicate erstellt werden (und die richtige Getter-Methode des Attributs der Klasse aufgerufen werden).

Validieren musst du in jedem Fall, besonders bei Benutzung von Reflection.

Der Aufwand, ein passendes Predicate zu erstellen, dürfte nicht viel größer sein, als über Reflection auf das Attribut zuzugreifen und passend zu vergleichen.

User.gender=male als gesamtes zu erkennen und dafür einfach nur den Enum Gender.Male zu finden, dürfte sogar leichter sein, als zu prüfen, on User existiert, ob gender existiert, ob mit male verglichen werden kann usw.

Die Frage ist überhaupt, ist es Sinnvoll, den Nutzer "User.gender=male" eingeben zu lassen? Bietet sich bei sowas nicht zB ein DropDown an?

Mit Factorys möchte ich erstmal nicht arbeiten, da ich vermutlich auch hier wieder das Problem der Erweiterbarkeit sehe. Da muss ich dann zwar nicht mehr meinen Parser ändern, wenn die Daten geändert werden, aber die Factory.
Wie meinst du das denn mit den Enums?

Enums kannst du über ihren Namen ansprechen, zB beim Filtern nach Geschlecht, is Gender.MALE einfach ein Predicate, welches alle Männlichen filter, und Gender.FEMALE, das entsprechende Gegenstück. Beide lassen sich aus dem String MALE bzw FEMALE von Haus aus erzeugen (man sollte nur dran denken, die möglichen Exceptions passend zu behandeln).
Factorys lagern einfach das erzeugen des passenden Predicates aus, erweiterbar bleibt es damit, anstatt den Parser umzuschreiben, fügt man einfach eine weitere Factory hinzu. Das ganze ist damit je nach Umsetzung auch einfacher zu testen und zu erweitern.



Gehts um was natives oder ne WebApp?
 

Naryxus

Aktives Mitglied
Validieren musst du in jedem Fall, besonders bei Benutzung von Reflection.

Der Aufwand, ein passendes Predicate zu erstellen, dürfte nicht viel größer sein, als über Reflection auf das Attribut zuzugreifen und passend zu vergleichen.

Ja validieren muss ich sicher. Das übernimmt ja auch der Parser. Das Problem ist, dass ich das Predicate ja mit einem Funktionsaufruf erstelle: Predicate<Data> pred = data -> data.getVar1() < 42 (zum Beispiel).
Der dazugehörige String wäre dann "Data.var1 < 42".
Und damit ich die Methode data.getVar1() aufrufen kann, habe ich bisher einen riesen switch-case-Block benutzt:
switch(className) {
case "Data":
switch(attributeName) {
case "var1":
return data -> data.getVar1() < 42;
...
}}
(Man entschuldige, dass ich gerade zu faul war, den Code-Editor zu benutzen)
Und das wollte ich mir ersparen durch die Reflections.


Die Frage ist überhaupt, ist es Sinnvoll, den Nutzer "User.gender=male" eingeben zu lassen? Bietet sich bei sowas nicht zB ein DropDown an?

Es ist insofern sinnvoll, da erstens mein Betreuer das gerne so hätte und es zweitens so möglich wird, das beliebig variabel zu gestalten. So hat man dann die Möglichkeit verschiedene Filter mit "AND" und "OR" miteinander zu verknüpfen (auch das hat mit switch-case schon super funktioniert).



Enums kannst du über ihren Namen ansprechen, zB beim Filtern nach Geschlecht, is Gender.MALE einfach ein Predicate, welches alle Männlichen filter, und Gender.FEMALE, das entsprechende Gegenstück. Beide lassen sich aus dem String MALE bzw FEMALE von Haus aus erzeugen (man sollte nur dran denken, die möglichen Exceptions passend zu behandeln).

Das fällt leider raus, weil ich das nicht so fest einprogrammieren möchte. Eben aus besagtem Grund der Erweiterbarkeit und der Wartbarkeit. Eine wichtige Anforderung ist: Wenn an der Datenbank was geändert oder hinzugefügt wird, sollen nur an minimal vielen Klassen Änderungen durchzuführen sein. Und meine Klasse gehört da leider nicht zu.


Factorys lagern einfach das erzeugen des passenden Predicates aus, erweiterbar bleibt es damit, anstatt den Parser umzuschreiben, fügt man einfach eine weitere Factory hinzu. Das ganze ist damit je nach Umsetzung auch einfacher zu testen und zu erweitern.

Werde ich nochmal drüber nachdenken, danke!



Gehts um was natives oder ne WebApp?

Letztendlich um ein Servlet. Aber gerade teste ich das lokal in Eclipse.
Ich frage mich sowieso, warum für das ganze Projekt nicht einfach PHP genutzt wurde, da hätte ich einen schönen Parser für die Sprache und das Erzeugen von SQL-Queries schreiben können...

Momentan hänge ich an dem Problem, dass ich bei dem Erstellen der Predicates aus den Reflections eine InvocationTargetException nicht behandelt bekomme. Ich fürchte der Compiler mag die Syntax aus funktionalen Schnittstellen und den Reflections nicht. Er sagt die ganze Zeit, ich solle die method.invoke-Methode mit einem try-catch-Block umgeben, aber egal wie oft ich das mache, möchte er noch weitere haben.

Ich war schon so weit zu sagen, bei jeder Klasse, die mit Hibernate gemappt wird, muss ein XML-Dokument liegen, in dem die Informationen über die Klasse liegen, sodass bei Änderungen der Klasse nur noch zusätzlich das Dokument geändert werden muss. Aber das würde das Problem mit dem Methodenaufruf auch nicht lösen.
 

mrBrown

Super-Moderator
Mitarbeiter
Ja validieren muss ich sicher. Das übernimmt ja auch der Parser. Das Problem ist, dass ich das Predicate ja mit einem Funktionsaufruf erstelle: Predicate<Data> pred = data -> data.getVar1() < 42 (zum Beispiel).
Der dazugehörige String wäre dann "Data.var1 < 42".
Und damit ich die Methode data.getVar1() aufrufen kann, habe ich bisher einen riesen switch-case-Block benutzt:
switch(className) {
case "Data":
switch(attributeName) {
case "var1":
return data -> data.getVar1() < 42;
...
}}
(Man entschuldige, dass ich gerade zu faul war, den Code-Editor zu benutzen)
Und das wollte ich mir ersparen durch die Reflections.

Den riesen switch-case kann man da sinnvoll in verschiedene Methoden (oder sogar Klassen) aufteilen ;)

Wie würdest du sowas denn kürzer mit Reflection validieren und ansprechen?

Das fällt leider raus, weil ich das nicht so fest einprogrammieren möchte. Eben aus besagtem Grund der Erweiterbarkeit und der Wartbarkeit. Eine wichtige Anforderung ist: Wenn an der Datenbank was geändert oder hinzugefügt wird, sollen nur an minimal vielen Klassen Änderungen durchzuführen sein. Und meine Klasse gehört da leider nicht zu.

Hardgecode ist da nur die Existenz einer Checks, ob Männlich oder Weiblich? Wie soll man so einen grundlegenden Check erweitern? Mehr Geschlechter -> einfach eintragen. Mit weiteren Checks verbinden -> #and benutzen...
Wartbar/Testbar ist es ohne Probleme

Wartbarkeit und Reflections sollte man dagegen sehr vorsichtig in einem Satz verwenden, am besten in Verbindung mit Negationen ;)

Wenn der Parser und das dazugehörige bei einer Änderung des DatenModells gleich bleiben soll, wird man um Reflection nicht drum rum kommen, ist aber imho keine Sinnvolle Lösung^^

Letztendlich um ein Servlet. Aber gerade teste ich das lokal in Eclipse.
Ich frage mich sowieso, warum für das ganze Projekt nicht einfach PHP genutzt wurde, da hätte ich einen schönen Parser für die Sprache und das Erzeugen von SQL-Queries schreiben können...

Also mir reicht da PHP als Grund ;)

Momentan hänge ich an dem Problem, dass ich bei dem Erstellen der Predicates aus den Reflections eine InvocationTargetException nicht behandelt bekomme. Ich fürchte der Compiler mag die Syntax aus funktionalen Schnittstellen und den Reflections nicht. Er sagt die ganze Zeit, ich solle die method.invoke-Methode mit einem try-catch-Block umgeben, aber egal wie oft ich das mache, möchte er noch weitere haben.
Das try-catch muss innerhalb der Methode liegen, LambdaExpressions können keine CheckedExeptions werfen
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
V Threads Probleme beim Aufrufen von Methoden einer anderen Klasse (Threads) Allgemeine Java-Themen 14
L Operatoren Java Reflections: Alle Methoden einer Klasse aufrufen ohne Exceptions Allgemeine Java-Themen 5
S Identische Methoden in einer Klasse Allgemeine Java-Themen 2
L Auflistung aller Methoden einer Klasse Allgemeine Java-Themen 9
C Mehrere main-Methoden in einer jar Allgemeine Java-Themen 7
B Leere vererbte Interface-Methoden Allgemeine Java-Themen 8
R Programm führt Methoden gleichzeitig aus Allgemeine Java-Themen 2
Encera Unterschied zweier "toString"-Methoden Allgemeine Java-Themen 1
torresbig Klasse mit extends Calendar über Methoden ändern (Hirnblockade) Allgemeine Java-Themen 7
Sachinbhatt Sind alle Methoden in Java implizit virtuell Allgemeine Java-Themen 2
B Arrays von Methoden möglich? Allgemeine Java-Themen 44
S Mit Methoden kann man definieren für was <T> steht. Geht das auch irgendwie für Variablen? Allgemeine Java-Themen 12
N abstracte klassen methoden Allgemeine Java-Themen 32
G Methoden für die Zukunft sinnvoll? Allgemeine Java-Themen 4
nonickatall Methoden Kann man Klassen/Methoden aus Variablen heraus aufrufen? Allgemeine Java-Themen 6
LimDul Hä? Lambda-Ausdruck geht, Methoden-Referenz nicht Allgemeine Java-Themen 8
B Methoden Java Getter und Setter Methoden Allgemeine Java-Themen 9
Y Java Methoden unterschiedliche Zahlenreihen Allgemeine Java-Themen 2
S Interface Design von HookUp oder Callback Methoden für eigenes Framework Allgemeine Java-Themen 9
F Sich automatisch aufrufende Java-Methoden Allgemeine Java-Themen 2
J Namen von Methoden über Reguläre Ausdrücke bearbeiten Allgemeine Java-Themen 6
D Methoden Methoden anpassen und fehlende Funktionen hinzufügen Allgemeine Java-Themen 475
R Statistische Methoden (Mathematik) Aufgabe Allgemeine Java-Themen 9
X Brüche kürzen mittels Methoden und ggT Allgemeine Java-Themen 15
L mehrere Methoden Allgemeine Java-Themen 19
KeexZDeveoper Zugriff auf Methoden vom Server Allgemeine Java-Themen 7
B StAX Parser - mehrere Methoden, ein XML Allgemeine Java-Themen 4
F Operationen/Methoden einen WebService im Browser mit Apache Axis aufrufen Allgemeine Java-Themen 4
A Automatisches Methoden Laufzeiten logging? Allgemeine Java-Themen 7
M Quellcode von Java-Methoden Allgemeine Java-Themen 9
rentasad Design-Frage - Interfaces, Klassen, statische Methoden Allgemeine Java-Themen 3
N HashMap und Methoden richtig einbinden Allgemeine Java-Themen 2
R Variable durch mehrere Methoden ändern und nutzen Allgemeine Java-Themen 17
Q-bert Methoden Methoden in Java Allgemeine Java-Themen 13
D Methoden Java-Aufgabe Allgemeine Java-Themen 2
M Compiler-Fehler Methoden-Referenz Allgemeine Java-Themen 5
X Threads Externe Variablen in Run Methoden verändern Allgemeine Java-Themen 4
S 2 methoden mit gleichen namen und ein Interface Allgemeine Java-Themen 9
F Enum-werte als Methoden-Parameter übergeben Allgemeine Java-Themen 6
N Vererbung Design-Problem mit vorhandenen, von der Klasse unabhängigen Methoden Allgemeine Java-Themen 12
E OOP Objekte und Methoden Allgemeine Java-Themen 1
K Java ruft Methoden nicht der Reihe nach auf Allgemeine Java-Themen 14
T Java Array in Methoden Allgemeine Java-Themen 1
D Code für bereitgestellte Methoden Allgemeine Java-Themen 1
P Entity Objekt Methoden vs Service methoden Allgemeine Java-Themen 2
R Signatur von Methoden in eine Datei schreiben? Allgemeine Java-Themen 4
A Methoden verändern Allgemeine Java-Themen 12
F Methoden Arraylist weiterverwenden nach methoden Aufruf Allgemeine Java-Themen 2
J Best Practice Testen von protected Methoden Allgemeine Java-Themen 7
L Methoden "Schiffe versenken" Quellcode in Methoden umwandeln Allgemeine Java-Themen 6
G Matrix reduzieren zwei Methoden Allgemeine Java-Themen 2
Sogomn Best Practice "Doppelte" Methoden Allgemeine Java-Themen 3
Paul15 String Methoden Allgemeine Java-Themen 7
G Methoden BMI -Wert Aufgabe(Methoden) Allgemeine Java-Themen 4
F Testen von Methoden Allgemeine Java-Themen 3
S "Vererben" statischer Felder/Methoden Allgemeine Java-Themen 4
F Methoden in der Enumeration Klasse Allgemeine Java-Themen 1
S Methoden ohne Methodenkopf ?! Allgemeine Java-Themen 5
T Überschreiben von Methoden Allgemeine Java-Themen 6
M Methoden werden in falscher Reihenfolge bearbeitet Allgemeine Java-Themen 10
S Methoden Methoden überschreiben Allgemeine Java-Themen 3
N Threads statische Methoden in Threads Allgemeine Java-Themen 5
O Java-Obfuscator, welcher einzelne Methoden, Klassen und Ordnerstrukturen ausnehmen kann. Allgemeine Java-Themen 1
A also definition von klassen und string methoden und algorithmik Allgemeine Java-Themen 13
X Eigene Annotation - mit Bedingung für ganze Klassen oder Methoden Allgemeine Java-Themen 2
A Threads Lock über mehrere Abschnitte in verschiedenen Methoden Allgemeine Java-Themen 5
S Methoden Frage Allgemeine Java-Themen 2
R Wie kann man diese Methoden in arrays etablieren? Allgemeine Java-Themen 8
M Methoden in Rescources speichern Allgemeine Java-Themen 4
G Synchronisation nicht statischer Methoden Allgemeine Java-Themen 4
A Vererbung finale Methoden überschreiben Allgemeine Java-Themen 24
A Methoden parallelisieren? Allgemeine Java-Themen 2
L Methoden methoden an generischen klassentyp anpassen Allgemeine Java-Themen 5
C Methoden Übernahme von standart nativen Methoden? Allgemeine Java-Themen 9
B Zusammenfassen verschiedener ähnlicher Methoden Allgemeine Java-Themen 8
K JNI: Methoden aus unterschiedlichen Threads aufrufen Allgemeine Java-Themen 3
P Unterschiedliche Clone- Methoden Allgemeine Java-Themen 5
MQue Spezialfrage Überschreiben von Methoden Allgemeine Java-Themen 14
B Methoden Alle Methoden und Variablen aus Java-Dateien auslesen. Allgemeine Java-Themen 7
MiMa Rekursive Methoden Allgemeine Java-Themen 3
S Programm das alle aufgerufenen Methoden ausgibt..? Allgemeine Java-Themen 6
F ListIterator (next & previous methoden) Allgemeine Java-Themen 5
W Frage zu Refactoring statischer Methoden Allgemeine Java-Themen 4
M Methoden/Klassen für andere Projekte Allgemeine Java-Themen 4
T Methoden per String-Namen aufrufen Allgemeine Java-Themen 2
C Kapselung Warum graift man auf Variablen nur über Methoden und nich direkt zu? Allgemeine Java-Themen 10
M Methoden Static Methoden und Thread??? Allgemeine Java-Themen 4
A Methoden ohne Referenzen finden Allgemeine Java-Themen 9
turmaline OOP zwei gleiche Methoden mit kleinen Unterschieden Allgemeine Java-Themen 15
G JUnit Test Methoden in anderen Thread verlagern Allgemeine Java-Themen 4
K Auf Methoden der Runnable Klasse zugreifen Allgemeine Java-Themen 2
S Methoden Class.forName() >> Methoden - Reihenfolge Allgemeine Java-Themen 5
D Passende Name für Methoden finden Allgemeine Java-Themen 3
D Wann sollte ich statische Methoden und Variablen benutzen? Allgemeine Java-Themen 44
A Methoden laufen im Konstruktor, außerhalb allerdings nicht Allgemeine Java-Themen 2
M Generische Methoden mit Java und globale Variablen Allgemeine Java-Themen 9
GianaSisters ArrayList in Methoden übergeben Allgemeine Java-Themen 3
S static methoden Allgemeine Java-Themen 9
J coole Methoden Allgemeine Java-Themen 6
R Methoden in einem Thread unterschiedlich oft ausführen Allgemeine Java-Themen 4

Ähnliche Java Themen

Neue Themen


Oben