Spring -Mongodb storing/retrieving enums as int not string
After a long digging in the spring-mongodb converter code,Ok i finished and now it's working :) here it is (if there is simpler solution i will be happy see as well, this is what i've done ) :
first define :
public interface IntEnumConvertable { public int getValue(); }
and a simple enum that implements it :
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; }}
Ok, now you will now need 2 converters , one is simple , the other is more complex. the simple one (this simple baby is also handling the simple convert and returns a string when cast is not possible, that is great if you want to have enum stored as strings and for enum that are numbers to be stored as integers) :
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(); } } } }
the more complex one , is actually a converter factory :
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; } }}
and now for the hack part , i personnaly didnt find any "programmitacly" way to register a converter factory within a mongoConverter , so i digged in the code and with a little casting , here it is (put this 2 babies functions in your @Configuration class)
@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; }
You will need to implement your custom converters and register it with spring.