Сохраните и загрузите дополнительные файлы Guava в MongoDB, используя Spring-Data.

Как настроить сопоставление Guava Optionals (или более поздних опций JDK8) с помощью Spring-Data-MongoDb?

В качестве примера следующий класс должен быть сопоставлен как json ниже.

@Data
public class Test
{
    Optional<String> stringOptionalNull    = null;
    Optional<String> stringOptionalAbsent  = Optional.absent();
    Optional<String> stringOptionalPresent = Optional.of("ExampleValue");   
}

Json (Примечание. Нулевой и отсутствующий случаи обрабатываются одинаково):

{
   "stringOptionalPresent" : "ExampleValue"
}

Когда они снова преобразуются обратно в java, null и absent должны быть преобразованы в Optional.absent().

Из Spring Data MongoDB Docs Я читал, что org.springframework...Converter - это то, что нужно. Но с помощью API мне не удалось правильно обработать null случаев.

Это полный тестовый пример для воспроизведения проблемы. Он передает null и проверяет, что загруженный объект содержит только Optional.absent().

public class OptionalMongoDbTest
{
    @Data
    @AllArgsConstructor
    static class ClassWithOptionals
    {
        private final Optional<String> stringOptionalNull;
        private final Optional<String> stringOptionalPresent;
        private final Optional<String> stringOptionalAbsent;
    }

    public static class OptionalToStringConverter<T> implements Converter<Optional<T>, String>
    {
        @Override
        public String convert(final Optional<T> arg0)
        {
            return arg0.isPresent() ? arg0.get().toString() : null;
        }
    }

    public static class StringToOptionalConverter implements Converter<String, Optional<String>>
    {
        @Override
        public Optional<String> convert(final String arg0)
        {
            return Optional.fromNullable(arg0);
        }
    }

    @Test
    public void persisted_object_should_be_equal() throws Exception
    {
        // Setup Mongodb connection
        final SimpleMongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(new Mongo(), "test");
        final MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory, new MongoMappingContext());

        // Register Custom Converter
        converter.setCustomConversions(new CustomConversions(Arrays.asList(new OptionalToStringConverter(), new StringToOptionalConverter())));
        converter.afterPropertiesSet();

        final MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, converter);
        mongoTemplate.setWriteConcern(WriteConcern.SAFE);

        // Test the mapping
        mongoTemplate.dropCollection(ClassWithOptionals.class);

        final ClassWithOptionals objectToSave = new ClassWithOptionals(null, Optional.of("ExampleValue"), Optional.<String> absent());
        mongoTemplate.save(objectToSave);

        final ClassWithOptionals objectFromMongo = mongoTemplate.findAll(ClassWithOptionals.class).get(0);

        // TODO: That test fails because there are null values comming from the databases
        assertThat(objectFromMongo, is(new ClassWithOptionals(Optional.<String> absent(), Optional.of("ExampleValue"), Optional.<String> absent())));
    }
}

Кроме того, json, сгенерированный этим тестом, выглядит так:

{
    "_id" : ObjectId("5343d8a5e4b0215d78a322d0"),
    "stringOptionalPresent" : "ExampleValue",
    "stringOptionalAbsent" : null // this line should be removed.
}

Изменить

Я думаю, что это невозможно, потому что Spring Data Mongo не запускает пользовательские преобразования для нулевых объектов. Это из-за этого: https://github.com/spring-projects/spring-data-mongodb/blob/master/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java#L1037-L1041


person d0x    schedule 03.04.2014    source источник
comment
Самая цель Optional – избежать нулевых значений! Зачем вообще давать возможность иметь null Optional?   -  person fge    schedule 03.04.2014
comment
Я знаю, но в любом случае нам нужно его правильно преобразовать!?   -  person d0x    schedule 04.04.2014
comment
Итак, в основном, вы хотите знать, как сериализовать Optional с помощью API MongoDB?   -  person fge    schedule 04.04.2014
comment
Да, сериализовать и десериализовать. Лучше всего для меня было бы преобразование, совместимое с данными Spring.   -  person d0x    schedule 04.04.2014
comment
И как бы вы десериализовали в Optional.absent()? Я не говорю, что это невыполнимо, но вам придется указать, что вы хотите. Кроме того, другим вариантом было бы, чтобы геттер возвращал только Optional; сеттер будет работать нормально.   -  person fge    schedule 04.04.2014


Ответы (1)


Я не использую Spring, поэтому я не знаю, сработает ли это для вас, но попробуйте заставить ваш сеттер работать «нормально» и преобразовать ваш геттер в это:

public Optional<String> getFoo()
{
    return Optional.fromNullable(foo);
}

Если foo равно null, это будет Optional.absent(), для которого .isPresent() вернет false.

В Java 8 (которая «украла» Optional из Guava) API немного отличается; это не Optional.absent(), а Optional.empty(), а .fromNullable() стало .ofNullable().

person fge    schedule 04.04.2014
comment
Привет, это не решит проблему преобразования. Я получаю это исключение, потому что у option (конечно) нет конструктора по умолчанию. org.springframework.data.mapping.model.MappingInstantiationException В вопросе я просил помощи в отображении - person d0x; 07.04.2014
comment
Затем сделайте так, чтобы Spring игнорировал переменные экземпляра и вместо этого использовал сеттеры... Не знаю, как это сделать с помощью Spring. - person fge; 07.04.2014