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
Related
When I get method from class instance, and want to get #override annotation.
but method has not any annotation.
Is it impossible to get #override annotation?
code is below.
package com.test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import javax.annotation.Resource;
public class ReflectionTest {
public static void main(String[] args) throws Exception {
ChildHoge childHoge = new ChildHoge();
Method method = childHoge.getClass().getMethod("init");
for (Annotation s : method.getAnnotations()) {
System.out.println(s);
}
Method method2 = childHoge.getClass().getMethod("a");
for (Annotation a : method2.getAnnotations()) {
System.out.println(a); // =>#javax.annotation.Resource(mappedName=, shareable=true, type=class java.lang.Object, authenticationType=CONTAINER, lookup=, description=, name=)
}
}
}
class SuperHoge {
public void init() {
}
}
class ChildHoge extends SuperHoge {
#Override
public void init() {
super.init();
}
#Resource
public void a() {
}
}
#Retention(RetentionPolicy.SOURCE)
public #interface Override {
}
It has RetentionPolicy.SOURCE which are discarded by the compiler, which means it cannot be obtained at runtime. You can see this described in JLS 9.6.4.2.
If an annotation a corresponds to a type T, and T has a
(meta-)annotation m that corresponds to
java.lang.annotation.Retention, then:
If m has an element whose value is
java.lang.annotation.RetentionPolicy.SOURCE, then a Java compiler must
ensure that a is not present in the binary representation of the class
or interface in which a appears.
And the Javadoc for RetentionPolicy also describes this:
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
...
You can use Reflection API to check if the method is overridden or not
e.g.
class.getMethod("myMethod").getDeclaringClass();
If the class that's returned is your own, then it's not overridden; if it's something else, that subclass has overridden it.
I've an EJB as follows:
public class Bar() {
private String s;
public Bar() {
this.s = "bar";
}
#Inject public Bar(String s) {
this.s = s;
}
}
How can I inject that bean by using the arg-constructor into another Foo class?
Then, I define the Foo class as EJB, with the aim to perform the DI for it into another class (for instance, a WebServlet). How can I inject a Foo class instance by passing a String to properly set up Bar arg-constructor as inner-dependency?
Is there a better way to define Bar in order to achieve points above?
The annotated constructor injection tells CDI that whenever someone requests an instance of Bar to be injected, it should use the constructor marked with #Inject.
The CDI container then tries to get instances for all required constructor parameters and fails, because it can not deal with "String". It just doesn't know which String you mean.
You have to help the container resolving the dependency by using a Producer and a Qualifier to tell him what String you want. I just give you the simplest possible solution here:
public class Bar {
#Inject
public Bar(#Named("myString") String s) {
this.s = s;
}
}
And then another class (doesn't have to be an different class, but its much more readable):
public class MyStringProducer {
#Produces
#Named("myString")
public String getMyString() {
return ...; // whatever you want ... read JSON, parse properties, randomize ...
}
}
#Inject only works when you are injecting "managed" objects. String is not a managed object, thus this won;t work.
However, the following example should work (I have used spring here. Use the DI initializaton code according to the library you are using):
#Named
public class Foo {
#Inject
Bar bar;
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.pkg1");
Foo foo = (Foo)ctx.getBean("foo");
System.out.println(foo.bar.getString());
}
}
#Named
public class Bar {
private String s;
public Bar() {
this.s = "bar";
}
#Inject
public Bar(Bar1 bar1) {
this.s = bar1.getS();
}
public String getString() {
return s;
}
}
#Named
class Bar1 {
private String s="bar1";
public String getS() {
return s;
}
}
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.
I'm using Spring since a few months for now, and I thought dependency injection with the #Autowired annotation also required a setter for the field to inject.
So, I am using it like this:
#Controller
public class MyController {
#Autowired
MyService injectedService;
public void setMyService(MyService injectedService) {
this.injectedService = injectedService;
}
...
}
But I've tried this today:
#Controller
public class MyController {
#Autowired
MyService injectedService;
...
}
And oh surprise, no compilation errors, no errors at startup, the application is running perfectly...
So my question is, is the setter required for dependency injection with the #Autowired annotation?
I'm using Spring 3.1.1.
You don't need a setter with the #Autowired, the value is set by reflection.
Check this post for complete explanation How does Spring #Autowired work
No, if Java security policy allows Spring to change the access rights for the package protected field a setter is not required.
package com.techighost;
public class Test {
private Test2 test2;
public Test() {
System.out.println("Test constructor called");
}
public Test2 getTest2() {
return test2;
}
}
package com.techighost;
public class Test2 {
private int i;
public Test2() {
i=5;
System.out.println("test2 constructor called");
}
public int getI() {
return i;
}
}
package com.techighost;
import java.lang.reflect.Field;
public class TestReflection {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> class1 = Class.forName("com.techighost.Test");
Object object = class1.newInstance();
Field[] field = class1.getDeclaredFields();
field[0].setAccessible(true);
System.out.println(field[0].getType());
field[0].set(object,Class.forName(field[0].getType().getName()).newInstance() );
Test2 test2 = ((Test)object).getTest2();
System.out.println("i="+test2.getI());
}
}
This is how it is done using reflection.
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"
}
}