Я использую 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
, то, когда я попытаюсь получить доступ к атрибуту 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. Как всегда, вся помощь приветствуется.