Objekte per Reflexion instanziieren

White_Fox

Top Contributor
Guten Abend allerseits

Folgende Probleme: Serialisierung macht Ärger, wenn man eine Klasse ändert, JSON zickt bei Zirkelreferenzen herum.

Und nun will ich eine Klasse schreiben, um diese Probleme zu erschlagen. Der Plan ist, die wesentlichen Informationen, die ein Objekt enthält, zu entnehmen und in einer Map zu speichern: Klassenname, Membervariablen und der Hash des Objekts um es eindeutig zu identifizieren. Wenn eine Membervariable ein Objekt ist, wird dessen Hash gespeichert und dieses Objekt ebenso zerlegt.

Aber irgendwie komme ich nicht weiter. Hier ist der Test:

Java:
public class UniversalDataTransferTest {

    //This class simulates a circular object reference
    class ClassToAnalyze {

        private int i;
        private String s;
        private ClassToAnalyze child;
        private ClassToAnalyze parent;

        public ClassToAnalyze() {
            this.i = 0;
            this.s = "TreeLevel " + this.i;
            this.parent = null;
            this.child = new ClassToAnalyze(this.i, this);
        }

        private ClassToAnalyze(int i, ClassToAnalyze parent) {
            this.i = ++i;
            this.s = "TreeLevel " + this.i;
            this.parent = parent;
            this.s = "TreeLevel " + this.i;

            this.child = this.i < 10 ? new ClassToAnalyze(this.i, this) : null;
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof ClassToAnalyze)) {
                return false;
            }

            ClassToAnalyze c = (ClassToAnalyze) obj;
            return this.i == c.i
                    && this.s.equals(c.s)
                    && this.child.equals(c.child);
        }
    }

    /**
     * Test of rebuild method, of class UniversalDataTransfer.
     */
    @Test
    public void testRebuild() {
        UniversalDataTransfer<ClassToAnalyze> instance;
        ClassToAnalyze strippedUpObject, rebuildObject;

        System.out.println("rebuild");

        strippedUpObject = new ClassToAnalyze();
        try {
            instance = new UniversalDataTransfer(strippedUpObject);
            rebuildObject = instance.rebuild();
            assertEquals(strippedUpObject, rebuildObject);
        }
        catch (IllegalAccessException | ObjectParseException | ClassNotFoundException | InstantiationException ex) {
            fail("Execption: " + ex.getClass().getName() + ": " + ex.getMessage());
        }
    }

    /**
     * Test of analyseObject method, of class UniversalDataTransfer.
     */
    @Test
    public void testAnalyseObject() {
        UniversalDataTransfer<ClassToAnalyze> instance;
        ClassToAnalyze strippedUpObject, rebuildObject;

        System.out.println("analyseObject");

        strippedUpObject = new ClassToAnalyze();
        instance = new UniversalDataTransfer();
        try {
            instance.analyseObject(strippedUpObject);
            rebuildObject = instance.rebuild();
            assertEquals(strippedUpObject, rebuildObject);
        }
        catch (IllegalAccessException | ObjectParseException | ClassNotFoundException | InstantiationException ex) {
            fail("Execption: " + ex.getClass().getName() + ": " + ex.getMessage());
        }
    }
}


Die Klasse(n):
Java:
class ObjectDescriptor {
    public String classType;
    public Integer objectHash;
    public ArrayList<MemberfieldDescriptor> fieldDescriptors;
   
    public ObjectDescriptor(){
        fieldDescriptors = new ArrayList<>();
    }
}

class MemberfieldDescriptor {
    public final String name;
    public final Object value;
    public final MemberType type;

    public MemberfieldDescriptor(String name, Object value, MemberType type) {
        this.name = name;
        this.value = value;
        this.type = type;
    }
}

public class UniversalDataTransfer<T> {

    private HashMap<Integer, ObjectDescriptor> objectDescriptions;
    private HashMap<Integer, Object> broughtToBeing;
    private Integer mainObjectHash;

