How can I access in main whether check in the Sample class is true or false?
What should I write in Main class?
package annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface annotation {
public String name() default "Jimmy";
public boolean check() default false;
}
package annotation;
#annotation(name = "Jack", check = false)
public class Sample {
public String str = "Hi";
public void printHi(String str) {
System.out.println(str);
}
}
package annotation;
public class Main {
public static void main(String[] args) {
}
}
Use Sample.class.getAnnotation(annotation.class) to get your annotation instance, and call check() to get the check value:
System.out.println(Sample.class.getAnnotation(annotation.class).check());
Note that classes should start with an upper-case letter, and that naming an annotation "annotation" is quite confusing.
Related
I want to create an annotation which is only available to a specific type of return values.
For example this is my annotation.
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface MyAnnotation {
}
I also have an interface:
public interface MyInterface {
String generateKey();
}
An example class that implements my interface:
public class ExampleClass implements MyInterface {
#Override
public String generateKey() {
return "Whatever";
}
}
So after these, I want to configure my annotation in a way that it won't even compile if the return type is not implementing MyInterface.
In this case, I expect this to compile fine:
#MyAnnotation
public ExampleClass anExampleMethod() {
return new ExampleClass();
}
And this to not compile:
#MyAnnotation
public String anotherMethod() {
return "Whatever";
}
I wonder if this is possible in any way. Sure I can check if the parameters implements this interface in my Aspect class but it would be better to have this kind of protection in my library in order to prevent misuse of any annotation.
Helper classer:
These are directly from your example, just with package names and imports.
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 MyAnnotation {}
package de.scrum_master.app;
public interface MyInterface {
String generateKey();
}
package de.scrum_master.app;
public class ExampleClass implements MyInterface {
#Override
public String generateKey() {
return "Whatever";
}
}
Class which should not compile:
This class has some annotated and some non-annotated methods. One annotated method does not return MyInterface or any of its implementing classes. The goal is to fail compilation.
package de.scrum_master.app;
public class Application {
#MyAnnotation
public MyInterface annotatedMethodReturningInterface(int number) {
return new ExampleClass();
}
#MyAnnotation
public ExampleClass annotatedMethodReturningImplementingClass() {
return new ExampleClass();
}
#MyAnnotation
public String annotatedMethodReturningSomethingElse() {
// This one should not compile!
return "Whatever";
}
public MyInterface nonAnnotatedMethodReturningInterface(int number) {
return new ExampleClass();
}
public ExampleClass nonAnnotatedMethodReturningImplementingClass() {
return new ExampleClass();
}
public String nonAnnotatedMethodReturningSomethingElse() {
return "Whatever";
}
}
Convention-checking aspect (native AspectJ syntax):
package de.scrum_master.aspect;
import de.scrum_master.app.MyAnnotation;
import de.scrum_master.app.MyInterface;
public aspect AnnotationCheckerAspect {
declare error :
#annotation(MyAnnotation) && execution(* *(..)) && !execution(MyInterface+ *(..)) :
"Method annotated with #MyAnnotation must return MyInterface type";
}
This aspect checks for
all method executions
where the method has #MyAnnotation
but where the return type is different from MyInterface or any subtype or implementing class.
This is what the result looks like in Eclipse:
Of course the compilation error is just the same if you compile from command line or via AspectJ Maven plugin or similar.
If you do not like native syntax (I prefer it but for some incomprehensible reason other people seem to prefer #AspectJ style):
Convention-checking aspect (annotation-based #AspectJ syntax):
package de.scrum_master.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareError;
#Aspect
public class AnnotationCheckerAspect {
#DeclareError(
"#annotation(de.scrum_master.app.MyAnnotation) && " +
"execution(* *(..)) && " +
"!execution(de.scrum_master.app.MyInterface+ *(..))"
)
static final String wrongSignatureError =
"Method annotated with #MyAnnotation must return MyInterface type";
}
See also my related answers here:
https://stackoverflow.com/a/27121947/1082681
https://stackoverflow.com/a/54067850/1082681
https://stackoverflow.com/a/41700647/1082681
https://stackoverflow.com/a/27312472/1082681
https://stackoverflow.com/a/50126576/1082681
I have a custom Annotation I created as below
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface TestConfig {
String[] value();
}
I have test that extends a BaseClass.
import org.testng.annotations.Test;
public class MyTest extends BaseClass {
#Test
#TestConfig({ "enableCookies" })
public void startTest() {
startInstance();
}
}
Now I need to access the values inside #TestConfig annotation inside my BaseClass which is below
import org.testng.annotations.BeforeSuite;
public class BaseClass {
public void startInstance() {
System.out.println("starting instance");
//I need to access the value supplied in "MyTest" inside #TestConfig annotation here. How do I do that.
}
#BeforeSuite
public void runChecks() {
System.out.println("Checks done....");
}
}
I know I can do TestConfig config = method.getAnnotation(TestConfig.class) but how do I access the TestNG TestMethodclass? Please help.
You can do something like (but remove the direct call in the test method):
#BeforeMethod
public void startInstance(Method m) {
System.out.println("starting instance");
//I need to access the value supplied in "MyTest" inside #TestConfig annotation here. How do I do that.
TestConfig tc = m.getAnnotation(TestConfig.class);
System.out.println(tc.value());
}
I can not get annotations of beans, i'm working with spring framework:
Runnable test class:
public class Main {
public static void main(String[] args) {
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(Test.class,"foo");
Method m=pd.getReadMethod();
System.out.println(m.isAnnotationPresent(Annot.class));
}
}
Bean class;
public class Test {
private String foo;
#Annot
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
}
Annotation class:
public #interface Annot {
}
The main class get "false" as output... why?
Your annotation is missing a runtime retention policy.
Do the following:
#Retention(RetentionPolicy.RUNTIME)
public #interface Annot {
}
Check out this SO question which explains the default policy and what it does.
To sum the information in that answer, the default retention policy is CLASS, which means that the annotation is in the bytecode, but does not have to be retained when the class is loaded
Unfortunately it seems that annotation inheritance is severely restricted by the fact that only class-level annotations from classes (and not interfaces) can be inherited.
Consider this code:
interface Foo {
#A
void bar(String str, #B int i);
}
class FooImpl implements Foo {
void bar(String str, #B int i) { ... }
}
If I have an instance of FooImpl is it possible to discover if the method has been annotated with A (either in the class (easy) or in the implemented interface)?
What about the method parameter? Is it possible to dicover if and which parameter has been annotated with B?
It seems that this is not possible with AspectJ and I need to use Java Reflection.
How would a solid solution look like?
Its possible use getInterfaces() on the class object and query the result.
parameter annotation
package mawi12345;
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.PARAMETER)
public #interface B {
int version() default 0;
}
method annotation
package mawi12345;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#Inherited
public #interface Revision {
int minor() default 0;
int major() default 1;
}
interface with annotations
package mawi12345;
public interface Foo {
#Revision(minor=1, major=3)
public void setMark(#B(version=3) int mark);
}
class with annotations and the Foo interface
package mawi12345;
public class Test implements Foo {
public void setMark(int mark) {
}
#Revision(minor=2, major=4)
public boolean isPassed() {
return true;
}
}
Test Class
package mawi12345;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class ReflectionTest {
public static void printAnnotations(Class<?> clazz) {
// array of methods
Method[] methods = clazz.getDeclaredMethods();
System.out.println("found "+methods.length+" methods");
for (int i=0; i<methods.length; i++) {
// get the annotations of this method
Annotation[] methodAnnotations = methods[i].getAnnotations();
// if you only wont to check for one annotation use getAnnotation(Class<T>)
for (Annotation methodAnnotation : methodAnnotations) {
System.out.println(methodAnnotation);
}
// get the parameter annotations (2d array)
Annotation[][] parameterAnnotations = methods[i].getParameterAnnotations();
// get an array of parameters
Class<?>[] parameters = methods[i].getParameterTypes();
for(int x=0; x<parameterAnnotations.length; x++) {
Class<?> parameter = parameters[x];
for(Annotation annotation : parameterAnnotations[x]){
// print the parameter name and his annotation
System.out.println(parameter.getName() + " " + annotation);
}
}
}
}
/**
* #param args
*/
public static void main(String[] args) {
// create Test object
Test test = new Test();
// get the class
Class<?> clazz = test.getClass();
System.out.println("Class Test");
// print annotations
printAnnotations(clazz);
System.out.println();
// get the interfaces of the class
Class<?>[] interfaces = clazz.getInterfaces();
System.out.println("found "+interfaces.length+" interfaces");
// print annotations for each interface
for (Class<?> type : interfaces) {
System.out.println(type);
printAnnotations(type);
}
}
}
Output
Class Test
found 2 methods
#mawi12345.Revision(minor=2, major=4)
found 1 interfaces
interface mawi12345.Foo
found 1 methods
#mawi12345.Revision(minor=1, major=3)
int #mawi12345.B(version=3)
I have created many annotation in my life and now came to strange case that i need this annotation to do and dont think it is supported by Java at all. Please someone tell me that i am right or wrong.
Here is my annotation :
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface DetailsField {
public String name();
}
And now the question! I would like that the default value of the name() function would be the name of the field it self where I have posted the annotation.
Dont know exactly how the classloader processes the annotations, i am pretty sure that this is not implemented in a standard classloader , but could be maybe achieved by bytecode instrumentation in the time of classloading by a custom classloader ?
(I am pretty sure if this is the only solution i would find a way around , just curious )
Any ideas? Or do i wish too much ?
I think that it is possible to instrument the bytecode (at class loading) to get this working, but this seems like a highly complicated, and possibly non-portable, solution.
The best solution to your problem is to create a class that decorates (a-la the Decorator design pattern) an instance of your annotation with the name calculation logic.
[Edit: Added the name() definition at the interface]
package p1;
import java.lang.annotation.*;
import java.lang.reflect.*;
public class A {
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface DetailsField {
public int n1();
public String name() default "";
}
public static class Nameable implements DetailsField {
private final DetailsField df;
private final Field f;
public Nameable(Field f) {
this.f = f;
this.df = f.getAnnotation(DetailsField.class);
}
#Override
public Class<? extends Annotation> annotationType() {
return df.annotationType();
}
#Override
public String toString() {
return df.toString();
}
#Override
public int n1() {
return df.n1();
}
public String name() {
return f.getName();
}
}
public class B {
#DetailsField(n1=3)
public int someField;
}
public static void main(String[] args) throws Exception {
Field f = B.class.getField("someField");
Nameable n = new Nameable(f);
System.out.println(n.name()); // output: "someField"
System.out.println(n.n1()); // output: "3"
}
}