8

How can I add my custom converter to mu spring boot application? My entity field

    @CreatedDate
    @Column(value = "create_time")
    private Instant createTime;

My converters are

    @Bean
    public Converter<Long, Instant> longInstantConverter() {
        return new Converter<Long, Instant>() {
            @Override
            public Instant convert(Long source) {
                return Instant.ofEpochMilli(source);
            }
        };
    }

    @Bean
    public Converter<Instant, Long> instantLongConverter() {
        return new Converter<Instant, Long>() {
            @Override
            public Long convert(@NotNull Instant source) {
                return source.toEpochMilli();
            }
        };
    }

I have an exception

org.springframework.data.mapping.MappingException: Could not read property @org.springframework.data.relational.core.mapping.Column(value=create_time) @org.springframework.data.annotation.CreatedDate()private java.time.Instant com.example.database.model.MyTable.createTime from result set!
.........
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Long] to type [java.time.Instant]
........

How can I fix it, please help me!

Vurtatoo
  • 346
  • 3
  • 8

2 Answers2

13

You need to register the converters with R2DBC:

@Bean
public R2dbcCustomConversions customConversions() {
    List<Converter<?, ?>> converters = new ArrayList<>();
    converters.add(new SomeReadConverter());
    converters.add(new SomeWriteConverter());
    return R2dbcCustomConversions.of(MySqlDialect.INSTANCE, converters);
    // deprecated: return new R2dbcCustomConversions(converters);
}

You don't need to override the whole R2dbcConfiguration.

Tires
  • 1,529
  • 16
  • 27
  • yeah that works. In new version of r2dbc constructor R2dbcCustomerConversions(converters) is deprecated, so from now we should use: R2dbcCustomConversions.of(SqlServerDialect.INSTANCE, converters) where you need to choose correct dialect for your DB – Moler Oct 12 '21 at 13:13
  • I'm not 100% sure why they force the implementer to specify the dialect. Things getting more complicated. – Tires Oct 13 '21 at 09:17
  • It works, just one thing to keep in mind: BlockHound sees this converters as a blocking. – Moler Nov 26 '21 at 10:51
  • @Moler There*s nothing blocking in this code. Of course you need non blocking implementations of the converters itself also. You should post a separate question with your blocking details. – Tires Nov 27 '21 at 11:33
  • This should be marked as the correct answer. Works just perfect! – Laess3r Jan 14 '22 at 10:16
5

Try to create ReadingConverter and WritingConverter respectively, and register them in the Config file.

public class DatabaseConfig extends AbstractR2dbcConfiguration {
    //...
    
    @Override
    protected List<Object> getCustomConverters() {
        return List.of(
                new PostReadingConverter(),
                new PostStatusWritingConverter()
        );
    }
}

Check the complete codes here.

For Spring Boot applications, try to override the default beans, or create a R2dbcCustomConversions.

@Bean
public R2dbcCustomConversions r2dbcCustomConversions(ConnectionFactory connectionFactory, ObjectMapper objectMapper) {
    var dialect = DialectResolver.getDialect(connectionFactory);
    var converters = List.of(
               ...
    );
    return R2dbcCustomConversions.of(dialect, converters);
}
Hantsy
  • 8,006
  • 7
  • 64
  • 109