Java Objekt über Klasse/Typ übergeben

Sp4rky

Cadet 4th Year
Registriert
März 2019
Beiträge
77
Hallo,
Ich habe vor ein Objekt als Container für verschiedene Daten einzusetzen. Die Daten sind alle in JSON Objekten verpackt, der Inhalt dieser wird zur einfacheren Verarbeitung von einem Objekt einer Unterklasse von der Klasse DataType bestimmt. Gekürzt sieht das so in etwa aus vom Aufbau:

Code:
class DataType
    // einige Variablen, Funktionen, ein privater Konstruktor
   
    class Typ1 extends DataType
        // super() über den Konstruktor
       
        static Typ1 Untertyp_1
        static Typ1 Untertyp_2
       
    class Typ2 extends DataType
        // super() über den Konstruktor
       
        static Typ2 Untertyp_1
        static Typ2 Untertyp_2

Soweit funktioniert das ganze, ich kann mit sowas wie DataType.Typ1.Untertyp_1 auf den entsprechenden Typ zugreifen.
Jetzt habe ich einen Container in den ich JSON Objekte sortiert nach DataTypes einsetzen und auslesen kann (DataType wird vereinfacht als Key benutzt). In etwa so

Code:
class Container
   
    JSONObject data
   
    JSONObject get(DataType)
    void set(Datatype, JSONObject)

Ich hoffe ich das ich nun halbwegs gut erkläre was ich von hier aus vor habe.

Die set() und get() Funktion soll überprüfen ob der Datentyp einem bestimmtem Datentypen gleicht, also sowas wie >datatype == DataType.Typ1.Untertyp_X<
Jetzt würde ich ganz gern die selbe Klasse des Containers zum speichern von verschiedenen Unterklassen der Datentypen benutzen. Somit muss ich also irgendwie, wenn z.Bsp der Container Daten vom Typ der Unterklasse DataType.Typ2 beinhalten soll an den Stellen wo der Vergleich der Datentypen kommt nicht mehr DataType.Typ1.Untertyp_X sondern DataType.Typ2.Untertyp_X abgefragt werden (Kennzeichnung des statischen Objekts bleibt gleich, Unterklasse ändert sich) abfragen. Nur wie.

Meine Ideen dazu wären irgendwie an den Konstruktor Unterklassen von DataType weiter zu geben und dann zu kucken wie ich von dort wieder an das statische Objekt kommt; Oder irgendwie die Unterklassen als als generische Typen (nennen wir ihn G) an die Klasse zu übergeben und dann von denen das Objekt raus zu ziehen.
Letzteres scheint mir vielversprechender, leider bekomme ich das ganze nicht umgesetzt.

Nehme ich G als Erweiterung von DataType (G extends DataType) kann ich zwar über G.Typ2.Untertyp_X auf den entsprechenden Datentypen zugreifen (was ja irgendwie unsinnig ist; G als DataType), aber leider ist G nicht allgemein für den Typen der Unterklasse nutzbar (G als DataType.TypX). Vermutlich ist mein Aufbau der DataType Klasse nicht passend, nur was müsste ich ändern?

Hilfe dazu würde mich sehr freuen :)
 
Hmm... wenn ich das nicht völlig falsch verstanden hab, brauchst Du einfach Unterklassen für den Container. Aber irgendwie ist entweder die Klassenhierarchie suspekt oder ich versteh das Problem nicht recht oder beides. 😕

In wenigen Worten zusammengefaßt: Du möchtest ein JSON-gestütztes Backend für JAVA haben, sodaß Du Objekte in JAVA transparent in JSON abbilden kannst und andersherum per Übergabe von JSON die damit abgebildete Konfiguration in JAVA bekommst. Dafür hast Du einen definierten Schlüsselsatz (in JSON), der - nehm ich mal an -- vorgegeben ist.

In etwa so?