    public UniversalDataTransfer() {

    }

    public UniversalDataTransfer(T o) throws IllegalAccessException {
        analyseObject(o);
    }

    public void analyseObject(T o) throws IllegalAccessException {
        this.objectDescriptions = new HashMap<>();
        this.mainObjectHash = o.hashCode();
        this.stripDown(o);
    }

    public T rebuild() throws ObjectParseException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        broughtToBeing = new HashMap<>();
        return (T) fitUp(objectDescriptions.get(mainObjectHash));
    }

    private void stripDown(Object o) throws IllegalAccessException {
        ObjectDescriptor od;

        if (objectDescriptions.containsKey(o.hashCode())) {
            return;
        }

        od = new ObjectDescriptor();
        od.classType = o.getClass().getTypeName();
        od.objectHash = o.hashCode();
        objectDescriptions.put(od.objectHash, od);

        for (Field field : o.getClass().getDeclaredFields()) {
            MemberfieldDescriptor fd;

            field.setAccessible(true);
            fd = getFieldDescriptor(field, o);
            od.fieldDescriptors.add(fd);
            if (fd.type == MemberType.OBJECT) {
                if (fd.value != null) {
                    stripDown(field.get(o));
                }
            }
        }
    }

    private Object fitUp(ObjectDescriptor od) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class cl;
        Object o;

        if (broughtToBeing.containsKey(od.objectHash)) {
            return broughtToBeing.get(od.objectHash);
        }

        cl = Class.forName(od.classType);
        o = cl.newInstance();                      // <- Hier gibt es Ärger
        broughtToBeing.put(od.objectHash, o);

        for (MemberfieldDescriptor md : od.fieldDescriptors) {
            restorMemberfield(md, o);
        }
        return o;
    }

    private MemberfieldDescriptor getFieldDescriptor(Field field, Object o) throws IllegalArgumentException, IllegalAccessException {
        String name;
        Object value;
        MemberType type;

        name = field.getName();
        type = getMembertype(field.get(o));
        if (field.get(o) != null) {
            value = (type == MemberType.OBJECT) ? field.get(o).hashCode() : field.get(o);
        }
        else {
            value = null;
        }

        return new MemberfieldDescriptor(name, value, type);
    }

    private MemberType getMembertype(Object o) {
        if (o == null) {
            return MemberType.OBJECT;
        }
        for (MemberType mt : MemberType.values()) {
            if (o.getClass().equals(mt.getAssociatedClass())) {
                return mt;
            }
        }
        return MemberType.OBJECT;
    }

    private void restorMemberfield(MemberfieldDescriptor md, Object o) throws IllegalArgumentException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        for (Field f : o.getClass().getDeclaredFields()) {
            if (f.getName().equals(md.name)) {
                f.setAccessible(true);
                if (md.type == MemberType.OBJECT) {
                    if (broughtToBeing.containsKey(md.value)) {
                        f.set(o, broughtToBeing.get(md.value));
                    }
                    else {
                        f.set(o, fitUp(objectDescriptions.get(md.value)));
                    }
                }
                else {
                    f.set(o, md.value);
                }
            }
        }
    }
}

Allerdings bekomme ich an der markierten Stelle ständig eine InstantiationException. Hat jemad eine Ahnung, warum? Ich hab die innere Testklasse im Verdacht, aber in einem kurzen Test habe ich das auch gemacht und da hat das funktioniert.

Edit:
Wenn jemand Vorschläge für Codeverbesserungen hat - immer her damit, ich bin damit noch nicht so richtig zufrieden, diese Ansammlungen verschachtelter If-Statements sehen nicht gerade schön aus.
 

abc66

