0

I want to create annotation (for which I can set some kind of id), which I can put on variable, and write method which return getter or setter method of this variable by annotations setted id;

As example I made something like that but only for method, so I need two annotations for both setter and getter method, or add more parameters to one annotation. Maybe it is possible to create one annotation for variable, and then find method which I need (setter or getter)?

What I managed to do:

Annotation class:

    public @interface FieldRawValue {

    String value() default "";
}

Model class with getters and setters (With annotation for getters):

public class PajamuModel extends AbstractModel{

private String id;
private String pajamuType;
private String pajamuSource;
private Date pajamuData;
private double pajamuSuma;
private String valiuta;
private String note;

@FieldRawValue(value = "pajamuType")
public String getPajamuType() {
    return pajamuType;
}

public void setPajamuType(String pajamuType) {
    this.pajamuType = pajamuType;
}

@FieldRawValue(value = "pajamuSource")
public String getPajamuSource() {
    return pajamuSource;
}

public void setPajamuSource(String pajamuSource) {
    this.pajamuSource = pajamuSource;
}

@FieldRawValue(value = "pajamuData")
public Date getPajamuData() {
    return pajamuData;
}...

Method which returns data by annotations value:

public class AbstractModel {

public Object get(String fieldName) {
    Class<? extends AbstractModel> obj = this.getClass();

    for (Method method : obj.getDeclaredMethods()) {
        if (method.isAnnotationPresent(FieldRawValue.class)) {
            FieldRawValue annotation = method
                    .getAnnotation(FieldRawValue.class);
            if (annotation.value().equals(fieldName)) {
                try {
                    return method.invoke(obj);
                } catch (IllegalAccessException | IllegalArgumentException
                        | InvocationTargetException e) {
                    e.printStackTrace();
                    return null;
                }
            }
        }
    }

    return null;
}

Btw, not tested get(String fieldName) method, but I expect it work.

So is it possible to set annotation on variable, and then find set or get method, when I need?

1 Answer 1

2

Im not sure why do you want to duplicate fieldname and have it in annotation, however here is the solution (Java8 required):

public class AbstractModel {

    public Object get(String fieldName) throws InvocationTargetException, IllegalAccessException {
        FieldRawValue fieldRawValueAnnotation = validateExistsAndGetFieldRawValueAnnotation(fieldName);

        String fieldRawValueString = fieldRawValueAnnotation.value();

        Optional<Method> getterMethodOptional = Stream.of(getClass().getMethods())
                .filter(method1 -> method1.getName().equalsIgnoreCase("get" + fieldRawValueString))
                .findFirst();

        return getterMethodOptional
                .orElseThrow(() -> new RuntimeException("No getter found for @FieldRawValue with value: " + fieldRawValueString))
                .invoke(this);
    }

    public Object set(String fieldName, Object value) throws InvocationTargetException, IllegalAccessException {
        FieldRawValue fieldRawValueAnnotation = validateExistsAndGetFieldRawValueAnnotation(fieldName);

        String fieldRawValueString = fieldRawValueAnnotation.value();

        Optional<Method> getterMethodOptional = Stream.of(getClass().getMethods())
                .filter(method1 -> method1.getName().equalsIgnoreCase("set" + fieldRawValueString))
                .findFirst();

        return getterMethodOptional
                .orElseThrow(() -> new RuntimeException("No setter found for @FieldRawValue with value: " + fieldRawValueString))
                .invoke(this, value);
    }

    private FieldRawValue validateExistsAndGetFieldRawValueAnnotation(String fieldName) {
        Class<? extends AbstractModel> obj = this.getClass();

        FieldRawValue fieldRawValueAnnotation = null;
        try {
            fieldRawValueAnnotation = obj.getDeclaredField(fieldName).getAnnotation(FieldRawValue.class);
        } catch (NoSuchFieldException e) {
            new RuntimeException("Field not found: " + fieldName);
        }

        if(fieldRawValueAnnotation == null){
            throw new RuntimeException("FieldRawValue annotation not found for a field: " + fieldName);
        }
        return fieldRawValueAnnotation;
    }

Model + usage:

public class TestModel extends AbstractModel{

    @FieldRawValue("test2")
    private String test;

    public String getTest2() {
        return test;
    }

    public void setTest2(String test) {
        this.test = test;
    }

    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        TestModel testModel = new TestModel();

        Object tst = testModel.get("test"); //== null
        testModel.set("test", "newVal"); //sets new value
        testModel.get("test"); //== "newVal
    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

Ok, thank you, as I understand there is no need for annotation.
Thats right, you can call getClass().getDeclaredField(fieldName) and if field exists try to find getter/setter for it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.