Is my use of Java Reflection an OK design?
Each domain object contains an annotation to declare what controller would be initialized to edit/create the object:
Each field of the domain object has an annotation to declare what control in the specified controller that the user would use to edit its value:
@Edit(controller = EmployeeController.class)
public class Employee extends Item {
@Node(name = "lastNameField", type = TextField.class)
private StringProperty lastName = new SimpleStringProperty();
//Control similar to a TableView
@Node(name = "contacts", type = ListBox.class)
private List <Contact> contacts;
}
public @interface Edit {
Class<? extends ModifyEntityController> controller();
}
public @interface Node {
String name();
Class<?> type();
}
public Class EmployeeController {
@FXML
private TextField lastNameField;
}
Double-clicking on a ListCell
would call .edit()
on the domain object.
This method is in the parent class Item
.
.edit()
does: example = employee.edit();
- create an instance of the
@Edit
controller - use
@Node
to create a binding between the specified control - set the root node of controller to the main window of the application.
//create an instance of the controller
Edit edit = getClass().getAnnotation(Edit.class);
Class<? extends Controller> controller = edit.controller();
Object controllerInstance = null;
try {
controllerInstance = edit.controller().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
//create bindings between the specified controls
List <Field> itemFields = FieldUtils.getFieldsListWithAnnotation(getClass(), Node.class);
for (Field field : itemFields ) {
Node node = field.getAnnotation(Node.class);
Object itemObject = FieldUtils.readField(field, this, true);
Object controllerControl = FieldUtils.readDeclaredField(controllerInstance, node.name(), true);
if (node.type() == TextField.class) {
TextInputControl tc = (TextInputControl) controllerControl;
StringProperty sp = (StringProperty) itemObject;
tc.textProperty().bindBidirectional(sp);
}
else if (node.type() == ListBox.class) {
ListBox lb = (ListBox) controllerControl;
List <CellObject> list = (List<CellObject>) itemObject;
lb.setList(FXCollections.observableArrayList(list));
}
}
*The implementation of a ListBox
is actually not a binding of properties but setting the value of its ListView
to the List Field of the domain object.
All objects that would be the value of a ListCell
would implement CellObject
.
//set the root node of controller to the main window of the application
AgendaApp.setContent(Controller) controllerInstance);
I went with reflection as the controllers to update/create domain objects consist of mainly TextFields
and ListBox's
. This would save a lot of time writing the application.