How to use reflection to find annotated Lambda Functions - java

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:
Is this an antipattern? If so, is there a better prescribed pattern?
How can I go from an Object to a Function<Task,Result> properly to put it into the map?
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);
}

Related

Is there a way to check if a generic parameter (HashMap<Integer, ArrayList<?>>) is of a certian type?

I have a function that uses a HashMap<Integer, ArrayList<CustomObject1>> map as a parameter. However, now functionality has been expanded and I need to call this function with a different HashMap that contains ArrayList<CustomObject2>>.
I've looked into generics and tried passing in HashMap<Integer, ArrayList<? extends CustomObjectBase>> map but I will need to know what is actually passed in so I can respond accordingly. Making another function did not work due to type erasure. I've also tried using java instanceof but that does not work either.
Any advice on how this could be solved? Thank you!
I've spent hours trying this on my own before, and it was a fruitless endeavor. It is generally preferred to instead pass the class as a parameter, like so:
public void <T> handle(HashMap<Integer, ArrayList<T>> map, Class<T> clazz)
{
// do whatever you need to, based on
}
Then, you'll call it like so:
var map1 = new HashMap<Integer, ArrayList<CustomObject1>>();
// map1 populate...
var map2 = new HashMap<Integer, ArrayList<CustomObject2>>();
// map1 populate...
var h = new Handler();
h.handle(map1, CustomObject1.class);
h.handle(map2, CustomObject2.class);
instanceof is your friend:
if (map instanceof CustomObject1) {
//...
} else {
//...
}
Also, you can use method overloading as well. You have method1 that you are talking about, yet you need to do some differentiation between the types. The custom logic that you need for can be delegated to method2 and you can implement different overloads if they are different.
Also, map.get(0).getClass().getName() can come in handy here if your array list is not empty, of course.

Why would one use a `java.util.function.supplier`, when one can just call a method?

I saw some example of of using supplier interface at https://dzone.com/articles/supplier-interface.
My question is, if in the above example I could do something as easy as :
driveVehicle(new Vehicle());
driveVehicle(new Car());
Why would one want to use supplier interface, if all it does is call a method, without taking in any parameters.
Suppose you have parameters stored in database that you want to keep in constant all over your app
// Assume retrieveSystemParameter query database which allows to change parameters
public static String SYSTEM_PARAMETER = StaticUtilities.retrieveSystemParameter();
That value will be initialized once and won't change untill a redeployment. That being said, if instead you use a supplier :
public static Supplier<String> SYSTEM_PARAMETER_SUPPLIER = StaticUtilities::retrieveSystemParameter;
When you need the value somewhere you will call SYSTEM_PARAMETER_SUPPLIER.get() which will retrieve parameter in the database when needed - that way if you change a parameter in database, you won't have to redeploy.
As you can see, Suppliers are lazy. They do the work when you ask them to work (by calling .get()) - that may allow you some performance gain if you deal with them wisely. Sometimes you will call a method which expect a variable X passing in method retrieveX and then end up not needing X in the method because some conditions were not met. In that case you will lose performance as you will execute the code to retrieve X while a supplier that retrieve X would only execute it when calling .get and you would only do that call if the conditions were met.
Disclaimer : the system parameter constant is just the first example that came to my mind, but considering it query the database on each .get() you'd rather cache the parameter and have the cache call .get() at a specific interval.
I guess Optional might be perfect example. Consider the following snippet:
final Product firstProduct = Optional.ofNullable(product)
.orElse(productDao.findProductById(id));
final Product secondProduct = Optional.ofNullable(product)
.orElseGet(() -> productDao.findProductById(id));
You're getting a product that may be null. In order to determine firstProduct java will have to call expression in orElse method so no matter product is null or not you always have to determine value that will be returned in case product is null.
In order to determine secondProduct database doesn't have to be queried in case product is not null because you're passing a Supplier that will be called only if product is null.
Another example is when your method that accepts a supplier is not pure (i.e., it has side effect), and the side effect happens before calling the lambda, and the behaviour of the lambda is affected by the side effect.
Consider, for instance, this example:
public class TestClass {
private String field;
public String getField() {
return field;
}
public void method(Supplier<String> supplier) {
field = "This is";
System.out.println(supplier.get() + " a test");
}
public static void main(String[] args) {
TestClass c = new TestClass();
c.method(() -> c.getField());
}
}
Here, method() is not pure, as it changes the value of field, which is used later in the lambda (through calling the getField() method). As the lambda is called in place (i.e., when get() is called), calling getField() will happen after setting the field. In other words, method() accepts a Supplier<String> instead of a String in an attempt to let the clients safely call the getField() method.
Of course, having side effects should be avoided wherever possible, and this is just a toy example, but it shows a potential place where a supplier can be used.
Supplier adds one more level of indirection.
Given that "All problems in computer science can be solved by another level of indirection", it's likely that there are some problems that can be solved by using a Supplier.
Beware, however, of the corollary "...except for the problem of too many layers of indirection."
So, if there's no problem to solve, then Supplier is overkill and you should stick to directly invoking new.
Put differently: mistrust any "pattern" or "best practice" that doesn't start by explaining a problem (your question shows, you actually do mistrust, so just keep on asking this kind of questions).
I use it to avoid the unnecessary creation of additional states:
private Supplier<Boolean> detach = () -> false;
private Supplier<Boolean> isAttached = () -> false;
private Supplier<Integer> index = () -> null;
private final Function<List<ObserverWrapper<X, Y>>, Boolean> attachFun = observers -> {
isAttached = () -> observers.contains(this);
detach = () -> observers.remove(this);
index = () -> observers.indexOf(this);
return observers.add(this);
};
public boolean attach(List<ObserverWrapper<X, Y>> observers) {
return attachFun.apply(observers);
}
public boolean isAttached() {
return isAttached.get();
}
public Integer observerIndex() {
return index.get();
}
Which some would say is unnecessary in itself, but then it becomes a philosophical problem.
A problem which would not exist if computers didn't exist, and then it becomes a real world problem of indirection.
I may admit that suppliers for me may have become an addiction, but in my mind they feel like the natural extrapolation and extension of all the programming axioms and principles.
You could use a Supplier in a map based factory class
public class StackService {
final static String INTEGERS = "Integers";
final static String DOUBLES = "Doubles";
final static String STRINGS = "Strings";
final static Map<String, Supplier<Stack>> stackType;
static {
stackType = new HashMap<>();
stackType.put(INTEGERS, Stack<Integer>::new);
stackType.put(DOUBLES, Stack<Double>::new);
stackType.put(STRINGS, Stack<String>::new);
}
public Stack<?> createStackOfType(String stackType) {
return stackType.get(stackType).get();
}
}
Here if you were to just use new Stack() you would be returning a reference to the same object rather than a new one.

