2017-03-26 2 views
3

Ich möchte einen bestimmten Setter in einem generischen Code aufrufen. Natürlich kann ich auf eine Fallaussage zurückgreifen, aber sie wird immer größer, deshalb bevorzuge ich eine Karte.So verwenden Sie eine Map zum Aufrufen einer Aktion für ein Objekt

Dies ist, was ich mit so weit kam:

public class Tester { 

private static final Map<String, Setter<Target, ?>> MY_SETTERS = new HashMap<>(); 
static { 
    MY_SETTERS.put("SOURCE1", (Target t, Source1 s) -> t.setSource1(s)); 
    MY_SETTERS.put("SOURCE2", (Target t, Source2 s) -> t.setSource2(s)); 
} 

@FunctionalInterface 
private interface Setter<T, S> { 

    void set(T target, S source); 
} 

public static void main(String[] args) { 

    Target t = new Target(); 
    MY_SETTERS.get("SOURCE1").set(t, new Source1()); 
}} 

aber das gibt mir ein „inkompatible Typen: Source1 nicht konvertiert werden kann # 1 wo CAP # 1 ist ein frischer Typ-Variable zu CAP : CAP # 1 erweitert Objekt von Capture von? "

Ich verstehe, warum es scheitert. Gibt es jedoch eine elegante Möglichkeit, dies zu tun, ohne auf eine Fallaussage zurückzugreifen?

+0

Ist es nicht in Frage, nur explizite Getter schreiben für jeden 'Setter '? Sie würden also einfach mit 'MY_SETTERS.getSource1Setter() festhalten. Set (t, new Source1());'. Natürlich hat dies den Nachteil, dass Sie genau wissen müssen, mit welchem ​​Setter Sie jedes Mal zu tun haben. – Obicere

+0

@Obicere .. Das Problem ist, dass mein Real Casus eine große JAXB generierte Choice-Klasse mit ziemlich vielen Einträgen ist. Ich möchte sie generisch behandeln, da der Rest der Verarbeitungsschritte derselbe ist. – sjaak

Antwort

1

Aufgrund dieses Platzhaltertyps in der Karte müssen Sie irgendwo eine Linie zeichnen. Dies ist etwas hässlich, aber es ist das, was ich manchmal tun:

definieren eine allgemeine Hilfsmethode, die die Setter auf Ihr Wunsch-Typ umgewandelt wird:

public static <T, S> Setter<T, S> getSetter(String id) { 
    return (Setter<T, S>) MY_SETTERS.get(id); 
} 

abrufen und die Setter wie folgt aufrufen:

getSetter("SOURCE1").set(t, new Source1()); 

Java wird Typargumente von Ihren übergebenen Parametern ableiten und der Aufruf selbst wird gut aussehen. Wegen dieser ungeprüften Besetzung werden Sie jedoch Beschwerden vom Compiler erhalten.

Offensichtlich müssen Sie absolut sicher sein, was Sie anfordern, ist was Sie erwarten, da sonst erhalten Sie eine ClassCastException. Z.B. Sie folgendermaßen vorgehen wird die Ausnahme erzeugen, wie Sie Setter für Source1 abrufen, sondern rufen Sie es mit Source2:

getSetter("SOURCE1").set(t, new Source2()); 
+0

Dies ist der perfekte Weg [den Haufen zu verschmutzen] (https://docs.oracle.com/javase/tutorial/java/generics/nonReifableVarargsType.html). –

+0

Können Sie bitte warum erläutern? Es ändert die Karte nicht. – Justas

+0

Ich habe meinen Downvote entfernt, weil Sie die Gefahr von "ClassCastException" mit einem klaren Beispiel gezeigt haben. Ich meinte nur, was du gezeigt hast. –

Verwandte Themen