Spring Boot 将自定义转换器添加到ProxyProjectionFactory,用于基于接口的投影

jjjwad0x  于 11个月前  发布在  Spring
关注(0)|答案(1)|浏览(137)

在更新到Sping Boot 3.2和Hibernate 6.2之后,枚举值的数据库列类型从整数更改为smallint更多信息在这里。
因此,我们将db列改为smallint。另一方面,Smallint被hibernateMap为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的新示例,而不是使用sharedInstance:

class ProxyProjectionFactory implements ProjectionFactory, BeanClassLoaderAware {

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


此示例不包含mit添加的自定义转换器。
有一段时间使用了sharedInstance,但不管出于什么原因,它被这个commit改变了。
所以我的问题是,有没有可能以任何方式添加一个自定义转换器,由ProxyProjectionFactory使用?
还是应该以一种完全不同的方式来处理这件事?

sulc1iza

sulc1iza1#

复杂对象转换从不受用于投影的转换服务的影响。转换服务可以调整轻微的转换(long到int),但在任何情况下都不能调整String到复杂对象的转换。
底层实体决定了需要在投影中使用的类型。或者,使用SpEL@Value,如本答案所述-
https://stackoverflow.com/a/70253539/16769477

相关问题