Hi, ich hofe mir kann jemand helfen.
Ich benutze xstream zur Serialisierung meiner Daten.
Jetzt habe ich ein Problem, dass ich einen Vector habe, der als Typ ein
Interface hat.
1 | public interface IProps{}
| 2 |
| 3 | @XStreamAlias("entry")
| 4 | public class CounterField implements IProps{
| 5 | public CounterField(String description, int count) {
| 6 | this.description = description;
| 7 | this.count = count;
| 8 | }
| 9 | public String description;
| 10 | public int count;
| 11 | }
| 12 |
| 13 | @XStreamAlias("list")
| 14 | public class CounterFieldVector implements IProps
| 15 | {
| 16 | public CounterFieldVector()
| 17 | {
| 18 | fields = new Vector<IProps>();
| 19 | }
| 20 |
| 21 | @XStreamAlias("elements")
| 22 | public Vector<IProps> fields;
| 23 |
| 24 | }
|
es soll noch mehrere Implementierungen von IProps geben.
Das ganze kann also beliebig geschachtelt werden.
raus kommt folgendes: 1 | <elements>
| 2 | <SimpleCounterApp.CounterField>
| 3 | <description>Example1</description>
| 4 | <count>0</count>
| 5 | </SimpleCounterApp.CounterField>
| 6 | <SimpleCounterApp.CounterField>
| 7 | <description>Example2</description>
| 8 | <count>1</count>
| 9 | </SimpleCounterApp.CounterField>
| 10 | <SimpleCounterApp.CounterField>
| 11 | <description>Example3</description>
| 12 | <count>2</count>
| 13 | </SimpleCounterApp.CounterField>
| 14 | </elements>
|
seltsamerweise ignoriert er die Aliase für die Klassen.
hätte aber gern, dass er diesen benutzt
im obigen Fall halt: 1 | <elements>
| 2 | <entry>
| 3 | <description>Example1</description>
| 4 | <count>0</count>
| 5 | </entry>
| 6 | <entry>
| 7 | <description>Example2</description>
| 8 | <count>1</count>
| 9 | </entry>
| 10 | <entry>
| 11 | <description>Example3</description>
| 12 | <count>2</count>
| 13 | </entry>
| 14 | </elements>
|
Das Problem wird sein das "entry" ein reservierter Bezeichner ist (wird
für maps verwendet). Selbiges könnte ein Problem bei "list" und
"elements" auch auftreten. Hast du es mal versucht den Alias direkt bei
der Xstream instanz einzusetzen?
Btw: Ein leeres Interface ist meistens nicht sehr sinnvoll, denk nochmal
drüber nach ob z.B. wenigstens Elementare Funktionen wie "getName" o.ä.
ins Interface wandern sollten.
Läubi .. schrieb:
> Das Problem wird sein das "entry" ein reservierter Bezeichner ist (wird
> für maps verwendet). Selbiges könnte ein Problem bei "list" und
> "elements" auch auftreten.
auch wenn ich die Namen komplett ändere, tut sich nix.
Läubi .. schrieb:
> Hast du es mal versucht den Alias direkt bei
> der Xstream instanz einzusetzen?
wie geht das?
In den Beispielen wird es immer nur über Annotations gemacht.
Vlad Tepesch schrieb:
> auch wenn ich die Namen komplett ändere, tut sich nix.
Vielleicht liegts doch an deiner komischen Struktur ;)
> wie geht das?
> In den Beispielen wird es immer nur über Annotations gemacht. 1 | XStream xstream = new XStream();
| 2 | xstream.alias("ArrayList", ArrayList.class);
| 3 | xstream.alias("Film", Film.class);
| 4 | xstream.alias("Gruppe", Gruppe.class);
|
Ansosnten geht ein Alias glaub ich auch nur für Klassen und nicht für
Felder.
Läubi .. schrieb:
> Vielleicht liegts doch an deiner komischen Struktur ;)
wieso komisch?
Ist doch das Grundkonzept der Polymorphie.
Collection vom Typ der Basisklasse (bzw. in dem Fall Interface (habs
auch schon mit Basisklasse, anstatt Interface bersucht)) mit Instanzen
von abgeleiteten Klassen.
Läubi .. schrieb:
> Ansosnten geht ein Alias glaub ich auch nur für Klassen und nicht für
> Felder.
nö, das geht für beides.
Wenn ich eine class A als classA annotiere steht in dem XML auch classA.
genauso, wenn ich deren Member int b als intB annotiere.
Außerdem will ich ja auch, dass Klassen der Alias der Klasse benutzt
wird.
Ich glaub ich werde mal an die Mailinglist posten.
Vlad Tepesch schrieb:
> wieso komisch?
Weil deine "Basis" IProps nichts enthält, d.h. du musst sowieso jedes
mal die konkrete Klasse suchen hast also keinen Vorteil gegenüber als
wenn du das ganze von Object ableitest.
D.h. für jede Funktion die ein IProps verarbeiten kann, kann damit
nichts anfangen weil keine einzige Basismethode vorhanden ist. Wenn aber
alle IProps Objekte nichts gemeinsam haben handelt es sich streng
genommen nicht um ein
> Grundkonzept der Polymorphie.
> Läubi .. schrieb:
>> Ansosnten geht ein Alias glaub ich auch nur für Klassen und nicht für
>> Felder.
>
> nö, das geht für beides.
Gut war mir neu, ob man das so weit customizen will/soll muß jeder für
sich entscheiden ;)
Übrigens sollte man keine "Implemntationsdetails" in den Klassennamen
schieben. Das CounterFieldVector ein Vektor ist ist eigentlich
uninteressant (wieso erbt es dann eigentlich nicht von Vektor wenn du
den einzigen Member der ein Vektor ist auch noch public deklarierst?),
ebenso das IProps ein Interface ist.
> Ich glaub ich werde mal an die Mailinglist posten.
Wenn du Vektor erweiterst hättest du glaub ich sowieso deine gewünscht
Struktur ganz ohne Alias.
Läubi .. schrieb:
> Weil deine "Basis" IProps nichts enthält, d.h. du musst sowieso jedes
> mal die konkrete Klasse suchen hast also keinen Vorteil gegenüber als
> wenn du das ganze von Object ableitest.
wenn ich das Interface weglasse, könnte ich ja beliebige Objekte da rein
stecken.
Das soll eigentlich nur ein Marker-Interface sein.
Zu jeder von IProps abgeleiteter Klasse, gibt es dann noch einen
Handler, der mit den Daten ein Gui-Element baut.
Nach Deserialisierung des Baumes aus IProps. wird für jeden Knoten ein
entsprechender Handler erzeugt, der die zugehörige GUI erzeugt und sich
wiederum darum kümmert, dass seine Kinder, falls welche da, gebaut
werden.
Das ganze funktioniert über eine Art Funktion, die ein Objekt vom IProp
Interface bekommt, dessen wahren Klasse erfragt und einen Objekt
Klassenname+"Handler" erzeugt.
Diesen Umweg habe ich gemacht, da die Serialisierung sonst zu viele
Daten enthalten hätte, die sie gar nicht enthalten soll.
So hat man klare Strukturierte kleine Klassen, die das Datenfile
abbilden.
Läubi .. schrieb:
> Gut war mir neu, ob man das so weit customizen will/soll muß jeder für
> sich entscheiden ;)
das macht höchstens Sinn, wenn man ein Member intern nicht umbenennen
möchte, oder kann, weil man sich an irgendwelche Benamungs-Richtlinen
halten muss.
Läubi .. schrieb:
> Übrigens sollte man keine "Implemntationsdetails" in den Klassennamen
> schieben. Das CounterFieldVector ein Vektor ist ist eigentlich
> uninteressant
nach außen hin ist es quasi eine Liste von Feldern. Der Name ist einfach
blöd gewählt.
> (wieso erbt es dann eigentlich nicht von Vektor wenn du
> den einzigen Member der ein Vektor ist auch noch public deklarierst?),
> ebenso das IProps ein Interface ist.
das hat noch komischere Ausgaben bei der serialisierung zur folge.
Da werden implementierungsdetails der Vectorklasse mit rausgeschrieben,
die eigentdlich komplette interna sind, zB reservierter Platz im Vector.
Das würde ich eigentlich als Bug in der Vector-Klasse sehen, dass das
nicht als transient deklariert ist.
Vlad Tepesch schrieb:
> wenn ich das Interface weglasse, könnte ich ja beliebige Objekte da rein
> stecken.
Jupp das könntest du. Da sich aber ein Objekt von einem welches ein
IProp implementiert in keiner Weise unterscheidet wäre das fast kein
Beinbruch.
> Das soll eigentlich nur ein Marker-Interface sein.
Leere Interfaces würde ich trotzdem vermeiden.
> Zu jeder von IProps abgeleiteter Klasse, gibt es dann noch einen
> Handler, der mit den Daten ein Gui-Element baut.
Wäre es dann nicht schlau wenigstens sowas wie "getHandler()" oder so
dem IF hinzuzufügen? Jedes IProps sollte ja hoffentlich wissen welcher
Handler hier zuständig ist und so würde:
> Nach Deserialisierung des Baumes aus IProps. wird für jeden Knoten ein
> entsprechender Handler erzeugt, der die zugehörige GUI erzeugt und sich
> wiederum darum kümmert, dass seine Kinder, falls welche da, gebaut
> werden.
sicherlich einfacher ablaufen. Ggf könnte man dann ein Generic Typ dem
Interface hinzufügen falls man den Typ des handlers noch spezieller
festlegen möchte.
> Das ganze funktioniert über eine Art Funktion, die ein Objekt vom IProp
> Interface bekommt, dessen wahren Klasse erfragt und einen Objekt
> Klassenname+"Handler" erzeugt.
Das "doofe" an dem Konzept ist nur: Fügst du eine neue IProps Klasse
hinzu mußt du diese Funktion ändern, ändert sich die Implementation mußt
du diese Klasse ebenfalls ändern, sowohl für die Klasse als auch für den
Handler. Daher würde ich diese Aufgabe an das Objekt selbst (bzw
Interface) deligieren.
> Diesen Umweg habe ich gemacht, da die Serialisierung sonst zu viele
> Daten enthalten hätte, die sie gar nicht enthalten soll.
Daten sollten man natürlich vom View trennen, dann sollten sich hier
keine Probleme ergeben.
> nach außen hin ist es quasi eine Liste von Feldern. Der Name ist einfach
> blöd gewählt.
Falls du die syncronizierung von Vektor nicht brauchst würde ich auf
List gehne (z.B. ArrayList).
Die Frage ist halt ob du wirklich eine eigene Klasse brauchst oder es
ein 1 | List<IProps> myList = new ArrayList<IProps>()
|
Nicht auch tun würde.
>> (wieso erbt es dann eigentlich nicht von Vektor wenn du
>> den einzigen Member der ein Vektor ist auch noch public deklarierst?),
>> ebenso das IProps ein Interface ist.
> das hat noch komischere Ausgaben bei der serialisierung zur folge.
> Da werden implementierungsdetails der Vectorklasse mit rausgeschrieben,
> die eigentdlich komplette interna sind, zB reservierter Platz im Vector.
> Das würde ich eigentlich als Bug in der Vector-Klasse sehen, dass das
> nicht als transient deklariert ist.
Nein! Das sind (für den Vektor) wichtige Informationen! Du kannst ohne
diese zwar einen (ähnlichen) Vektor erzeugen dieser würde sich aber
unterscheiden im Verhalten! Wenn du die speziellen Eigenschaften von
Vektor nicht benötigst würde ich wie gesagt einfach ArrayList benutzen.
> das hat noch komischere Ausgaben bei der serialisierung zur folge.
Allgemein würde ich mir nicht zu viele Gedanken um die Ausgabe machen.
Solange das ganze nur von Maschinen erzeugt/gelesen werden soll ist das
ganze recht unkritisch, da sollte man nicht zuviel Ehrgeiz reinstecken.
Läubi .. schrieb:
> Das "doofe" an dem Konzept ist nur: Fügst du eine neue IProps Klasse
> hinzu mußt du diese Funktion ändern, ändert sich die Implementation mußt
> du diese Klasse ebenfalls ändern, sowohl für die Klasse als auch für den
> Handler. Daher würde ich diese Aufgabe an das Objekt selbst (bzw
> Interface) deligieren.
Nein, muss nicht. da der tatsächliche Klassenname des Interfaces in
Erfahrung gebracht wird. Aus diesem Namen wird dann der Namen des
Handlers hergeleitet und nach einer Klasse dieses Namens gesucht.
Anschließend wird noch der überprüft ob es einen Konstruktor mit diesem
speziellen IProps als Parameter gibt und dieser aufgerufen.
Es muss also nur sichergestellt sein, dass der Handler einen bestimmten
Namen hat.
Aber du hast recht. ein
public IHandler createHandler(IProps);
wär einfacher.
Läubi .. schrieb:
> Falls du die syncronizierung von Vektor nicht brauchst würde ich auf
> List gehne (z.B. ArrayList).
Da hast du auch recht. Macht wahrscheinlich mehr Sinn. Bin von C++
std::vector gewohnt und hab nicht länger gesucht, als ich einen Vector
gefunden habe.
Läubi .. schrieb:
> Nein! Das sind (für den Vektor) wichtige Informationen! Du kannst ohne
> diese zwar einen (ähnlichen) Vektor erzeugen dieser würde sich aber
> unterscheiden im Verhalten! Wenn du die speziellen Eigenschaften von
> Vektor nicht benötigst würde ich wie gesagt einfach ArrayList benutzen.
wieso sollte es wichtig sein, wieviel Platz der Vektor schon im
Vorhinein reserviert hat? Das sind doch Interna, die nur das
Memory-Management betreffen.
Läubi .. schrieb:
> Allgemein würde ich mir nicht zu viele Gedanken um die Ausgabe machen.
> Solange das ganze nur von Maschinen erzeugt/gelesen werden soll ist das
> ganze recht unkritisch, da sollte man nicht zuviel Ehrgeiz reinstecken.
genau das ist es ja.
Diese Daten beschreiben die Konfiguration der Gui.
Da das ganze recht klein bleiben soll, will ich keine Gui bauen, um die
Struktur aufzubauen.
Daher sollte der Output/Input möglichst einfach schreibbar und lesbar
sein.
Vlad Tepesch schrieb:
> Nein, muss nicht. da der tatsächliche Klassenname des Interfaces in
> Erfahrung gebracht wird. Aus diesem Namen wird dann der Namen des
> Handlers hergeleitet und nach einer Klasse dieses Namens gesucht.
autsch ;) Das geht zwar ist aber höchst unschön, gerade wenn du
irgenwann mal auf ein automatische Refacotoring zurückgreifen willst,
ebenso verbaust du dir so die Möglichkeit das der Compiler im Vorfelde
dir Fehler mitteilt.
> Aber du hast recht. ein
> public IHandler createHandler(IProps);
> wär einfacher.
Jupp und weniger fehleranfällig. Auch hast du so die Möglichkeit die
Implementierung (z.B. anhand von Konfigparametern) einfach
auszutauschen.
> Läubi .. schrieb:
>> Falls du die syncronizierung von Vektor nicht brauchst würde ich auf
>> List gehne (z.B. ArrayList).
> Da hast du auch recht. Macht wahrscheinlich mehr Sinn. Bin von C++
> std::vector gewohnt und hab nicht länger gesucht, als ich einen Vector
> gefunden habe.
Es lohnt sich aber. Außerdem kannst du in Java ohne Probleme immer auf
die kleinste Basisklasse (in diesem Falle z.B. List) gehen. Ob du dann
konkret einen Vektor, eine Arraylist, oder Linkedlist nimmst ist egal.
> wieso sollte es wichtig sein, wieviel Platz der Vektor schon im
> Vorhinein reserviert hat? Das sind doch Interna, die nur das
> Memory-Management betreffen.
Ein Vektor hat folgende (interne) Größen die für ihn wichtig sind:
- elementCount: Die Anzahl gültiger Elemente
- capacityIncrement: die Anzahl neu zu alloziierender Elemente sobald
der Vektor einmal zu klein wurde.
Und (vieleicht) auch noch die initialCapacity welche der Vektor
wenigstens haben soll (zu Anfang), und die aktuelle Größe des Buffers
(welche man mit ensureCapacity ggf vor dem serialisieren erzwungen hat).
Diese Werte müssen aber wieder hergestellt werden um den Zustand des
Objektes zu erhalten!
> genau das ist es ja.
> Diese Daten beschreiben die Konfiguration der Gui.
Schon mal fertige Frameworks angeschaut?
http://www.google.de/search?q=java+gui+XML
Nicht das du das Rad unötigerweise neu erfindest ;)
> Daher sollte der Output/Input möglichst einfach schreibbar und lesbar
> sein.
Wenn das ganze wirklich eine (handkonfigurierbare) Einstellungsdatei
werden soll, würde ich ggf garnicht über Serialisierung gehen. Da hast
du nämlich das Problem das diese sofort fehlschlägt wenn der User was
"vermurkst" hat.
Wenn es unbedingt XML sein muß kannst du dies auch per SAX parsen und
dann deine Struktur völlig frei wählen.
ich habe die Ursache gefunden:
Ich habe vergessen die Liste mit dem processAnnotations zu erweitern.
*Kopf gegen die Wand schlag*
Läubi .. schrieb:
> Schon mal fertige Frameworks angeschaut?
> http://www.google.de/search?q=java+gui+XML
> Nicht das du das Rad unötigerweise neu erfindest ;)
Ich brauche nicht viel Spielraum bei dem ganzen.
Außerdem sollen in der Struktur auch noch Daten abgelegt werden.
Die Konfiguration ist also eigentlich nur ein Template.
So wie es jetzt ist (nach Hinzufügen von processAnnotations),
funktioniert es bestens.
Den Vector werde ich dennoch durch ArrayList ersetzen und ein
createHandler einbauen ;).
Läubi .. schrieb:
> Wenn es unbedingt XML sein muß kannst du dies auch per SAX parsen und
> dann deine Struktur völlig frei wählen.
Ist aber mehr Aufwand.
Ich wollte halt einfach "nur" schnell eine Datenstruktur abspeichern und
wieder laden, ohne was dazu tun zu müsssen. xstream sah da recht passend
aus.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|