Как использовать аннотации пользовательского типа в Java

В Java 8 есть функция, называемая аннотациями типов (JSR 308). Я хотел бы использовать его для простой структуры сопоставления объектов с объектами. Я хотел бы определить аннотацию @ExpectedType следующим образом

@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExpectedType {
    public Class<?> value();
}

А затем используйте его в моем коде следующим образом:

public class SomeServiceImpl() {
    public @ExpectedType(ObjectA_DTO.class) IObjectA doSomething(@ExpectedType(ObjectA_Entity.class) IObjectA obj) {
        return (ObjectA_Entity) obj; // it's correct
    }
}

IObjectA — это интерфейс, реализованный классами ObjectA_DTO и ObjectA_Entity. Услуга, которую я хотел бы использовать таким образом:

// it's correct
assert someService.doSomething(new ObjectA_DTO()).getClass() == ObjectA_DTO.class;

Я хотел бы изменить вызов методов SomeServiceImpl для использования средства сопоставления объектов. Этого можно добиться с помощью сгенерированного кода с использованием JSR 269 или с помощью АОП.

Проблема в том, что я написал простой процессор аннотаций, и он вообще не обрабатывает аннотации типов. Исходник простого обработчика аннотаций выглядит так:

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SimpleAnnotationsProcessor extends AbstractProcessor {

    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Messager messager = processingEnv.getMessager();
        try {
            for (TypeElement e : annotations) {
                messager.printMessage(Diagnostic.Kind.NOTE, e.toString());
                for (Element elem : roundEnv.getElementsAnnotatedWith(e)) {
                    messager.printMessage(Diagnostic.Kind.NOTE, elem.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }
}

Любые идеи, как использовать или как получить доступ к аннотациям типов с помощью SimpleAnnotationsProcessor? Использование Pluggable Annotation Processing API мне не нужно, я думаю, что это будет иметь лучшую производительность, чем отражение Java. Во всяком случае, я не знаю, как получить доступ к аннотации типа через Java Reflection.


person Boris Šuška    schedule 22.12.2014    source источник
comment
Наверное, я не понимаю, какую цель вы пытаетесь достичь. Почему бы просто не сделать сигнатуру метода ObjectA_DTO doSomething(ObjectA_Entity), если это именно то, что вы ожидаете от него?   -  person Ian McLaird    schedule 23.12.2014
comment
Подпись метода не может быть такой, потому что я хотел бы использовать экземпляр службы, подобный этому someService.doSomething(new ObjectA_DTO()). Я хочу реализовать средство сопоставления объектов для сопоставления ObjectA_DTO с ObjectA_Entity, а аннотация типа @ExpectedType определяет тип назначения. Именно поэтому подпись должна быть IObjectA doSomething(IObjectA).   -  person Boris Šuška    schedule 03.01.2015
comment
Я просто мимоходом уловил ваш вопрос... Я делал семестровый проект по разработке линейки продуктов, где мы обрабатывали аннотации. А пока я оставлю вас с этим важным руководством, которое действительно помогло мне разобраться в теме (вы можете пропустить часть 3 о генерации кода) — deors.wordpress.com/2011/09/26/annotation-types позже я еще раз проверю этот пост на наличие прогресса.   -  person ThisClark    schedule 05.01.2015
comment
Спасибо за вашу ссылку, я говорю об аннотациях, аннотированных как @Target(ElementType.TYPE_PARAMETER) или @Target(ElementType.TYPE_USE). Они не передаются методу process обработчика аннотаций.   -  person Boris Šuška    schedule 05.01.2015


Ответы (3)


Я не уверен, что понимаю, чего вы пытаетесь достичь, но вот пример того, как вы можете получить доступ к своим аннотациям с помощью API отражения Java:

package test;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Method;

public class TypeParameterTest {

    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ExpectedType {
        public Class<?> value();
    }

    public static interface IObjectA {}

    public static class ObjectA_DTO implements IObjectA {}

    public static class ObjectA_Entity implements IObjectA {}

    public static class SomeServiceImpl {
        public @ExpectedType(ObjectA_DTO.class) IObjectA doSomething(@ExpectedType(ObjectA_Entity.class) IObjectA obj) {
            return (ObjectA_Entity) obj;
        }
    }

    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        Method m = SomeServiceImpl.class.getMethod("doSomething", IObjectA.class);
        AnnotatedType returnType = m.getAnnotatedReturnType();
        Annotation returnTypeAnnotation = returnType.getAnnotation(ExpectedType.class);
        System.out.println(returnTypeAnnotation);

        AnnotatedType[] parameters = m.getAnnotatedParameterTypes();
        for (AnnotatedType p : parameters) {
            Annotation parameterAnnotation = p.getAnnotation(ExpectedType.class);
            System.out.println(parameterAnnotation);
        }
    }
}

Вывод выглядит следующим образом:

@test.TypeParameterTest$ExpectedType(value=class test.TypeParameterTest$ObjectA_DTO)
@test.TypeParameterTest$ExpectedType(value=class test.TypeParameterTest$ObjectA_Entity)

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

person Balder    schedule 05.01.2015
comment
Я хотел бы сделать это с помощью процессора аннотаций, потому что он может быть быстрее во время выполнения, чем отражение, в любом случае я принимаю ваш ответ. Инфраструктура Checker может читать аннотации типов из процессора аннотаций (не из байтового кода). Вы знаете, как дела? - person Boris Šuška; 05.01.2015
comment
Извините, я еще не использовал фреймворк Checker. Я не верю, что процессоры аннотаций будут быстрее, чем использование отражения (хотя и не уверен). Но я бы не стал думать о каких-либо оптимизациях, пока не столкнулся с реальными проблемами производительности. Обычно отражение происходит достаточно быстро... - person Balder; 05.01.2015
comment
Знаете ли вы, как получить доступ к аннотациям типов для типов, используемых с локальными переменными, через API отражения? Что-то вроде этого @NotNull String str = ""; или String str = (@Nullable String) null; внутри тела метода? Я хотел бы использовать аннотацию @ExpectedType следующим образом: ObjectA_DTO aDto = (@ExpectedType ObjectA_DTO) someService.doSomething(...); - person Boris Šuška; 06.01.2015
comment
Невозможно получить доступ к аннотациям типов, объявленным в объявлениях переменных или выражениях приведения, с помощью API отражения Java. Вы можете получить к ним доступ, прочитав байт-код метода с помощью внешней библиотеки, такой как ASM. Я использовал этот подход в примере с приветствием в самом конце этого ответа. Такой доступ к аннотациям типов, безусловно, является вариантом для статического анализа кода и инструментов, но я бы не рекомендовал такой подход для доступа к аннотациям типов во время выполнения... - person Balder; 06.01.2015

Я думаю, вы смешиваете использование аннотаций во время выполнения с их использованием во время «компиляции» различными инструментами. Processor предназначен для использования в инструментах (компиляторе, генераторе javadoc), а не в коде среды выполнения.

person Community    schedule 05.01.2015
comment
Я хочу сгенерировать код для повышения производительности, как MapStruct или Lombok, вместо использования отражения Java во время выполнения. - person Boris Šuška; 05.01.2015

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SearchDefinition {

    public String identifier() default "";

}

@SearchDefinition — можно использовать где угодно

person Rohith K    schedule 05.01.2015
comment
Этот ответ совершенно неверен @Target(ElementType.FIELD) аннотацию нельзя использовать нигде. Его можно использовать только с полями класса. Если @Target опущено, его можно использовать практически везде, кроме приведения типа ((@SearchDefinition String) "abc") или универсального типа (List<@SearchDefinition String>). - person Boris Šuška; 06.01.2015