首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >IllegalStateException:无法将'java.sql.Timestamp‘类型的值转换为属性所需的类型'java.time.LocalDateTime’

IllegalStateException:无法将'java.sql.Timestamp‘类型的值转换为属性所需的类型'java.time.LocalDateTime’
EN

Stack Overflow用户
提问于 2018-06-16 19:49:10
回答 2查看 2.4K关注 0票数 1

我正在做一个spring-boot/jpa/ mysql项目。到目前为止,当使用存储库获取/存储对象时,一切都与DateTime对象一起工作。

现在,当我使用Jdbc模板执行自定义sql查询时,出现了这个问题。

代码语言:javascript
复制
org.springframework.beans.ConversionNotSupportedException: Failed to convert property 
  value of type 'java.sql.Timestamp' to required type java.time.LocalDateTime' for 
  property 'from_time': no matching editors or conversion strategy found

其想法是获取与新传入条目重叠的时隙(具有开始时间和持续时间(以分钟为单位))。

为了取回我的对象,我首先使用了一个BeanPropertyMapper,然后切换到一个自定义的NestedRowMapper。我希望得到的冲突时隙如下所示:

代码语言:javascript
复制
{
   id: 1
   comment: "i worked 60minutes"
   from_time: "2018-06-16 13:00"
   duration_minutes: 60
   task: {
      name: "My task"
      ...
   }
}

这是我遇到问题的方法:

代码语言:javascript
复制
public List<TimeSlot> getOverlappingEntries(TimeSlot timeslot) throws SQLException {
        String sql = "SELECT time_slot.comment, time_slot.from_time,"
            + "DATE_ADD(from_time, INTERVAL duration_minutes MINUTE) AS end_time, "
            + " task.name as `task.name`, task.category as `task.category` "
            + " FROM `time_slot` " + " INNER JOIN task on task.id = time_slot.task_id "
            + " WHERE person_id = ? "
            + " HAVING ? < end_time AND DATE_ADD(? ,INTERVAL ? MINUTE) > from_time;";
        PreparedStatementCreator prepared = (con) -> {
            PreparedStatement prep = con.prepareStatement(sql);
            prep.setObject(1, timeslot.person.id);
            prep.setObject(2, timeslot.from_time);
            prep.setObject(3, timeslot.from_time);
            prep.setObject(4, timeslot.durationMinutes);
            logger.info(prep.toString());
            return prep;
        };
        return this.connector.query(prepared, NestedRowMapper.get(TimeSlot.class));
    }

现在我可以想象spring能够很容易地转换这些对象。无论如何,timestamp.toLocalDateTime()有一种简单的方法可以做到这一点。问题似乎更多的是如何将其注册为转换器服务,或者如何修复spring-boot配置来实现这一点。

我已经尝试了一个自定义的转换服务,但没有帮助:

代码语言:javascript
复制
@javax.persistence.Converter
public class SqlTimestampToLocalDateTimeConverter implements Converter<Timestamp, 
        LocalDateTime>, AttributeConverter<Timestamp, LocalDateTime> {

    @Convert
    @Override
    public LocalDateTime convert(Timestamp source) {
        return source.toLocalDateTime();
    }

    @Override
    public LocalDateTime convertToDatabaseColumn(Timestamp attribute) {
        return attribute.toLocalDateTime();
    }

    @Override
    public Timestamp convertToEntityAttribute(LocalDateTime dbData) {
        return Timestamp.valueOf(dbData);
    }
}

此外,互联网上的许多其他答案都提到,spring框架4.x已经实现了这一点。项目中的依赖项如下所示(build.gradle):

代码语言:javascript
复制
dependencies {
    compile "org.springframework.boot:spring-boot-starter-thymeleaf:2.0.2.RELEASE"
    compile "org.springframework.boot:spring-boot-starter-web:2.0.2.RELEASE"
    compile "org.springframework.boot:spring-boot-starter-security:2.0.2.RELEASE"
    compile "org.springframework.boot:spring-boot-starter-data-jpa:2.0.2.RELEASE"
    compile "mysql:mysql-connector-java:5.1.46"
    compileOnly "org.springframework.boot:spring-boot-devtools:2.0.2.RELEASE"
    compile 'org.springframework.data:spring-data-rest-webmvc:3.0.7.RELEASE'
    compile 'com.querydsl:querydsl-jpa:4.1.4'
    compile 'com.querydsl:querydsl-apt:4.1.4:jpa'

    testCompile("junit:junit")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("org.springframework.security:spring-security-test")
}

感谢您的任何提示,如何解决这个问题!

/edit:

我想我现在看到了一个可能的变通方法。我能做的就是获取所有时隙的id,然后使用存储库来获取实际的对象及其数据(还有它们的任务对象)。但这绝对不是最好的解决方案。

这是我使用的NestedRowMapper:

代码语言:javascript
复制
import org.springframework.beans.*;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.JdbcUtils;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class NestedRowMapper<T> implements RowMapper<T> {

    private Class<T> mappedClass;

    public static <T> NestedRowMapper<T> get(Class<T> mappedClass) {
        return new NestedRowMapper<>(mappedClass);
    }

    public NestedRowMapper(Class<T> mappedClass) {
        this.mappedClass = mappedClass;
    }

    @Override
    public T mapRow(ResultSet rs, int rowNum) throws SQLException {
        try {
            T mappedObject = this.mappedClass.newInstance();;
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);

            bw.setAutoGrowNestedPaths(true);

            ResultSetMetaData meta_data = rs.getMetaData();
            int columnCount = meta_data.getColumnCount();

            for (int index = 1; index <= columnCount; index++) {

                try {

                    String column = JdbcUtils.lookupColumnName(meta_data, index);
                    Object value = JdbcUtils.getResultSetValue(rs, index, Class.forName(meta_data
                        .getColumnClassName(index)));

                    bw.setPropertyValue(column, value);

                } catch (TypeMismatchException | NotWritablePropertyException
                    | ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }

            return mappedObject;
        } catch (InstantiationException | IllegalAccessException e1) {
            throw new RuntimeException(e1);
        }
    }
}
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50887647

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档