Java: Calling a method by reflection in a functional interface - java

does anyone know, if i can invoke a method by reflection in the body of a functional interface?
I want to return a predicate. So the typical syntax would be for example
Predicate<Data> pred = data -> data.getVar1().equals("foobar");
But in my special case neither the class nor the method to call is known since it's variable.
So I wanted to get something like this:
Method method = Class.forName("Data").getMethod("getVar1", (Class[]) null);
Predicate<T> pred = data ->
((String) method.invoke(data, (Object[]) null)).equals("foobar");
But Eclipse says: "Not handled TargetInvocationException". So I surrounded it with try-catch, but Eclipse shows already the same message.
Does anyone have a clue for me?

Try this:
Predicate<T> pred = data -> {
try {
return ((String) method.invoke(data, (Object[]) null)).equals("foobar");
} catch (IllegalAccessException illegalAccessException) {
//
} catch (IllegalArgumentException illegalArgumentException) {
//
} catch (InvocationTargetException invocationTargetException) {
//
}
return false;
};

Related

Bad return type in method reference: Cannot convert Employee to Optional<U>

I am trying to write a lambda function that gets employee location preference and have the code sample below.
But for my lambda function I get a compilation error at flatMap(this::buildEmployeeGeolocation)
saying Bad return type in method reference: cannot convert com.abc.EmployeeGeolocation to java.util.Optional<U>.
What am I missing here?
public Optional<EmployeeGeolocation> getEmployee(final SessionId sessionId) {
return Optional.ofNullable(employeePreferencesStore.getEmployeeAccountPreferences(sessionId))
.map(preferences -> preferences.getPreference(PreferenceKey.Location))
.filter(StringUtils::isNotBlank)
.map(this::readEmployeelocation)
.flatMap(this::buildEmployeeGeolocation);
}
private Optional<EncryptedGeolocation> readEmployeeLocation(#NonNull final String encryptedGeolocation) {
try {
return Optional.ofNullable(objectMapper.readValue(encryptedGeolocation, EmployeeGeolocation.class));
} catch (final IOException e) {
log.error("Error while reading the encrypted geolocation");
throw new RuntimeException(e);
}
}
private EmployeeGeolocation buildEmployeeGeolocation(#NonNull final EncryptedGeolocation unditheredEncryptedGeolocation) {
return EmployeeGeolocation.builder()
.latitude(10.0)
.longitude(10.0)
.accuracy(1.0)
.locationType(ADDRESS)
.build();
}
It seems like what you really need to do is swap the map and flatMap. Change the code
.map(this::readEmployeeLocation)
.flatMap(this::buildEmployeeGeolocation);
to
.flatMap(this::readEmployeeLocation) // since you already have an Optional<String>
.map(this::buildEmployeeGeolocation); // above results in Optional<EncryptedGeolocation>
Important: Inferred from the code Optional.ofNullable(...).map(...).filter(StringUtils::isNotBlank), that it would result in an Optional<String> until this operation.

Java 8 generic Retry if specific exception

