SimpleJdbcCall не преобразовывает ответ в массив. Кидает ClassCastException

java.lang.ClassCastException: 
class [Ljava.lang.Object; cannot be cast to class 
[Lru.yota.finservices.rs.db.model.MonthAvgServiceData; 
([Ljava.lang.Object; is in module java.base of loader 'bootstrap'; 
[Lru.yota.finservices.rs.db.model.MonthAvgServiceData; is in unnamed module of loader 'app')

текст ошибки такой.

метод вызова хранимой процедуры.

SimpleJdbcCall call = new SimpleJdbcCall(template)
                .withCatalogName(CATALOG_NAME)
                .withFunctionName("getMonthAVGServiceRegistryData")
                .declareParameters(monthAvgServiceData());
        SqlParameterSource source = new MapSqlParameterSource()
                .addValue("p_date", date, Types.DATE)
                .addValue("p_Service_id", serviceId, Types.BIGINT);
        List<MonthAvgServiceData> monthAvgServiceData = Arrays.asList(call.executeFunction(MonthAvgServiceData[].class, source));  // тут ошибка.

метод .declareParameters(monthAvgServiceData());

private SqlOutParameter monthAvgServiceData() {
        return new SqlOutParameter("return",
                OracleTypes.ARRAY,
                "T_MONTH_AVG_SERVICE_DATA_LIST",
                new SqlReturnStructArray<>(RecursiveBeanPropertyStructArrayMapper.newInstance(MonthAvgServiceData.class))
        );
    }

из самой хранимой процедуры данные возвращаются в виде Object. скриншот.

введите сюда описание изображения

но при попытке преобразовать в массив падает с ошибкой.


Ответы (1 шт):

Автор решения: Темка тоже

Тут скорее всего тебя подводит неявный синтаксический сахар от Java. Если посмотреть внутрь реализации SimpleJdbcCall#executeFunction, то можно увидеть следующее:

SimpleJdbcCall#executeFunction

Т.е. первый параметр сам по себе не используется, а нужен как синтаксический сахар. Возможно твой компилятор заменяет

List<MonthAvgServiceData> monthAvgServiceData = Arrays.asList(call.executeFunction(MonthAvgServiceData[].class, source));

на

List<MonthAvgServiceData> monthAvgServiceData = Arrays.asList((MonthAvgServiceData[])call.executeFunction(MonthAvgServiceData[].class, source));

Потому ошибка и падает.

Почему возвращается Object[], а не MonthAvgServiceData[]. Если заглянуть в реализацию SqlReturnStructArray, то можно увидеть такого рода конструкцию

введите сюда описание изображения

А метод List#toArray() возвращает нетипизованный массив, в отличии от своего собрата позицией ниже. введите сюда описание изображения

Наглядно это проблема может быть показана таким падающим тестом:

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

public class GenericTest {

    @Test
    void test() {
        Object[] arr = new Object[]{"bla", "asd"};
        List<String> list = Arrays.asList((String[]) executeFunction(String[].class, arr));
    }

    public <T> T executeFunction(Class<T> returnType, Object bla) {
        return (T) bla;
    }

}

Результат теста:

введите сюда описание изображения

Попробуй небольшую хитрость вида:

List tmp = Arrays.asList((Object[])call.executeFunction(Object[].class, source));
List<MonthAvgServiceData> monthAvgServiceData = (List<MonthAvgServiceData>) tmp;
→ Ссылка