MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Spring -Mongodb speichert/ruft Enums als int ab, nicht als String

Nach langem Graben im Spring-Mongodb-Konvertercode, Ok, ich bin fertig und jetzt funktioniert es :) Hier ist es (wenn es eine einfachere Lösung gibt, werde ich mich auch freuen, das zu sehen, was ich getan habe):

zuerst definieren :

public interface IntEnumConvertable {
      public int getValue();    
}

und eine einfache Aufzählung, die es implementiert:

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, jetzt brauchen Sie 2 Konverter, einer ist einfach, der andere ist komplexer. die einfache (dieses einfache Baby handhabt auch die einfache Konvertierung und gibt eine Zeichenfolge zurück, wenn eine Umwandlung nicht möglich ist. Das ist großartig, wenn Sie Aufzählungen als Zeichenfolgen speichern möchten und für Aufzählungen Zahlen sind, die als Ganzzahlen gespeichert werden sollen):

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();
            }               
        }
    }   
 }

die komplexere ist eigentlich eine Konverterfabrik :

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;   
            }
        }
}

und jetzt für den Hack-Teil, ich persönlich habe keinen "programmatischen" Weg gefunden, eine Konverterfabrik in einem MongoConverter zu registrieren, also habe ich den Code ausgegraben und mit ein wenig Casting, hier ist es (setzen Sie diese 2 Baby-Funktionen in Ihre @Configuration Klasse)

      @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;
    }