I'm finding myself writing alot of retry loops that look like
int triesRemaining = 3;
while (triesRemaining > 0) {
try {
<MY FUNCTION CALL>
LOGGER.info("success");
break;
} catch (Exception e) {
if (e.getCause() instanceof SocketTimeoutException) {
triesRemaining--;
LOGGER.info(e.getMessage() + " trying again. Tries Remaining: " + triesRemaining);
} else {
LOGGER.error(e.getMessage(), e);
return;
}
}
}
if (triesRemaining == 0) {
LOGGER.error("Failed over too many times");
}
I want to write a generic function that accepts a Lambda and only retries on a specific error (in the above case thats SocketTimeoutException). I've seen some functions that accept a Runnable which is fine, but they don't seem to allow limiting to specific exceptions.
Any advice?
Well it's already done. It also accepts list of exceptions on which you want to retry. It also provides linear/exponential retry strategies.
Have a look https://github.com/rholder/guava-retrying
A simple example from it's readme, you can compose and use a retryer like:-
Callable<Boolean> callable = new Callable<Boolean>() {
public Boolean call() throws Exception {
return true; // do something useful here
}};
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfResult(Predicates.<Boolean>isNull())
.retryIfExceptionOfType(IOException.class)
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.build();
try {
retryer.call(callable);
} catch (RetryException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Have a look to org.springframework.retry
There is an annotation #Retryable which corresponding to your need. You can specify the type of exception to retry and configure the number of attempt, etc...
Check out Failsafe:
RetryPolicy retryPolicy = new RetryPolicy()
.retryOn(SocketTimeoutException.class)
.withMaxRetries(3);
Failsafe.with(retryPolicy)
.onRetry((c, f, ctx) -> log.warn("Failure #{}. Retrying.", ctx.getExecutions()))
.onFailure(e -> LOGGER.error(e.getMessage(), e))
.run(() -> myFunctionCall());
What's the problem of just making this function to accept a Runnable argument and then run it in <MY FUNCTION CALL>?
public static void retry(Runnable r) {
// ...
while (triesRemaining > 0) {
try {
r.run();
LOGGER.info("success");
break;
}
// ...
}
then call it (if you prefer - with a lambda):
retry(() -> {
connectToServer();
// todo what-ever-you-want
});
I believe you're looking for pure Java based solution. Based on assumption, I would say Java 8 uses functional interface, an interface with single abstract method. I would create a new RetryCommand class that has a run method which takes in a function.

Method wrapper for dealing with Exceptions?

I'm implementing an Iterator and in order to deal with the Exceptions I'm using the following pattern: The actual work is done in the private hasNextPriv() method whereas the hasNext() method deals with the Exceptions. The reason for doing it this way is because I don't want to litter hasNextPriv() with try-catch blocks.
#Override
public boolean hasNext()
{
try {
return hasNextPriv();
} catch (XMLStreamException e) {
e.printStackTrace();
try {
reader.close();
} catch (XMLStreamException e1) {
e1.printStackTrace();
}
}
return false;
}
Questions:
Is there a better way to do this?
What would be a good name for the private method hasNextPriv()?
Another way to handle exceptions would be to extract each part that throws exception in a small pure function that properly handles each exception. And then construct final result composing those functions.
Optional<Resource> open() {
try{
//...
return Optional.of(resource);
} catch {
//....
return Optional.empty();
}
}
Optional<Value> read(Resource resource) {
try{
//...
return Optional.of(resource.value);
} catch {
//....
return Optional.empty();
}
}
boolean hasNext() {
open().flatMap(this::read).isPresent();
}
There is no need to return Optional everywhere. Usually there is some dummy value like in Null Object Pattern
Another pattern is to wrap a function execution in object that produces either result or error value. In library javaslang it looks like
return Try.of(this::hasNextPriv)
.recover(x -> Match(x).of(
Case(instanceOf(Exception_1.class), /*handle exception*/),
Case(instanceOf(Exception_2.class), ...)))
.getOrElse(false);
Try object is similar to java 8 Optional but instead of holding present value or missing value Try contains value of either success or failure.
Regarding naming hasNextPriv in your case there is specific domain of data structure. Probably you could come up with more specific name like hasMoreNodes or notEmpty etc.

GWT work-around for missing Class.isInstance()

I'm trying to write a job scheduling system in GWT that maintains an array of exceptions (Class<? extends Exception>[] exceptions), that might be resolved by retrying the job. For this, if the scheduler catches an exception, I need to see if this exception matches one of the classes in the array. So, I would like to have a function like this:
boolean offerRetry(Exception exception) {
for (Class<? extends Exception> e: exceptions)
if (e.isInstance(exception)) return true;
return false;
}
Unfortunately Class.isInstance(...) isn't available in GWT.
Is there a good work-around for this? My current best guess is something like this:
public static boolean isInstance(Class<?> clazz, Object o) {
if ((clazz==null) || (o==null)) return false;
if (clazz.isInterface()) throw new UnsupportedOperationException();
Class<?> oClazz = o.getClass();
while (oClazz!=null) {
if (oClazz.equals(clazz)) return true;
oClazz = oClazz.getSuperclass();
}
return false;
}
Unfortunately, this approach does not support testing against interfaces, and I don't have any idea how to fix that either as Class.getInterfaces() is also not available. But would this approach at least work the same way as Java's Class.isInstance in all other cases, excluding interfaces? Specifically, if I look at GWT's source for Class.java, the getSuperclass() method contains a check of isClassMetadataEnabled(), which might return false (but I don't know in which cases), as it contains a comment saying "This body may be replaced by the compiler".
Or is there a better way entirely to do this?
I use following code:
public static <T> boolean isInstanceOf(Class<T> type, Object object) {
try {
T objectAsType = (T) object;
} catch (ClassCastException exception) {
return false;
}
return true;
}
Maybe something like this would help:
boolean offerRetry(Exception exception) {
try{
throw exception;
} catch (SpecException se) {
return true;
} catch (SpecException1 se1) {
return true;
...
} catch (Exception e) {
return false;
}
}
It depends on how you construct the array of exceptions. If the java 7 stuff works properly then you could put all exceptions in one catch:
boolean offerRetry(Exception exception) {
try{
throw exception;
} catch (SpecException | SpecException1 | ... se) {
return true;
} catch (Exception e) {
return false;
}
}

Event handling with Java Reflection

Ok so, this is quite confusing to explain. I will try my best.
Inspired by the Bukkit Event System where you can make voids an event handler by just using #EventHandler.
Example:
#EventHandler
public void aRandomName(PlayerMoveEvent ev) {
}
As you can see, the name of the method doesn't matter. Which event is passed on is determined by the event argument type.
All events extend the Event class.
I have made up some code which I think would work, except for one thing.
public List<Object> eventContainers;
public void fireEvent(Event e) {
Method[] methods;
for (Object o : eventContainers) {
Object[] classes = o.getClass().getClasses();
for (Object clss : classes) {
methods = clss.getClass().getMethods();
for (Method m : methods) {
if (m.getAnnotation(EventHandler.class) != null) {
try {
Class[] requiredTypes = m.getParameterTypes();
for(Class cl : requiredTypes) {
if(e.equals(cl)) {
m.invoke(clss, e);
}
}
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException ex) {
} catch (InvocationTargetException ex) {
}
}
}
}
}
}
What my code does:
Loops through all the classes in eventContainers, looks for methods that have the #EventHandler annotation and sends the specified event to that method. However, I want to see what kind of event the given event in fireEvent(Event e) is, and then look at the methods who require an event parameter of that kind. How would I do that? I figure that
Class[] requiredTypes = m.getParameterTypes();
for(Class cl : requiredTypes) {
if(e.equals(cl)) {
m.invoke(clss, e);
}
}
will not work.
Ultimately I want to be able to pass on events to plugins. Like this:
EventManager.fireEvent(new PlayerMoveEvent(player));
Which will be sent to all plugins and the plugins that have
#EventHandler
public void aVoid(PlayerMoveEvent e) {
//stuff
}
If you have any questions, I will try to explain it better. Thanks in advance for your help!
Your code uses e.equals(cl), which is comparing an instance of Event with an instance of Class (the class of an instance of Event) - this will never return true. What you want to do instead is:
if(e.getClass().equals(cl)) {
m.invoke(clss, e);
}
Alternatively, if you want methods annotated with #EventHandler to handle all subclasses of the class that their method signature defines (i.e. a method like handle(Event e) would be called with PlayerMoveEvents as well as all other events), then you want:
if(cl.isAssignableFrom(e.getClass())) {
m.invoke(clss, e);
}
See the Class Javadoc here for more information.
Note that I think there are a few other problems in you code. For example, Method.invoke should be called with an instance of the class that contains a method that is annotated with #EventHandler. It is a little unclear from your code, but I believe this should therefore be:
m.invoke(o, e);
Also, by calling o.getClass().getClasses(), you are iterating over the classes defined in the class of o - you probably want to iterate over the methods of the class of o directly, i.e.:
for (Method m : o.getClass().getMethods()) {
if (m.getAnnotation(EventHandler.class) != null) {
Class[] requiredTypes = m.getParameterTypes();
if (requiredTypes.length == 1 && requiredTypes[0].isAssignableFrom(e.getClass()) {
m.invoke(o, e);
}
}
}
You can get the parameter types from a Method using method.getGenericParameterTypes(), so:
m.invoke(clss, m.getGenericParameterTypes()[0].class.cast(e));
Not sure if that's what you want.
Assuming the EventHandler annotated method only has one parameter
Method[] methods = YourClass.class.getDeclaredMethods();
Object yourInstance = null; // get it
Event e = null; // get it
for (Method method : methods) {
EventHandler handler = method.getAnnotation(EventHandler.class);
if (handler != null) {
Class<?>[] parameterTypes = method.getParameterTypes();
// you're going to need different logic if you have more than one parameter
if (parameterTypes.length == 1 && parameterTypes[0].isAssignableFrom(e.getClass())) {
method.invoke(yourInstance, e);
}
}
}
I've not included any exception handling.
Get all the methods of event handler candidate classes and iterate over them. If a method has the #EventHandler annotation, get its parameter type list. If it only has one parameter and that type is assignable from your event type e.getClass(), then invoke it passing in your event.
I have now modified the code to a working event system!!!!!! :D thanks so much andersschuller!
public void fireEvent(Event e) {
Method[] methods;
for (Object o : eventContainers) {
methods = o.getClass().getMethods();
for (Method m : methods) {
if (m.getAnnotation(EventHandler.class) != null) {
try {
if (m.getParameterTypes()[0].isAssignableFrom(e.getClass())) {
m.invoke(o, e);
}
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException ex) {
} catch (InvocationTargetException ex) {
}
}
}
}
}
I kept all answers in mind, thanks all!

Categories

Resources