Accessing Spring Beans inside AttributeConverter class

后端 未结 3 1399
逝去的感伤
逝去的感伤 2020-12-10 02:25

I\'m developing a Spring Data JPA application, and I\'ve created an AttributeConverter class in order to save an ArrayList of objects as JSON in a

相关标签:
3条回答
  • 2020-12-10 03:02

    With JPA 2.2, Spring 5.1( SPR-16305) and Hibernate 5.3.0 (HHH-12135) you no longer need to use the mutable static property hack and can use dependency injection just like you would on a regular spring managed bean (note that annotations are no longer necessary):

    public class MyAttributeConverter implements AttributeConverter<X,Y> {
    
        private final MySpringBean bean;
    
        public MyAttributeConverter(MySpringBean bean) {
            this.bean = bean;
        }
    
        public Y convertToDatabaseColumn(X attribute) {
          ...
        }
    
        public X convertToEntityAttribute(Y dbData) {
          ...
        }
    }
    
    0 讨论(0)
  • 2020-12-10 03:03

    You can inject a bean(@Component, @Service, @Repository) inside an AttributeConverter using static properties

    Setps:

    1. Set in your AttributeConverter with the following annotations: @Component, @Converter and @Configurable
    2. Define the field that you want to autowired with the static modifier access
    3. Create an init method in order to autowired the repository
    4. Implement the methods defined in the interface AttributeConverter

    Basically, the code should look like this...

    //Step 1
    @Component
    @Converter
    @Configurable
    public class MyAttributeConverter implements AttributeConverter<X,Y> {
        //Where: X = the type of the entity attribute and Y = the type of the database column
    
        //Step 2
        private static MyRepository myRepository;
    
        //Step 3
        @Autowired
        public void initMyRepository(MyRepository myRepository){
            MyAttributeConverter.myRepository = myRepository;
        }
    
        //Step 4
        Y convertToDatabaseColumn(X attribute){//TODO implement method}
        X convertToEntityAttribute(Y dbData){//TODO implement method}
    }
    

    I hope it can help!!!

    0 讨论(0)
  • 2020-12-10 03:12

    Generally Ipandzic's answer is the right hint I guess. However it did not work for me how he described it. I argument-constructor also looks a little strange in a Spring-environment. I played around a bit and was able to use an AttributeConverter of the following form (indeed you do not need the @Converter-annotation or any other on the AttributeConverter-class itself):

    import javax.persistence.AttributeConverter;
    import org.springframework.beans.factory.annotation.Autowired;
    
    public class MyConverter implements AttributeConverter<String, String> {
        @Autowired
        private MyBean mybean;
    
        public String convertToDatabaseColumn(String value) {
            return myBean.changeValue(value);
        }
    
        public String convertToEntityAttribute(String dbValue) {
            return myBean.undoChange(dbValue);
        }
    }
    

    But creating this class and upgrading to Spring-Boot 2.1 (including Spring 5.1, Hibernate 5.3 and JPA 2.2) did not do the trick for me. The thing was, that I used LocalContainerEntityManagerFactoryBean to configure my persistent storage which will not enable Dependency injection for AttributeConverters. Reading the first link Ipandzic posted suggests you have to bring LocalSessionFactoryBuilder into play somehow. That's why I ended up with the following configuration:

    //...
    
    @Bean
    public LocalSessionFactoryBean entityManagerFactory(DataSource dataSource, Environment env) {
        LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
        factory.setDataSource(dataSource);
    
        // somehow tell the factory where you entitiy-definitions are, this is just
        // one possibility of doing so:
        String entityPackage = JpaMarkerModel.class.getPackage().getName();
        log.info("EntityManager will scan for entities in package [{}].", entityPackage);
        factory.setPackagesToScan(entityPackage);
    
        return factory;
    }
    
    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }
    
    //...
    

    This "answer" is merely an addition to Ipandzi's, but maybe it helps some people to solve their problem quicker than I did.

    0 讨论(0)
提交回复
热议问题