私は Web アプリケーションに Tapestry 5.3.6 を使用しており、ユーザーが Web フォームを使用して Java クラス (「Bean」、または POJO) のインスタンスを編集することを望んでいます (すぐに の使用を提案しますbeaneditform
) - ただし、Java クラスは編集対象はかなり複雑な構造をしています。Tapestry 5 でこれを行う最も簡単な方法を探しています。
まず、いくつかのユーティリティ クラスを定義しましょう。
public class ModelObject {
private URI uri;
private boolean modified;
// the usual constructors, getters and setters ...
}
public class Literal<T> extends ModelObject {
private Class<?> valueClass;
private T value;
public Literal(Class<?> valueClass) {
this.valueClass = valueClass;
}
public Literal(Class<?> valueClass, T value) {
this.valueClass = valueClass;
this.value = value;
}
// the usual getters and setters ...
}
public class Link<T extends ModelObject> extends ModelObject {
private Class<?> targetClass;
private T target;
public Link(Class<?> targetClass) {
this.targetClass = targetClass;
}
public Link(Class<?> targetClass, T target) {
this.targetClass = targetClass;
this.target = target;
}
// the usual getters and setters ...
}
これで、次のようなかなり複雑なデータ構造を作成できます。
public class HumanBeing extends ModelObject {
private Literal<String> name;
// ... other stuff
public HumanBeing() {
name = new Literal<String>(String.class);
}
// the usual getters and setters ...
}
public class Project extends ModelObject {
private Literal<String> projectName;
private Literal<Date> startDate;
private Literal<Date> endDate;
private Literal<Integer> someCounter;
private Link<HumanBeing> projectLeader;
private Link<HumanBeing> projectManager;
// ... other stuff, including lists of things, that may be Literals or
// Links ... e.g. (ModelObjectList is an enhanced ArrayList that remembers
// the type(s) of the objects it contains - to get around type erasure ...
private ModelObjectList<Link<HumanBeing>> projectMembers;
private ModelObjectList<Link<Project>> relatedProjects;
private ModelObjectList<Literal<String>> projectAliases;
// the usual constructors, getters and setters for all of the above ...
public Project() {
projectName = new Literal<String>(String.class);
startDate = new Literal<Date>(Date.class);
endDate = new Literal<Date>(Date.class);
someCounter = new Literal<Integer>(Integer.class);
projectLeader = new Link<HumanBeing>(HumanBeing.class);
projectManager = new Link<HumanBeing>(HumanBeing.class);
projectMembers = new ModelObjectList<Link<HumanBeing>>(Link.class, HumanBeing.class);
// ... more ...
}
}
Project.class のインスタンスをbeaneditform
指定すると、多くのカスタム コーサー、トランスレーター、バリューエンコーダーなどを提供する必要が生じる前に、それほど遠くまで到達することはありません。それでも、ジェネリックを使用できないという問題に遭遇します「貢献する」とは、強制者、翻訳者、バリューエンコーダーなどです。
次に、これらの問題を回避するために独自のコンポーネントを作成し始めました (例:ModelObjectDisplay
およびModelObjectEdit
)。しかし、これには、学習する時間よりもはるかに多くのタペストリーの内臓を理解する必要があります。標準コンポーネントを使用し、「デリゲート」などを自由に使用したいのですが、これで私がたどる簡単な道を誰かが見ることができますか?
ここまで読んでくれてありがとう。
PS: なぜ私がこのようなことをしたのか疑問に思っているなら、それはモデルが RDF グラフ データベース (別名トリプル ストア) からのリンクされたデータを表しているためです。リンク)他のデータへのリンク(これを行うためのより良い方法を提案することも歓迎します:-)
編集:
@uklanceは、表示ブロックと編集ブロックの使用を提案しました-これは私がすでに試したことです:
まず、 AppPropertyDisplayBlocks.tml に次のものがありました...
<t:block id="literal">
<t:delegate to="literalType" t:value="literalValue" />
</t:block>
<t:block id="link">
<t:delegate to="linkType" t:value="linkValue" />
</t:block>
そしてAppPropertyDisplayBlocks.javaで...
public Block getLiteralType() {
Literal<?> literal = (Literal<?>) context.getPropertyValue();
Class<?> valueClass = literal.getValueClass();
if (!AppModule.modelTypes.containsKey(valueClass))
return null;
String blockId = AppModule.modelTypes.get(valueClass);
return resources.getBlock(blockId);
}
public Object getLiteralValue() {
Literal<?> literal = (Literal<?>) context.getPropertyValue();
return literal.getValue();
}
public Block getLinkType() {
Link<?> link = (Link<?>) context.getPropertyValue();
Class<?> targetClass = link.getTargetClass();
if (!AppModule.modelTypes.containsKey(targetClass))
return null;
String blockId = AppModule.modelTypes.get(targetClass);
return resources.getBlock(blockId);
}
public Object getLinkValue() {
Link<?> link = (Link<?>) context.getPropertyValue();
return link.getTarget();
}
AppModule.modelTypes は Java クラスからタペストリーで使用される String へのマップです。
public static void contributeDefaultDataTypeAnalyzer(
MappedConfiguration<Class<?>, String> configuration) {
for (Class<?> type : modelTypes.keySet()) {
String name = modelTypes.get(type);
configuration.add(type, name);
}
}
public static void contributeBeanBlockSource(
Configuration<BeanBlockContribution> configuration) {
// using HashSet removes duplicates ...
for (String name : new HashSet<String>(modelTypes.values())) {
configuration.add(new DisplayBlockContribution(name,
"blocks/AppPropertyDisplayBlocks", name));
configuration.add(new EditBlockContribution(name,
"blocks/AppPropertyEditBlocks", name));
}
}
私は編集ブロックに同様のコードを持っていました...しかし、これはどれもうまくいかないようでした.リテラルに格納された値またはリンクが指しているオブジェクト (うーん... [Ll]inkValue ではなく、[Ll]inkTarget である必要があります)。また、Tapestry が適切な「トランスレーター」、「バリューエンコーダー」、または「コーサー」を見つけられないというエラーに遭遇し続けました...私はしばらくプレッシャーにさらされているので、抜け出すためにこれらの曲がりくねった通路をたどるのは困難です迷路 :-)