Вывод типа, похоже, терпит неудачу. Try vavr работает с функцией jOOQ fetchOne ()

Я использую vavr и jOOQ, две фантастические библиотеки, появившиеся в последнее время, которые позволяют нам использовать функциональные диалекты в обычных серверных приложениях Java.

Я пытаюсь использовать jOOQ, что эквивалентно SQL select count (*).

Запрос формируется так:

 ResultQuery query = dsl.selectCount()
                .from(Tables.SH_PLAYER_REPORT)
                .join(Tables.SH_PLAYERS)
                .on(Tables.SH_PLAYERS.PLAYER_ID.eq(Tables.SH_PLAYER_REPORT.PLAYER_ID))
                .join(Tables.SH_LOCATION)
                .on(Tables.SH_LOCATION.LOCATION_ID.eq(Tables.SH_PLAYERS.LOCATION))
                .and(Tables.SH_PLAYER_REPORT.START_ON.ge(Timestamp.from(fromWhenInUTCInstant)))
                .and(Tables.SH_PLAYER_REPORT.START_ON.le(Timestamp.from(toWhenInUTCInstant)))
                .and(Tables.SH_LOCATION.LOCATION_ID.eq(criteriaAllFieldsTeam.getLocation_id()));

Генератор jOOQ работает отлично, и здесь нет несоответствия типов. Так что, полагаю, запрос сформирован правильно.

Затем я использую Try vavr, таким образом:

Optional<Integer> mayBeCount = Optional.empty();

try (final Connection cn = this.ds.getConnection()) {

    DSLContext dsl = DSL.using(cn, this.dialect);

    Try<Integer> countFromDBAttempted =
               Try
               .of(() -> prepareCountOfGamesPlayedQuery(dsl,criteriaAllFieldsTeam))
               .map(e -> e.fetchOne(0, Integer.class)) // Here's the problem!
               .onFailure(e -> logger.warning(String.format("Count Of Games Played, status=Failed, reason={%s}",e.getMessage())));

           mayBeCount = (countFromDBAttempted.isFailure() ? Optional.empty() : Optional.of(countFromDBAttempted.getOrElse(0)));

  } catch (SQLException ex) {

    logger.warning(
         String.format("DB(jOOQ): Failed, counting games played, using criteria {%s},reason={%s}",criteriaAllFieldsTeam.toString(),ex.getMessage()));
  }

  return (mayBeCount);

Компилятору не удается определить тип поля, несмотря на то, что я помогаю ему, описывая целевой тип: Integer.class!

../ReportByTeamRecordProducerImpl.java:66: error: incompatible types: Try<Object> cannot be converted to Try<Integer>
.onFailure(e -> logger.warning(String.format("Count Of Games Played, status=Failed, reason={%s}",e.getMessage())));
                         ^

Неудивительно, что когда я принуждаю тип, код работает отлично. Я просто ввожу явное приведение в строку, которую компилятор считает .. э-э... неприятным!

Try<Integer> countFromDBAttempted =
   Try
   // The following function returns the ResultQuery shown above
   .of(() -> prepareCountOfGamesPlayedQuery(dsl,criteriaAllFieldsTeam))
   // Casting below, because of some incompatibility between vavr and jOOQ
  .map(e -> ((Integer) e.fetchOne(0, Integer.class)))
  .onFailure(e -> logger.warning(String.format("Count Of Games Played, status=Failed, reason={%s}",e.getMessage())));

Я попробовал несколько других способов, основанных на моем понимании библиотеки jOOQ и особенно этого объяснение от @LukasEder.

Чего я пока не пробовал, так это введения преобразователя, потому что для одного значения поля это кажется ненужным, на мой взгляд! Однако, если это так, то я хотел бы получить подсказку.

В ответ на @LukasEder:

private ResultQuery prepareCountOfGamesPlayedQuery(DSLContext dsl, CriteriaAllFieldsTeam criteriaAllFieldsTeam) {

        Instant fromWhenInUTCInstant =
                convertToDBCompatibleInstantUTC(
                        criteriaAllFieldsTeam.getDate_range().getFromWhen(),
                        criteriaAllFieldsTeam.getDate_range().getInTimeZone());

        Instant toWhenInUTCInstant =
                convertToDBCompatibleInstantUTC(
                        criteriaAllFieldsTeam.getDate_range().getToWhen(),
                        criteriaAllFieldsTeam.getDate_range().getInTimeZone());

        ResultQuery query = dsl.selectCount()
                .from(Tables.SH_PLAYER_REPORT)
                .join(Tables.SH_PLAYERS)
                .on(Tables.SH_PLAYERS.PLAYER_ID.eq(Tables.SH_PLAYER_REPORT.PLAYER_ID))
                .join(Tables.SH_LOCATION)
                .on(Tables.SH_LOCATION.LOCATION_ID.eq(Tables.SH_PLAYERS.LOCATION))
                .and(Tables.SH_PLAYER_REPORT.START_ON.ge(Timestamp.from(fromWhenInUTCInstant)))
                .and(Tables.SH_PLAYER_REPORT.START_ON.le(Timestamp.from(toWhenInUTCInstant)))
                .and(Tables.SH_LOCATION.LOCATION_ID.eq(criteriaAllFieldsTeam.getLocation_id()));

        return (query);
    }

