Reordering two type parameter constraints causes a Java runtime error

The following code fails at runtime, but if you change this line to Model & Serializablebecome Serializable & Model, then it works fine. Can anyone explain what is happening? Is this a bug in Java? It doesn't seem like the order of type restrictions should matter.

import java.io.Serializable;

interface Model {
    void foo();
}

class ModelA implements Model, Serializable {
    public void foo() {

    }
}

class MemcachedHelper<T extends Serializable> {
    T getCached(String key, Maker<T> make) {
        return make.get();
    }
    interface Maker<U extends Serializable> {
        U get();
    }
}

class Query {
    Object getResult() {
        return new ModelA();
    }
}
public class Main {

    // private static <T extends Serializable & Model>
    private static <T extends Model & Serializable>
    T getModel(Class<T> modelClass, MemcachedHelper<T> cache) {
        String key = "key:" + modelClass.getSimpleName();
        T thing = cache.getCached(key, () -> {
            Query q = new Query();
            return (T)q.getResult();
        });
        return thing;
    }

    public static void main(String[] args) {
        MemcachedHelper<ModelA> cache = new MemcachedHelper<>();
        Model thing = getModel(ModelA.class, cache);
        System.out.printf("Got thing: %s\n", thing);
    }

}

Runtime Error:

Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
  at java.lang.invoke.CallSite.makeSite(CallSite.java:341)
  at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
  at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
  at Main.getModel(Main.java:33)
  at Main.main(Main.java:42)
  ...  
Caused by: java.lang.invoke.LambdaConversionException: Type mismatch for lambda expected return: interface Model is not convertible to interface java.io.Serializable
  at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:286)
  at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
  at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
  ... 9 more

This is JDK version 1.8.0_101.

+4
source share
1 answer

There is an angular register in which the order of type constraints is specified. The raw method signature of a generic method or a method related to type variables is determined by an evaluation of the first type.

, T getModel <T extends Model & Serializable>, Model, <T extends Serializable & Model>, Serializable.

<T extends Object & Serializable & Model>, Object.

-, javac , , T. , Maker<U extends Serializable> () -> U, () -> Serializable. , getModel s T, , Object Model, , , Serializable.

, , Maker interface Maker<U extends Object & Serializable>, Object, T s .

, , . , , , , . . , . , ​​ , .

+4

Source: https://habr.com/ru/post/1663855/


All Articles