Let's assume we have an enum, that represents searchable fields:
enum SearchableFields {
ALL,
FIELD1,
FIELD2,
FIELD3;
}
This enum is displayed via a (combobox) selection inside a GUI. At runtime, I want to evaluate the selection of this combobox and search accordingly.
Depending on the selection, I need to retrieve the fields to search from a POJO (example below) via a getter.
class FieldPojo {
private String field1;
private String field2;
private String field3;
...
public String getField1() {
return field1;
}
...
}
I currently use a switch
statement to evaluate the selection of SelectableFields
and to then retrieve the correct field(s) to search:
private String retrieveField(FieldPojo f) {
switch (selectedField) {
case ALL:
return retrieveAll(); // method that retrieves all available fields
case FIELD1:
return f.getField1();
...
}
This does work, however I feel like it's clunky.
Question:
Is there a more concise way to do this without evaluating the enum
via a switch
? (Java 8)
CodePudding user response:
You could store a reference to the getter in your enum constants:
enum SearchableFields {
ALL(FieldPojo::retrieveAll),
FIELD1(FieldPojo::getField1)
private final Function<FieldPojo, String> accessor;
SearchableFields(Function<FieldPojo, String> acccessor) {
this.accessor = accessor;
}
public String get(FieldPojo fp) {
return accessor.apply(fp);
}
}
CodePudding user response:
Enums can contain method definitions, so one way is to define the method that retrieves the field name based on the enum value. I assume you have the actual field name stored as a member field also. Then you can override the method for the special ALL
value:
enum SearchableFields {
ALL("all") { // all is just a placeholder in this case
@Override
String retrieveField(FieldPojo f) {
// logic for all fields
}
},
FIELD1("field1"),
FIELD2("field2"),
FIELD3("field3");
SearchableFields(String fieldName) {
this.fieldName = Optional.of(fieldName);
}
SearchableFields() {
fieldName = Optional.empty();
}
private final Optional<String> fieldName;
String retrieveField(FieldPojo f) {
if (fieldName.isPresent()) {
return (String) f.getClass().getField(fieldName.get()).get(f);
} else {
// ...
}
}
}
CodePudding user response:
You can create a static map instead of the switch-case.
private static final Map<SearchableFields,Supplier<String>> searchableFieldsToFieldPojo = Map.of(
ALL, this::retrieveAll,
FIELD1, FieldPojo::retrieveAll
);
And then you can access via:
searchableFieldsToFieldPojo.get(selectedField).get();
CodePudding user response:
Given that you can modify all parts of the code, you have several options:
- Put the
retrieveField
into the classFieldPojo
and modify it's parameter so it takes the enumSearchableFields
as parameter. - Put the fields of
FieldPojo
as values into a map with a key of typeSearchableFields
. You can then decide whether you want to have "ALL" as an extra entry of the map or handle it as special case in a method similar toretrieveField
. You could use this to have a "default" handling if you want to update the enum but not theFieldPojo
class. - You put
retrieveField
into the classFieldPojo
together with theSearchableFields
enum - since onlyFieldPojo
knows, which fields it actually provides as searchable fields. - You use introspection to gather the list of possible searchable fields and also access their contents.
Depending on your real requirements (you only showed a very abstract and specific version of them) one or the other method might be "the right one" for you. I would actually prefer the "everything into FieldPojo
" as the most robust one, but on the other hand if you are not able to change FieldPojo
and have to handle many different classes like it, the introspection variant might be the right one. (Be aware that it is fragile in terms of security and also probably very slow.)