【问题标题】:spring data jpa - Custom type conversion in interface-based projectionspring data jpa - 基于接口的投影中的自定义类型转换
【发布时间】:2020-02-13 11:07:57
【问题描述】:

我正在尝试实现Interface-based Projection,但无法使其与我的自定义类型列一起使用。

下面是我正在尝试做的示例:

存储库:

@Query(value = "SELECT customType from TABLE", nativeQuery = true)
List<TestClass> getResults();

界面投影:

public interface TestClass {
  @Convert(converter = MyCustomTypeConverter.class)
  MyCustomType getCustomType();
}

转换器:

@Converter
public class MyCustomTypeConverter implements Converter<String, MyCustomType> {

      @Override
      public MyCustomType convert(String source) {
        // whatever
      }
}

当我在存储库上调用 getResults() 时,我收到了预期的结果列表,但是当我尝试在其中一个结果上调用 getCustomType() 时,我得到了异常:

java.lang.IllegalArgumentException: Projection type must be an interface!
at org.springframework.util.Assert.isTrue(Assert.java:118)
at org.springframework.data.projection.ProxyProjectionFactory.createProjection(ProxyProjectionFactory.java:100)
at org.springframework.data.projection.SpelAwareProxyProjectionFactory.createProjection(SpelAwareProxyProjectionFactory.java:45)
at org.springframework.data.projection.ProjectingMethodInterceptor.getProjection(ProjectingMethodInterceptor.java:131)
at org.springframework.data.projection.ProjectingMethodInterceptor.invoke(ProjectingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.ProxyProjectionFactory$TargetAwareMethodInterceptor.invoke(ProxyProjectionFactory.java:245)

我发现问题出在

org.springframework.data.projection.ProxyProjectionFactory

使用

org.springframework.core.convert.support.DefaultConversionService

这显然没有注册我的自定义类型转换器。

如果我在 ConversionService 中的断点处停止并在运行时手动添加我的转换器,投影将毫无问题地工作。

所以问题是:我可以以某种方式将我的自定义转换器注册到 spring jpa 在基于接口的投影期间使用的 ConversionService 吗?

编辑:

我在 InitializingBean 中将我的转换器添加到 DefaultConversionService 的 sharedInstance 中,如下所示,它起作用了。

@Component
public class DefaultConversionServiceInitializer implements InitializingBean {

    @Override
    public void afterPropertiesSet() {
        DefaultConversionService conversionService = (DefaultConversionService) DefaultConversionService.getSharedInstance();
        conversionService.addConverter(new MyCustomTypeConverter());
    }
}

【问题讨论】:

  • 我有同样的问题,但这个解决方案不起作用。自定义转换器在上下文创建时添加到共享转​​换服务,但在解析 ProxyProjectionFactory 中的转换器时仍未找到。你用的是什么版本的spring-data?
  • 弹簧靴 2.2.1.RELEASE。您是否在转换时检查 DefaultConversionService 是否包含您的转换器?我注意到 MyCustomTypeConverter 不是 AttributeConverter 而是 org.springframework.core.convert.converter.Converter。也许这就是问题所在。我会更新我的问题。
  • 要检查的另一件事是转换器的源类型是否符合您的预期。例如,在一种情况下,我必须使用源类型字符而不是字符串创建转换器。我会调试它并检查它尝试转换的确切类型
  • 我在 2.0.4 spring boot 中遇到了这个问题,所以我想这是一个固定的问题。我尝试调试这个不透明的系统,并且在为我的存储库构建的动态代理中根本没有使用转换服务的共享实例。非常感谢您的反馈!进行更改的提交:github.com/spring-projects/spring-data-commons/commit/…
  • spring-boot 2.0.9 中引入了该问题的修复

标签: java spring-data-jpa projection converters nativequery


【解决方案1】:

这在 Spring Data Jpa 2.4.0 中再次出现问题(请参阅 this closed GitHub issue)。

根据用户 ajobra76 (link) 的建议,一种解决方法是指定要使用的转换器,如下所示:

public interface TestClass {
    @Value("#{@myCustomTypeConverter.convert(target.customType)}")
    MyCustomType getCustomType();
}

其中myCustomTypeConverter 将是ApplicationContext 中的一个bean。当然还有其他方法可以使用SpEL指定方法,包括创建new对象,调用静态方法。但这只是为了表明它可以做到。

target 是一个标识符,将绑定到“支持投影的聚合根”(Spring Data Jpa 文档,"An Open Projection" 部分)。

【讨论】:

    【解决方案2】:

    使用的ConversionServiceDefaultConversionService.getSharedInstance()

    所以您应该能够访问它并添加您的转换器。

    【讨论】:

    • 好的,成功了。我只需要将它转换为 DefaultConversionService 因为 ConversionService 没有 addConverter() 方法。
    猜你喜欢
    • 2019-02-26
    • 2021-06-19
    • 2019-09-26
    • 2018-04-18
    • 2020-01-10
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-01
    相关资源
    最近更新 更多