Перегрузка отражения. Заполнение отраженного массива для отраженного метода varargs

#java #reflection

#java #отражение

Вопрос:

Я участвую в конкурсе на самую большую ошибку всех времен. Мне нужно использовать Spring JDBC, даже не делая ссылки на него. Пользовательский загрузчик классов предоставляет контекст, и мне нужно использовать отражение для вызова методов. Одним из таких методов является SimpleJdbcCall.declareParameters(SqlParameter …)

Моя проблема заключается в создании и настройке переменных SqlParameter (эти экземпляры также должны быть отражены). Мне нужно вставить один параметр в массив, чтобы удовлетворить сигнатуре varargs.

Далее загрузка класса опущена для краткости. Но предположим Class<?> simpleJdbcCallClass = SimpleJdbcCall.class и т.д.

 Constructor sqlOutParameterConstructor =
    sqlOutParameterClass.getConstructor(String.class, int.class);
Object sqlOutParameter = sqlOutParameterConstructor.newInstance(param, type);

Object paramArray = Array.newInstance(sqlParameterArrayClass, 1);
Array.set(paramArray, 0, sqlParameterClass.cast(sqlOutParameter));
// IllegalArgumentException thrown above.
// It is thrown without the call to .cast too.

Method declareParametersMethod = 
    simpleJdbcCallClass.getMethod("declareParameters", sqlParameterArrayClass);
declareParametersMethod.invoke(procedure, paramArray);
  

Генерируемое исключение является:

 java.lang.IllegalArgumentException: array element type mismatch
at java.lang.reflect.Array.set(Native Method)
  

Метод принимает, SqlParameter ... и у меня есть экземпляр подкласса SqlOutParameter . Следовательно, я пытаюсь выполнить приведение с помощью sqlParameterClass.cast(sqlOutParameter) . Исключение генерируется с этим приведением или без него.

При отладке я могу подтвердить, что paramArray это SqlParameter[] и sqlParameterClass.cast(sqlOutParameter) является SqlOutParamter (не SqlParameter как приведенное). Я подозреваю, что это может быть проблемой.

Комментарии:

1. Просто любопытно, но я хотел бы узнать историю, стоящую за этим

2. Несколько месяцев назад я провел крупный рефакторинг, преобразовав использование SQLExecutor в Spring 3 JDBC (чтобы обойти критические условия гонки). Наше приложение находится в среде поставщика, которая объединяет Spring 1. Некоторые подписи в Spring JDBC изменились по сравнению с этими версиями. Это привело к MethodNotFoundExceptions или аналогичному во время выполнения. Пока мы ждем обновления поставщика до Spring 3, я взламываю динамическую загрузку Spring 3 JDBC только для наших DAO. Счастливый, счастливый, радость, радость.

Ответ №1:

Я думаю, что проблема в этой строке:

 Object paramArray = Array.newInstance(sqlParameterArrayClass, 1);
  

В частности, вы не говорите нам, что sqlParameterArrayClass такое, но, основываясь на имени, я предполагаю, что это класс типа array. На самом деле, это должен быть класс элемента массива; newInstance(...) методы см. в javadoc.

Комментарии:

1. Также вызов Class.cast() , вероятно, не нужен, вам не кажется?

2. Да, это была проблема. И приведение было ненужным (это было частью моего устранения неполадок, как описано в вопросе).