9

MongoDB, Spring Data, findAll() method error:

No converter found capable of converting from type [java.lang.String] to type [java.time.LocalDateTime]

public class EntityName {
    @Id
    private String id;
    private Map<LocalDateTime, Integer> statistic;
}

I am able to save entity, but not able to load it. Any quick fixes?

Maksym
  • 4,434
  • 4
  • 27
  • 46
  • 1
    **Quick Fix: ** Change `Map` to `Map`. Save `LocalDateTime` as String and make `LocalDateTime` out of the String while retrieving. – user2004685 May 04 '18 at 20:25
  • 2
    You can try programatically defining a new custom converter for this. Something similar to this: https://stackoverflow.com/questions/13780692/set-mongodb-converter-programmatically – user2004685 May 04 '18 at 20:40

3 Answers3

7

This solved the problem:

@Configuration
public class MongoConfiguration extends AbstractMongoConfiguration {

    @Value("${spring.data.mongodb.database:test}")
    private String database;

    @Value("${spring.data.mongodb.host:localhost}:${spring.data.mongodb.port:27017}")
    private String host;

    @Autowired
    private MappingMongoConverter mongoConverter;

    // Converts . into a mongo friendly char
    @PostConstruct
    public void setUpMongoEscapeCharacterConversion() {
        mongoConverter.setMapKeyDotReplacement("_");
    }

    @Override
    protected String getDatabaseName() {
        return database;
    }

    @Override
    public Mongo mongo() throws Exception {
        return new MongoClient(host);
    }

    @Bean
    @Override
    public CustomConversions customConversions() {
        List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>();
        converterList.add(new MongoLocalDateTimeFromStringConverter());
        return new CustomConversions(converterList);
    }

    private static final class MongoLocalDateTimeFromStringConverter implements Converter<String, LocalDateTime> {
        @Override
        public LocalDateTime convert(String source) {
            return source == null ? null : LocalDateTime.parse(source);
        }
    }
}
Maksym
  • 4,434
  • 4
  • 27
  • 46
  • In 2023, you can override `protected void configureConverters(MongoCustomConversions.MongoConverterConfigurationAdapter converterConfigurationAdapter)` and just register your custom converter in there via `converterConfigurationAdapter.registerConverter(new MongoDoubleToDateConverter());` – takanuva15 Aug 03 '23 at 20:19
0

@Maksym's way has helped me as well. I had to adjust it a little bit for Spring Framework 5 and Spring Boot 2:

@Bean
@Primary
public MappingMongoConverter mongoConverter(
        @Autowired MongoMappingContext mongoMappingContext,
        @Autowired MongoDbFactory mainMongoFactory,
        @Autowired MongoCustomConversions conversions
) {
    DbRefResolver dbRefResolver = new DefaultDbRefResolver(mainMongoFactory);
    MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
    mongoConverter.setMapKeyDotReplacement("#");
    mongoConverter.afterPropertiesSet();
    mongoConverter.setCustomConversions(conversions);
    return mongoConverter;
}


@Bean
public MongoMappingContext mongoMappingContext() {
    MongoMappingContext context = new MongoMappingContext();
    context.setSimpleTypeHolder(new SimpleTypeHolder(new HashSet<>(Arrays.asList(
            DateTime.class,
            LocalDateTime.class
    )), MongoSimpleTypes.HOLDER));
    return context;
}

@Bean
public MongoCustomConversions customConversions() {
    List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>();
    converterList.add(new MongoLocalDateTimeFromStringConverter());
    converterList.add(new MongoDateTimeFromStringConverter());
    return new MongoCustomConversions(converterList);
}

private static final class MongoLocalDateTimeFromStringConverter implements Converter<String, LocalDateTime> {
    @Override
    public LocalDateTime convert(String source) {
        return source == null ? null : LocalDateTime.parse(source);
    }
}

private static final class MongoDateTimeFromStringConverter implements Converter<String, DateTime> {
    @Override
    public DateTime convert(String source) {
        return source == null ? null : DateTime.parse(source);
    }
}
Sergey Shcherbakov
  • 4,534
  • 4
  • 40
  • 65
0

Ref - https://github.com/lordofthejars/nosql-unit#dataset-format

If you want to use ISODate function or any other javascript function you should see how MongoDB Java Driver deals with it. For example in case of ISODate:

In your json file use $date for conversion

"bornAt":{ "$date" : "2011-01-05T10:09:15.210Z"}
Davide
  • 1,931
  • 2
  • 19
  • 39
StackOverFlow
  • 4,486
  • 12
  • 52
  • 87