How to detect ambiguous method calls that would cause a ClassCastException in Java 8?

限于喜欢 提交于 2019-12-21 07:39:07

问题


We are currently in the process of migrating an application from Java 7 to Java 8. After fixing a some compilation issues, I stumbled upon an issue similar to the following question: ClassCast Error: Java 7 vs Java 8.

To summarise, here is a sample code that shows the issue:

public class Test {
    public static void main(String[] args) {
        System.out.println(String.valueOf(getVal("xxx"))); // 7: prints the result, 8: Exception 
    }

    @SuppressWarnings("unchecked")
    public static <T> T getVal(String param) {
        // do some computation based on param...
        return (T) result; // actual return type only depends on param so the caller knows what to expect
    }
}

The idea was that we would thrust that the caller knows the expected type, and this would avoid him an explicit cast (I don't say this was a good idea…). In a lot of cases, the caller just expects an Object so there was no implicit cast at all.

As stated in the question above, the String.valueOf example worked fine in Java 7 because there was no type inference, hence Object was assumed. Now in Java 8, the compiler chooses the most specific type (here char[]), which causes a ClastCastException at runtime.

The problem is that we have around 350 calls of this getVal method. Is there a way to detect overloaded method calls that would differ between Java 7 and Java 8? I.E. detect when the Java 8 compiler would select a different method from the Java 7 compiler.


回答1:


A better alternative would be:

public class Test {
    public static void main(String[] args) {
        System.out.println(String.valueOf(getVal("xxx"))); // 7: prints the result, 8: Exception
    }

    @SuppressWarnings("unchecked")
    public static <T> T getVal(T param) {
        // do some computation based on param...
        return   param; // actual return type only depends on param so the caller knows what to expect
    }
}

which will work in both Java 7 and Java 8.




回答2:


In the end the solution was to change getVal() to return Object:

    public static Object getVal(String param) {
        // do some computation based on param...
        return result;
    }

and add a second method that also takes the desired class as parameter:

    public static <T> T getVal(String param, Class<T> clazz) {
        return clazz.cast(getVal(param));
    }

then fix all compilation issues (where caller didn't expect Object) by adding the appropriate class parameter.

Adding a cast would have also worked but it would have caused a lot of warnings for unconditional casts. The unconditional cast is actually still there (through the clazz parameter), but this allows to easily identify all callers that need a cast as they use the method with 2 parameters.

Additionally – and this is very specific to this case – it appeared that the param itself was often the result of a method call on some TypedParam<T> where T was the expected return type of getVal(), and which also contained T's class.

I could thus implement an additional convenience method:

    public static <T> T getVal(TypedParam<T> param) {
        return getVal(param.stringValue(), param.getValueClass());
    }

and replaced all getVal(param.stringValue()) by just getVal(param).

This solution does not resolve the general casedetect overloaded method calls that would differ between Java 7 and Java 8 – but it resolves it for methods that are known to cause this problem. And we didn't find it elsewhere since then.



来源:https://stackoverflow.com/questions/30517768/how-to-detect-ambiguous-method-calls-that-would-cause-a-classcastexception-in-ja

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!