Issue
I have the following code which builds and works fine under JDK8:
@FunctionalInterface
public interface ThrowingFunction<T, R, E extends Throwable> {
R apply(T t) throws E;
static <T, R, E extends Throwable> Function<T, R> unchecked (ThrowingFunction<T, R, E> function) {
return t -> {
try {
return function.apply(t);
}
catch (Throwable e) {
throw new RuntimeException(e);
}
};
}
}
And:
@Component
public class CronJobDuplicationCheckStrategiesRegistry {
private final Map<String, Set<CronJobDuplicationCheckStrategy>> duplicationStrategies;
CronJobDuplicationCheckStrategiesRegistry(final CronJobsRegistry cronJobsRegistry) {
duplicationStrategies = cronJobsRegistry.get()
.stream()
.collect(Collectors.toMap(
clazz -> clazz.getName(),
ThrowingFunction.unchecked(
clazz -> clazz.getDeclaredConstructor()
.newInstance()
.getDuplicationStrategies())));
}
public Set<CronJobDuplicationCheckStrategy> get(String jobClass) {
return duplicationStrategies.get(jobClass);
}
}
This code fails to compile under JDK11 with the following error:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.3:compile (default-compile) on project cron-api: Compilation failure: Compilation failure:
[ERROR] /java/org/foo/src/main/java/org/foo/jobs/CronJobDuplicationCheckStrategiesRegistry.java:[26,120] unreported exception java.lang.NoSuchMethodException; must be caught or declared to be thrown
[ERROR] /java/org/foo/src/main/java/org/foo/src/main/java/org/foo/cron/jobs/CronJobDuplicationCheckStrategiesRegistry.java:[27,109] unreported exception java.lang.InstantiationException; must be caught or declared to be thrown
Could somebody please explain what it's unhappy about and how to fix it?
Solution
Could somebody please explain what it's unhappy about and how to fix it?
Replace the E
generic type with the actual Throwable
:
@FunctionalInterface
public interface ThrowingFunction<T, R> {
R apply(T t) throws Throwable;
static <T, R> Function<T, R> unchecked(ThrowingFunction<T, R> function) {
return t -> {
try {
return function.apply(t);
} catch (Throwable e) {
throw new RuntimeException(e);
}
};
}
}
... the following code which builds and works fine under JDK8
I believe the issue originates in the catching mechanism that is not somehow compatible with the E
generic type and is related to the statement at JLS 8.1.2. Generic Classes and Type Parameters:
It is a compile-time error if a generic class is a direct or indirect subclass of Throwable (§11.1.1).
This restriction is needed since the catch mechanism of the Java Virtual Machine works only with non-generic classes.
Frankly, it's a guess and I have no idea why is this is reproducible with JDK 11 but not JDK 8 - that's very strange.
I hope I helped you at least fix the issue.
Answered By - Nikolas Charalambidis
Answer Checked By - Timothy Miller (JavaFixing Admin)