Top Contributor
Java:
	public static Object instantiate(Class<?> cl) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Constructor<?>[] constructors = cl.getConstructors();
		for (Constructor<?> constructor : constructors) {
			if (constructor.getParameterCount() == 0) {
				return constructor.newInstance(new Object[0]);
			}
		}
		return null;
	}

.newInstance(); is deprecated und Du hast new Object[0] vergessen.
 

White_Fox

Top Contributor
.newInstance(); is deprecated
Hm, in Java 8 anscheinend noch nicht. Aber danke dafür. Eine Merkwürdigkeit ist da aber noch drin: Ich finde in cl.getConstructors() keinen Konstruktor, der ein getParameterCount() == 0 zurückliefert. Sondern es wird 1 zurückgegeben. Die Methode getDeclaredConstructors() liefert noch einen, der drei Parameter verlangt, aber der andere Konstruktor benötigt nur zwei.

Irgendeine Idee, was da passiert?
 

White_Fox

Top Contributor
Sicher. Aber das erkärt mir noch nicht, warum ich ihn nicht aufrufen kann bzw. warum der nach einem Parameter verlangt, den ich nicht deklariert habe.
 

White_Fox

Top Contributor
Es lag doch daran, daß das Testobjekt über eine innere Klasse gebaut wird und ich das nicht berücksichtigt habe. Jetzt muß ich darauf auch noch achten...wenn es insgesamt mal läuft.
 

White_Fox

Top Contributor
So, da ich mal wieder Zeit (aber vor allem Lust) habe, mich damit weiterzubefassen: Innere Klassen instanzieren, weiter gehts.

Bei tutorialspoint.com habe ich dieses Beispiel:
Java:
class OuterClass {
   private int value = 20;
      class InnerClass {
         void show() {
            System.out.println("Value is: "+ value);
      }
   }
}
public class Test {
   public static void main(String args[]) {
      OuterClass obj = new OuterClass();
      OuterClass.InnerClass in = obj.new InnerClass();
      in.show();
   }
}

Wie mache ich das aber, wenn ich die Klassennamen zur Programmierzeit gar nicht kenne/kennen will?
 

Wurstkopp

Bekanntes Mitglied

