Подтвердить что ты не робот

Могу ли я получить имя класса как константу времени компиляции без жесткого кодирования в строковом литерале?

Я работаю над обработчиком аннотаций. Этот код компилируется:

package sand;

import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.TypeElement;

@SupportedAnnotationTypes("sand.Foo")
public class FooProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false; // TODO
    }
}

Тем не менее, я недоволен строковой константой "sand.Foo" (в данном случае это не так уж и много, но в целом для будущего).

Если Foo переименовано или перенесено в другой пакет, этот код все равно будет компилироваться, но он не будет работать.

Я хотел бы сделать что-то вроде:

@SupportedAnnotationTypes(Foo.class)

Таким образом, если имя Foo изменяется, компиляция завершится неудачно, и кто-то должен будет исправить файл.

Но это не работает, потому что Class не является String. Поэтому я попробовал:

@SupportedAnnotationTypes(Foo.class.getName())

Но компилятор не считает это постоянным выражением, которое требуется в этом контексте, так что это тоже не сработает.

Есть ли способ принудить литерал класса к его имени во время компиляции?

4b9b3361

Ответ 1

Вместо использования аннотации ваш процессор может реализовать getSupportedAnnotationTypes() для предоставления поддерживаемых имен типов аннотаций во время выполнения:

Set<String> getSupportedAnnotationTypes() {
    Set<String> supportedAnnotationTypes = new HashSet<>();
    supportedAnnotationTypes.add(Foo.class.getName());
    return supportedAnnotationTypes;
} 



Если вы хотите продолжать использовать (нестандартные) аннотации для этого, вы можете создать свою собственную аннотацию, которая принимает тип времени компиляции как аргумент, например, @k_g. @SupportedAnnotationTypes на самом деле ничего особенного, он используется только автоматически, когда вы расширяете AbstractProcessor в любом случае. Взгляните на исходный код AbstractProcessor.getSupportedAnnotationTypes().

Подпись вашей пользовательской аннотации должна использоваться Class<?>[] вместо String[]:

@Target(TYPE)
@Retention(RUNTIME)
public @interface SupportedAnnotationTypes {
    Class<?>[] value();
}

Переопределите getSupportedAnnotationTypes и найдите свою пользовательскую аннотацию так же, как AbstractProcessor. Например, например:

public Set<String> getSupportedAnnotationTypes() {
    Class<?>[] types = getClass().getAnnotation(SupportedAnnotationTypes.class).value();
    return Arrays.stream(types).map(Class::getName).collect(Collectors.toSet());
}

Ответ 2

Вы можете определить свой собственный.

public @interface SupportedAnnotationTypes_Class {
    Class supported();
}

а затем используйте @SupportedAnnotationTypes_Class(supported = sand.Foo.class), чтобы использовать его.