3

我正在尝试在注释中创建一些信息树结构。经过一些尝试和帮助(请参阅Java 注释中的类型层次结构),我转向了以下模型。

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

这个节点应该允许我定义一级条件树。logicalExpression 中的值定义子节点(属性和另一个节点)之间的关系。问题是注释不允许递归依赖:

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

即使我将一些 NodeList 注释放入 Node 并且 NodeList 包含节点列表,循环依赖也会再次被识别。

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

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

循环注释定义有什么解决方案吗?

4

3 回答 3

2

这是因为这个错误

并且注释的继承、多态性、“循环检测”限制是……线程讨论它。

您可以创建如下所示的内容

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


@interface Node {
    NodeInfo[] nodes() default {};
}
于 2012-09-06T09:06:28.437 回答
2

由于上述 Java 中的限制,您无法定义无限递归定义。但是你可以支持一些固定深度的结构,感觉就像递归的结构(直到你达到深度限制)

这是深度为 3 的布尔表达式语言的示例:

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

为每个级别定义“与”操作:

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 回答
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 回答