オブジェクトのツリーを生成する Java で小さな内部 DSL を作成しようとしています。DSL コードは次のようになります。
RuleBuilder builder = new RuleBuilder(new Syntax());
Syntax s =
builder.rule("rule1")
.identifier("foo")
.choice()
.terminal("bar")
.end() // 1) Here it works.
.end() // 2) Here complains the compiler.
.rule("rule2")
.identifier("bar")
.end()
.build();
コンパイラは (2 で)java.lang.Object
によって返されたオブジェクトにend()
メソッドがないと文句を言いますrule()
。Object にこのメソッドがないことは明らかです。ビルダー コードは次のとおりです (ツリーを組み立てるコードは簡単にするために残されています)。
class RuleBuilder {
private final Syntax syntax;
public RuleBuilder(Syntax syntax) {
this.syntax = syntax;
}
public GenericBuilder<RuleBuilder> rule(String name) {
return new GenericBuilder<RuleBuilder>(this);
}
public Syntax build() { return syntax; }
}
class GenericBuilder<P> {
private final P parentBuilder;
public GenericBuilder(P parentBuilder) {
this.parentBuilder = parentBuilder;
}
public <P> P end() {
return (P)parentBuilder;
}
public GenericBuilder<P> identifier(String value) { return this; }
public GenericBuilder<P> terminal(String value) { return this; }
public GenericBuilder<GenericBuilder> choice() { return new GenericBuilder<GenericBuilder>(this); }
// ... other sub node types
}
私の実装の背後にある主なアイデア: 生成された構文ツリーは、いくつかのルール ノードを持つ構文ルート ノードで構成されます。このルール ノードには、いくつかのサブノードを含めることができます。サブノードには、リーフとノードの 2 つのタイプがあります (コード例では、簡単にするために選択のみを行っています)。ノードとリーフをツリーに追加できる流暢なインターフェースを提供します。ツリー ブランチを「終了」するにend()
は、親ビルダーを返すメソッドがあります。
私が解決しようとしている問題は、メソッドend()
が親ビルダー オブジェクトを返す必要があることRuleBuilder
ですGenericBuilder
。上記の例で、1) で機能し、2) で機能しない理由がわかりません。
List<T>
ジェネリックに関する多くのリソースを読み、どのように機能するかを理解してMap<K,V>
います。そして、実行時に型情報が失われるという「消去」のことを認識しています。したがって、型情報が消去されると、実行時end()
に が返されることを理解できます。java.lang.Object
しかし、コンパイル時エラーが発生しました。Super Type Tokens と Typesafe Heterogenous Containers に関する Neal Gafter のブログも読みました。しかし、これで問題が解決するかどうかはわかりません。(Web での検索中に) いくつかの異なるアプローチを試みましたが、今は行き詰っています。