Reputation: 484
I have some Jpa repositories and several Entity class. I need to create a helper object for one of my Entity. Inside that helper I use @Autowire to access the Jpa repositories.
@Entity
class A {
@Transient
Helper helper;
...
}
class Helper {
A a;
@Autowired
CRepository repo;
public Helper(A a) {
this.a = a;
}
}
However, the repo is always null. I've tried using SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this) and @Configurable, but both of them failed. Can anybody provide some hint for me?
BTW, A is instantiated inside a rest controller.
Thanks!.
Upvotes: 1
Views: 8420
Reputation: 241
You can use a BeanUtil class to get any bean that created in Springl
@Service
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
Then you can get the bean.
MyBean obj = BeanUtil.getBean(MyBean.class);
Upvotes: 9
Reputation: 1308
@Configurable annotation works fine, but you need to use @EnableSpringConfigured annotation in any configuration class in order to make it work. Read my answer in other stackoverflow post: spring autowiring not working from a non-spring managed class
Entity class should not contain any helpers, even if transient. For a clean design you need to separate concerns, so the entity should not be aware of your business logic. I cannot help you more since I don't know which is the goal of that helper, but here you have other alternatives:
ALTERNATIVE 1 (based on your description seems that helper is an stateful bean, so it is not candidate to be a @Service, which I personally think it should be)
@Controller
public MyController {
@RequestMapping(...)
public void processRequest() {
A a = new A();
...
Helper helper = new Helper(a); // CRepository is successfully autowired
}
}
@Configurable(autowire = Autowire.BY_TYPE)
public class Helper {
A a;
@Autowired
CRepository repo;
}
@Configuration
@EnableSpringConfigured
public Application {
...
}
ALTERNATIVE 2 (make your Helper class stateless so that spring is aware of your beans without the need of extra stuff like @Confgurable/@EnableSpringConfigured)
@Controller
public MyController {
@Autowired Helper helper; // CRepository is correctly autowired
@RequestMapping(...)
public void processRequest() {
A a = new A();
...
helper.doSomething(a);
}
}
@Service
public class Helper {
// A a; remove dependency to A to make it stateless
@Autowired
CRepository repo;
public Helper() {
}
public void doSomething(A a) {
...
repo.save(a);
}
}
Upvotes: 0
Reputation: 77177
Use constructor injection instead of field injection; this is a best practice all the time anyway. Then it's trivial to inject your A
into the controller and pass it as a constructor argument.
Upvotes: 0
Reputation: 2102
You cannot autowire nothing in your Helper class because it isn't managed by Spring. You can use this approach:
public class HelperManager {
@Autowired
private ApplicationContext context;
public Helper getHelper(A a) {
return context.getBean(Helper.class, a);
}
Configure Helper to be a prototype bean:
@Configuration
public class MyConfiguration {
@Bean
public HelperManager helperManager() {
return new HelperManager();
}
@Bean
@Scope("prototype")
public Helper helper(A a) {
return new Helper(a);
}
}
And finally in your controller:
@Controller
public class MyController {
@Autowired
private HelperManager helperManager;
public someMethodWhereToInstanceYourHelper(A a) {
...
Helper helper = helperManager.getHelper(a);
...
}
}
Upvotes: -1