How to store Java 8 Instant to MongoDB as date type using Spring MongoTemplate?

I have a Java class that has a member variable Instant

:

public class SomeRecord {
    private String someId;

    private Instant someInstant;

    // getters and setters
}

      

I am using MongoTemplate to update a field someInstant

in a database:

public SomeRecord updateSomeRecordBySomeId(final String someId, Object someInstant) {
        Query query = new Query();
        query.addCriteria(Criteria.where("someId").is(someId));

        Update update = new Update();
        update.set("someInstant", someInstant);

        return operations.findAndModify(query, update, new FindAndModifyOptions().returnNew(true), SomeRecord.class);
}

      

This works great if I call the method like:

updateSomeRecordBySomeId("SOME-ID", Instant.now());

storing the field in the DB as a type Date

: "someInstant" : ISODate("2017-07-11T07:26:44.269Z")


Now this method can also be called as follows: updateSomeRecordBySomeId("SOME-ID", "2017-07-11T07:26:44.269Z");

In this case, I am getting an exception like:

org.springframework.core.convert.ConverterNotFoundException: There is no converter that can be converted from type [java.lang.String] to type [java.time.Instant]

which makes sense. (It updates the field in the DB like String

though. "someInstant" : "2017-07-11T07:26:44.269Z"

)


So I added a converter like this:

MongoConfig.java:

@Configuration
@ComponentScan(basePackages = {"dao package path here"})
public class MongoConfig {
    @Autowired
    private MongoDbFactory mongoDbFactory;

    @Bean
    public MongoTemplate mongoTemplate() {
        MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory),
                new MongoMappingContext());

        converter.setCustomConversions(new CustomConversions(Collections.singletonList(new StringToInstantConverter())));

        return new MongoTemplate(mongoDbFactory, converter);
    }
}

      

StringToInstantConverter.java:

public class StringToInstantConverter implements Converter<String, Instant> {
    @Override
    public Instant convert(String utcString) {
        // TODO: Make it generic for any time-zone
        return Instant.parse(utcString);
    }
}

      

After adding the above converter, I don't get any more ConverterNotFoundException

, but the field is someInstant

saved as a simple string:"someInstant" : "2017-07-11T07:26:44.269Z"

And that's my question. I know the converter is identified, so I no longer get the exception. But why doesn't the converter convert String

to Instant

? Why is the field saved as normal String

? Is the inverter installed correctly? How do I write a converter for this case?

Note:

  • I've simplified the code to focus on the real problem. The method does not actually receive a field someInstant

    as a parameter. Therefore, you won't write an overloaded method here. Also any type of validation instanceOf

    within a method will not work for a real scenario. So the focus is on why the conversion isn't happening?

  • The actual data store for us is DocumentDB, but we are using DocumentDB with the MongoDB API (as Spring Data does not support DocumentDB) for our database operations.

+3


source to share


1 answer


Your update logic is written as type agnostic: you can pass any type of object (Integer, Long, Boolean, String, Date, etc.) and it will persist in the DB, overriding the existing value / type with the new value and a new type . Note. Documented databases like MongoDB do not have a fixed schema, so the stored data can change data types arbitrarily.

The problem before entering the converter with ConverterNotFoundException

was not during the update action, but during retrieving the updated object and installing it in your Java bean model: Java class property someInstant

t22> / Date

, but the database has a value String

.



After entering the converter, the reading problem was resolved, but only for types String

and Date

. If you update the property someInstant

with some value boolean

, you are back to the problem to read the object and map it to you Java bean.

+1


source







All Articles