Java:
          Class<?> enclosingClass = Class.forName("OuterClass");
          Object enclosingInstance = enclosingClass.getDeclaredConstructor().newInstance();

          Class<?> innerClass = Class.forName("OuterClass$InnerClass");
          Constructor<?> ctor = innerClass.getDeclaredConstructor(enclosingClass);

          Object innerInstance = ctor.newInstance(enclosingInstance);
          
          ((OuterClass.InnerClass) innerInstance).show();
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
schegga_B javax.crypto - Cipher Objekte - Sevice Provider matching? Allgemeine Java-Themen 1
berserkerdq2 Weiß jemand wie ich im Scenebuilder das Fenster so darstellen kann, dass beim Vollbildmodus die Objekte so angezeigt werden? Allgemeine Java-Themen 1
A Einzelne Objekte und Unterobjekte einer ArrayList ausgeben Allgemeine Java-Themen 53
B Java Reflection Probleme beim wehcselseitigen Referenzieren zweier Klassen/Objekte Allgemeine Java-Themen 14
N einem Array Objekte hinzufügen die ihr Array position gespeichert haben Allgemeine Java-Themen 34
E Objekte in einen String packen und wieder laden Allgemeine Java-Themen 5
L Objekte in Set nicht gefunden Allgemeine Java-Themen 13
Avalon Data Transfer Objekte aus Datenbank erstellen Allgemeine Java-Themen 8
G Objekte mit Strings Aufrufen Allgemeine Java-Themen 8
H Objekte speichern und laden Allgemeine Java-Themen 10
H Objekte speichern und laden Allgemeine Java-Themen 1
MiMa Referenz auf Objekte und deren Inhalte Allgemeine Java-Themen 12
W Objekte reproduzieren Allgemeine Java-Themen 2
W Unittest - Objekte simulieren Allgemeine Java-Themen 7
T OOP Objekte mit Erweiterung Initialisieren Allgemeine Java-Themen 6
O Erste Schritte Objekte als Datenelemente Allgemeine Java-Themen 14
J Equals Mock Objekte Allgemeine Java-Themen 5
J Mockito - Objekte miteinander vergleichen (equals) Allgemeine Java-Themen 6
N Bei Mouse Events nicht mehrere Objekte erstellen Allgemeine Java-Themen 13
J Zugriff auf erstellte Objekte einer Klasse von einer Klasse ausserhalb Allgemeine Java-Themen 3
J Java Objekte = null, Garbagecollector Allgemeine Java-Themen 12
F Listen - Mehrere Objekte Allgemeine Java-Themen 1
J Verständnis Frage zur Instanz, Objekte, Instanzierung, Referenz Allgemeine Java-Themen 14
F Objekte erzeugen Allgemeine Java-Themen 1
E Threads ThreadPoolExecutor remove mit callable Objekte Allgemeine Java-Themen 3
P mehrer Verschiedene Objekte in einer Klasse erstellen. Allgemeine Java-Themen 4
E OOP Objekte und Methoden Allgemeine Java-Themen 1
@SupressWarnings() Umgebungsvariable Objekte "gekoppelt" Allgemeine Java-Themen 6
S Algorithmus um Objekte auf einer Flaeche mit gleichem Abstand anzuordnen..? Allgemeine Java-Themen 20
C Objekte in Array List speichern? Allgemeine Java-Themen 1
OnDemand Objekte speichern Allgemeine Java-Themen 8
B Objekte anhand von Properties file Allgemeine Java-Themen 41
U Tiefe Objekte schreiben Allgemeine Java-Themen 1
R Abstrakte Basisklasse und instanzierte Objekte der abgeleiteten Klasse als Basisklasse übergeben Allgemeine Java-Themen 2
E 3D Objekte in 2D Bild finden Allgemeine Java-Themen 5
J Daten aus GUI auslesen und in Objekte umwandeln Allgemeine Java-Themen 6
F FileOutput/Input Objekte Allgemeine Java-Themen 6
OnDemand Objekte serialisieren Allgemeine Java-Themen 3
J unterschiedliche Objekte, selbe getter und setter Allgemeine Java-Themen 15
L Lib gesucht: Java-Objekte mit JSON Allgemeine Java-Themen 2
U Set erklären dass objekte gleich sind Allgemeine Java-Themen 12
E Best Practice Verdammt große Objekte Allgemeine Java-Themen 10
B Mehrere Objekte verschlüsselt serialisieren Allgemeine Java-Themen 6
G Liste anzahl der gleichen Objekte Allgemeine Java-Themen 6
N Objekte an eine andere Applikation übergeben Allgemeine Java-Themen 3
N 2 Objekte zu einer Gruppe zusammenfügen Allgemeine Java-Themen 7
M Instanzierte Objekte in XML Dokument speichern Allgemeine Java-Themen 3
B Verschiedene Objekte in Abhängigkeit eines Typs instanziieren. Allgemeine Java-Themen 17
K Input/Output Im Programm instanzierte Objekte Speichern und laden Allgemeine Java-Themen 3
S OOP Objekte als Return-Werte: Einen Klon zurückgeben oder Instanz auf das Feld? Allgemeine Java-Themen 10
H Objekte Serialisiert speichern Allgemeine Java-Themen 10
L MouseListener für viele Objekte erstellen Allgemeine Java-Themen 16
5 Objekte Sortieren lassen Allgemeine Java-Themen 7
N Objekte aus Array Inhalt erzeugen Allgemeine Java-Themen 8
L Input/Output Textdatei in Objekte überführen? Allgemeine Java-Themen 4
R Input/Output Objekte speichern ohne überschreiben Allgemeine Java-Themen 7
A Collections HashMap.containsKey findet keine immutablen Objekte Allgemeine Java-Themen 3
H Threads Thread stirbt aber Objekte in ihm leben weiter?! Allgemeine Java-Themen 9
M Java Objekte in XML mit JAXB Allgemeine Java-Themen 9
C Strings und JSON Objekte so klein wie möglich im Speicher ablegen Allgemeine Java-Themen 5
H COM-Objekte/ AktiveX Objekte Allgemeine Java-Themen 4
C Script für Website mit Objekte Ausblenden Allgemeine Java-Themen 3
M Txt einlesen & Objekte erzeugen Allgemeine Java-Themen 2
X Objekte aus TableModel serialisieren und deserialisieren Allgemeine Java-Themen 4
T ObjectInputStream - Arrayliste, die unbekannte Objekte enthält Allgemeine Java-Themen 9
B class dateien "einlesen" und objekte erzeugen Allgemeine Java-Themen 6
D Grafische Objekte zeichnen Allgemeine Java-Themen 4
A Wie zur Laufzeit auf Objekte zugreifen Allgemeine Java-Themen 7
F Referenzen auf Objekte Allgemeine Java-Themen 5
H Eclipse und Objekte Allgemeine Java-Themen 6
S Objekte die Objekte enthalten: Keine Vererbung Allgemeine Java-Themen 4
E Objekte in einer Liste suchen. Allgemeine Java-Themen 4
I Über eine Liste iterieren und Objekte löschen. Wie löst man das sauber? Allgemeine Java-Themen 5
I Pattern zum Erweitern existierender Objekte Allgemeine Java-Themen 4
N Dynamische Objekte / DB Allgemeine Java-Themen 5
J Objekte binär speichern Allgemeine Java-Themen 10
TiME-SPLiNTER Unbekannte Anzahl serialisierter Objekte lesen Allgemeine Java-Themen 2
V Objekte in Kategorien einteilen. Allgemeine Java-Themen 6
M 3D Objekte mit einer Linie Verbinden Allgemeine Java-Themen 3
F Wie zur Laufzeit ganz neue Objekte erzeugen? Allgemeine Java-Themen 5
A Dummy-Objekte für Webgui erzeugen Allgemeine Java-Themen 12
W Objekte speichern mit JFileChooser Allgemeine Java-Themen 8
D befehl auf mehrere objekte anwenden Allgemeine Java-Themen 7
L Objekte in Liste packen Allgemeine Java-Themen 2
S XML in Objekte wandeln. Euer Rat? Allgemeine Java-Themen 12
G Objekte serialisieren Allgemeine Java-Themen 2
L Parameter-Objekte verändern oder nicht? Allgemeine Java-Themen 6
D Objekte nur unter bestimmten Voraussetzungen erzeugen Allgemeine Java-Themen 4
S Objekte mit Arrays Allgemeine Java-Themen 9
F Objekte oder besser ID in Listen speichern? Allgemeine Java-Themen 2
S erzeugte objekte zählen Allgemeine Java-Themen 3
U auf Objekte mit variablem Namen zugreifen Allgemeine Java-Themen 4
Airwolf89 dynamischer Zugriff auf Variablen/ Objekte Allgemeine Java-Themen 4
Landei Objekte ohne Konstruktoraufruf erzeugen Allgemeine Java-Themen 7
E tiefe Kopie nicht serialisierbarer Objekte Allgemeine Java-Themen 3
J Speicherbedarf und persistente Objekte Allgemeine Java-Themen 4
J ArrayList Objekte anhand Propertywerte filtern Allgemeine Java-Themen 3
R Moeglichst viele Datumsstrings in Date Objekte konvertieren? Allgemeine Java-Themen 3
J Eindeutige ID für Objekte als Keys in TreeMap Allgemeine Java-Themen 12
G Unveränderbare Objekte Allgemeine Java-Themen 9

Ähnliche Java Themen

Neue Themen


Oben