Search code examples
jdbi

how to combine Jdbi @GeneratedKeys with @RegisterMapper


@RegisterMapper(PhoneNumberMapper.class)
public interface PhoneNumberJdbiDAO
{
    @Transaction
    @GetGeneratedKeys(columnName = "ID", value = OracleGeneratedKeyMapper.class)
    @SqlUpdate("INSERT INTO PHONE_NUMBER (ID, COUNTRY_CODE_ISO2, PHONE_NUMBER, CREATE_DATETIME, UPDATE_DATETIME) " +
           "VALUES (PHONE_NUMBER_SEQ.NEXTVAL, :countryCode, :phoneNumber, :createDateTime, :updateDateTime)")
    PhoneNumber save(@BindBean PhoneNumber phoneNumber);
}

Can the OracleGeneratedKeyMapper.class and PhoneNumberMapper.class co-exist to return the mapped bean? When I execute this, java.lang.ClassCastException: java.math.BigDecimal cannot be cast to me.nave.persistence.domain.PhoneNumber is being thrown.

The intent is to return a bean with the generated ID.

The PhoneNumberMapper

public class PhoneNumberMapper implements org.skife.jdbi.v2.tweak.ResultSetMapper<PhoneNumber>
{
    @Override
    public PhoneNumber map(int index, ResultSet rs, StatementContext ctx) throws SQLException
    {
        CountryCode countryCodeIso2 = CountryCode.getByCodeIgnoreCase(rs.getString("COUNTRY_CODE_ISO2"));

        DateTime phoneNumberCreateDatetime =
            new DateTime(rs.getTimestamp("CREATE_DATETIME").getTime(), DateTimeZone.UTC);

        DateTime phoneNumberUpdateDatetime =
            new DateTime(rs.getTimestamp("UPDATE_DATETIME").getTime(), DateTimeZone.UTC);

        return new PhoneNumber
            .Builder(countryCodeIso2, rs.getString("PHONE_NUMBER"))
            .id(rs.getBigDecimal("ID"))
            .createDateTime(phoneNumberCreateDatetime)
            .updateDateTime(phoneNumberUpdateDatetime)
            .build();
    }
}

Here is the OracleGeneratedKeyMapper.

public class OracleGeneratedKeyMapper implements org.skife.jdbi.v2.tweak.ResultSetMapper<BigDecimal>
{
    @Override
    public BigDecimal map(int index, ResultSet r, StatementContext ctx) throws SQLException
    {
        return r.getBigDecimal(1);
    }
}

The table and Sequences

CREATE SEQUENCE  "PHONE_NUMBER_SEQ"  MINVALUE 1 INCREMENT BY 1;

CREATE TABLE "TEST"."PHONE_NUMBER"
(     "ID" NUMBER NOT NULL,
      "COUNTRY_CODE_ISO2" VARCHAR2(2 CHAR) NOT NULL,
      "PHONE_NUMBER" VARCHAR2(32 CHAR) NOT NULL,
      "CREATE_DATETIME" TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP(0) NOT NULL,
      "UPDATE_DATETIME" TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP(0) NOT NULL,
  CONSTRAINT "PHONE_NUMBER_PK" PRIMARY KEY ("ID")
);

Solution

  • @Mapper and @RegisterMapper is not used while getting inserted id back. If you want PhoneNumber object (with id alone) to be returned after insert, You can use following mapper.

    public class PhoneNumberIdMapper implements org.skife.jdbi.v2.tweak.ResultSetMapper<BigDecimal>
    {
      @Override
      public BigDecimal map(int index, ResultSet r, StatementContext ctx) throws SQLException
      {
        return new PhoneNumber(r.getBigDecimal(1));
      }
    }
    

    But if you are looking to get the whole PhoneNumber object, we need to do it manually. I could think of two options,

    public abstract PhoneNumber savePhoneNumber(PhoneNumber phoneNumber) {
        BigDecimal id = save(phoneNumber);
        phoneNumber.setId(id)
    }
    

    Or read it from DB again.

    public abstract PhoneNumber savePhoneNumber(PhoneNumber phoneNumber) {
        BigDecimal id = save(phoneNumber);
        getPhoneNumber(id); // reading it from DB
    }