更新到 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 使用的自定义转换器?
或者无论如何应该以完全不同的方式处理?
复杂的对象转换从来不受用于投影的转换服务的影响。转换服务可以调整轻微的转换(long 到 int),但在任何情况下都不能调整 String 到复杂对象的转换。
底层实体决定了投影中需要使用的类型。或者,按照此答案中的说明使用
SpEL
到 @Value
-