我正在尝试使用JPA Projection(Spring v1.5.9.RELEASE)从JpaRepository
返回自定义类型,如下所示(MCVE):
@Repository
public interface TestRepository extends JpaRepository<Void, Void> {
public interface TestValue {
UUID getId();
int getNum();
}
@Query(value = "SELECT :id as id, 1 as num", nativeQuery = true)
List<TestValue> getTestValues(@Param("id") UUID id);
}
我想按如下方式使用存储库:
List<TestValue> testValues = testRepository.getTestValues(UUID.randomUUID());
int num = testValues.get(0).getNum(); // Returns 1 as expected
UUID id = testValues.get(0).getId(); // ***Fails with an exception***
但是,调用getId()
失败,但出现以下异常:
java.lang.IllegalArgumentException: Projection type must be an interface!
at org.springframework.util.Assert.isTrue(Assert.java:92) ~[spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.data.projection.ProxyProjectionFactory.createProjection(ProxyProjectionFactory.java:110) ~[spring-data-commons-1.13.9.RELEASE.jar:?]
at org.springframework.data.projection.SpelAwareProxyProjectionFactory.createProjection(SpelAwareProxyProjectionFactory.java:42) ~[spring-data-commons-1.13.9.RELEASE.jar:?]
at org.springframework.data.projection.ProjectingMethodInterceptor.getProjection(ProjectingMethodInterceptor.java:126) ~[spring-data-commons-1.13.9.RELEASE.jar:?]
at org.springframework.data.projection.ProjectingMethodInterceptor.invoke(ProjectingMethodInterceptor.java:76) ~[spring-data-commons-1.13.9.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.data.projection.ProxyProjectionFactory$TargetAwareMethodInterceptor.invoke(ProxyProjectionFactory.java:264) ~[spring-data-commons-1.13.9.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56) ~[spring-data-commons-1.13.9.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at com.sun.proxy.$Proxy199.getId(Unknown Source) ~[?:?]
at ***my.company***
返回的TestValue
代理对象将id
属性存储为原始byte
数组。我希望ProjectingMethodInterceptor
最终执行对UUID
实例的实际类型转换。查看源代码(ProjectingMethodInterceptor.invoke(..):74
),似乎它使用ConversionService
进行转换。我尝试了以下方法:
@Configuration
public class MyApplicationConfig {
@Bean
public ConversionService conversionService() {
DefaultConversionService service = new DefaultConversionService();
service.addConverter(new UUIDConverter());
return service;
}
}
类UUIDConverter
实现接口org.springframework.core.convert.converter.Converter<byte[], UUID>
。不幸的是,该方法不起作用,因为通过ProjectingMethodInterceptor
创建了使用过的ProxyProjectingFactory
,它绕过了配置的ConversionService
并实例化了DefaultConversionService
({ {1}}。
我还尝试将注释ProxyProjectionFactory.ctor():65
添加到@Convert(converter = UUIDConverter.class)
中的getId()
声明中,但是,此方法也不起作用。
我显然可以将TestValue
方法的返回类型更改为getId()
,并在应用程序代码中实际转换为byte[]
,但是这种方法并不适合的方法。
问题1: JPA接口投影中如何定义自定义类型转换?
问题2: 如果不可能,那么使用上述确切方法签名和基础查询来实现上述存储库方法的“春季计划”方式是什么。