Следуя подталкиванию Лукаса, я изменил метод следующим образом:

private ResultQuery<Record1<Integer>> prepareCountOfGamesPlayedQuery(DSLContext dsl, CriteriaAllFieldsTeam criteriaAllFieldsTeam) {

        Instant fromWhenInUTCInstant =
                convertToDBCompatibleInstantUTC(
                        criteriaAllFieldsTeam.getDate_range().getFromWhen(),
                        criteriaAllFieldsTeam.getDate_range().getInTimeZone());

        Instant toWhenInUTCInstant =
                convertToDBCompatibleInstantUTC(
                        criteriaAllFieldsTeam.getDate_range().getToWhen(),
                        criteriaAllFieldsTeam.getDate_range().getInTimeZone());

        ResultQuery<Record1<Integer>> query = dsl.selectCount()
                .from(Tables.SH_PLAYER_REPORT)
                .join(Tables.SH_PLAYERS)
                .on(Tables.SH_PLAYERS.PLAYER_ID.eq(Tables.SH_PLAYER_REPORT.PLAYER_ID))
                .join(Tables.SH_LOCATION)
                .on(Tables.SH_LOCATION.LOCATION_ID.eq(Tables.SH_PLAYERS.LOCATION))
                .and(Tables.SH_PLAYER_REPORT.START_ON.ge(Timestamp.from(fromWhenInUTCInstant)))
                .and(Tables.SH_PLAYER_REPORT.START_ON.le(Timestamp.from(toWhenInUTCInstant)))
                .and(Tables.SH_LOCATION.LOCATION_ID.eq(criteriaAllFieldsTeam.getLocation_id()));

        return (query);
    }

..и, теперь мир снова воцарился в мире!

Спасибо, Лукас!


person Nirmalya    schedule 13.12.2018    source источник
comment
Не могли бы вы указать нам общедоступный javadoc метода fetchOne, который вы используете?   -  person Nándor Előd Fekete    schedule 13.12.2018
comment
Можете ли вы показать точное определение prepareCountOfGamesPlayedQuery   -  person Lukas Eder    schedule 13.12.2018
comment
@NándorElődFekete, я имел в виду это: jooq.org/javadoc /3.11.x/org/jooq/ResultQuery.html   -  person Nirmalya    schedule 13.12.2018


Ответы (1)


Учитывая код, который вы предоставили до сих пор, и предполагая, что в нем нет опечатки, это, вероятно, вызвано вашей необработанной ссылкой на тип ResultQuery. Вместо этого используйте ResultQuery<?> или ResultQuery<Record1<Integer>>.

Никогда не используйте необработанные типы, если вам это действительно не нужно. А вы, наверное, нет.

person Lukas Eder    schedule 13.12.2018
comment
Лукас, твоя догадка верна. Я использовал необработанную ссылку типа на ResultQuery. По какой-то причине я предположил, что тип будет выведен (может быть, это нездоровое пережиток мира Scala). Для полноты картины я обновил исходный вопрос модифицированным методом. - person Nirmalya; 13.12.2018
comment
@Nirmalya: Что ты обновил? Вы все еще используете необработанный тип. Не используйте необработанный тип. Он путает все дженерики и вывод типов Java с нечестивыми правилами, которые никто не может расшифровать. Просто сделайте так, чтобы ваш метод возвращал ResultQuery<?> (и включал предупреждения компилятора и исправлял все остальные ссылки на необработанные типы) :) - person Lukas Eder; 13.12.2018
comment
Извините, я был немного медленнее, чем вы! Вы должны были ввести эти дополнительные слова! :-/ - person Nirmalya; 13.12.2018
comment
@Nirmalya: Понятно, не беспокойтесь :) Обратите внимание, вам не нужно давать ответ / объяснение в своем вопросе. Достаточно принять правильный ответ здесь, в Stack Overflow. - person Lukas Eder; 13.12.2018
comment
Да, я знаю. Но я подумал, что должен как-то искупить свою глупую ошибку! :-) - person Nirmalya; 13.12.2018