【问题标题】:Spring -Mongodb storing/retrieving enums as int not stringSpring -Mongodb 将枚举存储/检索为 int 而不是字符串
【发布时间】:2012-09-05 08:10:00
【问题描述】:

我的枚举以 int 形式存储在 mongodb 中(来自 C# 应用程序)。现在在 Java 中,当我尝试检索它们时,它会引发异常(似乎枚举只能从字符串值转换)。有什么办法可以吗?

此外,当我将一些集合保存到 mongodb(来自 Java)时,它会将枚举值转换为字符串(而不是它们的值/基数)。有没有可用的覆盖?

这可以通过在类级别编写 mongodb-converter 来实现,但我不想为每个类编写 mondodb-converter,因为这些枚举位于许多不同的类中。

那么我们在现场层面有什么东西吗?

【问题讨论】:

    标签: spring mongodb spring-mongo


    【解决方案1】:

    在对spring-mongodb转换器代码进行了长时间的挖掘之后, 好的,我完成了,现在它正在工作:) 在这里(如果有更简单的解决方案,我也会很高兴看到,这就是我所做的):

    先定义:

    public interface IntEnumConvertable {
          public int getValue();    
    }
    

    以及一个实现它的简单枚举:

    public enum tester implements IntEnumConvertable{   
        vali(0),secondvali(1),thirdvali(5);
    
        private final int val;
        private tester(int num)
        {
            val = num;          
        }
        public int getValue(){
            return val;
        }
    }
    

    好的,现在你需要 2 个转换器,一个很简单, 另一个更复杂。最简单的(这个简单的宝贝也处理简单​​的转换,并在无法进行强制转换时返回一个字符串,如果你想将枚举存储为字符串,而枚举是数字存储为整数,那就太好了):

    public class IntegerEnumConverters {
        @WritingConverter
        public static class EnumToIntegerConverter implements Converter<Enum<?>, Object> {
            @Override
            public Object convert(Enum<?> source) {
                if(source instanceof IntEnumConvertable)
                {
                    return ((IntEnumConvertable)(source)).getValue();
                }
                else
                {
                    return source.name();
                }               
            }
        }   
     }
    

    更复杂的,其实是一个转换器工厂:

    public class IntegerToEnumConverterFactory implements ConverterFactory<Integer, Enum> {
            @Override
            public <T extends Enum> Converter<Integer, T> getConverter(Class<T> targetType) {
                Class<?> enumType = targetType;
                while (enumType != null && !enumType.isEnum()) {
                    enumType = enumType.getSuperclass();
                }
                if (enumType == null) {
                    throw new IllegalArgumentException(
                            "The target type " + targetType.getName() + " does not refer to an enum");
                }
                return new IntegerToEnum(enumType);
            }
            @ReadingConverter
            public static class IntegerToEnum<T extends Enum>  implements Converter<Integer, Enum> {
                private final Class<T> enumType;
    
                public IntegerToEnum(Class<T> enumType) {
                    this.enumType = enumType;
                }
    
                @Override
                public Enum convert(Integer source) {
                      for(T t : enumType.getEnumConstants()) {
                          if(t instanceof IntEnumConvertable)
                          {
                              if(((IntEnumConvertable)t).getValue() == source.intValue()) {
                                    return t;
                                }                         
                          }                     
                        }
                        return null;   
                }
            }
    }
    

    现在对于 hack 部分,我个人没有找到任何“programmitacly”方法来在 mongoConverter 中注册转换器工厂,所以我挖掘了代码并进行了一些铸造,这就是(将这 2 个婴儿函数放入你的@Configuration 类)

          @Bean
            public CustomConversions customConversions() {
                List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
                converters.add(new IntegerEnumConverters.EnumToIntegerConverter());     
    // this is a dummy registration , actually it's a work-around because
    // spring-mongodb doesnt has the option to reg converter factory.
    // so we reg the converter that our factory uses. 
    converters.add(new IntegerToEnumConverterFactory.IntegerToEnum(null));      
                return new CustomConversions(converters);
            }
    
        @Bean
        public MappingMongoConverter mappingMongoConverter() throws Exception {
            MongoMappingContext mappingContext = new MongoMappingContext();
            mappingContext.setApplicationContext(appContext);
            DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
            MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mappingContext);        
            mongoConverter.setCustomConversions(customConversions());       
            ConversionService convService = mongoConverter.getConversionService();
            ((GenericConversionService)convService).addConverterFactory(new IntegerToEnumConverterFactory());                  
            mongoConverter.afterPropertiesSet();
            return mongoConverter;
        } 
    

    【讨论】:

    • 上述收据对我来说并不顺利,因为 Spring Mongo 开始应用给定的转换器将所有 Integer 类型的查询值转换为 Enum 在我的情况下,从而导致 nulls对于所有整数类型的值。为了解决这个问题,我必须将@ReadingConverter 放在转换器工厂(因此将其从IntegerToEnum 转换器中删除)。
    【解决方案2】:

    【讨论】:

    • 这将适用于班级级别..我不希望**已经在问题中提到了这一点
    • 没有注意到(请格式化您的问题,难以阅读)-您尝试过吗?我认为它也适用于领域。
    • 另一个选项是为进行转换的实体添加另一个 getter / setter for ints。枚举的 getter/setter 应标记为 @Transient。
    • 它将第一个输入作为 class 。所以它不会是通用的,对于每个枚举/类我必须添加一个转换器。您提供的其他选项效果很好,但这是一种解决方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    相关资源
    最近更新 更多