Automatically merge several collections to one

I have some Guava Functions like Function<String,Set<String>>. Using those with FluentIterable.transform() leads to a FluentIterable<Set<String>>, however I need a FluentIterable<String>. So my idea now would be to subclass FluentIterable<E> and add a new method transform2() which simply merges everything to one collection before returning it.
The original transform method looks like this:
public final <T> FluentIterable<T> transform(Function<? super E, T> function) {
return from(Iterables.transform(iterable, function));
}
I thought of something like this for my subclass and transform2() method:
public abstract class FluentIterable2<E> extends FluentIterable<E>
{
public final <T> FluentIterable<T> transform2(Function<? super E, Collection<T>> function) {
// (PROBLEM 1) Eclipse complains: The field FluentIterable<E>.iterable is not visible
Iterable<Collection<T>> iterables = Iterables.transform(iterable, function);
// (PROBLEM 2) Collection<T> merged = new Collection<T>(); // I need a container / collection - which one?
for(Collection<T> iterable : iterables)
{
// merged.addAll(iterable);
}
// return from(merged);
}
}
Currently I have two problems with my new subclass, marked above with PROBLEM 1 and PROBLEM 2
PROBLEM 1: The iterable field in the original FluentIterable class is private - what can I do about this? Can I create a new private field with the same name in my subclass, will this then be OK? What about methods in my subclass that call super.someMethod() which uses this field? Will they then use the field of the super class, which probably has a different value?
PROBLEM 2: I need some generic collection where I can combine the content of several collections, but collections is an interface, so I can't instantiate it. So, which class can I use there?
It would be acceptable if the solution only works with sets, though I'd prefer a solution that works with sets and lists.
Thanks for any hint on this!
Does FluentIterable.transformAndConcat(stringToSetFunction) not work for your use case?
Why subclass FluentIterable just to do this? You just need a simple loop:
Set<String> union = Sets.newHashSet();
for (Set<String> set : fluentIterableOfSets) {
union.addAll(set);
}
Use FluentIterable.transformAndConcat(f), where f is a Function mapping an element to some kind of iterable over the element type.
In your case, let's say your Function<String, Set<String>> is called TOKENIZE, and your initial Iterable<String> is called LINES.
Then to get a Set<String> holding all the distinct tokens in LINES, do this:
Iterable<String> LINES = ...;
Function<String, Set<String>> TOKENIZE = ...;
Set<String> TOKENS = FluentIterable.from(LINES)
.transformAndConcat(TOKENIZE)
.toSet();
But consider JB Nizet's answer carefully. Try it both ways and see which works better.

Get the class for a generic collection without using an instance

Iwould like to do something like the following:
public class Test {
public static void main(String[] args) {
Map<String, Set<String>> map = new HashMap<String, Set<String>>();
map.put("key1", new HashSet<String>());
Set<String> theSet = getObjectAs(map, ***Set<String>.class***);
}
private static <T> T getObjectAs(Object object, Class<T> cls){
return cls.cast(object);
}
}
But this doesn't work, I can't get the class object out of that Set using .class (see in bold) because it is parameterized.
I want to make that method to return a Set who's type may vary (it won't always be a set of Strings) but which I know and I can give as a parameter.
Is there another way of doing something like this?
The only way you can possibly do this is to accept that you need to do unsafe casts. There is no such thing as Set<String>.class, because it would be exactly equal, in every respect, to Set.class.
The only other thing you might be able to do is use one of the "generic Class" types from a library somewhere, like Guava's TypeToken, but this wouldn't let you get around the need for unsafe casts -- it would only let you specify it with generics. Guava's TypeToInstanceMap works similarly.

