2014-02-05 8 views
13

Ich versuche die beste Lösung für ein Problem zu finden, das ich mit der Zuordnung einer einfachen Bean-Struktur, die an eine browserbasierte JavaScript-Anwendung gesendet wird, habe. Die aktuelle Anforderung besteht darin, den größten Teil der Anzeigesteuerung im alten Java-Backend zu verwalten. Derzeit haben wir eine Service-Stil-Schicht, die Wertobjekte ohne Anzeigelogik in sie aufgebaut produziert mag:Complex Bean Mapping

public class Example1 { 
    String value1; 
    Boolean value2; 
    Example3 value3; 

    public String getValue1(){...} 
    public void setValue1(){...} 
    .... 
} 

Mein Ziel eine allgemeine Struktur über alle Felder abzubilden so in der Lage ist, dass es die neue Anzeigestruktur fügt das wird vom Front-End benötigt. Ich möchte nur die ursprüngliche Strukturklassenstruktur (Beispiel1-Klasse) verwalten und einfach die zusätzlichen Werte in einem Wrapper auf die alte Serviceschicht einstellen.

Die allgemeine Struktur würde die Form der folgenden Klasse nehmen:

public class Presentable<T> { 
    T value; 
    boolean visible = true; 
    boolean mandatory = false; 
    List<String> errors = new ArrayList<>(); 

    public T getValue() {...} 
    public void setValue(T value) {...} 
    ... 
} 

Das Endergebnis etwas wie folgt aussehen würde, wobei Wert auf den Wert in der ursprünglichen Struktur ist gleich:

public class Example2{ 
    Presentable<String> value1; 
    Presentable<Boolean> value2; 
    Presentable<Example3> value3; 

    public Presentable<String> getValue1(){...} 
    public void setValue1(){...} 
    ... 
} 

Gibt es eine Lösung für dieses Problem, ohne eine Example2-Stilklasse zu schreiben und jeden einzelnen Wert zu kopieren? Ich bin offen für die Änderung der Klasse Example1, da sie die Kunden des alten Dienstes nicht betrifft.

Danke.

+0

Update: Die einzige Lösung, die ich gefunden habe, ist die Verwendung von Code-Generationen mit Anmerkungen. Obwohl ich ein schnelles POC geschrieben habe, ist es sehr dreckig. –

+0

Sie müssen mehrere Objekte von Example1 auf der Grundlage der Client-Anforderung haben. Warum brauchen Sie dafür eine generische Klasse? Sie können ein Front-End-Arraylist-Mapping verwenden. Jedes Mal, wenn ein Benutzer ein neues hinzufügt, fügt es automatisch ein weiteres Objekt von Example1 in die ArrayList ein. Sie haben eine Liste , die alle Objekte von example1 enthält. – Dileep

Antwort

4

Sie können grundsätzlich AOP (Aspect Oriented Programming) mit Spring verwenden. Im Frühjahr können Sie ein Proxy-Objekt mit zusätzlichen Informationen erstellen, die Sie benötigen. Guter Ausgangspunkt ist: http://www.mkyong.com/spring3/spring-aop-aspectj-annotation-example/

Offizielle Seite auf Aspect Oriented Programming: http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/aop.html

Dieses Beispiel/Antwort kann nützlich sein: Intercepting method with Spring AOP using only annotations

+0

Das ist nah an dem, was ich suche, aber Frühling ist keine Option, obwohl ich weiß, dass die meisten Enterprise Java-Anwendung Spring in diesen Tagen zu integrieren. –

1

Also ich bin nicht sicher, ob ich das richtig verstanden habe Sie. Jedoch ...

Dies ist ein Ort, wo wir sehr einfach Reflexion verwenden können.

Für unsere Klasse Example1.class rufen wir getDeclaredMethods, getDeclaredFields (im einfachen Anwendungsfall) oder getMethods, getFields in komplexer (einfache pojo, aber mit Vererbung). Sie benötigen möglicherweise eine einfache Logik, um beispielsweise Felder mit dem Modifikator static oder ähnlichem zu entfernen.

