Pierced
I'm new here

Umgang mit Generics bei EditorValue

Hallo,

Es geht um das Interface EditorValue<T>.

Um direkt einzusteigen, hier ein Code-Auszug:

 // key enthaelt einen Bezeichner einer Editor-Komponente           

for (String key : myMap.keySet()) {

            // (!) EditorValue is a raw type. 

            EditorValue editorValue = data.get(key).getEditor();


            try {


// (!) Type safety: The method set(Language, Object) belongs to the raw type EditorValue

                editorValue.set(masterlanguage, scriptData.get(key).getEditor().get(masterlanguage));


            } catch (InvalidValueException e) {


//...

            }


}

Die beiden mit :smileyalert: markierten Stellen werden von Eclipse berechtigermaßen bemängelt, weil man sich über Generics hinwegsetzt. Sie werden ja durch das Interface EditorValue<T> hier gefordert.

Da wir über eine Collection von Bezeichnern von Editor-Komponenten iterieren, ist jedoch der Typ des konkreten EditorValue unklar, so dass man nicht auf bestimmte konkrete EditorValue-Typen (z.B. TextEditorValue) casten darf.

Meine Fragen:

Gibt es einen Weg, um diesen Fall elegant zu lösen, ohne auf @SuppressWarnings oder eine "hundertfache" instanceof-Behandlung zurückgreifen zu müssen?

Besten Dank

Georg

9 Replies
Peter_Jodeleit
Crownpeak employee

Über "editorValue.getValueType().cast(..)", am besten über eine Hilfsmethode:

public <T> void setValue(final EditorValue<T> editorValue, final Language language, final Object value) throws InvalidValueException {

    editorValue.set(language, editorValue.getValueType().cast(value));

}

Hier kann natürlich eine ClassCastException fliegen, wenn die aufrufende Stelle eine ungültigen Werte-Typ liefert. Es muss also der Aufrufer sicherstellen, das nur korrekte Kombinationen benutzt werden.

Zu Generics kann ich folgende Web-Seite empfehlen: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html

Peter

Ja die Angelika kenn' ich, für mich das weiblich Pendant zu Josh Bloch ;-).

Danke für den Tipp, ich werde ihn ausprobieren.

0 Kudos

Sorry,

ich muss hier nochmal einhaken und nachhaken.

Folgender Code:

Listable bodies = page.getChildren(Body.class);
for (Body body : bodies) {
Listable<Section> sections = body.getChildren(Section.class);
...
}

Jetzt ist es so, dass getChildren einen Rückgabewert Listable<Section> hat.

Jedoch ist Section an und für sich generisch (ein Umstand übrigens, den ich nicht verstehe, denn was für unterschiedliche Dinge enthält so eine Section? In der Regel ist es außerdem kein beliebiges "T" für Section<T>, sondern ein Section<T extends SectionTemplate).

Aber zurück zur Frage:

Dieser Code lässt sich nur dann ohne Warnung anführen, wenn man "@SuppressWarnings("rawtypes")" verwendet.

Wie unschön! Und das vermutlich nur, weil getChildren eine ungenerische Section zurückliefert.

Vermutlich habe ich mir die Antwort jetzt schon selbst vorweg genommen, daher:

Wäre es möglich die API so zu aktualisieren, dass getChildren ebenfalls generisch arbeitet? In dem Zug wäre es für mich auch ausreichend, hier statt einem "Listable" eine echte List<Section<T>>  zurückzubekommen.

Danke... und jetzt dürft ihr mich teern und federn.

0 Kudos

Im Codebeispiel fehlt der generische Typ für das erste Listable:

Listable<Body> bodies = page.getChildren(Body.class);

Damit sollte auch die Warnung verschwinden.

Die Typisierung von Section bezieht sich auf das Template (es gibt Sections für Absatztemplates und für Tabellentemplates).

Peter
0 Kudos

Hallo Peter,

Die Typisierung von Section bezieht sich auf das Template (es gibt Sections für Absatztemplates und für Tabellentemplates).

Ah - vor dem Hintergrund macht die Typisierung an der Stelle schon mehr Sinn. Sehe gerade dass SectionTemplate durch TableTemplate erweitert wird.

Hier nochmal der SourceCode

Listable<Body> bodies = page.getChildren(Body.class);

for (Body body : bodies) {

// @SuppressWarnings("rawtypes")

  Listable<Section> sections = body.getChildren(Section.class);

  // ^^^^^^^^

    for (Section<?> section : sections) {..}

}

Die markierte Zeile wird nachwievor gelb mit dem Hinweis auf "Section is a raw type." bemängelt. Meines Erachtens liegt das daran, dass body.getChildren keinen eine einfache Section, zurückgibt, jedoch nicht Section<T>.

0 Kudos

Hallo,

Georg Stach schrieb:

Die markierte Zeile wird nachwievor gelb mit dem Hinweis auf "Section is a raw type." bemängelt. Meines Erachtens liegt das daran, dass body.getChildren keinen eine einfache Section, zurückgibt, jedoch nicht Section<T>.

das ist technisch auch leider nicht anders möglich, weil hier die Klasse als Parameter den Rückgabetyp bestimmt. Und Klassen kann man so in Java nicht parameterisieren.

Gruß

Stefan

0 Kudos

das ist technisch auch leider nicht anders möglich, weil hier die Klasse als Parameter den Rückgabetyp bestimmt. Und Klassen kann man so in Java nicht parameterisieren

Würde ich so nicht unterschreiben. Eine Signatur wie diese sollte es tun:

public <T> Listable<? extends T> getChildren(Class<? extends T> clazz)

0 Kudos

Das ist sicherlich richtig. Parameterisiert die Klasse natürlich nicht, aber es würde das "Warning" Problem lösen. Eine Kleinigkeit fehlt noch in der Signatur, die dann so aussähe (betrifft im übrigen auch weitere API-Methoden dieser Art):

public <T extends StoreElement> Listable<? extends T> getChildren(Class<? extends T> clazz)

Der Änderung entgegen steht allerdings, dass dadurch zahlreiche Code-Stellen quellinkompatibel werden würden, was im Rahmen der API natürlich nicht machbar ist (das übliche API Problem). Für den Gewinn (ein Warning weniger) lohnt die Änderung jedenfalls nicht.

Gruß

Stefan

.. dass dadurch zahlreiche Code-Stellen quellinkompatibel ..

Ja, das sehe ich ein.

Dennoch, vielleicht ist es als Anregung hilfreich. Denn gerade weil es nicht die einzige Stelle in der API ist, die inkonsistent ist, könnte man hier über eine Anpassung nachdenken.

Dann natürlich mit einem MajorRelease (ich will keine Nummern nennen Smiley Wink)...

0 Kudos