I wrote a program to read annotations from an external class and print out their names:
public class Application {
public static void main(String[] args) {
for (Field field : Car.class.getDeclaredFields()) {
for (Annotation a : field.getAnnotations()) {
System.out.println(a.toString());
}
for (Annotation d : field.getDeclaredAnnotations()) {
System.out.println(d.toString());
}
}
}
}
public class Car {
#Id
private Integer carId;
#NotNull
private String carName;
}
Everything works fine when debugging, but when I compile and run it as JAR executable, the annotations are not found. How can I get the annotations when running the program as JAR file?
So I compiled my application as a JAR file. To run this file I use the following:
<output_path> $ java -jar <application-name>.jar
and I put my Car class (compiled as class) in:
<output_path>/code/com/example/base/myapp/classes/Car.class
Look at the RetentionPolicy for the annotation. If it is SOURCE or CLASS you shouldn't expect to see them at runtime. Only RUNTIME annotations will be able to be read reflectively at runtime.
You also need to make sure that the annotation classes are on the classpath at runtime.
Here's an example:
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.Field;
public class AnnotationExample {
#Retention(RetentionPolicy.SOURCE)
#Target(ElementType.FIELD)
#interface SourceAnnotation {
}
#Retention(RetentionPolicy.CLASS)
#Target(ElementType.FIELD)
#interface ClassAnnotation {
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
#interface RuntimeAnnotation {
}
#SourceAnnotation
#ClassAnnotation
#RuntimeAnnotation
int foo;
public static void main(String[] args) {
for (Field field : AnnotationExample.class.getDeclaredFields()) {
for (Annotation a : field.getAnnotations()) {
System.out.println(a.toString());
}
}
}
}
let's compile this and look at the class files:
$ javac AnnotationExample.java
$ ls *.class
AnnotationExample$ClassAnnotation.class AnnotationExample$SourceAnnotation.class
AnnotationExample$RuntimeAnnotation.class
AnnotationExample.class
If we run it:
$ java -cp . AnnotationExample
#AnnotationExample$RuntimeAnnotation()
Now we delete the class file for the annotation:
$ rm AnnotationExample\$RuntimeAnnotation.class
$ java -cp . AnnotationExample
$
No error, but the annotation is not found.
Related
I want to write an annotation in Java, which executes something before and after execution of the annotated method, similar to what can be done in Spring with aspects.
I've already tried a Spring aspect, but it only works for Beans (as this guy here mentioned) and I want to stay independent from the Spring framework.
A simple class that writes a String to the console:
public class Main {
public static void main(String[] args) {
say("How are you?");
}
#Hello
private static void say(String s) {
System.out.println(s);
}
}
The associated annotation:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Hello {}
And I need something like (deduced from the Spring aspect)
public Object process(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("Hello");
Object proceed = null;
try {
proceed = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("world!");
return proceed;
}
I want the following output:
Hello
How are you?
world!
Edit:
I created the following Aspect (without annotations), but it does not work
#lombok.extern.java.Log
public aspect Log {
pointcut methodExecuted():execution(* **(..));
void around(): methodExecuted() {
log.info("Hello");
proceed();
log.info("world!");
}
}
Where is my mistake?
Assuming that you successfully compiled your aspect with the AspectJ compiler, it should work with the code you used, only that it would log all method executions, i.e. also main(..), so you would se the aspect's output twice before and after "How are you?". If you don't see anything probably you made a mistake in setting up your build system.
You should change the pointcut to actually limit logging to annotated methods: execution(* *(..)) && #annotation(Hello). Furthermore if your around advice has a void return type, logging will not work with non-void methods. So you should rather use a return type of Object and actually return the result of proceed().
I also strongly urge you to not just blindly wield a powerful tool like AspectJ but also study some documentation before you do. It is quite obvious that you have not done so or only very cursorily. Then you get the effect of being a not-so-capable-user with a tool. ;-)
Here is my MCVE:
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target(METHOD)
public #interface Hello {}
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
say("How are you?");
}
#Hello
private static void say(String s) {
System.out.println(s);
}
}
package de.scrum_master.aspect;
import de.scrum_master.app.Hello;
public aspect LoggingAspect {
pointcut methodExecuted() : execution(* *(..)) && #annotation(Hello);
Object around(): methodExecuted() {
System.out.println("Hello");
Object result = proceed();
System.out.println("world!");
return result;
}
}
Console log:
Hello
How are you?
world!
I have created some custom annotations to use for system tests which are run via JUnit.
A test e.g. looks like this:
#TestCaseName("Change History")
public class ChangeHistory extends SystemTestBase
{
#Test
#Risk(1)
public void test()
{
...
I am now implementing a Test Runner which shall report the test name, the risk and the somewhere for documentation purposes.
public class MyRunner extends BlockJUnit4ClassRunner
{
...
#Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier)
{
...
System.out.println("Class annotations:");
Annotation[] classanno = klass.getAnnotations();
for (Annotation annotation : classanno) {
System.out.println(annotation.annotationType());
}
System.out.println("Method annotations:");
Annotation[] methanno = method.getAnnotations();
for (Annotation annotation : methanno) {
System.out.println(annotation.annotationType());
}
The output is
Class annotations:
Method annotations:
interface org.junit.Test
So getAnnotations() seems to return annotations of JUnit only and not all annotations. This is not mentioned in the documentation of JUnit:
Returns the annotations on this method
The return type is java.lang.Annotation which made me believe that I can use any annotation. I defined the annotation like follows - I just used it and when there was an error I let Eclipse generate the annotation:
public #interface Risk {
int value();
}
How do I get all annotations of the test class and test method?
You need to set the retention policy of the Risk annotation to RUNTIME. Otherwise, the annotation will be discarded after the compilation and won't be available during the execution of the code.
This should be working:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Risk {
int value();
}
I'm trying to understand how this annotation is invoked #WebMethod
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
#WebService //<----- is this annotation nested in WebService class
#SOAPBinding(style = Style.RPC)
public interface TimeServer {
#WebMethod String getTimeAsString(); //<-------is this nested in a class too
#WebMethod long getTimeAsElapsed();
}
According to my import javax.jws.WebMethod, and to Java docs
http://docs.oracle.com/javase/7/docs/api/javax/jws/WebMethod.html
public #interface WebMethod is described.
Is the #WebMethod annotation defined as the WebMethod class?
Could the source code for the WebMethod class be something like this?
Public class WebMethod{
//members
//methods
public #interface WebMethod{ //annotation definition in class, is this possible
}
}
If this is not the case, please let me how it's done with a simple example.
No, like it says in the Javadoc you linked to, this is defined as
#Retention(value=RUNTIME)
#Target(value=METHOD)
public #interface WebMethod
So this is an annotation (#interface) that you put on a method (#Target(value=METHOD)).
#WebMethod is not "nested" into #WebService, those are two independent annotations (but of course, they work in concert). That one goes on a method and the other on a class is defined by the #Target.
While that does not seems to be the case in this specific instance I ran across the same question of whether inner annotations where ok.
According to my experiments this works
Annotation definition:
// pkg2/I.java
package pkg2;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
public final class I {
private I(){
}
#Retention(RetentionPolicy.RUNTIME)
public static #interface Inner {}
}
Usage:
// pkg/C.java
package pkg;
import pkg2.I;
#I.Inner
public class C {
public static void main(String[] args) throws Exception {
System.out.println(C.class.getAnnotation(I.Inner.class));
}
}
Running:
$ java pkg/C
#pkg2.I$Inner()
Searchable.java
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Searchable { }
Obj.java
public class Obj {
#Searchable
String myField;
}
void main(String[] args)
Annotation[] annotations = Obj.class.getDeclaredField("myField").getAnnotations();
I would expect annotations to be containing my #Searchable. Though it is null. According to documentation, this method:
Returns all annotations present on this element. (Returns an array of length zero if this element has no annotations.) The caller of this method is free to modify the returned array; it will have no effect on the arrays returned to other callers.
Which is even more weird (to me), since it returns null instead of Annotation[0].
What am I doing wrong here and more important, how will I be able to get my Annotation?
I just tested this for you, and it just works:
public class StackOverflowTest {
#Test
public void testName() throws Exception {
Annotation[] annotations = Obj.class.getDeclaredField("myField").getAnnotations();
System.out.println(annotations[0]);
}
}
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
#interface Searchable {
}
class Obj {
#Searchable
String myField;
}
I ran it, and it produces the following output:
#nl.jworks.stackoverflow.Searchable()
Can you try running the above class in your IDE? I tried it with IntelliJ, openjdk-6.
Your code is correct. The problem is somewhere else. I just copied and run your code and it works.
It is possible that you are importing the wrong Obj class in your code you may want to check that first.
In my case, i had forgotten to add
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
to the method, so in the end it should look like:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
}
In my case, the error was in my own annotation.
I fixed a couple of things, and it finally ended up like this:
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Target( { METHOD, FIELD, ANNOTATION_TYPE })
#Retention(RUNTIME)
public #interface MyAnnotation{
}
It works now
I would like to use annotations in my application. For this reason I create "hello world" for annotations:
follows example:
public class HelloAnnotation
{
#Foo(bar = "Hello World !")
public String str;
public static void main(final String[] args) throws Exception
{
System.out.println(HelloAnnotation.class.getField("str").getAnnotations().length);
}
}
And this is the Annotation:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
#Target(ElementType.FIELD)
public #interface Foo
{
public String doTestTarget();
}
My problem is now that getAnnotations() in main is empty. What is wrong with my code?
Add the following to your annotation:
#Retention(RetentionPolicy.RUNTIME)
From the javadoc for #Retention:
the retention policy defaults to RetentionPolicy.CLASS
From the javadoc for RetentionPolicy:
CLASS
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time.
RUNTIME
Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.
SOURCE
Annotations are to be discarded by the compiler.