I have an application that has many declared Lambdas. I've added an annotation to them so that I can use reflection to find all the functions marked with the annotation. They are all defined as:
@FooFunction("abc")
public static Function<Task, Result> myFunc = task -> {... returns new Result}
At startup, my application uses reflection to find all of the annotated functions and add them to the hashmap.
static HashMap<String, Function<Task, Result>> funcMap = new HashMap<>();
static {
Reflections reflections = new Reflections("my.package", Scanners.values());
var annotated = reflections.getFieldsAnnotatedWith(FooFunction.class);
annotated.forEach(aField -> {
try {
var annot = aField.getAnnotation(FooFunction.class);
var key = annot.value();
funcMap.put(key, aField.get(null);
} catch (Exception e) {
...;
}
}
The above code definitely won't work, especially on the put since aField.get(null) returns an Object. If I cast the object to Function<Task,Result>, I get an unchecked cast warning. No matter how I circle around it, I can't get rid of the warning (without using Suppress).
I've tried changing the Function<Foo, Bar> to something more generic like Function<?,?>
but that took me down another rabbit hole.
All of the functions are declared as static since they really don't need to belong to a specific class. They are grouped under various classes simply for organizational purposes.
The underlying objective is: the API will receive a list of tasks. There are about 100 different Task types. Each Task has an "id" field which is used to determine which Function should be used to process that Task. It looks something like this:
var results = Arrays.stream(request.getTasks())
.map(task -> functionMap.getOrDefault(task.getId(), unknownTaskFn).apply(task)
.toList();
My questions:
Thanks
Casting is inevitable, because Field.get
returns Object
by design, but it could be done without warnings.
I would also suggest define a custom interface
public interface TaskResultFunction extends Function<Task, Result> {
}
and use it for lambda declarations
@FooFunction("abc")
public static TaskResultFunction myFunc = task -> {... returns new Result}
(otherwise we will have to deal with ParameterizedTypeReference, but in this case it is not necessary and overcomplicated)
Map<String, Function<Task, String>> funcMap = ...
// or more strict
Map<String, TaskResultFunction> funcMap = ...
//...
if (TaskResultFunction.class.isAssignableFrom(field.getType())) {
TaskResultFunction fn = (TaskResultFunction) field.get(null);
taskResultFunctions.put(key, fn);
}