2010-12-09 12 views
10

Ich habe Paare von Klassen, in denen die Felder von einer Teilmenge der Felder eines anderen ist und die Getter der Oberklassen alle vorhersagbar benannt sind (getFoo()). Gibt es einen Weg zu effizient Kopieren Sie alle allgemeinen Felder über die Superset-Klasse in die Subset-Klasse, oder zumindest den Code dafür automatisch generieren.Copy Felder zwischen ähnlichen Klassen in Java

Ich sollte beachten, dass:

  • Aus verschiedenen Gründen kann ich die Oberklassen nicht bearbeiten, noch kann ich sie nur in ganz nutzen zu vermeiden, dass die Datenkopie zu tun.
  • Ich kann möglicherweise neue Methoden in den Subset-Klassen erstellen, aber ich kann ihre Felder nicht ändern.
  • Wir haben Dutzende dieser Paare, und einige der Klassen haben viele viele Felder, so dass dies per Hand zu tun ist unhandlich, um es gelinde auszudrücken.
  • Ein Kollege hat mit einem Verfahren kam eine allgemeine Kopiermethode zu erstellen, die Java-Reflexion nutzt alle zwei Klassen zu nehmen, durchlaufen die Felder wie Streicher, keine Manipulation String den Getter Namen zu bestimmen, und dann automatisch ausführen zu das Feld in der Teilmengenklasse. Es ist schrecklich, aber es scheint zu funktionieren. Ich hoffe wirklich, dass es einen besseren Weg gibt.

Edit: einige einfache Code wie gewünscht

public class SuperClass { 
    private int foo; 
    private int bar; 
    private float bat; 
    public int getFoo() { return foo; } 
    public int getBar() { return bar; } 
    public float getBat() { return bat; } 
} 

public class SubClass { 
    private int foo; 
    private float bat; 
} 

//wanted 
public static copySuperFieldsToSubMethod(Object super, Object sub) { ??? } 

// also acceptable would be some way to autogenerate all the assignment 
// functions needed 
+0

Wenn Sie die Superset-Klassen bearbeiten könnten, könnten Sie sie einfach dazu bringen, Ihre Subset-Klassen zu erweitern und alle ihre Felder und Methoden in klassischer OO-Mode zu erben. Warum können Sie die Oberklassen nicht bearbeiten? – Asaph

+0

@Asaph - leider sind die Oberklassen Teil einer externen Bibliothek, die separat entwickelt wurde und die ich jetzt in die Klassen umwandeln muss, die für dieses spezifische Projekt erstellt wurden, die nicht viel von den Informationen in den größeren verwenden . – Dusty

+0

Was passiert, wenn Sie die Beziehung auf den Kopf stellen und Ihre Subset-Klassen von der Superset-Klasse erben lassen? Sie können alle Methoden in Bezug auf Felder, die Sie nicht benötigen, mit leeren Körpern überschreiben. Es ist nicht zu elegant, aber zumindest können Sie Code ohne Kopieren/Einfügen, Spiegeln oder Codegenerierung wiederverwenden. – Asaph

Antwort

12

könnten Sie die BeanUtils Klasse im Spring Framework verwenden, um dies zu tun. Es ist nicht unbedingt effizienter als Ihre reflexionsbasierte Technik, aber es ist sicherlich einfach zu programmieren. Ich gehe davon aus, dass alles, was Sie würden tun müssen, ist:

BeanUtils.copyProperties(source, target); 

Javadoc für diese Methode bei http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/BeanUtils.html#copyProperties(java.lang.Object,%20java.lang.Object)

verfügbar Wenn das nicht passen, könnten Sie auch prüfen, BeanWrapper/BeanWrapperImpl im Frühjahr Framework um die Eigenschaften Ihrer Klassen zu durchlaufen. Dies wäre einfacher als die Verwendung von Low-Level-Reflektions-APIs.

+1

Wow, das ist im Wesentlichen genau das, wonach ich suche, aber ich denke nicht, dass es machbar ist, das Spring Framework für genau dieses eine Problem einzubinden. – Dusty

+4

Apache Commons BeanUtils könnte dann geeignet sein, es ist ein bisschen leichter als Spring. Es hat eine gleichnamige Klasse und Methode, die verdächtig ähnlich aussieht, obwohl ich sie nie benutzt habe. Siehe http://commons.apache.org/beeutils/ – gutch

+0

Die Spring-Version funktioniert besser bei Klassen, die durch Vererbung in Beziehung stehen. – raffian

0

Können Sie einige Beispiel-Code aus Ihrer Anwendung zur Verfügung stellen, die das Szenario zeigt Sie in Ihrem Beitrag erwähnt haben? Gerade jetzt scheint die Reflexion der beste Weg zu sein, da Sie die Klassenmitglieder zur Laufzeit untersuchen können.

+0