How can I map a String to a function in Java?

Currently, I have a bunch of Java classes that implement a Processor interface, meaning they all have a processRequest(String key) method. The idea is that each class has a few (say, <10) member Strings, and each of those maps to a method in that class via the processRequest method, like so:
class FooProcessor implements Processor
{
String key1 = "abc";
String key2 = "def";
String key3 = "ghi";
// and so on...
String processRequest(String key)
{
String toReturn = null;
if (key1.equals(key)) toReturn = method1();
else if (key2.equals(key)) toReturn = method2();
else if (key3.equals(key)) toReturn = method3();
// and so on...
return toReturn;
}
String method1() { // do stuff }
String method2() { // do other stuff }
String method3() { // do other other stuff }
// and so on...
}
You get the idea.
This was working fine for me, but now I need a runtime-accessible mapping from key to function; not every function actually returns a String (some return void) and I need to dynamically access the return type (using reflection) of each function in each class that there's a key for. I already have a manager that knows about all the keys, but not the mapping from key to function.
My first instinct was to replace this mapping using if-else statements with a Map<String, Function>, like I could do in Javascript. But, Java doesn't support first-class functions so I'm out of luck there. I could probably dig up a third-party library that lets me work with first-class functions, but I haven't seen any yet, and I doubt that I need an entire new library.
I also thought of putting these String keys into an array and using reflection to invoke the methods by name, but I see two downsides to this method:
My keys would have to be named the same as the method - or be named in a particular, consistent way so that it's easy to map them to the method name.
This seems WAY slower than the if-else statements I have right now. Efficiency is something of a concern because these methods will tend to get called pretty frequently, and I want to minimize unnecessary overhead.
TL; DR: I'm looking for a clean, minimal-overhead way to map a String to some sort of a Function object that I can invoke and call (something like) getReturnType() on. I don't especially mind using a 3rd-party library if it really fits my needs. I also don't mind using reflection, though I would strongly prefer to avoid using reflection every single time I do a method lookup - maybe using some caching strategy that combines the Map with reflection.
Thoughts on a good way to get what I want? Cheers!
There aren't any first-class standalone functions, but you can do what you want with an interface. Create an interface that represents your function. For example, you might have the following:
public interface ComputeString
{
public String invoke();
}
Then you can create a Map<String,ComputeString> object like you want in the first place. Using a map will be much faster than reflection and will also give more type-safety, so I would advise the above.
While you can't have first class functions, there are anonymous classes which can be based on an interface:
interface ProcessingMethod {
String method();
}
Map<String, ProcessingMethod> methodMap = new HashMap<String, ProcessingMethod>();
methodMap.put("abc", new ProcessingMethod() {
String method() { return "xyz" }
});
methodMap.put("def", new ProcessingMethod() {
String method() { return "uvw" }
});
methodMap.get("abc").method();
Or you could use Scala :-)
Couldn't you do String to Method? Then you can cache the methods you need to execute.
This example uses an enum of named functions and an abstract FunctionAdapter to invoke functions with a variable number of homogeneous parameters without reflection. The lookup() function simply uses Enum.valueOf, but a Map might be worth it for a large number of functions.
As you've noticed, you can do what you want using the Reflection API, but you loose some benefits of the Java compiler, on top of the issues you've already come up with. Would wrapping your Strings in an object and using the Visitor pattern solve your issue? Each StringWrapper would only accept a Visitor that has the right method, or something along those lines.
Use a Map where the key is a string and the value is an object that implements an interface containing method(). That way you can get the object containing the method you want out of the map. Then just call that method on the object. For example:
class FooProcessor implements Processor{
Map<String, FooMethod> myMap;
String processRequest(String key){
FooMethod aMethod = myMap.getValue(key);
return aMethod.method();
}
}
What about Method class from the reflection API? You can find methods of a class based on name, parameters, or return type. Then you just call Method.invoke(this, parameters).
That's pretty much the same as a Map from JavaScript you are talking about.
public class CarDetailsService {
private final CarRepository carRepository;
private final Map<String, Function<CarDTO, String>> carColumnMapper = new HashMap<>();
public ApplicationDetailsServiceImpl(CarRepository carRepository) {
this.carRepository = carRepository;
//---- Initialise all the mappings ------- //
carColumnMapper.put("BRAND", CarDTO::getBrandName);
carColumnMapper.put("MILEAGE", CarDTO::getMileage);
}
public Map<String, List<CarDTO>> getListOfCars(String groupBy) {
return carRepository.findAll()
.stream()
.map(toCarDTO)
.collect(groupingBy(carColumnMapper.get(groupBy.toUpperCase())));
}
Function<CarDetails, CarDTO> toCarDTO = (carDetails) -> CarDTO
.builder()
.brand(carDetails.getBrand())
.engineCapacity(carDetails.getEngineCapacity())
.mileage(carDetails.getMileage())
.fuel(carDetails.getFuel())
.price(carDetails.getPrice())
.build();
}

Categories