Search code examples
springspring-bootspring-dataspring-data-jdbc

Spring Data Jdbc - map inner class to table column


Using Spring Data JDBC I would like for the Inner variable 'inner' to be mapped to a varchar column in the outer table rather than being mapped to its own table. Is this possible?

public class Outer {
    @Id
    private String id;
    private Inner inner;
}

...

public class Inner {
   private String value;
}

...

public OuterRepository implements CrudRepository<Outer, String> {}

Here is my context configuration:

@Configuration
@EnableJdbcRepositories
public class Config extends JdbcConfiguration {

    @Bean
    protected JdbcCustomConversions jdbcCustomConversions() {
        return new JdbcCustomConversions(asList(StringToInner.INSTANCE, InnerToString.INSTANCE));
    }

    @WritingConverter
    enum InnerToString implements Converter<Inner, String> {

        INSTANCE;

        @Override
        public String convert(Inner source) {
            return source.getValue();
        }
    }

    @ReadingConverter
    enum StringToInner implements  Converter<String, Inner> {

        INSTANCE;

        @Override
        public Inner convert(String source) {
            return new Inner(source);
        }
    }
}

Solution

  • Yes, this is possible. You need to provide converters from Inner to String and back.

    In your application context configuration register a bean for jdbcCustomConversions:

    @Bean
    CustomConversions jdbcCustomConversions() {
        return new JdbcCustomConversions(asList(InnerToString.INSTANCE, StringToInner.INSTANCE));
    }
    

    Define the referenced converters as follows:

    @WritingConverter
    enum InnerToString implements Converter<Inner, String> {
    
        INSTANCE;
    
        @Override
        public String convert(Inner inner) {
    
            return inner == null ? null : inner.value;
        }
    }
    
    @ReadingConverter
    enum StringToInner implements Converter<String, Inner> {
    
        INSTANCE;
    
        @Override
        public Inner convert(String source) {
    
            Inner inner = new inner();
            inner.value = source;
            return inner;
        }
    }
    

    The converters don't have to be enums, but there is no point in having more than one instance as long as the converter is not parameterized.

    The annotations @WritingConverter and @ReadingConverter are important since they control if the converters get used when writing to the database or reading from the database.

    Note that this works for classes that get stored in a single column. Proper embedded entities that get mapped to a list of columns aren't yet supported. See DATAJDBC-111.