Für jede Methode/Feld wir geeignete Methode/Feld von Example2.class mit getMethod (String name) oder getField (String name)

und setzen unseren Wert für neues Objekt durch Feld oder Setter bekommen. Wenn es ein Problem mit Modifikatoren wie privat gibt, verwenden wir setAccessible.

Einige Code für einfachen Anwendungsfall:

public Example2 decorateWithWrapper(Example1 obj) { 
    Example2 wrapped = new Example2(); 
    for (Field field : obj.getClass().getDeclaredFields()) { 
     Field toAssign = wrapped.getClass().getField(field.getName()); 
     toAssign.setAccessible(true); 
     toAssign.set(wrapped, field.get(obj)); 
    } 
    return wrapped; 
} 

Es ist ziemlich einfach allgemeinere Methode von diesem oben genannten zu tun, wenn nötig.

Sie benötigen keine externe Bibliothek oder Werkzeug.

1

können Sie Jackson ObjectMapper verwenden und [Dozer][1] Mapper konfigurieren, dass diese komplexe Bean-Mapping zu tun und lassen JSON zwischen Anwendung & Browser kommunizieren.

können Sie einmal Klasse in andere Feld für Feld zuordnen. Basic-Code für Dozer Mapping ist unten dargestellt:

<mappings>   
    <mapping> 
    <class-a>org.dozer.vo.TestObject</class-a> 
    <class-b>org.dozer.vo.TestObjectPrime</class-b> 
    <!-- Any custom field mapping xml would go here --> 
    </mapping> 
</mappings> 

Hier in obigem Beispiel alle Variablen von TestObject zu TestObjectPrime abgebildet werden. Für Ihren Fall müssen Sie benutzerdefinierte Zuordnung zu dieser Konfigurationen hinzufügen, wie unten gezeigt:

<mapping> 
    <class-a>org.dozer.vo.deep.SrcDeepObj</class-a> 
    <class-b>org.dozer.vo.deep.DestDeepObj</class-b> 

    <field> 
    <a>srcNestedObj.src1</a> 
    <b>dest1</b> 
    </field> 

    <field> 
    <a>srcNestedObj.src2</a> 
    <b>dest2</b> 
    </field> 

    <field> 
    <a>srcNestedObj.srcNestedObj2.src5</a> 
    <b>dest5</b> 
    </field> 

    <field><!-- java.util.List to java.util.List --> 
    <a>srcNestedObj.hintList</a> 
    <b>hintList</b> 
    <a-hint>java.lang.String</a-hint>   
    <b-hint>java.lang.Integer</b-hint> 
    </field> 

    <field> 
    <a>srcNestedObj.hintList2</a> 
    <b>hintList2</b> 
    <a-hint>org.dozer.vo.TheFirstSubClass</a-hint> 
    <b-hint>org.dozer.vo.TheFirstSubClassPrime</b-hint> 
    </field> 

    <field copy-by-reference="true"> 
    <a>srcNestedObj.hintList3</a> 
    <b>hintList3</b> 
    </field-deep> 

</mapping> 

Als Planierraupe Tutorial sagt:

Es ist möglich, tiefe Eigenschaften abzubilden. Ein Beispiel wäre, wenn Sie ein Objekt mit einer String-Eigenschaft haben. Ihr anderes Objekt verfügt über eine Eigenschaft "String ", befindet sich jedoch mehrere Ebenen tief im Objektdiagramm. Im Beispiel unten hat DestDeepObj geschachtelte Attribute innerhalb des Objekts Graph, die zugeordnet werden müssen. Typhinweise werden für Deep-Field- -Zuordnungen unterstützt. Die Attribute copy-by-reference, type = one-way und relationship-type können ebenfalls verwendet werden.

Die obigen Beispiele sind Auszug aus Dozer documentation.

Shishir

0

AspectJ zu aktivieren, müssen Sie aspectjrt.jar, aspectjweaver.jar und feder aop.jar. Für unsere Klasse Example1.class rufen wir getDeclaredMethods, getDeclaredFields (im einfachen Anwendungsfall) oder getMethods, getFields in komplexeren (einfache pojo, aber mit Vererbung) auf.