In dem Fall müßtest Du Deine Klassenhierarchie nach der JSON-Spezifikation modellieren. Besser noch: nach derjenigen Spezifikation, die am Ende in diesen JSON-Daten resultierte. Irgendwelche generischen Ansätze helfen da nicht viel weiter. Immerhin beschreibt JSON nur, was schon da ist; irgendwelche neuen Dinge gehen damit nicht.

Die Containerfrage kann man durchaus als Dictionary abhandeln (ich vermute mal, Du hast nur zur Vereinfachung die Ausweisung als Liste(n) in den Feldern weggelassen) aber JSON hat damit nichts mehr zu tun. Einfach das Ganze stinknormal modellieren, so wie Du's auch sonst modellieren würdest.

Was bedeutet, daß "dieselbe Klasse zum Speichern verwenden" immer nur logisch funktionieren kann. Die Superklasse kennt die Unterklassen ja nicht und kann sie auch nicht kennen, spätestens beim Hinzufügen einer neuen schlägt das fehl.

Du kannst aber abstrakte Methoden definieren und die in Unterklassen implementieren. Dann funktioniert es. Dazu am besten ein Interface für die Unterklassen definieren und zB sagen, die Unterklasse muß die Methoden object readData() und void writeData() implementieren. Dann kannst Du einfach die Methoden der Superklasse aufrufen und nach übergebenem Objekt kümmert sich JAVA dann schon selber um die Auswahl der richtigen Implementierung.
 
Bevor du hier viele Stunden verschenkst: das was du brauchst wurde alles schon implementiert in "Jackson" - Json Bibliothek. Mit Annotationen kannst du da Klassen-Hierarchien markieren und zwar auch so dass diese Info im Json steckt (wenn du willst). Beim Deserialisieren erhälst dann automatisch die das Objekt des richtigen typs:
https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization

Falls es aber ein Programmierübung ist:

Den Typ musst du glaube als "Class" übergeben - im Constructor ist gut. new Container(Untertyp1.class, ...)
Zu dem solltest du Generics benutzen z.B. class Container<T> - im Constructor gibst dann z.B. eben Untertyp1.class.
 
Vielen Dank fürs lesen, ist glaube ich etwas wirr geworden was ich da geschrieben habe.

In wenigen Worten zusammengefaßt: Du möchtest ein JSON-gestütztes Backend für JAVA haben, sodaß Du Objekte in JAVA transparent in JSON abbilden kannst und andersherum per Übergabe von JSON die damit abgebildete Konfiguration in JAVA bekommst. Dafür hast Du einen definierten Schlüsselsatz (in JSON), der - nehm ich mal an -- vorgegeben ist.

Ganz so komplex soll es eigentlich nicht werden. Eventuell kann ich es an einem Beispiel etwas besser erklären.
Ich habe zwei komplette Datensätze in JSON Form welche von ihrem Aufbau her unterschiedlich sein können.
Code:
# 1
{
  "typ": "",
  "array": [],
  "objekt:": {
    "a": ""
  }
}
# 2
{
  "typ": "",
  "andererkeyfüranderes_array": [],
  "andererkeyfüranderes_objekt:": {
    "a": ""
  }
}
Anhand des Keys typ 'erkenne' ich wie der Rest des JSON Objekts aufgebaut sein muss und ich kann dann daran eine Unterklasse von DataType auswählen.
Code:
{
  "typ": "frucht",
  "frucht_unnützesarray": [],
  "frucht_eigenschaften:": {
    "a": ""
  }
}
Wenn ich typ = frucht habe kommen alle meine anderen Keys welche in dem JSON vorkommen sollen, auch als Objekte der Unterklasse DataType.Frucht vor. Also frucht_eigenschaften würde ich über DataType.Frucht.Eigenschaften darstellen lassen. Dieses Objekt beinhaltet dann zum einen den eigentlichen Key (frucht_eigenschaften) und zum anderen den Objekt Typ des Values, also ob es ein Objekt, ein Array, ein String etc ist. Das ganze soll es möglichst einfach machen später die Daten richtig zu ordnen.

