10

Java 8 has feature called Type annotations (JSR 308). I would like to use it for simple Object to Object mapper framework. I would like define annotation @ExpectedType like this

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

And then use it in my code like this:

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

IObjectA is an interface implemented by classes ObjectA_DTO and ObjectA_Entity. The service I would like to use this way:

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

I would like change call of SomeServiceImpl methods to use Object mapper. It could be achieved by generated code using JSR 269 or by AOP.

The problem is I wrote simple annotations processor and it doesn't handle type annotations at all. The source of simple annotations processor looks like this:

@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;
    }
}

Any ideas how to use or how to access type annotations by SimpleAnnotationsProcessor? Usage of Pluggable Annotation Processing API is not necessary for me I think it would has better performance than Java reflection. Anyway I don't know how to access type annotation via Java Reflection too.

Boris Šuška
  • 1,796
  • 20
  • 32
  • I guess I'm unclear what goal you're trying to achieve. Why not just make the method signature `ObjectA_DTO doSomething(ObjectA_Entity)` if that's what you're expecting it to do? – Ian McLaird Dec 22 '14 at 21:52
  • Method signature can't be that way, because I would like use service instance like this `someService.doSomething(new ObjectA_DTO())`. I want implement object mapper to map `ObjectA_DTO` to `ObjectA_Entity` and type annotation @ExpectedType defines destination type. It is reason why signature has to be `IObjectA doSomething(IObjectA)`. – Boris Šuška Jan 03 '15 at 12:43
  • I just caught your question in passing... I did a semester project on product line development where we processed annotations. For now, I will leave you with this important tutorial that really got me going on the subject (you can skip part 3 about code generation) - https://deors.wordpress.com/2011/09/26/annotation-types/ later, I will re-check this post for progress. – ThisClark Jan 05 '15 at 14:11
  • Thank you for your link, I'm talking about annotations annotated as `@Target(ElementType.TYPE_PARAMETER)` or `@Target(ElementType.TYPE_USE)`. They're not passed to annotation processor's `process` method. – Boris Šuška Jan 05 '15 at 14:21

3 Answers3

3

I'm not sure I understand what you try to achieve, but here is an example how you can access your annotations with the Java reflection api:

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);
        }
    }
}

The output looks like this:

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

Note though, that not all possible type annotations are accessible through the reflection api, but you can always read them from the byte code if necessary (see my answer here).

Community
  • 1
  • 1
Balder
  • 8,623
  • 4
  • 39
  • 61
  • I would like do it using annotation processor because it could be faster in runtime then reflection, anyway I accept your answer. Checker framework can read type annotations from annotation processor (not from byte code). Do you know how is it doing? – Boris Šuška Jan 05 '15 at 15:30
  • Sorry, I haven't used Checker framework yet. I do not believe that annotation processors would be faster than using reflection (not sure though). But I wouldn't think about any optimizations before running into actual performance issues. Usually reflection is fast enough... – Balder Jan 05 '15 at 15:47
  • Do you know how to access type annotations for types used with local variables via reflection API? Something like this `@NotNull String str = "";` or `String str = (@Nullable String) null;` inside of method body? I would like use `@ExpectedType` annotation like this: `ObjectA_DTO aDto = (@ExpectedType ObjectA_DTO) someService.doSomething(...);` – Boris Šuška Jan 06 '15 at 08:58
  • It is not possible to access type annotations declared on variable declarations or cast expressions using the Java reflection api. You could access them by reading the byte code of the method with an external library like [ASM](http://asm.ow2.org/). I used this approach in the hello world example at the very end of [this answer](http://stackoverflow.com/a/22435715/3270595). Accessing type annotations this way is certainly an option for static code analysis and tooling but I wouldn't recommend such an approach for runtime access to type annotations... – Balder Jan 06 '15 at 09:25
0

I think you're mixing up the use of annotations at run time versus the use of same at "compile" time by various tools. Processor interface is for use in tools (compiler, javadoc generator), not in your runtime code.

  • I want to generate the code for better performance like MapStruct or Lombok does instead of using java reflection on runtime. – Boris Šuška Jan 05 '15 at 15:42
-1
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SearchDefinition {

    public String identifier() default "";

}

@SearchDefinition - can be used anywhere

Rohith K
  • 1,433
  • 10
  • 15
  • 2
    This answer is completely wrong `@Target(ElementType.FIELD)` annotation can't be used anywhere. It can be used only with class fields. If `@Target` is omitted it can be used almost anywhere except of type cast (`(@SearchDefinition String) "abc"`) or generic type (`List<@SearchDefinition String>`). – Boris Šuška Jan 06 '15 at 13:34