0

I'm trying to make custom forms with annotations. My idea is that given an annotated class, my code could generate a FX GUI form to edit objects of that class. It should be clearer in the code:

@...
@interface Form {
  String label() default "";
}

@Form
class SomeData {
  @Form(label="Name")
  String name;
  @Form(label="Age")
  int age;
  ...
}

class FormBuilder {
  Pane makeForm(Class annotated) {
    Pane pane = ... ;
    for (/*each annotated field*/) {
      Label label = new Label(/*field's annotated label*/));
      Control field = generateControl(/*annotated field's type*/));
      ...
      pane.getChildren().addAll(label, field);
    }
    return pane;
  }

  Control generateControl(Class type) {
    // returns the control that matches with the type
    // its everything OK here
  }

  main(...) {
    Pane someDataForm = makeForm(SomeData.class);
    ...
  }
}

I am starting in custom annotations now, and didn't get yet how to:

  • Iterate over annotated fields of an annotated class
  • Get its annotated data (label:String)
  • Get annotated field's type (name:String and age:Integer in this case)

in order to implement the method makeForm

LBald
  • 473
  • 2
  • 11

1 Answers1

0

Before we get to reflections code, I think you're going to need another annotation to represent your classes that represent a custom form. Your current @Form annotation is better suited at the field level, since it's representing the label for each form field. I would rename this to @FormField. Then, your @Form annotation can just be used to tell the reflections API which classes are custom forms.

Now, on to the code. First, you'll need to initialize reflections within your application. The package will be the first package where you want to utilize reflection in your app.

private static Reflections reflections = new Reflections("your.java.package");

To get every class annotated with your @Form annotation, you can use:

Set<Class<? extends Forms>> customForms = reflections.getTypesAnnotatedWith(Form.class)

Now, you can loop through each custom form, and parse through the annotations of each field:

// Loop through every class with Form annotation
    for (Class<? extends Forms> form : customForms) {
        for (Field field : form.getDeclaredFields()) {
            // Check each field, if it has your FormField attribute, you can then access the annotation methods
            if (field.isAnnotationPresent(FormField.class)) {
                Label label = new Label(field.getAnnotation(FormField.class).label());
                // Do additional stuff to build your form
            }
        }
    }
dylansheppard
  • 136
  • 1
  • 6
  • Thanks @dylansheppard, but where in the code should I initialize the reflections? Inside `main`, or do I use it as an attribute of the `FormBuilder`? – LBald Jan 31 '20 at 21:25
  • You can do either. If main is part of the `FormBuilder` class, I would make reflections a static class variable and initialize it in the main method. That way when `makeForm` is called, all the reflection stuff is already initialized. – dylansheppard Jan 31 '20 at 21:28
  • Although it worked without it, I didn't get what is the `Reflections` purpose. Is it from an external Java library? – LBald Feb 01 '20 at 01:53
  • It's an external library. Sorry, forgot it wasn't included with Java. You can find the source code [here](https://github.com/ronmamo/reflections) on github. You can either use a dependency management tool like Maven, or simply download the source and put it in your project. If you're not pressed for time, Maven is the route to go. – dylansheppard Feb 05 '20 at 17:18