Java 使用JDBI插入localdate类型字段时出现问题

Java 使用JDBI插入localdate类型字段时出现问题,java,dropwizard,jdbi,localdate,Java,Dropwizard,Jdbi,Localdate,我目前正在使用JDBI将POJO持久化到数据库中。我正在使用MS SQL Server作为我的数据库。我当前无法在表中插入行,因为映射时LocalDate变量没有值 scoreDate字段是LocalDate类型,是非强制性的,我不会为此字段传递任何值。但是在尝试运行下面的测试时,我得到了下面的错误 请告知问题可能是什么以及如何解决? 测试类 @Test public void testInsertClientScore() throws Exception { fina

我目前正在使用JDBI将POJO持久化到数据库中。我正在使用MS SQL Server作为我的数据库。我当前无法在表中插入行,因为映射时
LocalDate
变量没有值

scoreDate
字段是
LocalDate
类型,是非强制性的,我不会为此字段传递任何值。但是在尝试运行下面的测试时,我得到了下面的错误

请告知问题可能是什么以及如何解决?

测试类

@Test
    public void testInsertClientScore() throws Exception {
        final DBI dbi = databaseResource.getDBI();
        final ClientScoreDao clientScoreDao = dbi.onDemand(ClientScoreDao.class);

        final ClientScore clientScore = ImmutableClientScore.builder()
                .id(1L)
                .ClientName("TESTCLIENT")
                .build();

        assertEquals(1,clientScoreDao.insert(clientScore));

    }
错误跟踪

org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException: com.microsoft.sqlserver.jdbc.SQLServerException: 
Implicit conversion from data type varbinary to date is not allowed. Use the CONVERT function to run this query. [statement:"insert into ICEBERG.ClientScore (scoreId, clientname, scoredate) values (:id, :ClientName, :scoreDate)", located:"insert into ICEBERG.ClientScore (scoreId, clientname, scoredate) values (:id, :ClientName, :scoreDate)", rewritten:"insert into ICEBERG.ClientScore (scoreId, clientname, scoredate) values (?, ?, ?)", arguments:{ positional:{}, named:{ClientName:'TESTCLIENT',id:1,scoreDate:null}, finder:[]}]

    at org.skife.jdbi.v2.SQLStatement.internalExecute(SQLStatement.java:1338)
    at org.skife.jdbi.v2.Update.execute(Update.java:56)
    at org.skife.jdbi.v2.sqlobject.UpdateHandler$2.value(UpdateHandler.java:67)

.....
....

Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Implicit conversion from data type varbinary to date is not allowed. Use the CONVERT function to run this query.
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:217)
数据库表定义

-- ClientScore table
CREATE TABLE ICEBERG.ClientScore (
   ScoreId                 INTEGER                                         NOT NULL,
   ClientName              VARCHAR(50)                                  NOT NULL,
   ScoreDate               DATE                                            NULL,
   CONSTRAINT PK_CLIENTSCORE_TEST PRIMARY KEY (ScoreId)
)
POJO

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.mercuria.dali.jdbi.Jdbi;
import com.mercuria.dali.jdbi.JdbiOptions;
import org.immutables.value.Value;

import javax.annotation.Nullable;
import java.io.Serializable;
import java.time.LocalDate;

@Value.Immutable
@Jdbi(tableName = "ICEBERG.ClientScore")
@JsonSerialize(as = ImmutableClientScore.class)
@JsonDeserialize(as = ImmutableClientScore.class)
public interface ClientScore extends Serializable {

    @JsonProperty("scoreid")
    @JdbiOptions(columnName = "scoreId")
    Long id();

    @JsonProperty("clientname")
    @JdbiOptions(columnName = "clientname")
    String ClientName();

    @JsonProperty("scoredate")
/*    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)*/
    @JdbiOptions(columnName = "scoredate")
    @Nullable
    LocalDate scoreDate();  
}
在配置JDBI连接时,我为
LocalDate
数据类型设置了映射器。

 public static void configureDbi(DBI dbi) {
        // Register argument factories
        dbi.registerArgumentFactory(new NullDoubleArgumentFactory());
        dbi.registerArgumentFactory(new UuidArgumentFactory());
        dbi.registerArgumentFactory(new LocalDateArgumentFactory());
        dbi.registerArgumentFactory(new InstantArgumentFactory(Optional.of(TimeZone.getTimeZone("UTC"))));
        dbi.registerColumnMapper(new InstantMapper(Optional.of(TimeZone.getTimeZone("UTC"))));

        dbi.registerArgumentFactory(new OptionalArgumentFactory("com.microsoft.sqlserver.jdbc.SQLServerDriver"));
        dbi.registerArgumentFactory(new OptionalIntArgumentFactory());
        dbi.registerArgumentFactory(new OptionalDoubleArgumentFactory());

        // Register column mappers
        dbi.registerColumnMapper(new UuidColumnMapper());
        dbi.registerColumnMapper(new LocalDateMapper());
    }

我也遇到了他的问题,发现Dropwizard LocalDateArgumentFactory类决定是否创建参数类来处理该值的方式是使用instanceof check:

public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
    return value instanceof LocalDate;
}
public boolean接受(类expectedType、对象值、语句上下文ctx){
返回值instanceof LocalDate;
}
由于值为null,因此返回false,我通过创建以下内容解决了此问题:

public class NullAwareLocalDateArgumentFactory extends LocalDateArgumentFactory {
    @Override
    public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
        if(value == null){
            //Look at the expected type. Tbh. not sure why it isn't simply doing this by default ...
            return LocalDate.class.isAssignableFrom(expectedType);
        }
        else {
            return super.accepts(expectedType, value, ctx);
        }
    }
}
公共类NullAwareLocalDateArgumentFactory扩展了LocalDateArgumentFactory{
@凌驾
公共布尔接受(类expectedType、对象值、语句上下文ctx){
如果(值==null){
//查看预期的type.Tbh。不确定它为什么不只是默认执行此操作。。。
返回LocalDate.class.isAssignableFrom(expectedType);
}
否则{
返回super.accepts(expectedType、value、ctx);
}
}
}