2012-09-06 114 views
3

我想在注释中创建一些信息树结构。经过一些尝试和帮助后(见Type hierarchy in java annotations),我转向以下模型。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 

即使我把一些节点列表标记信息节点和节点列表包含节点列表的循环依赖被再次确认。

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

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

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

+0

我没有看到问题? ...我会试图找到一种方法来描述你的数据,而不使用递归依赖。 –

+0

是的,重写整个逻辑可能是解决方案,但对于我的具体问题(定义用于休眠目的的条件树结构)是纯粹的注释解决方案是不可能的。 –

回答

2

这是因为这个bug

And annotations' inheritance, polymorphism, 'cycle detected' limitations are...线程讨论它。

您可以创建类似下面

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


@interface Node { 
    NodeInfo[] nodes() default {}; 
} 
+1

不幸的是,这种或类似的结构不允许多层结构的节点,这对我来说是必不可少的。 –

1

您不能定义由于上述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([email protected]({@Term("a"), @Term("b")})) 
class B{} 


// a or (not(b and c)) 
@Expression([email protected](
    [email protected]("a"), 
    [email protected](not=true, value={ 
     @Term("b"), 
     @Term("b") 
    }) 
)) 
class B{} 

正如你所看到的想法是,每次添加一个嵌套的表达时间incease您的操作员注释索引。

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')) 

虽然它的可读性是有问题的,我觉得这是最好的当不允许显式递归时我们可以达成妥协。