Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird java.lang.InstantiationException and java.lang.NoSuchMethodException after upgrading from JDK8 to JDK11

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?

like image 808
carlspring Avatar asked Oct 16 '22 03:10

carlspring


1 Answers

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.

like image 188
Nikolas Charalambidis Avatar answered Oct 22 '22 11:10

Nikolas Charalambidis