带有 UUID 的 Spring 接口投影

try*_*its 7 java spring projection spring-boot

我正在尝试使用JPA 投影(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);
    
}
Run Code Online (Sandbox Code Playgroud)

我想按如下方式使用存储库:

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***
Run Code Online (Sandbox Code Playgroud)

但是,调用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***
Run Code Online (Sandbox Code Playgroud)

返回的TestValue代理对象将该id属性存储为原始byte数组。我希望ProjectingMethodInterceptor最终执行到UUID实例的实际类型转换。查看源代码 ( ProjectingMethodInterceptor.invoke(..):74) 似乎它使用 aConversionService进行转换。我尝试了以下方法:

@Configuration  
public class MyApplicationConfig {

    @Bean
    public ConversionService conversionService() {
        DefaultConversionService service = new DefaultConversionService();
        service.addConverter(new UUIDConverter());
        return service;
    }
}
Run Code Online (Sandbox Code Playgroud)

UUIDConverter实现接口org.springframework.core.convert.converter.Converter<byte[], UUID>。不幸的是,这种方法不起作用,因为 usedProjectingMethodInterceptor是通过ProxyProjectingFactory绕过配置ConversionService并实例化 a DefaultConversionService( ProxyProjectionFactory.ctor():65) 创建的。

我还尝试将注释添加@Convert(converter = UUIDConverter.class)到 中的getId()声明中TestValue,但是,这种方法也不起作用

我显然可以将方法的返回类型更改getId()byte[]UUID在我的应用程序代码中执行实际的转换,但是这种方法感觉不是正确的方法。

问题 1:在JPA Interface Projections 中如何定义自定义类型转换?

问题 2:如果这是不可能的,那么使用确切的方法签名和底层查询来实现上述存储库方法的“Spring 预期”方式是什么。