以编程方式设置MongoDb转换器

27

我正在尝试在spring-data-mongodb中使用自定义转换器。 我想以编程方式创建它,但是我遇到了以下错误:

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of     converting from type org.joda.time.LocalDate to type java.lang.String
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:475)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:154)
....
....

以下是出现问题的代码片段:

    Mongo mongo = new Mongo();
    MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo, "database");

    List<Converter> converters = new ArrayList<>();
    converters.add(new LocalDateWriteConverter());
    converters.add(new LocalDateReadConverter());
    CustomConversions customConversions = new CustomConversions(converters);

    MappingContext mappingContext = new SimpleMongoMappingContext();
    MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(mongoDbFactory, mappingContext);
    mappingMongoConverter.setCustomConversions(customConversions);

    MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, mappingMongoConverter);

    MongoDbEvent mongoEvent = new MongoDbEvent(new LocalDate(2012, 12, 8));
    mongoTemplate.insert(mongoEvent);

这里是我的转换器类:

class LocalDateReadConverter implements Converter<String, LocalDate> {
    @Override
    public LocalDate convert(String s) {
        // Conversion code omitted.
    }
}

class LocalDateWriteConverter implements Converter<LocalDate, String> {

    @Override
    public String convert(LocalDate localDate) {
        // Conversion code omitted.
    }
}

我想持久化的类的样子是这样的:

import org.joda.time.LocalDate;

public class MongoDbEvent {

    private String id;
    private LocalDate date;

    public MongoDbEvent(LocalDate date) {
        this.date = date;
    }

    public String getId() {
        return id;
    }

    public LocalDate getDate() {
        return date;
    }

    @Override
    public String toString() {
        return "MongoDbEvent{" +
                "id='" + id + '\'' +
                ", date=" + date +
                '}';
        }
}
6个回答

33

这个答案可能对提问者来说有点晚,但今天我也遇到了同样的问题,并找到了解决方案...

如果要通过编程方式进行设置,您需要在使用之前调用MongoMappingConverter.afterPropertiesSet()。我是通过阅读MongoTemplate.getDefaultMongoConverter(MongoDbFactory)的代码意识到这一点的。

以下是一个示例:

MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory, context);
converter.setTypeMapper(mapper);
converter.setCustomConversions(new CustomConversions(
        Arrays.asList(
                new TimeZoneReadConverter(),
                new TimeZoneWriteConverter()
        )
));
converter.afterPropertiesSet();
MongoTemplate template = new MongoTemplate(mongoDbFactory, converter);

1
非常感谢!当我在Spring Data的单元测试中看到.afterPropertiesSet();时,我没有给予足够的关注... - Zarathustra
救星!!:) 谢谢你,虽然我仍需要理解文档。 - SatyaRajC

21

提醒一下。我在使用Java配置时遇到了问题,具体是关于spring-data-mongodb 1.5.1.RELEASE的。由于某些类已更改,我将我的解决方案发布出来。

在标注有@Configuration的配置类中添加以下定义:

@Bean
public Mongo mongo() throws Exception {
    MongoPropertiesResolver resolver = mongoResolver();
    return new MongoClient(resolver.getUrl());
}

@Bean
public MongoDbFactory mongoDbFactory() throws Exception {
    return new SimpleMongoDbFactory(mongo(), "database");
}

@Bean
public MongoTemplate mongoTemplate() throws Exception {
    return new MongoTemplate(mongoDbFactory(), mongoConverter());
}

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

@Bean
public MappingMongoConverter mongoConverter() throws Exception {
    MongoMappingContext mappingContext = new MongoMappingContext();
    DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
    MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mappingContext);
    mongoConverter.setCustomConversions(customConversions());
    return mongoConverter;
}

2
构造函数SimpleMongoDbFactory(Mongo,String)已过时 - 我正在使用Spring Boot 1.3.2。 - Kumar Sambhav
感谢您提供的代码示例,这对我在使用Fongo组合一些单元测试时设置自定义转换器非常有帮助。 - Jitesh Vassa

7

在这里详细介绍了如何使用自定义转换器自定义Mongo:

http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mapping-configuration

我注入了默认配置值,这样我就可以从application.properties的配置设置中受益。
  @Configuration
  public class MongoConfiguration extends AbstractMongoConfiguration {
    @Value("${spring.data.mongodb.database:test}")
    String database;

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

    @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 MongoColorWriter());
      converterList.add(new MongoColorReader());
      return new CustomConversions(converterList);
    }
  }

1
分享的链接非常有帮助。 - Vikas Prasad

2

对于我来说,问题出在将我的转换器注册为读取器而不是写入器。要解决这个问题,您需要在转换器类中添加@WritingConverter注释。

@Component
@WritingConverter
public class NoteWriterConverter implements Converter<Note, DBObject> {

@Override
public DBObject convert(Note source) {
    DBObject obj = new BasicDBObject();

    obj.put("title", source.getTitle());
    obj.put("reviewDate", source.getReviewDate());

    obj.removeField("_class");
    return obj;
    }
}

2

在Java 8中引入了java.time包,我使用新的LocalDate和LocalDateTime类时遇到了类似的问题。这是我的解决方法:

我编写了一个转换器来处理以下4种转换选项:

  • DateToLocalDateTimeConverter
  • DateToLocalDateConverter
  • LocalDateTimeToDateConverter
  • LocalDateToDateConverter

下面是一个示例:

public class DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {

    @Override 
    public LocalDateTime convert(Date source) { 
        return source == null ? null : LocalDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault()); 
    }
}

然后将以下内容包含在mongodb连接的xml配置中,我就能够使用java 8日期与mongodb进行交互(记得添加所有的转换器):

<mongo:mapping-converter>
    <mongo:custom-converters>
        <mongo:converter>
            <bean class="package.DateToLocalDateTimeConverter" />
        </mongo:converter>
    </mongo:custom-converters>
</mongo:mapping-converter>

1
自从org.springframework.data:spring-data-commons:1.13.3.RELEASE版本以来,以下是如何通过编程方式创建具有自定义转换器的MongoTemplate
public MongoTemplate mongoTemplate(String mongoUri) throws Exception {
    MongoDbFactory factory = new SimpleMongoDbFactory(new MongoClientURI(mongoUri));
    CustomConversions conversions = new CustomConversions(
            Arrays.asList(new FooWriteConverter(), new FooReadConverter()));
    MongoMappingContext mappingContext = new MongoMappingContext();
    DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
    MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mappingContext);
    mongoConverter.setCustomConversions(conversions);
    mongoConverter.afterPropertiesSet();
    return new MongoTemplate(factory, mongoConverter);
}

转换器(实现被省略)

class FooWriteConverter implements Converter<Foo, DBObject> { ... }
class FooReadConverter implements Converter<DBObject, Foo> { ... }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接