'Provide an AttributeConverter using @Bean

I am trying to provide an AttributeConverter using a Bean, but it does not seems to be picked up?

@SpringBootApplication
class TestJpaConvertApplication implements CommandLineRunner {
    
    @Autowired
    private CoordinateRepository repository;
    
    @Override
    public void run(String... args) throws Exception {
        repository.save(new Coordinate().setAt(new Complex(1, 2)));
        
        System.out.println(repository.findAll());
    }
    
    /* Bean to provide to the context, that is not being picked-up by JPA */
    @Bean
    public ComplexConverter complexConverter() {
        return new ComplexConverter(":");
    }
    
    public static void main(String[] args) {
        SpringApplication.run(TestJpaConvertApplication.class, args);
    }
    
};

/* Dummy AttributeConverter that need to be instanciated with a specific value */
/* Use cases would be providing a password for encryption */
class ComplexConverter implements AttributeConverter<Complex, String> {
    
    private final String separator;
    
    public ComplexConverter(String separator) {
        this.separator = separator;
    }
    
    @Override
    public String convertToDatabaseColumn(Complex attribute) {
        /* output would be 'i:j' for example */

        return String.format("%d%s%d", attribute.getI(), separator, attribute.getJ());
    }
    
    @Override
    public Complex convertToEntityAttribute(String dbData) {
        String[] ij = dbData.split(separator);
        
        return new Complex(Integer.parseInt(ij[0]), Integer.parseInt(ij[1]));
    }
    
}

/* Dummy class */
@Data
@AllArgsConstructor
class Complex {
    
    private int i;
    private int j;
    
};

/* Dummy entity class */
@Entity
@Table
@Data
@Accessors(chain = true)
class Coordinate {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    
    @Column
    @Convert(converter = ComplexConverter.class)
    private Complex at;
    
};

@Repository
interface CoordinateRepository extends JpaRepository<Coordinate, Long> {
    
}

Is is possible to do something like that?

A real use case is to provide a password that will store the encrypted version (and then can decrypt too).

Here is the error I get:

......
2022-04-12 21:00:59.446 ERROR 30864 --- [  restartedMain] j.LocalContainerEntityManagerFactoryBean : Failed to initialize JPA EntityManagerFactory: Unable to determine basic type mapping via reflection [test.Coordinate -> at]
......
2022-04-12 21:00:59.693 ERROR 30864 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in test.ComplexConverter required a bean of type 'java.lang.String' that could not be found.


Action:

Consider defining a bean of type 'java.lang.String' in your configuration.

The problem seems that when Hibernate start mapping entity classes, not all of the bean has been discovered? That what I discovered by running the code with the debugger. When trying to find the bean, the reference map was empty, so he was having no other choice than to create a new instance.

EDIT 1: Added more comment

EDIT 2: Added output



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source