Inject spring beans into a non-managed class - java

I have this non-managed class that I want to inject spring beans (that I don't known a-priory what they are). How can I do that?
For example, let's say I have the following class:
public class NonManagedClass extends APIClass {
#Resource
private Service1 service;
#Resource
private Service2 service2;
// here i can declare many different dependencies
#Resource
private ServiceN serviceN;
#Override
public void executeBusinessStuffs() {
// business logics
}
}
I need in someway to let spring inject these dependencies in my class. I have access to these objects after created, so it's easy to me call any method that can accomplish this functionality. For example:
#Service
public void SomeAPIService {
#Resource
private BeanInjector beanInjector; // I'm looking for some funcionality of spring like this
public void someProcessingFunction(Class<? extends APIClass> clazz) throws Exception {
APIClass instance = clazz.getConstructor().newInstance();
beanInjector.injectBeans(instance);
instance.executeBusinessStuffs();
}
}
Does Spring have such functionality to inject beans based on fields annotation for a non-managed class?

Replace BeanInjector with ApplicationContext and you are almost there. From there you can get the AutowireCapableBeanFactory which provides some handy methods like createBean and autowireBean.
#Service
public void SomeAPIService {
#Resource
private ApplicationContext ctx;
public void someProcessingFunction(Class<? extends APIClass> clazz) throws Exception {
APIClass instance = ctx.createBean(clazz);
instance.executeBusinessStuffs();
}
}
or if you really like to construct stuff yourself instead of using the container:
#Service
public void SomeAPIService {
#Resource
private ApplicationContext ctx;
public void someProcessingFunction(Class<? extends APIClass> clazz) throws Exception {
APIClass instance = clazz.getConstructor().newInstance();
ctx.getAutowireCapableBeanFactory().autowireBean(instance);
instance.executeBusinessStuffs();
}
}

Related

How inject a service class into a class not managed by spring

I have this situation:
public class Other {
public void test() {
new ClassA().process();
}
}
public class ClassA {
#Autowired
private ClassB classB;
public void process() {
classB.executeSomething(); //--> NUllPOinter because classA was not created by spring.
}
}
#Service
public class ClassB {
public void executeSomething() {
// execute something
}
}
I tried use ApplicationContext but the problem continued.
Someone, have a idea what i should do ?
Thanks.
This is always the right way to declare a class dependency (always for annotated ioc spring bean):
public class ClassA {
private final ClassB objectB;
public ClassA(final ClassB objectB) {
this.objectB = objectB;
}
public void process() {
objectB.executeSomething();
}
}
In Other class, we should retrieve the singleton ClassB instance. Then it must be a bean component.
#Component
public class Other {
private final ApplicationContext applicationContext;
#Autowired
public Other(final ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void test() {
new ClassA(applicationContext.getBean(ClassB.class)).process();
}
}
If Other class can't be a spring component, you can't retrieve the application context and then you can't inject the ClassB instance.
You can clearly autowire directly the ClassB object instance into Other component, but this example underline that you can handle bean fetching with an ApplicationContext ref.

Autowired NullPointerException [duplicate]

Is there some way to use #Autowired with static fields. If not, are there some other ways to do this?
In short, no. You cannot autowire or manually wire static fields in Spring. You'll have to write your own logic to do this.
#Component("NewClass")
public class NewClass{
private static SomeThing someThing;
#Autowired
public void setSomeThing(SomeThing someThing){
NewClass.someThing = someThing;
}
}
#Autowired can be used with setters so you could have a setter modifying an static field.
Just one final suggestion... DON'T
Init your autowired component in #PostConstruct method
#Component
public class TestClass {
private static AutowiredTypeComponent component;
#Autowired
private AutowiredTypeComponent autowiredComponent;
#PostConstruct
private void init() {
component = this.autowiredComponent;
}
public static void testMethod() {
component.callTestMethod();
}
}
Create a bean which you can autowire which will initialize the static variable as a side effect.
Wanted to add to answers that auto wiring static field (or constant) will be ignored, but also won't create any error:
#Autowired
private static String staticField = "staticValue";
You can achieve this using XML notation and the MethodInvokingFactoryBean. For an example look here.
private static StaticBean staticBean;
public void setStaticBean(StaticBean staticBean) {
StaticBean.staticBean = staticBean;
}
You should aim to use spring injection where possible as this is the recommended approach but this is not always possible as I'm sure you can imagine as not everything can be pulled from the spring container or you maybe dealing with legacy systems.
Note testing can also be more difficult with this approach.
You can use ApplicationContextAware
#Component
public class AppContext implements ApplicationContextAware{
public static ApplicationContext applicationContext;
public AppBeans(){
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
then
static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);
Disclaimer This is by no means standard and there could very well be a better spring way of doing this. None of the above answers address the issues of wiring a public static field.
I wanted to accomplish three things.
Use spring to "Autowire" (Im using #Value)
Expose a public static value
Prevent modification
My object looks like this
private static String BRANCH = "testBranch";
#Value("${content.client.branch}")
public void finalSetBranch(String branch) {
BRANCH = branch;
}
public static String BRANCH() {
return BRANCH;
}
We have checked off 1 & 2 already now how do we prevent calls to the setter, since we cannot hide it.
#Component
#Aspect
public class FinalAutowiredHelper {
#Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}
#Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}
public class ModifySudoFinalError extends Error {
private String msg;
public ModifySudoFinalError(String msg) {
this.msg = msg;
}
#Override
public String getMessage() {
return "Attempted modification of a final property: " + msg;
}
}
This aspect will wrap all methods beginning with final and throw an error if they are called.
I dont think this is particularly useful, but if you are ocd and like to keep you peas and carrots separated this is one way to do it safely.
Important Spring does not call your aspects when it calls a function. Made this easier, to bad I worked out the logic before figuring that out.
Generally, setting static field by object instance is a bad practice.
to avoid optional issues you can add synchronized definition, and set it only if private static Logger logger;
#Autowired
public synchronized void setLogger(Logger logger)
{
if (MyClass.logger == null)
{
MyClass.logger = logger;
}
}
:
Solution 1 : Using Constructor #Autowired For Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
public MyClass(MyService service) {
TestClass.service= service;
}
}
Solution 2 : Using #PostConstruct to set the value to Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
private MyService srv;
#PostConstruct
public void init() {
this.service= srv;
}
}
Refer here for more detail
I use private static inner Component: FieldSetter, to inject static field: MyBean, at last SelfDestroyBean will help me remove redundant FiledSetter bean
public final class MyClass {
private static MyBean myBean;
#Component
private static class FieldSetter extends SelfDestroyBean {
public FieldSetter(MyBean myBean) {
MyClass.myBean = myBean;
}
}
}
#SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
#Autowired
private ApplicationContext context;
#PostConstruct
public void destroy() {
final String[] beanNames = context.getBeanNamesForType(this.getClass());
final BeanDefinitionRegistry registry =
((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
for (String beanName : beanNames) {
registry.removeBeanDefinition(beanName);
}
}
}
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);

Using Jersey's Dependency Injection in a Standalone application

I have a interface here
interface Idemo{
public int getDemo(int i);
}
And it's one implementation
class DemoImpl implements Idemo{
#Override
public int getDemo(int i){
return i+10;
}
}
And there is a class which has a dependency on Idemo
class Sample{
#Inject
Idemo demo;
public int getSample(int i){
return demo.getDemo(i);
}
}
Now say I want to test Sample class
public class SampleTest extends JerseyTest {
#Inject
Sample s;
#Override
protected Application configure() {
AbstractBinder binder = new AbstractBinder() {
#Override
protected void configure() {
bind(Demo.class).to(Idemo.class);
bind(Sample.class).to(Sample.class); //**doesn't work**
}
};
ResourceConfig config = new ResourceConfig(Sample.class);
config.register(binder);
return config;
}
#Test
public void test_getSample() {
assertEquals(15, s.getSample(5)); //null pointer exception
}
}
Here the Sample instance is not getting created and s remains null.I suppose this is because by the time the execution reaches line where binding is specified this test class has already been created.But I am not sure.With Spring Autowired instead of jersey CDI the same works
Had Sample been a resource/controller class the test framework would create an instance of it with no need to inject it but is it possible to test any other non-web class using Jersey DI ?
The reason it works with Spring is that the test class is managed by the Spring container by using #RunWith(SpringJUnit4ClassRunner.class). The runner will inject all managed objects into the test object. JerseyTest is not managed this way.
If you want, you can create your own runner, but you need to understand a bit how HK2 (Jersey's DI framework) works. Take a look at the documentation. Everything revolves around the ServiceLocator. In a standalone, you might see something like this to bootstrap the DI container
ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
ServiceLocator locator = factory.create(null);
ServiceLocatorUtilities.bind(locator, new MyBinder());
Then to get the service, do
Service service = locator.getService(Service.class);
In the case of the test class, we don't need to gain any access to the service object, we can simply inject the test object, using the ServiceLocator:
locator.inject(test);
Above, test is the test class instance that gets passed to us in our custom runner. Here is the example implementation of a custom runner
import java.lang.annotation.*;
import org.glassfish.hk2.api.*;
import org.glassfish.hk2.utilities.*;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.*;
public class Hk2ClassRunner extends BlockJUnit4ClassRunner {
private final ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
private Class<? extends Binder>[] binderClasses;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public static #interface Binders {
public Class<? extends Binder>[] value();
}
public Hk2ClassRunner(Class<?> cls) throws InitializationError {
super(cls);
Binders bindersAnno = cls.getClass().getAnnotation(Binders.class);
if (bindersAnno == null) {
binderClasses = new Class[0];
}
}
#Override
public Statement methodInvoker(FrameworkMethod method, final Object test) {
final Statement statement = super.methodInvoker(method, test);
return new Statement() {
#Override
public void evaluate() throws Throwable {
ServiceLocator locator = factory.create(null);
for (Class<? extends Binder> c : binderClasses) {
try {
ServiceLocatorUtilities.bind(locator, c.newInstance());
} catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
locator.inject(test);
statement.evaluate();
locator.shutdown();
}
};
}
}
In the runner, the methodInvoker is called for every test method, so we are creating a fresh new set of objects for each test method called.
Here is a complete test case
#Binders({ServiceBinder.class})
#RunWith(Hk2ClassRunner.class)
public class InjectTest {
public static class Service {
#Inject
private Demo demo;
public void doSomething() {
System.out.println("Inside Service.doSomething()");
demo.doSomething();
}
}
public static class Demo {
public void doSomething() {
System.out.println("Inside Demo.doSomething()");
}
}
public static class ServiceBinder extends AbstractBinder {
#Override
protected void configure() {
bind(Demo.class).to(Demo.class);
bind(Service.class).to(Service.class);
}
}
#Inject
private Service service;
#Test
public void testInjections() {
Assert.assertNotNull(service);
service.doSomething();
}
}
I was facing the same situation but in the context of running some integrations test that needs to have some of the singletons that my application have already defined.
The trick that I found is the following. You just need to create a normal test class or a standalone that use the DropwizardAppRule
In my case, I use JUnit as I was writing some integration test.
public class MyIntegrationTest{
//CONFIG_PATH is just a string that reference to your yaml.file
#ClassRule
public static final DropwizardAppRule<XXXConfiguration> APP_RULE =
new DropwizardAppRule<>(XXXApplication.class, CONFIG_PATH);
}
The #ClassRule will start your application like is said here . That
means you will have access to everything and every object your application needs to start. In my case, I need to get access to a singleton for my service I do that using the #Inject annotation and the #Named
public class MyIntegrationTest {
#ClassRule
public static final DropwizardAppRule<XXXConfiguration> APP_RULE =
new DropwizardAppRule<>(XXXAplication.class, CONFIG_PATH);
#Inject
#Named("myService")
private ServiceImpl myService;
}
Running this will set to null the service as #Inject is not working because we don't have at this point anything that put the beans into the references. There is where this method comes handy.
#Before
public void setup() {
ServiceLocator serviceLocator =((ServletContainer)APP_RULE.getEnvironment().getJerseyServletContainer()).getApplicationHandler().getServiceLocator();
//This line will take the beans from the locator and inject them in their
//reference, so each #Inject reference will be populated.
serviceLocator.inject(this);
}
That will avoid creating other binders and configurations outside of the existing on your application.
Reference to the ServiceLocator that DropwizardAppRule creates can be found here

How to make autowire object initialized in ApplicationListener?

I want to read data in ApplicationListener, but my object is not initialized. Below is my code:
AppContextListener.java
#Component
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
AppContext.getInstance();
}
}
AppContext.java
public class AppContext {
private static AppContext instance;
#Autowired
MyElasticsearchRepository repository;
public AppContext(){
InitData();
}
public static synchronized AppContext getInstance() {
if (instance == null) {
instance = new AppContext();
}
return instance;
}
private void InitData(){
List<MyEntity> dataList = repository.findAllEntities();//repository is null here
//.......
}
}
MyElasticsearchRepository.java
public interface MyElasticsearchRepository extends ElasticsearchRepository<MyEntity,String>
{ }
problem
As you can see in my code, at InitData(), repository is null. I don't
know why #Autowired MyElasticsearchRepository repository; does not
worked here.
Please show me how to fix this. Thank you very much.
There are a couple of things wrong with your code.
First you are using the singleton pattern which I would say is an anti-pattern especially when combined with auto wiring.
Second in your getInstance() method you are creating a new instance of AppContext yourself. This instance isn't managed by Spring so #Autowired is pretty much useless here, Spring is only able to inject dependencies into beans it knows about.
Instead make your AppContext a component (or service what ever you like). Remove the getInstance method and use constructor injection instead.
#Component
public class AppContext {
private final MyElasticsearchRepository repository;
#Autowired
public AppContext(MyElasticsearchRepository repository){
this.repository=repository;
}
...
}
Thirdly you are trying to use the #Autowired instance from the constructor (you are doing method call which expects it to be there), however auto wiring can only be done on an instance of a bean. So at that moment the auto wiring hasn't taken place and your variable will always be null. Instead of calling the method from the constructor either, use constructor inject or annotate the InitData method with #PostConstruct.
#PostConstruct
private void InitData(){
List<MyEntity> dataList = repository.findAllEntities();
...
}
Now that your AppContext is a component it will be detect by spring and you can simply inject it into your ApplicationListener.
#Component
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
private final AppContext appContext;
#Autowired
public AppContextListener(AppContext appContext) {
this.appContext=appContext;
}
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// Do your thing with appContext
}
}
Note: I prefer constructor injection for required fields and setter injection for optional fields. You should avoid field injection (i.e. #Autowired on instance fields) as that is considered a bad practice. See here why field injection is evil and should be avoided.
#Autowired will only work if bean is marked with Stereotype annotation (What's the difference between #Component, #Repository & #Service annotations in Spring?) or you explicitly define it in spring configuration.
AppContextListener.java
#Component // AFAIR not needed. Spring will create this bean when it will see that class implements `ApplicationListener` interface.
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
#Autowired
private AppContext appContext;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
appContext.initData();
}
}
AppContext.java
#Component
public class AppContext {
#Autowired
MyElasticsearchRepository repository;
public void initData(){
List<MyEntity> dataList = repository.findAllEntities();//repository is null here
//.......
}
}
#Autowired will work only after AppContext object constructed. Since you try to access #Autowired element inside constructor, it doesn't exist.
Can't you just do this?
#Component
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicantContext context = event.getApplicationContext();
MyElasticsearchRepository repository = context.getBean(MyElasticSearchRepository.class);
//do stuff
}
}
http://docs.spring.io/autorepo/docs/spring/4.1.4.RELEASE/javadoc-api/org/springframework/context/event/ContextRefreshedEvent.html