Hinzugefügt einige Beispielcode, aber generische (ich kann den tatsächlichen Code nicht zeigen) – Dusty

+0

@ gutch Ansatz genau passt Ihre Anforderung, aber leider können Sie nicht verwenden. –

2

Wenn Sie die Aufgabe wollen effizient (in Bezug auf die Laufzeitleistung), dann die Kopie Hand-Codierung Getter und Setter verwendet, ist der Weg zu gehen. Wenn es an den Getter- oder Setter-Methoden nicht etwas Tolles gibt, werden ihre Körper so inline, dass sie genauso schnell sind wie Feldzuweisungen.

Der reflektive Ansatz (z. B. mit einer vorhandenen Klasse wie BeanUtils) ist weniger Codierung, aber wahrscheinlich eine Größenordnung langsamer als Getter und Setter auf einfache Weise aufrufen. Wenn Sie versuchen, dies selbst zu implementieren, werden Sie möglicherweise mehr Arbeit haben, als Sie erwartet haben, insbesondere wenn Ihre reflektierende Kopierklasse/Methode mit überladenen Methoden, Vererbung, Wertumwandlung, Boxen/Unboxing usw. zurechtkommt.

Mit dem Code-Generierung Ansatz, müssen Sie den Aufwand und die Komplexität der Implementierung die Codegenerierung (mit welcher Technik Sie wählen) im Vergleich zu dem Aufwand des Schreibens der Kopiermethoden von Hand balancieren. Wahrscheinlich werden Sie vor 20 Unterrichtsstunden nicht mit dem Code Generation Ansatz brechen ...und viele mehr, wenn Sie mit der Technologie nicht vertraut sind.

1

Ich würde ein einfaches Java-Tool schreiben, um automatisch den Quellcode für Klassen zu generieren, die die Subsets-Felder mit den gemeinsamen Feldern von Superset füllen können. Dieses Tool verwendet Reflektion, um die Namen der Getter- und Setter-Methoden abzurufen. Der Rest sind (triviale) String-Operationen, um eine Quelldatei im Speicher zu "schreiben" und sie in einer *.java Datei zu speichern. Kompilieren Sie alle diese automatisch generierten Dateien und fügen Sie die Klassendateien dem Klassenpfad hinzu.

Die Klasse könnte wie folgt aussehen:

class AClassToBClassPopulator implements Populator { 
    @Overwrite 
    public void populate(Object superSet, Object subSet) { 
     subSet.setFieldA(superSet.getFieldA()); 
     subSet.setFieldB(superSet.getFieldB()); 
     // .. and so on. The method body is created through reflection 
    } 
} 
0

Dies ist offensichtlich eine Aufgabe für Java Reflexion und während andere bereits gültig vorgeschlagen haben, obwohl vielleicht ein bisschen Schwergewicht Lösungen, hier ein Mehr noch:

Vor etwa einem Jahr schrieb ich eine kleinere JavaBean-Eigenschaft Modifikator-Bibliothek mit dem Namen BeanPropertyController. Obwohl ich es nicht ausdrücklich jedem empfehle, denke ich, dass die Namensgeberklasse der Bibliothek (see source) als Referenz verwendet werden kann, um ähnliche Funktionalität Ihren Bedürfnissen anzupassen. Als kleines Beispiel hier ist, wie ich BPC verwendet zu tun (fast!), Was Sie fragen:

// somewhere in code... 
SuperClass a = new SuperClass(); 
a.foo = 101; 
a.bar = 102; 
a.bat = 103f; 

SubClass b = new SubClass(); 
b.foo = 201; 
b.bat = 202f; 

BeanPropertyController fromB = BeanPropertyController.of(b, ExtractionDepth.QUESTIMATE); 
BeanPropertyController toA = BeanPropertyController.of(a, ExtractionDepth.QUESTIMATE); 

// This is where the magic happens: 
for (String propertyName : fromB.getPropertyNames()) { 
    toA.mutate(propertyName, fromB.access(propertyName)); 
} 
a = (SuperClass) toA.getObject(); 
b = (SubClass) fromB.getObject(); 

System.out.println("SuperClass' foo="+a.foo+" bar="+a.bar+" bat="+a.bat); 
System.out.println("SubClass' foo="+b.foo+" bat="+b.bat); 

Dies gibt

SuperClass' foo=201 bar=102 bat=202.0 
SubClass' foo=201 bat=202.0 

Also, was ich vorschlagen, ist, dass Sie gehen an die URL, die ich verlinkt habe, und passe diesen Code an deine Bedürfnisse an. Ich bin mir ziemlich sicher, dass Sie die verschiedenen Instanziierungsmethoden, Vorschlagswertanbieter usw., die ich aufgenommen habe, nicht benötigen. Und ja, BPC kann als veraltet angesehen werden.

Verwandte Themen