Аннотация нескольких типов аннотаций - PullRequest
0 голосов
/ 02 июля 2018

Я хочу иметь возможность аннотировать класс списком двух типов аннотаций, которые связаны по функциям, но совершенно различаются по аргументам. Порядок этого списка имеет значение, хотя. Я уже пытался найти это, но не смог найти никаких ссылок на это (я не был уверен, как это назвать).

Edit:

Что я хочу сделать в итоге:

//place holder for example (Abstract)
public @interface A {
}

@Target(PARAMETER)
public @interface B extends A {
    //Gets stuff
    Class type();
    int key();
}

@Target(PARAMETER)
public @interface FlaggedListOfA extends A {
    //List of A
    A[] set();
}

//Goal is to have annotation that does this
@Target(METHOD)
public @interface ImportantFunc {
    A[] dataForA() default {};
    String[] names();
    int property() default 0;
    //etc.
}

//End goal:
public class SomeImportantClass {

    @ImportantFunc(dataForA = {@B(...), @B(...}, ...)
    public void doStuff() {

    }

    //So I can have an end goal of this (Order matters, may contain repeats,
    //and has unknown length!)
    @ImportantFunc(dataForA = {@B(...), @FlaggedListOfA(@B(...), @B(...))}, ...)
    public void doStuffB() {

    }

    @ImportantFunc(dataForA = {@FlaggedListOfA(@B(...)), @FlaggedListOfA(@B(...), @B(...))}, ...)
    public void doStuffC() {

    }

    @ImportantFunc(dataForA = {@FlaggedListOfA(@B(...), @FlaggedListOfA(@B(...), @B(...))), @B(...)}, ...)
    public void doStuffD() {

    }
}

Размышления для получения всех использований ImportantFunc (например, 100 его использований) в пакете и использования этих данных для выбора, какую функцию использовать. Аннотация должна помочь с отражением, поскольку, как только он получает данные из @ImportantFunc, он затем преобразует их во входные данные для библиотеки, которая фактически выбирает, какую функцию выполнять (это внутреннее и не может быть изменено). Этого также можно добиться гораздо более длинными и раздражающими способами, но я надеялся использовать аннотации для упрощения процесса определения всех этих функций.

Изменить:

Другой способ решить эту проблему - найти способ сгруппировать две аннотации вместе.

Возможность сделать это не была бы полностью идеальной, но определенно сделала бы это гораздо более работоспособным:

public @interface Example {
    AnyTypeOfAnnotation[] set();
}

Ответы [ 2 ]

0 голосов
/ 02 июля 2018

Один хитрый способ сделать это - заставить A быть объединением B и C. Это означает, что он имеет все поля и B и C, но вы можете использовать его только как или a B или a C.

Вот рабочий пример.

import java.lang.annotation.*;

enum NoType {;}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface A {
    Class<?> data()  default NoType.class; // field from B
    int      dataA() default 0;            // field from C
    String   dataB() default "";           // field from C
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface D {
    A[] value() default {};
}

class Foo {}
class Bar {}

class Example {
    @D({
        @A(data = Bar.class),
        @A(dataA = 5, dataB = "Bla"),
        @A(data = Foo.class)
    })
    public static void main(String[] args) throws Exception {
        for (A a : Example.class.getMethod("main", String[].class)
                        .getAnnotation(D.class).value()) {
            if (a.data() != NoType.class) {
                System.out.printf("B(%s)%n", a.data());
            } else {
                System.out.printf("C(dataA = %d, dataB = \"%s\")%n",
                    a.dataA(), a.dataB());
            }
        }
    }
}

Выход этой программы :

B(class Bar)
C(dataA = 5, dataB = "Bla")
B(class Foo)

Конечно, это не очень красивое решение, но оно работает.

0 голосов
/ 02 июля 2018

Не уверен, что этого будет достаточно для вашего варианта использования:

public @interface A {
}

public @interface B extends A {
    //Gets stuff
    Class data();
}

public @interface C extends A {
    //Gets different stuff related to same goal
    int dataA();

    String dataB();
}

public @interface D {
    Class<? extends A>[] order();
}


@B(Bar.class)
@C(dataA = 5, dataB = "Bla")
@D(order = {B.class, C.class})
public class SomeImportantClass {

}

Этот метод использует аннотацию D в качестве среднего значения для сохранения порядка аннотаций. Плохо то, что вы не можете добавить несколько аннотаций одного типа.

Существует еще один метод, который превращает A, B и C в обычные классы.

public abstract class AnnotationAttribute {
    public abstract Class<?>[] getDataTypes();
    public abstract Object[] getData();
}

public class B extends AnnotationAttribute {
    @Override public Class<?>[] getDataTypes() {
        return new Class<?>[] {Foo.class, Bar.class};
    }
    @Override public Object[] getData() {
        return new Object[] {new Foo(), new Bar()};
    }
}

public @interface D {
    Class<? extends AnnotationAttribute>[] data() default {};
}

@D(data = {B.class});
public class Test {
}

Этот метод требует, чтобы вы создали один класс для одного конкретного типа атрибута. Это связано с тем, что аннотации должны быть постоянными во время компиляции, а ссылки через Class требуют от вас определения класса в коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...