2

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);
        }
    }
}
Brett Y
  • 7,171
  • 1
  • 28
  • 42
  • I don't think this is something spring data jdbc directly supports, but maybe you could try using property access for you inner instance and manually handle assigning its string value. – Nima Ajdari Nov 13 '18 at 18:06

2 Answers2

5

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.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • This is exactly what I want but I must be doing something wrong as I'm getting the following error when I do `respository.save(outer);`: https://pastebin.com/BMiHsfTc – Brett Y Nov 14 '18 at 09:39
  • It is not picking up the custom conversions. Can you update the question with your current context configuration? – Jens Schauder Nov 14 '18 at 09:52
  • I receive The bean 'jdbcCustomConversions', defined in class path resource [org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfiguration$SpringBootJdbcConfiguration.class], could not be registered. A bean with that name has already been defined in my.pack .Main and overriding is disabled. – gstackoverflow Jan 20 '22 at 17:01
  • I am trying to apply it but I am not successful. More details are here: https://stackoverflow.com/questions/70790593/spring-data-jdbc-cant-add-custom-converter-for-enum – gstackoverflow Jan 20 '22 at 17:18
0

According to this documentation it's not possible to use inner class in entity.

Entity Class Requirements A portable JPA entity class:

should be a top-level class (i.e. not a nested / inner class). should have a public or protected no-arg constructor. cannot be final and cannot have final methods or final instance variables.

https://www.objectdb.com/java/jpa/entity/types

But you can check @Embeddable annotation, here is example https://www.callicoder.com/hibernate-spring-boot-jpa-embeddable-demo/ https://springframework.guru/embedded-jpa-entities-under-spring-boot-and-hibernate-naming/

Ishikawa Yoshi
  • 1,779
  • 8
  • 22
  • 43