在@DataJpaTest 中启用@Converter

Posted

技术标签:

【中文标题】在@DataJpaTest 中启用@Converter【英文标题】:Enabling @Converter in @DataJpaTest 【发布时间】:2020-11-26 16:20:53 【问题描述】:

我正在尝试通过 JPA 保存 LocalDate。按照本指南:https://thorben-janssen.com/persist-localdate-localdatetime-jpa/ 我实现了一个转换器。

现在这工作正常了。

但是,我有一些使用 @DataJpaTest 注释的 RepositoryTests 应该使用这个转换器。

现在这些都坏了。我得到了一些类似的东西

wrong column type encountered in column [...] in table [...]; found [date (Types#DATE)], but expecting [timestamp (Types#TIMESTAMP)]

这就是我添加该死转换器的确切原因。所以显然转换器没有被拾取并在@DataJpaTest 的上下文中使用。 我该如何改变呢?

问题中的可嵌入类:

@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Embeddable
public class MyEntity 
    @Column
    private LocalDate dateToStore;

转换器:

@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> 
   
    @Override
    public Date convertToDatabaseColumn(LocalDate locDate) 
        return locDate == null ? null : Date.valueOf(locDate);
    

    @Override
    public LocalDate convertToEntityAttribute(Date sqlDate) 
        return sqlDate == null ? null : sqlDate.toLocalDate();
    


我正在使用 Hibernate 5.4.20.Final 使用 Spring Boot 2.3.3 还有 Liquibase,这是变更集:

<changeSet>   
    <addColumn tableName="tableName">
        <column name="DATE_TO_STORE" type="DATE"/>
    </addColumn>
</changeset>

破解测试很简单,就是这样:

@DataJpaTest
class MyRepositoryTest 

    @Autowired
    private MyRepository myRepository;

    @Test
    void save()
        myRepository.save(new MyEntity());
    

提前致谢!

【问题讨论】:

请向我们展示有问题的代码,以及有问题的实体 附带说明一下,您使用的是哪个 Hibernate 版本?最新的 Hibernate 版本对 java.time 类型的支持相当不错,无需自定义转换器 你试过this answer的解决方案吗? 【参考方案1】:

问题是@DataJpaTest 不扫描@Converter 类,这可以在Spring Doc - Testing 中看到

@WebMvcTest 的相关部分(正常工作):

要测试 Spring MVC 控制器是否按预期工作,请使用 @WebMvcTest 注释。 @WebMvcTest 自动配置 Spring MVC 基础设施并将扫描的 bean 限制为 @Controller, @ControllerAdvice、@JsonComponent、转换器、GenericConverter、 过滤器、WebMvcConfigurer 和 HandlerMethodArgumentResolver

@DataJpaTest 在哪里:

您可以使用 @DataJpaTest 注释来测试 JPA 应用程序。经过 默认情况下,它会扫描 @Entity 类并配置 Spring Data JPA 仓库

这可能是 Spring 中的一个错误,因为在我看来,加载转换器应该始终与 JPA 测试相关(类似于 commit)。

我的解决方法是通过向测试添加新的排除过滤器来手动加载测试中的转换器:

@DataJpaTest
@OverrideAutoConfiguration(enabled = true)
@TypeExcludeFilters(DataJpaTypeExcludeFilterWithConverter.class)
class SomeTest 
...

自定义过滤器:

public class DataJpaTypeExcludeFilterWithConverter extends StandardAnnotationCustomizableTypeExcludeFilter<DataJpaTest> 
        private static final Set<Class<?>> DEFAULT_INCLUDES;

        static 
            Set<Class<?>> includes = new LinkedHashSet<>();
            includes.add(Converter.class);
            includes.add(GenericConverter.class);
            try 
                includes.add(Module.class);
            
            catch (Throwable ex) 
                // ignore
            
            DEFAULT_INCLUDES = unmodifiableSet(includes);
        

        protected DataJpaTypeExcludeFilterWithConverter(Class<?> testClass) 
            super(testClass);
        

        @Override
        protected Set<Class<?>> getDefaultIncludes() 
            return DEFAULT_INCLUDES;
        
    

【讨论】:

以上是关于在@DataJpaTest 中启用@Converter的主要内容,如果未能解决你的问题,请参考以下文章

DataJpaTest 无法在单元测试中更新

使用 @DataJpaTest 进行集成测试

SpringBoot 的 DataJpaTest 与 Flyway

如何在使用 DataJpaTest 的 Spring Boot 2.0 测试中访问 H2 控制台

Spring @DataJpaTest 与 JUnit 5

Spring Boot:使用 @DataJpaTest 和 Flyway 设置 Hibernate 命名策略