Can you use #Autowired with static fields?

Is there some way to use #Autowired with static fields. If not, are there some other ways to do this?
In short, no. You cannot autowire or manually wire static fields in Spring. You'll have to write your own logic to do this.
#Component("NewClass")
public class NewClass{
private static SomeThing someThing;
#Autowired
public void setSomeThing(SomeThing someThing){
NewClass.someThing = someThing;
}
}
#Autowired can be used with setters so you could have a setter modifying an static field.
Just one final suggestion... DON'T
Init your autowired component in #PostConstruct method
#Component
public class TestClass {
private static AutowiredTypeComponent component;
#Autowired
private AutowiredTypeComponent autowiredComponent;
#PostConstruct
private void init() {
component = this.autowiredComponent;
}
public static void testMethod() {
component.callTestMethod();
}
}
Create a bean which you can autowire which will initialize the static variable as a side effect.
Wanted to add to answers that auto wiring static field (or constant) will be ignored, but also won't create any error:
#Autowired
private static String staticField = "staticValue";
You can achieve this using XML notation and the MethodInvokingFactoryBean. For an example look here.
private static StaticBean staticBean;
public void setStaticBean(StaticBean staticBean) {
StaticBean.staticBean = staticBean;
}
You should aim to use spring injection where possible as this is the recommended approach but this is not always possible as I'm sure you can imagine as not everything can be pulled from the spring container or you maybe dealing with legacy systems.
Note testing can also be more difficult with this approach.
You can use ApplicationContextAware
#Component
public class AppContext implements ApplicationContextAware{
public static ApplicationContext applicationContext;
public AppBeans(){
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
then
static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);
Disclaimer This is by no means standard and there could very well be a better spring way of doing this. None of the above answers address the issues of wiring a public static field.
I wanted to accomplish three things.
Use spring to "Autowire" (Im using #Value)
Expose a public static value
Prevent modification
My object looks like this
private static String BRANCH = "testBranch";
#Value("${content.client.branch}")
public void finalSetBranch(String branch) {
BRANCH = branch;
}
public static String BRANCH() {
return BRANCH;
}
We have checked off 1 & 2 already now how do we prevent calls to the setter, since we cannot hide it.
#Component
#Aspect
public class FinalAutowiredHelper {
#Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}
#Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}
public class ModifySudoFinalError extends Error {
private String msg;
public ModifySudoFinalError(String msg) {
this.msg = msg;
}
#Override
public String getMessage() {
return "Attempted modification of a final property: " + msg;
}
}
This aspect will wrap all methods beginning with final and throw an error if they are called.
I dont think this is particularly useful, but if you are ocd and like to keep you peas and carrots separated this is one way to do it safely.
Important Spring does not call your aspects when it calls a function. Made this easier, to bad I worked out the logic before figuring that out.
Generally, setting static field by object instance is a bad practice.
to avoid optional issues you can add synchronized definition, and set it only if private static Logger logger;
#Autowired
public synchronized void setLogger(Logger logger)
{
if (MyClass.logger == null)
{
MyClass.logger = logger;
}
}
:
Solution 1 : Using Constructor #Autowired For Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
public MyClass(MyService service) {
TestClass.service= service;
}
}
Solution 2 : Using #PostConstruct to set the value to Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
private MyService srv;
#PostConstruct
public void init() {
this.service= srv;
}
}
Refer here for more detail
I use private static inner Component: FieldSetter, to inject static field: MyBean, at last SelfDestroyBean will help me remove redundant FiledSetter bean
public final class MyClass {
private static MyBean myBean;
#Component
private static class FieldSetter extends SelfDestroyBean {
public FieldSetter(MyBean myBean) {
MyClass.myBean = myBean;
}
}
}
#SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
#Autowired
private ApplicationContext context;
#PostConstruct
public void destroy() {
final String[] beanNames = context.getBeanNamesForType(this.getClass());
final BeanDefinitionRegistry registry =
((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
for (String beanName : beanNames) {
registry.removeBeanDefinition(beanName);
}
}
}
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);

Categories

Resources