将自定义转换器添加到 ProxyProjectionFactory 以实现基于接口的投影

问题描述 投票:0回答:1

更新到 Spring Boot 3.2 以及 Hibernate 6.2 后,枚举值的数据库列类型从整数更改为smallint 更多信息请参见此处

因此,我们将 db 列更改为smallint。 另一方面,Smallint 被 hibernate 映射为 Short。

因此,我们在包含枚举的基于接口的投影方面遇到了问题:

public interface MyProjection { 
  MyEnum getEnum();
}

因为没有默认转换器,我们收到此错误

java.lang.UnsupportedOperationException: Cannot project java.lang.Short to com.bbraun.nemo.enums.MyEnum; Target type is not an interface and no matching Converter found

at org.springframework.data.projection.ProjectingMethodInterceptor.potentiallyConvertResult(ProjectingMethodInterceptor.java:110)
at org.springframework.data.projection.ProjectingMethodInterceptor.invoke(ProjectingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.projection.ProxyProjectionFactory$TargetAwareMethodInterceptor.invoke(ProxyProjectionFactory.java:243)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:249)

为了解决这个问题,我尝试添加一个自定义转换器 Short-To-Enum:

@Component
final class ShortToEnumConverterFactory implements ConverterFactory<Short, Enum> {

  @Override
  public <T extends Enum> Converter<Short, T> getConverter(Class<T> targetType) {
    return new ShortToEnum(targetType);
  }

  private static class ShortToEnum<T extends Enum> implements Converter<Short, T> {

    private final Class<T> enumType;

    public ShortToEnum(Class<T> enumType) {
      this.enumType = enumType;
    }

    @Override
    public T convert(Short source) {
      return this.enumType.getEnumConstants()[source];
    }
  }

通过

注册
@Configuration
...

  @Override
  public void addFormatters(FormatterRegistry registry) {
    registry.addConverterFactory(new ShortToEnumConverterFactory());   
  }

...

以及像这样将其添加到 DefaultConversionService

DefaultConversionService sharedInstance = (DefaultConversionService)DefaultConversionService.getSharedInstance();
    sharedInstance.addConverterFactory(new ShortToEnumConverterFactory());

没有修复它。

问题是,在 ProxyProjectionFactory 中创建了 DefaultConversionService 的新实例,而不是使用共享实例:

class ProxyProjectionFactory implements ProjectionFactory, BeanClassLoaderAware {

    static final GenericConversionService CONVERSION_SERVICE = new DefaultConversionService();
...

此实例不包含添加的自定义转换器。

有一段时间,使用了sharedInstance,但无论出于何种原因,它都随着这个commit而改变。

所以我的问题是,是否可以以任何方式添加 ProxyProjectionFactory 使用的自定义转换器?

或者无论如何应该以完全不同的方式处理?

java spring-boot hibernate spring-data-jpa spring-data
1个回答
0
投票

复杂的对象转换从来不受用于投影的转换服务的影响。转换服务可以调整轻微的转换(long 到 int),但在任何情况下都不能调整 String 到复杂对象的转换。

底层实体决定了投影中需要使用的类型。或者,按照此答案中的说明使用

SpEL
@Value
-

https://stackoverflow.com/a/70253539/16769477

© www.soinside.com 2019 - 2024. All rights reserved.