0

I have these 4 classes -

  1. Component.java -> which will be annotated using custom annotation,
  2. Properties.java -> the annotation class
  3. Utilities.java -> class where the annotation is used
  4. AnnotationProcessor.java -> where the annotation logic using reflection is built What I want is, based on the annotation, I will set a property of the Component object. This is my code -

//class which will be annotated using custom annotation

public class Component {
private String name;
private String id;

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}

//annotation class

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Properties {
    String compName();
}

//class where the annotation is used

public class Utility {

@Properties(compName = "myName")
Component comp1;

@Properties(compName = "myPassword")
Component comp2;

public void login() throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
    comp1 = new Component();
    comp2 = new Component();

    comp1.setId("1111");
    comp2.setId("2222");
    AnnotationProcessor annotationProcessor = new AnnotationProcessor();
    annotationProcessor.process(this, comp1);
    annotationProcessor.process(this, comp2);
}}

//class where the annotation is processed

public class AnnotationProcessor {
    public void process (Object callingClass, Component c){
    System.out.println("In AnnotationProcessor:process");

    Class<? extends Object> aClass = callingClass.getClass();
    Field[] declaredFields = aClass.getDeclaredFields();

    for (Field field: declaredFields) {
        if(field.isAnnotationPresent(Properties.class)){
          if (field.get(callingClass) != null) { //Added newly
            Properties annotation = field.getAnnotation(Properties.class);
            String val = annotation.compName();
            c.setName(val);
            field.set(callingClass, c); //Added newly
            System.out.println("For field " + field.getName() + ", component id is : " + c.getId() + " and name is : --> " + c.getName());
            break; //Added newly
        }

    }
}

}

I want to achieve to set the name of "comp1" to be "myName" and name of "comp2" to be "myPassword". Basically, the output I expect is this -

For field comp1, component id is : 1111 and name is : --> myName
For field comp2, component id is : 2222 and name is : --> myPassword

But the actual output is this (after //added newly changes)-

In AnnotationProcessor:process
For field comp1, component id is : 1111 and name is : --> myName
In AnnotationProcessor:process
For field comp1, component id is : 2222 and name is : --> myName

My problem is, how to assign the "name" of the component as per the annotation for that component object only and not for all the fields the Utility class has. I feel there is some if condition in the middle that might help achieve this, but not able to find it out.

MuCh
  • 103
  • 1
  • 9
  • Check if the field value is `null`, otherwise skip the field. And `break` after the first field is set. – Johannes Kuhn May 21 '22 at 16:45
  • @JohannesKuhn Could you please explain what you mean by if the field is `null`. I wrote this and this is never true - `if(field == null) `. – MuCh May 21 '22 at 17:35
  • `if (field.get(callingClass) != null) {...; field.set(callingClass, c); break;}` – Johannes Kuhn May 21 '22 at 18:02
  • Doesn't solve the problem - `if (field.isAnnotationPresent(Properties.class)) { if (field.get(callingClass) != null) { //Added newly Properties annotation = field.getAnnotation(Properties.class); String val = annotation.compName(); c.setName(val); field.set(callingClass, c); //Added newly System.out.println("For field " + field.getName() + ", component id is : " + c.getId() + " and name is : --> " + c.getName()); break; //Added newly }}}}` – MuCh May 21 '22 at 23:53
  • Now output is - `In AnnotationProcessor:process For field comp1, component id is : 1111 and name is : --> myName In AnnotationProcessor:process For field comp1, component id is : 2222 and name is : --> myName` – MuCh May 21 '22 at 23:56
  • You forgot the `break`. – Johannes Kuhn May 22 '22 at 00:01
  • Sorry for the bad formatting. I updated the original post with //Added newly comment. I did add the `break`, after the `sysout`. – MuCh May 22 '22 at 00:01
  • 1
    Ok, `(field.get(callingClass) != null)` should be `(field.get(callingClass) == c)`. remove the `field.set(callingClass, c);` – Johannes Kuhn May 22 '22 at 00:35
  • Thanks @JohannesKuhn. Its perfect, works like a charm now ! – MuCh May 23 '22 at 09:09
  • Maybe, just one more question. Is there any way to get the `Object callingClass` from the `Component c` ? That is, can my process method be like this to achieve same result ? `public void process (Component c)` – MuCh May 23 '22 at 11:34
  • 1
    The parameter name `callingClass` is misleading, as it is not the class but an instance you’re passing. So, no, you can’t get that object in a different way. But what is this feature all about? Is writing `@Properties(compName = "myPassword")`, plus `annotationProcessor.process(this, comp2);` in the constructor, really an improvement over writing just `comp2.setName("myPassword");` in the constructor? – Holger May 25 '22 at 12:21

0 Answers0