Как обнаружить неоднозначные вызовы методов, которые вызовут ClassCastException в Java 8?

Мы в настоящее время находимся в процессе переноса приложения с Java 7 на Java 8. После исправления некоторых проблем с компиляцией я наткнулся на проблему, похожую на следующий вопрос: ClassCast Error: Java 7 vs Java 8 .

Итак, вот пример кода, который показывает проблему:

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 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 } } 

Идея заключалась в том, что мы запустим, что вызывающий абонент знает ожидаемый тип, и это позволит избежать явного приведения ( я не говорю, что это была хорошая идея … ). Во многих случаях вызывающий абонент просто ожидает Object поэтому не было никакого скрытого приведения.

Как указано в вышеприведенном String.valueOf пример String.valueOf отлично работал на Java 7, потому что не было вывода типа, поэтому Object был принят. Теперь в Java 8 компилятор выбирает наиболее специфический тип (здесь char[] ), который вызывает ClastCastException во время выполнения.

Проблема в том, что у нас около 350 вызовов этого метода getVal . Есть ли способ обнаружить перегруженные вызовы методов, которые будут отличаться между Java 7 и Java 8? IE обнаруживает, когда компилятор Java 8 выберет другой метод из компилятора Java 7.

Лучшей альтернативой могло бы стать:

 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 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 } } 

который будет работать как на Java 7, так и на Java 8.

В итоге решение было изменить getVal() чтобы вернуть Object :

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

и добавьте второй метод, который также принимает желаемый class в качестве параметра:

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

затем исправить все проблемы компиляции (когда вызывающий Object не ожидал Object ), добавив соответствующий параметр classа.

Кроме того, было бы добавлено добавление роли, но это вызвало бы много предупреждений о безусловных переводах. Безусловный clazz самом деле по-прежнему существует (через параметр clazz ), но это позволяет легко идентифицировать всех вызывающих абонентов, которым требуется приведение, поскольку они используют метод с двумя параметрами.

Кроме того, и это очень специфично для этого случая – оказалось, что сам param часто являлся результатом вызова метода для некоторого TypedParam где T был ожидаемым типом возвращаемого значения getVal() и который также содержал class T.

Таким образом, я мог бы использовать дополнительный метод удобства:

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

и заменил все getVal(param.stringValue()) просто getVal(param) .

Это решение не разрешает общий случайобнаруживает перегруженные вызовы методов, которые будут отличаться между Java 7 и Java 8, но он разрешает его для методов, которые, как известно, вызывают эту проблему. И с тех пор мы не находили его в другом месте.