Можно ли узнать, переопределен ли метод аннотации (логические значения)? - PullRequest
1 голос
/ 17 мая 2019

Я много чего перепробовал в сети, но, похоже, у меня ничего не работает.Я хочу знать, был ли метод аннотации @Override n (либо с тем же значением, что и его default).

Взгляните на этот пример:

public class AnnoTest {

    @Anno
    private String something;

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, NoSuchMethodException {
        Field field = AnnoTest.class.getDeclaredField("something");
        field.setAccessible(true);
        boolean isDefault= field.getAnnotation(Anno.class).annotationType().getDeclaredMethod("include").isDefault();
        System.out.println(isDefault); //returns false

    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.FIELD })
    public @interface Anno {
        boolean include() default false;
    }
}

Дляпо какой-то причине он возвращает ложь.Когда я изменяю его на:

@Anno(include = false)
private String something;

Возвращает false снова.Есть ли способ узнать, было ли значение объявлено в аннотации?

Я знаю, что мог бы просто сравнить значение по умолчанию и его текущее значение, но оно не будет работать для меня.Я хочу знать, было ли это объявлено.


Другими словами, мне нужен какой-то магический логический код, который выполняет следующее:

@Anno
private String something;

return false.

@Anno(include = true)
private String something;

return true.

@Anno(include = false)
private String something;

return true.


Причина этого в том, что я хочу добавить метод (к моей аннотации) с именем "parent".Когда родитель (строка) был объявлен аннотацией, это поле будет наследовать аннотацию поля с именем parent.Взгляните на этот пример:

public class AnnoTest {

    @Anno(include = false)
    private Something something = new Something();

    @Anno(parent = "something")
    private Something somethingElse  = new Something();

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, NoSuchMethodException {
        AnnoTest test = new AnnoTest();

        Field somethingField = AnnoTest.class.getDeclaredField("something");
        somethingField.setAccessible(true);

        Field somethingElseField = AnnoTest.class.getDeclaredField("somethingElse");
        somethingField.setAccessible(true);

        Anno anno = somethingElseField.getAnnotation(Anno.class);

        if (anno.parent().equals("something")) {
            boolean include = somethingField.getAnnotation(Anno.class).include();
            test.somethingElse.isIncluded = include;
        }

        //If not declared it will return true, which it should be false, because "something" field has it false.
        boolean include = somethingElseField.getAnnotation(Anno.class).include();
        //if somethingElse has declared "include", dominate the value, else keep it from the parent
        test.somethingElse.isIncluded = include;

    }

    public class Something {
        boolean isIncluded;
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.FIELD })
    public @interface Anno {
        boolean include() default false;

        String parent() default "";
    }
}

1 Ответ

1 голос
/ 18 мая 2019

Отражение API не позволяет запрашивать, было ли значение аннотации указано явно или просто по умолчанию.

Обычный обходной путь - указать значение по умолчанию, которое никто в здравом уме не указал бы явно, и проверитьвместо этого значения.Например, JPA использует для этой цели "".

Можно попробовать

Boolean value() default null;

, но, как вы правильно заметили в комментариях, Java не поддерживаетBoolean значения аннотации, только boolean единицы.Вместо этого вы можете использовать перечисление с 3 значениями, но это, вероятно, обременительно для ваших пользователей.

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

Учитывая

@Anno(false)
public void foo() 

, мы получаем

Constant pool:
    ...
    #16 = Utf8               Lstackoverflow/Anno;
    #17 = Utf8               value
    #18 = Integer            0

  public void foo();
    descriptor: ()V
    flags: ACC_PUBLIC
    RuntimeVisibleAnnotations:
      0: #16(#17=Z#18)

, но учитывая

@Anno()
public void foo() {

мы получаем

Constant pool:
  ...
  #16 = Utf8               Lstackoverflow/Anno;

public void foo();
  descriptor: ()V
  flags: ACC_PUBLIC
  RuntimeVisibleAnnotations:
    0: #16()

Тем не менее, даже если вам удастся это сделать, вы можете удивить своих пользователей и спутать их инструменты.Например, вполне возможно, что IDE пометит явные присвоения значения по умолчанию как избыточные.

Если это вообще возможно, я бы поэтому изменил вашу аннотацию, чтобы вам не приходилось различать, имеет ли логическое значениебыл указан явно.

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