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

jjjwad0x  于 2024-01-06  发布在  Spring
关注(0)|答案(1)|浏览(161)

在更新到Sping Boot 3.2和Hibernate 6.2之后,枚举值的数据库列类型从整数更改为smallint更多信息在这里。
因此,我们将db列改为smallint。另一方面,Smallint被hibernateMap为short。
因此,我们遇到了基于接口的包含枚举的投影的问题:

  1. public interface MyProjection {
  2. MyEnum getEnum();
  3. }

字符串
因为没有默认的转换器,我们得到这个错误

  1. 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
  2. at org.springframework.data.projection.ProjectingMethodInterceptor.potentiallyConvertResult(ProjectingMethodInterceptor.java:110)
  3. at org.springframework.data.projection.ProjectingMethodInterceptor.invoke(ProjectingMethodInterceptor.java:80)
  4. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
  5. at org.springframework.data.projection.ProxyProjectionFactory$TargetAwareMethodInterceptor.invoke(ProxyProjectionFactory.java:243)
  6. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
  7. at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:249)


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

  1. @Component
  2. final class ShortToEnumConverterFactory implements ConverterFactory<Short, Enum> {
  3. @Override
  4. public <T extends Enum> Converter<Short, T> getConverter(Class<T> targetType) {
  5. return new ShortToEnum(targetType);
  6. }
  7. private static class ShortToEnum<T extends Enum> implements Converter<Short, T> {
  8. private final Class<T> enumType;
  9. public ShortToEnum(Class<T> enumType) {
  10. this.enumType = enumType;
  11. }
  12. @Override
  13. public T convert(Short source) {
  14. return this.enumType.getEnumConstants()[source];
  15. }
  16. }


注册通过

  1. @Configuration
  2. ...
  3. @Override
  4. public void addFormatters(FormatterRegistry registry) {
  5. registry.addConverterFactory(new ShortToEnumConverterFactory());
  6. }
  7. ...


以及像这样将其添加到DefaultConversionService

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


不是在修复它
问题是,在ProxyProjectionFactory中创建了DefaultConversionService的新示例,而不是使用sharedInstance:

  1. class ProxyProjectionFactory implements ProjectionFactory, BeanClassLoaderAware {
  2. static final GenericConversionService CONVERSION_SERVICE = new DefaultConversionService();
  3. ...


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

sulc1iza

sulc1iza1#

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

相关问题