3

注釈内に情報ツリー構造を作成しようとしています。いくつかの試行とヘルプ ( Java 注釈の型階層を参照) の後、次のモデルに移行しました。

@interface Node {
  LogicalExpression logicalExpression() default LogicalExpression.AND;
  Attribute[] attributes() default {};
  Node[] nodes() default {};
}

このノードを使用すると、条件ツリーの 1 つのレベルを定義できます。logicalExpression 内の値は、子 (属性と別のノード) 間の関係を定義します。問題は、注釈が再帰的な依存関係を許可していないことです:

Cycle detected: the annotation type Node cannot contain attributes of the annotation type itself

NodeList アノテーションを Node に配置し、NodeList に Node のリストが含まれていても、循環依存関係が再び認識されます。

@interface NodeList {
  Node[] nodes();
}

@interface Node {
  LogicalExpression logicalExpression() default LogicalExpression.AND;
  Attribute[] attributes() default {};
  NodeList nodes() default EmptyList;
}

循環アノテーション定義に関する解決策はありますか?

4

3 に答える 3

2

上記の Java の制限により、無限再帰定義を定義することはできません。ただし、再帰的なもののように感じる、一定の深さの構造をサポートできます(深さの制限に達するまで)

深さ 3 のブール式言語の例を次に示します。

public @interface Expression {
    public Term value () default @Term;
    public And and () default @And;
    public Or or () default @Or;
}

各レベルの「and」操作を定義します。

public @interface And {
    public boolean not () default false;

    public Term[] value () default {};

    public Or1[] or1 () default {};
    public Or2[] or2 () default {};

    public And1[] and1 () default {};
    public And2[] and2 () default {};
}

public @interface And1 {
    public boolean not () default false;

    public Term[] value () default {};

    public Or2[] or2 () default {};

    public And2[] and2 () default {};
}

public @interface And2 {
    public boolean not () default false;
    public Term[] value () default {};
}

各レベルの「または」操作を定義します。

public @interface Or {
    public boolean not () default false;

    public Term[] value() default {};

    public Or1[] or1 () default {};
    public Or2[] or2 () default {};

    public And1[] and1 () default {};
    public And2[] and2 () default {};
}

public @interface Or1 {
    public boolean not () default false;

    public Term[] value () default {};

    public Or2[] or2 () default {};

    public And2[] and2 () default {};
}

public @interface Or2 {
    public boolean not () default false;
    public Term[] value () default {};
}

これで、次のように使用できます。

@Expression(@Term("a"))
class A{}

// a or b
@Expression(or=@Or({@Term("a"), @Term("b")}))
class B{}


// a or (not(b and c))
@Expression(or=@Or(
    value=@Term("a"),
    and1=@And1(not=true, value={
        @Term("b"),
        @Term("b")
    })
))
class B{}

ご覧のとおり、ネストされた式を追加するたびに、演算子注釈のインデックスを増やすという考え方です。

于 2014-09-30T12:34:49.993 に答える
2

これはこのバグによるものです。

そして、注釈の継承、ポリモーフィズム、「検出されたサイクル」の制限は...スレッドでそれについて議論します。

以下のようなものを作成できます

@interface NodeInfo {
    LogicalExpression logicalExpression() default LogicalExpression.AND;
    Attribute[] attributes() default {};
}


@interface Node {
    NodeInfo[] nodes() default {};
}
于 2012-09-06T09:06:28.437 に答える
0

少し遅れていることはわかっていますが、今日は同じ問題を解決する必要があり、実際の解決策や回避策なしでこの質問を見つけました。

ただし、次の構造を使用して再帰を「代理」することができました。

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Expression
{
    Node value();

    SubExpression[] subExpressions() default {};
}

@Retention(RetentionPolicy.RUNTIME)
@interface SubExpression
{
    String id();

    String operator();

    Node[] nodes();
}

@Retention(RetentionPolicy.RUNTIME)
@interface Node
{
    String subExpression() default "";

    String name() default "";

    String value() default "";
}

@Expression(
    value = @Node(subExpression = "1"),
    subExpressions = {
        @SubExpression(id = "1", operator = "AND",
            nodes = {
                @Node(name = "responsible", value = "foo"),
                @Node(subExpression = "2")
            }),
        @SubExpression(id = "2", operator = "OR",
            nodes = {
                @Node(name = "status", value = "closed"),
                @Node(name = "visibility", value = "public")
            }),
    })
public class TestAnnotationRecursion
{
    public static void main(String[] args)
    {
        Expression expression = TestAnnotationRecursion.class.getAnnotation(Expression.class);

        Map<String, SubExpression> subExpressionMap = Arrays.stream(expression.subExpressions())
            .collect(Collectors.toMap(x -> x.id(), x -> x));

        String result = parseNode(expression.value(), subExpressionMap);

        System.out.println(result);
    }

    public static String parseNode(Node node, Map<String, SubExpression> subExpressionMap)
    {
        String subExpressionId = node.subExpression();
        if(subExpressionId.isEmpty())
        {
            return node.name() + " = '" + node.value() + "'";
        }

        SubExpression subExpression = subExpressionMap.get(subExpressionId);

        return Arrays.stream(subExpression.nodes())
            .map(n -> parseNode(n, subExpressionMap))
            .collect(Collectors.joining(" " + subExpression.operator() + " ", "(", ")"));
    }
}

そして、これは次のように評価されます。

(responsible = 'foo' AND (status = 'closed' OR visibility = 'public'))

読みやすさには疑問がありますが、これは明示的な再帰が許可されていない場合に達成できる最善の妥協点だと思います。

于 2016-03-03T15:54:59.167 に答える