I have a function that goes through a list of HappyObjects and sets their fields asynchronously. In the Callable, a JsonProcessingException can occur. I have to wrap this and other exceptions from this function into a custom exception (ControllerException) and throw that instead.
Other Stack Overflow posts seem to suggest collect into a List of Futures and use get() to catch the exceptions. Thus, this is what I have so far:
default List<HappyObj> fillfunction(final List<HappyObj> happyObjs) throws ControllerException {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
List<Future<HappyObj>> futures = new ArrayList<>();
for (HappyObj happyObj : happyObjs) {
Future<HappyObj> future = executor.submit(
() -> {
final List<Mood> moods = getMoods();
for (Mood mood : moods) {
final String json = getJsonEmotion();
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
List<Emotion> emotions =
mapper.readValue(json, new TypeReference<List<Emotion>>() {}); //JsonProcessingException can occur here
MoodMetadata metadata = mood.getMoodMetadata();
if (metadata != null && metadata.getEmotionMetadata() != null) {
metadata.getEmotionMetadata().setEmotions(emotions);
}
}
happyObj.setMoods(moods);
return happyObj;
});
futures.add(future);
}
executor.shutdown();
final long maxSlaSec = 1;
try {
executor.awaitTermination(maxSlaSec, TimeUnit.SECONDS);
List<HappyObj> happyResult = new ArrayList<>();
for (Future<HappyObj> future : futures) {
happyResult.add(future.get());
}
return happyResult;
} catch (InterruptedException | ExecutionException e) {
executor.shutdownNow();
throw new ControllerException(e);
}
}
Is there a more elegant way than iterating through List<Future>
and calling get on each to catch ExecutorException? I thought about using execute() vs. submit(), but then I can't handle the JsonProcessingException. I saw another post suggesting creating a ThreadPoolExecutor subclass and override the afterExecute(), but I wasn't able to handle the JsonProcessingException.
One of the reasons I asked this question is because since this method consists mainly of setters, the function was originally manipulating the given objects and returning void.
According to the docs of ExecutionException
(and also the docs of Future#get
), it already has wrapped that information. That is, you can use its getCause
to inspect the Exception
thrown by the Callable
's body.
Notice that Callable#call
itself throws an Exception
... When you throw an Exception
from the Callable
, it will be wrapped into an ExecutionException
which will be thrown from the Future#get
method, for each Callable
, meaning that you can change your loop to catch an ExecutionException
for each Future
and inspect its getCause
!
So you don't actually need to wrap it to a custom ControllerException
.
The Callable
s you create, can still return null
of type Void
for example, without needing to do anything about them.
Unless the scenario changes, then you don't need to extend ThreadPoolExecutor
in this case. You don't even have to cast to ThreadPoolExecutor
, because the ExecutorService
interface already has the submit
s you need. Just throw whatever Exception
you need from the Callable
(such as JsonProcessingException
that you mentioned) when something goes wrong in the Callable
, and then inspect the ExecutionException
from each Future#get
method to tell if an JsonProcessingException
was thrown (and you can also determine in which one it was thrown, if you need).
Is there a more elegant way than iterating through List and calling get on each to catch ExecutorException?
In my opinion, no, there is not, because you want to submit all Callable
s first, then let them run in parallel, and at the end inspect their ExecutionException
for any Exception
thrown by the Callable
s' body for each Callable
(via Future#get
of the returned Future
by submit
).