spring data jpa - 基于接口的投影中的自定义类型转换
spring data jpa - Custom type conversion in interface-based projection
我正在尝试实施 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());
}
}
使用的ConversionService
是DefaultConversionService.getSharedInstance()
。
因此您应该能够访问它并添加您的转换器。
这在 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" 部分)。
我正在尝试实施 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());
}
}
使用的ConversionService
是DefaultConversionService.getSharedInstance()
。
因此您应该能够访问它并添加您的转换器。
这在 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" 部分)。