Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java annotation recursive dependency

I am trying to create some information tree structure inside annotations. After some tryings and helps (see Type hierarchy in java annotations) I moved to following model.

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

This node should allow me define one level of condition tree. Value inside logicalExpression defines relation between children (attributes and another nodes). Problem is that annotation does not allow recursive dependency:

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

Even if I put some NodeList annotation into Node and NodeList contain list of Nodes the cyclic dependency is recognized again.

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

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

Is there any solution on cyclic annotation definition?

like image 673
Jan Stanicek Avatar asked Oct 24 '25 23:10

Jan Stanicek


2 Answers

This is because of this bug.

And annotations' inheritance, polymorphism, 'cycle detected' limitations are... thread discuss about it.

You can create Something like below

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


@interface Node {
    NodeInfo[] nodes() default {};
}
like image 82
Amit Deshpande Avatar answered Oct 27 '25 13:10

Amit Deshpande


You can't define infinite recursive definition due to the restrictions in Java mentioned above. But you can support structures of some fixed depth, that feels like recursive one (until you hit the depth restriction)

Here is an example of an boolean expression language of depth 3:

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

Define "and" operation for each level:

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 {};
}

Define "or" operations for each level:

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 {};
}

Now we can use it like this:

@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{}

As you can see the idea is to incease index of your operator-annotations every time you add a nested expression.

like image 35
Boris Brodski Avatar answered Oct 27 '25 11:10

Boris Brodski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!