Java Builder-Generatorproblem

8

In meinem Projekt habe ich zwei Pakete voller DTOs, POJOs mit nur Getter und Setter. Es ist zwar wichtig, dass es sich um einfache Java-Beans handelt (z. B. weil Apache CXF sie zum Erstellen von Web-Service-XSDs usw. verwendet), aber es ist auch schrecklich und fehleranfällig, so zu programmieren.

%Vor%

Ich bevorzuge fließende Interfaces und Builder-Objekte, daher verwende ich maven / gmaven, um automatisch Builder für die DTOs zu erstellen. Für den obigen Code wird also automatisch ein FooBuilder generiert, das ich so verwenden kann:

%Vor%

Ich erstelle auch automatisch Unit-Tests für die generierten Builder. Ein Komponententest würde beide oben genannten Codes generieren (Builder-Version und Nicht-Builder-Version) und bestätigen, dass beide Versionen in Bezug auf equals() und hashcode() gleichwertig sind. Die Art, wie ich das erreichen kann, ist eine global zugängliche Karte mit Standardeinstellungen für jeden Eigenschaftstyp. Etwas wie das:

%Vor%

Ein weiterer nicht-trivialer Aspekt ist, dass die Pojos manchmal Sammlungsmitglieder haben. z.B.:

%Vor%

aber in meinem Builder möchte ich, dass zwei Methoden aus diesem Fall generiert werden: eine set-Methode und eine add-Methode:

%Vor%

Ich habe das gelöst, indem ich eine benutzerdefinierte Annotation zu den Eigenschaftsfeldern in Foo

hinzugefügt habe %Vor%

Der Builder für Builder (sic) liest die Annotation und verwendet den Wert als generischen Typ der zu generierenden Methoden.

Wir nähern uns jetzt der Frage (Entschuldigung, die Kürze gehört nicht zu meinen Verdiensten: -)).

Ich habe festgestellt, dass dieser Builder-Ansatz in mehr als einem Projekt verwendet werden kann, also denke ich daran, es in ein Maven-Plugin umzuwandeln. Mir ist völlig klar, wie man ein Maven-Plugin generiert, also ist das nicht Teil der Frage (und auch nicht, wie man einen gültigen Java-Quellcode generiert). Mein Problem ist: Wie kann ich mit den beiden oben genannten Problemen umgehen, ohne irgendwelche gemeinsamen Abhängigkeiten (zwischen Projekt und Plugin) einzuführen:

<Question>

  1. Ich brauche eine Defaults-Klasse (oder einen ähnlichen Mechanismus), um Standardwerte für generierte Komponententests zu erhalten (dies ist ein wichtiger Teil des Konzepts, ich würde automatisch generierten Buildern nicht vertrauen, wenn sie nicht vollständig getestet wurden) . Bitte helfen Sie mir, eine gute und generische Lösung für dieses Problem zu finden, da jedes Projekt über eigene Domain-Objekte verfügt.

  2. Ich brauche eine allgemeine Methode, generische Typen mit dem Builder-Generator zu kommunizieren. Die aktuelle annotierungsbasierte Version, die ich verwende, ist nicht zufriedenstellend, da sowohl das Projekt als auch das Plugin die gleiche Anmerkung beachten müssen.

</Question>

Irgendwelche Ideen?

BTW: Ich weiß, dass der wahre Schlüsselpunkt der Verwendung von Bauelementen darin besteht, Objekte unveränderlich zu machen. Ich kann meine nicht unveränderlich machen, weil Standard-Java-Beans notwendig sind, aber ich setze AspectJ durch, um zu erzwingen, dass weder set-Methoden noch Konstruktoren irgendwo in meiner Codebasis aufgerufen werden, außer in den Buildern, so dass die resultierenden Objekte aus praktischen Gründen unveränderlich sind .

Auch: Ja, ich kenne existierende Builder-Generator IDE Plugins. Das passt nicht zu meinem Ziel, ich möchte eine automatisierte Lösung, die immer dann auf dem neuesten Stand ist, wenn sich der zugrunde liegende Code geändert hat.

Matt B hat einige Informationen darüber angefordert, wie ich meine Builder erstelle. Folgendes mache ich:

Ich lese eine Klasse pro Reflexion, verwende Introspector.getBeanInfo(clazz).getPropertyDescriptors() , um ein Array von Eigenschaftsdeskriptoren zu erhalten. Alle meine Builder haben eine Basisklasse AbstractBuilder<T> wobei T im obigen Fall Foo wäre. Hier ist der Code der Abstract Builder-Klasse . Für jede Eigenschaft im Array PropertyDescriptor wird eine Methode mit dem Namen der Eigenschaft generiert. Dies wäre die Implementierung von FooBuilder.bar(String) :

%Vor%

Die Methode build() in AbstractBuilder instanziiert das Objekt und weist alle Eigenschaften in seiner Eigenschaftenzuordnung zu.

    
Sean Patrick Floyd 23.11.2010, 14:33
quelle

2 Antworten

1

Haben Sie Diezel angeschaut? Es ist ein Generator-Generator.

  1. Es behandelt generische Typen, daher könnte es hier für die Frage 2
  2. hilfreich sein
  3. Es generiert alle Schnittstellen und die Implementierungs-Kesselbeschriftung anhand einer XML-Beschreibungsdatei. Sie könnten durch Introspektion in der Lage sein, diese XML zu generieren (oder geht sogar direkt in die untere API)
  4. Es ist als Maven-Plugin gebündelt.
eric 17.12.2011, 22:09
quelle
2

Ein POJO ist ein Objekt, das nicht dem Java Bean spoec folgt. dh. es hat keine Setzer / Getter.

JavaBeans müssen keine Setter haben. Wenn Sie nicht möchten, dass sie aufgerufen werden, erzeugen Sie sie nicht. (Ihr Builder kann ein lokales oder privates Konstruktorpaket aufrufen, um Ihre unveränderlichen Objekte zu erstellen)

    
Peter Lawrey 23.11.2010 15:28
quelle