Reputation: 22409
I am trying to learn how to write custom annotations in Java.
For learning purposes, I decided to try to create an annotation that make a field available for a class using the annotation, ie: injection but not necessary as a singleton to keep it a bit more simple ( I think ), but that is welcome as well.
=================================CLASS 1=================================
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;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface AutoInject {
}
=================================CLASS 2=================================
// The class to be injected in Main.java
public class TestClass0 {
void printSomething(){
System.out.println("PrintSomething: TestClass0");
}
}
=================================CLASS 3=================================
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
public class Main {
TestClass0 ts0;
// Injecting here!!
@AutoInject
public TestClass0 getTso() {
return ts0;
}
public void setTso(TestClass0 ts) {
ts0 = ts;
}
public static void main(String[] args) {
performAnnotationScanOnClass (Main.class);
// Create instance
Main main = new Main();
main.getTso().printSomething();
}
public static void performAnnotationScanOnClass(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for ( Field field : fields ) {
Annotation[] annotations = field.getAnnotations();
for (Annotation annotation : annotations) {
if ( annotation instanceof AutoInject ) {
AutoInject autoInject = (AutoInject) annotation;
// if ( field.get( ... ) == null )
// field.set( ... , value)
}
}
}
}
}
As you can see in the static void main() ... I am trying to call the method in TestClass0, expecting it to be available. I know that the above is long from near completion, but I just started learning annotations and would like your guidance.
How can we fire a piece of code, that initializez a property either on new or when the get method is called. Using annotations. I am thinking without altering invoke method.
Thanks!
Upvotes: 1
Views: 5186
Reputation: 656
You are iterating over fields in your scan code, but the annotation you defined only allows annotation on methods. This means you'll never see any annotations.
It looks like you are trying to use fields like they were java beans properties. Here's an example of setter injection using your AutoInject and TestClass0 classes as-is:
Main.java:
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class Main {
public TestClass0 ts0;
public TestClass0 getTso() {
return ts0;
}
@AutoInject
public void setTso(TestClass0 ts) {
ts0 = ts;
}
public static void main(String[] args) {
// Create instance
Main main = new Main();
injectDependencies(main).getTso().printSomething();
}
public static <T> T injectDependencies(final T obj) {
try {
Class clazz = obj.getClass();
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
Method readMethod = pd.getReadMethod();
Method writeMethod = pd.getWriteMethod();
if (writeMethod == null) {
continue;
}
Object existingVal = pd.getReadMethod().invoke(obj);
if (existingVal == null) {
for (Annotation annotation : writeMethod.getAnnotations()) {
if (annotation instanceof AutoInject) {
Class propertyType = pd.getPropertyType();
writeMethod.invoke(obj, propertyType.newInstance());
}
}
}
}
} catch (Exception e) {
// do something intelligent :)
}
return obj;
}
}
Upvotes: 3