Jetzt habe ich ja von einem Container erzählt welcher dieses große JSON Objekt beinhaltet. Dieser stellt neben dem aufbewahren des JSONs noch die Funktionen für den Zugriff auf die entsprechenden Dateien und beinhaltet wann jeder dieser zuletzt geändert wurde.
Also über die DataType.Sub.Objekte kann ich auf die Elemente des JSONs zugreifen welche hinter dem Key definiert über das Objekt liegen und diese lesen, verändern, etc.

Jetzt habe ich damit zwei Probleme:

- Ich kann theoretisch bei einem Container der eigentlich Daten im Schema A (Inhalt lässt sich durch Objekte der Klasse DataType.A beschreiben) beinhaltet, Daten von Schema B abfragen.
Das kann ich allerdings gut über generics lösen.

- Da ich je DataTyp Unterklasse ein bestimmtes Objekt gewählt habe um zu ermöglichen den kompletten Inhalt des JSONs zu ändern/zurück zu geben (DataType.###.Everything) müsste ich eine bestimmte Abfrage auf dieses Objekt haben da dieses ja nicht über einen Key im JSON definiert ist/sein kann. Ich könnte hier das Objekt sich einfach über einen einheitlichen, nicht im JSON genutzten Key identifizieren, allerdings würde das dazu führen das die Eindeutigkeit fehlt. Daten von DataType.A.Everything sind ja ungleich zu DataType.B.Everything.
Ich müsste also irgendwie die Klasse übergeben können in der sich mein Objekt dann befindet und daraus dann ein statisches Objekt ziehen.
Also sowas wie ich übergebe DataType.B (Klasse.Klasse) an den Konstruktor, speichere das als Class zwischen und greife auf mein statisches Objekt über Class.Everything zu war meine Idee. Jetzt scheinen Objekte vom Typ Class sich allerdings nicht so zu verhalten wie die eigentliche Klasse an sich.
Jetzt weiß ich nicht wie ich auf das Objekt zugreifen kann. (mit einem Switch zwischen den Klassen geht das sicherlich, ist aber nicht wirklich sauber)
Screenshot_1.png

Code:
public JSONObject getData(DataType dataType){

        if(dataType != DataType.ABCD.Everything){    // soll abhängig sein je nachdem was in dem Container gespeichert wird
            if(JSONDATA.has(dataType.getID())){
                JSONObject response = new JSONObject();
                response.put(dataType.getKey(), JSONDATA.get(dataType.getKey()));
                return response;
            }else{
                return null;
            }
        }else{
            JSONObject response = new JSONObject();
            response.put(dataType.getKey(), JSONDATA);
            return response;
        }
    }



Die Containerfrage kann man durchaus als Dictionary abhandeln (ich vermute mal, Du hast nur zur Vereinfachung die Ausweisung als Liste(n) in den Feldern weggelassen) aber JSON hat damit nichts mehr zu tun. Einfach das Ganze stinknormal modellieren, so wie Du's auch sonst modellieren würdest.
Der Container ist nur dafür da um dem JSON einige Zugriffsfunktionen und einen 'DataType' zuzuordnen.

Du kannst aber abstrakte Methoden definieren und die in Unterklassen implementieren. Dann funktioniert es. Dazu am besten ein Interface für die Unterklassen definieren und zB sagen, die Unterklasse muß die Methoden object readData() und void writeData() implementieren. Dann kannst Du einfach die Methoden der Superklasse aufrufen und nach übergebenem Objekt kümmert sich JAVA dann schon selber um die Auswahl der richtigen Implementierung.
Würde das nicht dazu führen das ich mehrfach den fast identischen Ablauf zusammensetzen würde um nur die Objekte eines Vergleiches zu ändern? Ich glaube das muss ich mir noch etwas näher ansehen.

//Edit
Habe eine Lösung gefunden, mit .getClass().getDeclaredField().get() lässt sich das gewünschte Objekt beschaffen. Das löst zumindest das Problem auf wo ich ein Objekt habe das eh schon auf den Typen passt.
 
Zuletzt bearbeitet:
Zurück
Oben