Java resolve annotation method

How to suppress warning ‘cannot resolve method’ because you generate the method using annotation?

My expected result: The IDE knows that getId method will be injected at compile-time.

My actual result: The IDE throws warning.

import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Main < public static Logger logger = LoggerFactory.getLogger(Main.class); public static void main(String[] args) < Product product = new Product(); logger.debug(Integer.toString(product.getId())); >> 
import lombok.Getter; public class Product < @Getter private int >PS: I heard it needs Lombok plugin to be installed. Is there a way to do it without plugin? I need it to implement it in my own annotation.

What you run into is exactly my main gripe about Lombok: it’s not something that can be implemented in a pure annotation processor, so it depends on the plugin for your IDE and/or build system to work. It can’t work without those plugins.

And a second pet peeve of mine: Annotations are passive metadata. They are in themselves nothing more than slightly more codified machine-readable comments. It’s up to some other piece of software to interpret that metadata and make something happen based on them. Lombok is one approach of doing it and annotation processing is a similar one (less powerful than Lombok, but at least it’s standardized and works everywhere). A third way to use them is something like Spring which reads and interprets annotations at runtime for its configuration.

Читайте также:  Java update and windows 8

@JoachimSauer that is exactly what I intend to do. To implement @Autowired and @Service kind of thing without the Spring Framework. I will take a look at annotation processing and Spring Depedency Injection tomorrow.

2 Answers 2

Lombok isn’t an annotation processor. Lombok is a unique bit of software, and (as one of the core authors), what lombok does is not trivial in the slightest: You’d have to fork the lombok code base if you want to do lombok-esque things.

Looking at lombok as an example of what annotations can do is in that sense not a good idea: Lombok is its own thing, and merely uses annotations to know where to act, it is not a processor (but, weirdly enough, it registers itself as one in order to become part of the compilation process).

To answer your direct questions:

  1. Yes, you need the lombok plugin installed; recent versions of intellij have it installed by default if memory serves.
  2. No, lombok cannot be made to work without that.
  3. However, an actual normal annotation processor would work just fine.
  4. Basic (non-lombok) annotation processors can only make new files — they cannot change existing files. Only lombok can do that (and it requires a plugin). If you write a basic annotation processor (which therefore can only make new files), what you’ve done (turn on ‘annotation processing’) is all that is needed.

Note that basic annotation processors tend to need to go through a full build and have issues with incremental compilation (as in, incrementally compiling tools generally just compile everything, every time, if annotation processors are loaded. Most tools know lombok isn’t an annotation processor / works just fine in incremental compilation scenarios and know not to fall back to ‘compile all the things all the time’). For medium to large project, ‘compile everything’ is a gigantic time waster which you want to avoid.

  • Consider if the changes you want to make can be done solely by making new files. If the answer is No, I must change existing files, give up. Or, fork lombok and spend half a year figuring out the inner workings of javac, ecj, and intellij :/
  • If you CAN do the job by making only new files, know that the experience won’t be as smooth and speedy as what lombok does. Forget lombok as an example, it’s not a normal annotation processor. Find any tutorial on annotation processing / read up on the APIs / have a look at the source of a project such as AutoValue for an example of how a ‘normal’ annotation processor works. Know that you can do what you want, and all it takes is what you already did: Enable that ‘run processors’ checkbox.

Источник

Find method level custom annotation in a Spring context

In fact, this code does find other annotations such as @RequestMapping. I am not sure what I am doing wrong with my custom annotation.

3 Answers 3

Going through your code, I figured out that you are using Spring AOP with CGLIB Proxying. Due to which your classes (which have methods annotated with @Versioned ) are being proxied.

I have tested this solution with your code base.

Use the following code, and it should resolve your issue. Look for more options below the code snippet:

@Configuration public class VersionScanner implements ApplicationContextAware < public void setApplicationContext(ApplicationContext applicationContext) throws BeansException < for (String beanName : applicationContext.getBeanDefinitionNames()) < Object obj = applicationContext.getBean(beanName); /* * As you are using AOP check for AOP proxying. If you are proxying with Spring CGLIB (not via Spring AOP) * Use org.springframework.cglib.proxy.Proxy#isProxyClass to detect proxy If you are proxying using JDK * Proxy use java.lang.reflect.Proxy#isProxyClass */ ClassobjClz = obj.getClass(); if (org.springframework.aop.support.AopUtils.isAopProxy(obj)) < objClz = org.springframework.aop.support.AopUtils.getTargetClass(obj); >for (Method m : objClz.getDeclaredMethods()) < if (m.isAnnotationPresent(Versioned.class)) < //Should give you expected results >> > > > 
  • For Spring AOP proxy using any proxying mechanism use org.springframework.aop.support.AopUtils#isAoPProxy
  • If you are proxying with Spring CGLIB (not via Spring AOP), use org.springframework.cglib.proxy.Proxy#isProxyClass
  • If you are proxying using JDK Proxy, use java.lang.reflect.Proxy#isProxyClass

I have just written one if condition which is sufficient in your case; but in case multiple proxying utilities are used, multiple if-else conditions will have to be written based on the information above.

Источник

How to run all methods with a given annotation?

That’s not possible. What exactly do you want to achieve? What do you want to happen in your example?

I’d appreciate more clarity on this question’s intention. Valid suggestions below, but the direction is questionable.

3 Answers 3

