Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection into Spring non-managed beans

I have a JPA domain class that is non managed. It is instantiated via the new operator.

UserAccount account = new UserAccount();
userRepository.save(account)

In my UserAccount class, I have a beforeSave() method which is dependent on my SecurityService to hash encode a password.

My questions is "How do I get spring DI to inject the security service into my entity?". Seems that AspectJ and LoadTimeWeaving is what I need. I've tried an array for configurations, but I can't seem to get any of them to work. I always get a NullPointerException when trying to call a method on the injected object.

UserAccount.java (This is the JPA Entity)

@Entity
@Repository
@Configurable(autowire = Autowire.BY_TYPE)
public class UserAccount implements Serializable {

    @Transient
    @Autowired
    SecurityService securityService;

    private String passwordHash;

    @Transient
    private String password;

    public UserAccount() {
        super();
    }

    @PrePersist
    public void beforeSave() {
        if (password != null) {
            // NullPointerException Here!!!
            passwordHash = securityService.hashPassword(password);  
        }
    }
}

Trying to indicate to spring to use AspectJ:

NitroApp.java (The main class)

@SpringBootApplication
@EnableTransactionManagement
@EnableSpringConfigured
@PropertySources(value = {@PropertySource("classpath:application.properties")})
public class NitroApp extends SpringBootServletInitializer {


    public static void main (String[] args) {
        SpringApplication.run(NitroApp.class);
    }

}

build.gradle (Configuration)

buildscript {
    repositories {
        mavenCentral()
        jcenter()
    }

    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:1.2.2.RELEASE"
        classpath "org.springframework:springloaded:1.2.2.RELEASE"
        classpath "org.springframework:spring-aspects:4.1.6.RELEASE"
    }
}

apply plugin: 'java'
apply plugin: 'aspectj'
apply plugin: 'application'
apply plugin: 'idea'
apply plugin: 'spring-boot'

repositories {
    jcenter()
    mavenLocal()
    mavenCentral()
}

mainClassName = 'com.noxgroup.nitro.NitroApp'
applicationName = "Nitro"

idea {
    module {
        inheritOutputDirs = false
        outputDir = file("$buildDir/classes/main/")
    }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.springframework.boot:spring-boot-starter-actuator")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("net.sourceforge.nekohtml:nekohtml:1.9.15")
    compile("commons-codec:commons-codec:1.9")
    compile("org.postgresql:postgresql:9.4-1201-jdbc41")
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.3'
}
like image 816
sparkyspider Avatar asked Jun 17 '15 11:06

sparkyspider


People also ask

Can we use @bean without configuration?

@Bean methods may also be declared within classes that are not annotated with @Configuration. For example, bean methods may be declared in a @Component class or even in a plain old class. In such cases, a @Bean method will get processed in a so-called 'lite' mode.

Can we use @autowired in normal class?

It depends on how you bootstrap your applciation, but you can use <context:component-scan base-package="com. myCompany. myProject" /> for XML config or @ComponentScan for java configuration.


1 Answers

You can inject Spring applicationContext in the class used to instanciate UserAccount.

@Autowired
private ApplicationContext applicationContext;

Then, create your UserAccount bean this way :

UserAccount userAccount = applicationContext.getBean(UserAccount.class);

This way, you can inject your required dependencies in the UserAccount class.

like image 148
Baptiste Avatar answered Sep 25 '22 09:09

Baptiste