Почему Javassist настаивает на поиске значения аннотации по умолчанию, если оно явно указано? - PullRequest
1 голос
/ 31 декабря 2011

Я использую Javassist для добавления и изменения аннотаций к package-info «классу».

В некоторых случаях мне приходится иметь дело со следующим крайним случаем.Кто-то (неправильно) указал аннотацию @XmlJavaTypeAdapters для пакета package-info, но не предоставил атрибут value (который определен как обязательный ).Вот так это выглядит так:

@XmlJavaTypeAdapters // XXX incorrect; value() is required, but javac has no problem
package com.foobar;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;

В Javassist это происходит немного странно.

javassist.bytecode.annotation.Annotation, представляющий аннотацию @XmlJavaTypeAdapters, не имеет значения элемента (getMemberValue("value")возвращает null), как и ожидалось.

Конечно, можно добавить value() значение члена, и вот что я сделал:

if (adaptersAnnotation.getMemberValue("value") == null) {
    final ArrayMemberValue amv = new ArrayMemberValue(new AnnotationMemberValue(constantPool), constantPool);
    adaptersAnnotation.addMemberValue("value", amv);
    annotationsAttribute.addAnnotation(adaptersAnnotation);
}

В кодеВ приведенном выше фрагменте я создал новое значение элемента для хранения массива аннотаций, поскольку атрибут value() для @XmlJavaTypeAdapters представляет собой массив @XmlJavaTypeAdapter.Я указал его тип массива, пытаясь предугадать намерение Zen-подобной документации - кажется, что если вы предоставите еще один MemberValue, этот MemberValue каким-то образом будет служить типом массива.В моем случае я хочу, чтобы тип массива был @XmlJavaTypeAdapter, что является аннотацией, поэтому единственным видом MemberValue, который показался подходящим, был AnnotationMemberValue.Поэтому я создал пустой из них и установил его в качестве типа массива.

Это прекрасно работает, пока вы остаетесь "внутри" Javassist.

Однакокажется, что-то пошло не так.Если я прошу Javassist преобразовать все свои собственные аннотации в подлинные Java java.lang.annotation.Annotation s, то при попытке доступа к атрибуту value() этой аннотации @XmlJavaTypeAdapters Javassist скажет мне, что по умолчанию значение отсутствует.Да?

Другими словами, это нормально - действительно, нет - но я указал, что, как я надеялся, был массив нулевой длины (то есть значение по умолчанию не должно использоваться; мое явно указаноВместо этого следует использовать массив нулевой длины):

final List<Object> annotations = java.util.Arrays.asList(packageInfoClass.getAnnotations());
for (final Object a : annotations) {
  System.out.println("*** class annotation: " + a); // OK; one of these is @XmlJavaTypeAdapters
  System.out.println("    ...of type: " + a.getClass()); // OK; resolves to XmlJavaTypeAdapters
  System.out.println("    ...assignable to java.lang.annotation.Annotation? " + java.lang.annotation.Annotation.class.isInstance(a)); // OK; returns true

  if (a instanceof XmlJavaTypeAdapters) {
    final XmlJavaTypeAdapters x = (XmlJavaTypeAdapters)a;
    System.out.println("    ...value: " + java.util.Arrays.asList(x.value())); // XXX x.value() throws an exception
  }
}

Так почему же в этом случае Javassist ищет значение по умолчанию?

Моя большая проблема, конечно, это решить (к сожалению, несколькообщий) случай, когда указан @XmlJavaTypeAdapters без дополнительной информации.Мне нужно добавить value значение члена, которое может содержать массив аннотаций @XmlJavaTypeAdapter.Я не могу понять, как сделать это с Javassist.Как всегда, вся помощь приветствуется.

1 Ответ

2 голосов
/ 31 декабря 2011

Для потомков, похоже, что в данном конкретном случае (чтобы избежать NullPointerException и / или RuntimeException), вам нужно сделать следующее:

if (adaptersAnnotation.getMemberValue("value") == null) {
    final ArrayMemberValue amv = new ArrayMemberValue(constantPool);
    amv.setValue(new AnnotationMemberValue[0]);
    adaptersAnnotation.addMemberValue("value", amv);
    annotationsAttribute.addAnnotation(adaptersAnnotation);
}

Обратите внимание, в частности, что я преднамеренно опускаю тип массива при построении ArrayMemberValue (включение любого любого вида приведет к исключению). Затем я явно устанавливаю его значение в пустой массив типа AnnotationMemberValue. Любая другая комбинация здесь приведет к исключению.

Кроме того, как ни странно, последняя строка в этом блоке if является критической. Несмотря на то, что в данном конкретном случае сама аннотация была найдена и, следовательно, уже присутствовала в AnnotationsAttribute, , вы должны повторно добавить ее . Если вы этого не сделаете, вы получите RuntimeException жалобу на отсутствие значения по умолчанию.

Надеюсь, это поможет другим хакерам Javassist.

...