Проекция интерфейса Spring с UUID - PullRequest
0 голосов
/ 25 июня 2018

Я пытаюсь использовать 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 (ProxyProjectionFactory.ctor():65).

Я также попытался добавить аннотацию @Convert(converter = UUIDConverter.class) к объявлению getId() в TestValue, однако этот подход тоже не работает .

Я, очевидно, мог бы изменить тип возвращаемого значенияметода getId() в byte[] и выполнить фактическое преобразование в UUID в коде моего приложения, но этот подход не кажется правильным способом сделать это.

Вопрос 1: Как определяются пользовательские преобразования типов в Интерфейсах JPA ?

Вопрос 2: Если это невозможно, каков «пружинный» способ реализации вышеуказанного метода хранилища с этимточная подпись метода и базовый запрос.

...