You can do it using classpath scanning: Basically you go over every method of every class in the classpath and get all annotated with your given annotation. After that, you invoke the found methods.

Below is a runAllAnnotatedWith() method that would do it. It uses Reflections to do the dirty work of classpath scanning. For simplicity, it executes all found methods as if they were static and required no parameters.

public static void runAllAnnotatedWith(Class annotation) throws Exception < Reflections reflections = new Reflections(new ConfigurationBuilder() .setUrls(ClasspathHelper.forJavaClassPath()) .setScanners(new MethodAnnotationsScanner())); Setmethods = reflections.getMethodsAnnotatedWith(annotation); for (Method m : methods) < // for simplicity, invokes methods as static without parameters m.invoke(null); >> 
runAllAnnotatedWith(mod.class); 

Note: It is possible to do it without using Reflections, but the code will get dirtier and dirtier.

Here’s the full code (paste it all into a RunClass.java file):

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.Method; import java.util.Set; import org.reflections.Reflections; import org.reflections.scanners.MethodAnnotationsScanner; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; public class RunClass < public static void main(String args[]) throws Exception < runAllAnnotatedWith(mod.class); >public static void runAllAnnotatedWith(Class annotation) throws Exception < Reflections reflections = new Reflections(new ConfigurationBuilder() .setUrls(ClasspathHelper.forJavaClassPath()).setScanners( new MethodAnnotationsScanner())); Setmethods = reflections.getMethodsAnnotatedWith(annotation); for (Method m : methods) < m.invoke(null); // for simplicity, invoking static methods without parameters >> @mod(name = "me1") public static void calledcs() < System.out.println("called"); >@mod(name = "me2") public static void calledcs2() < System.out.println("called2"); >> @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface mod

To run it, you have to add the Reflections JAR to your project. You can download it here.

If you use Maven, you can add it using:

 org.reflections reflections 0.9.9-RC1  

Источник

Retrieve Java Annotation Attribute

That’s not really an effective programming method. There’s no advantage here to having the values set in an annotation as opposed to being set in final variables inside the code, or being set in final static variables outside the method.

I know that this is late but can you please share the definition of your @MyAnnotation interface as well? So the question has more context. Thanks

4 Answers 4

Method m = getClass().getMethod("myMethod"); MyAnnotation a = m.getAnnotation(MyAnnotation.class); MyValueType value1 = a.attribute1(); 

You’ll need to catch / handle the appropriate exceptions, of course. The above assumes you are indeed retrieving method from the current class (replace getClass() with Class.forName() otherwise) and the method in question is public (use getDeclaredMethods() if that’s not the case)

Regarding step 1, obtain the method instance using the following solution: stackoverflow.com/a/5891326/435605

Please note that a method name might change by obfuscation or even compiler specific optimizations, in the end it is absolutely not guaranteed to be referenced by name during runtime.

  • There is no way to get the current method, e.g. there is no getMethod() such as getClass(). Therefore, the method accessing its own annotation would need to know its own name.
  • The retention policy of the annotation must be set to RUNTIME , so you can access the annotation at runtime. The default is compile-time, which means annotations are available in the class file, but cannot be accessed at runtime using reflection.
@Retention(RetentionPolicy.RUNTIME) public static @interface MyAnnotation < String value1(); int value2(); >@Test @MyAnnotation(value1 = "Foo", value2 = 1337) public void testAnnotation() throws Exception

There is a way to get current method. Either Thread.currentThread().getStackTrace()[2].getMethodName() or new Throwable().fillInStackTrace().getStackTrace()[0].getMethodName() should do it.

@ChssPly76, building a stacktrace isn’t entirely reliable, as the javadocs mention: «Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information [. ] is permitted to return a zero-length array from this method.»

To get the current method, try using this code:

Thread.currentThread().getStackTrace()[1].getClassName().toString()+\".\"+Thread.currentThread().getStackTrace()[1].getMethodName().toString() 

@mhaller: a bit too long for a comment on your post. Obviously would need further refinement to deal with overloaded methods, but it is not impossible.:

import java.lang.reflect.Method; public class Hack < public static void main (String[] args) < (new Hack()).foobar(); >public void foobar () < Method here = getCurrentMethod(this); System.out.format("And here we are: %s\n", here); >public static final Method getCurrentMethod(Object o) < String s = Thread.currentThread().getStackTrace()[2].getMethodName(); Method cm = null; for(Method m : o.getClass().getMethods())< if(m.getName().equals(s))< cm = m; break; >> return cm; > > 
[edit: credit/thanks to Alexandr Priymak for spotting the error in main()]

I have a feeling that if you actually do this in production code, it summons the Great Old Ones to devour your very soul!

@Skip Head — why? There are two things to be careful about here — (1) array index in theory may be different from 2 on some JVMs but that’s easy to work around by walking through whole trace; (2) this won’t work for overloaded methods; you can do some black magic with javassist to guess the right one based on line number but that really is somewhat iffy. Other then that, though, it works perfectly — how do you think stack traces work?

@ChssPly76: No need to walk the whole trace. The trace method starts at top and walks until it finds itself. And the caller is the next.

@alphazero — you’d think so, but no 🙂 That is, this is normally the case but it’s not spec’ed anywhere AFAIK, meaning you can have a JVM implementation that behaves differently (e.g. the method in question may be in 2nd or even 1st argument of stack trace array)

Источник

Оцените статью