i want to create a custom el functions to get in a fast way select options from dao. I'm using Spring and i want to inject spring bean dao in my custom el functions class.
In el functions class i'm using static methods and i'm unable to access application context.
I used an implementation of ApplicationContextAware in this way
public class AppContextUtil implements ApplicationContextAware
{
private ApplicationContext applicationContext;
private static final AppContextUtil instance=new AppContextUtil();
private AppContextUtil()
{
}
public static AppContextUtil getInstance()
{
return instance;
}
public <T> T getBean(Class<T> clazz)
{
return applicationContext.getBean(clazz);
}
/**
* {#inheritDoc}
*/
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
}
but applicationContext is null.
The only way to access to applicationContext is as belove
WebApplicationContext appCtx =
WebApplicationContextUtils.getWebApplicationContext(context.getServletContext());
MyDAO myDAO = appCtx.getBean(MyDAO.class);
but in this way i need to pass PageContext in el functions params.
How i can create an el functions class with spring bean support? how i can access in static way to applicationContext?
Thank you.
A dirty solution to "inject" a bean or Application Context into an static field:
#Component
public class AppContextUtil {
private static ApplicationContext applicationContext;
#Autowire
private set ApplicationContext(ApplicationContext applicationContext) {
AppContextUtil.applicationContext = applicationContext;
}
}
Related
I am using JUnit5, with sureFire version:
<maven.surefire.plugin.version>3.0.0-M5</maven.surefire.plugin.version>
and code
#ExtendWith(MockitoExtension.class)
#ContextConfiguration(classes =....ContextConfiguration.class)
#TestPropertySource({"classpath:application-${env:dev}.properties", "classpath:app-${env:dev}.properties"})
class TestRunner{
#Test
void testService(){
BeanUtils.getBean(...);
}
}
#Service
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext; // NOSONAR
}
/**
* Use this method to manually autowire Spring Beans into classes that are not managed by Spring.
*
* #param beanClass - Class type of the required bean.
**/
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
My ContextConfigurationClass has #ComponentScan directed to BeanUtils class, but the ApplicationContext is always null, not autowired.
I am using #ExtendWith(MockitoExtension.class) cuz i am also mocking in the test.
What JUnit5extension do i need to use in order to init it?
You should use SpringExtension.
You could also check this post to understand the differences between MockitoExtension and SpringExtension
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();
}
}
I am using Spring beans in a non-spring framework and for that I have implemented the ApplicationContextAware to access the spring beans.
#Service
public class ApplicationContextProviderService implements ApplicationContextAware {
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextProviderService.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> beanType) {
System.out.println("bean out: " + applicationContext);
return applicationContext.getBean(beanType);
}
}
I try to access a Spring service: ConnectionStateService from the non-spring class:
this.connectionStateService = ApplicationContextProviderService.getBean(ConnectionStateService.class);
I get the following error:
java.lang.IllegalStateException:
**org.springframework.context.annotation.AnnotationConfigApplicationContext#7f485fda has not been refreshed yet at
** org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:1072) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1102) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE] at com.example.app.service.ApplicationContextProviderService.getBean(ApplicationContextProviderService.java:19) ~[classes/:na] at com.example.app.CustomFilter.<init>(CustomFilter.java:26) ~[classes/:na]
How to resolve this issue?
The issue is related when the application tries to call to ApplicationContext before the application runs, so you won't be able to have application context because it wasn't created. The solution is create a singleton for ConnectionStateService class so you won't need to create a service for calling the ApplicationContext.
public class ConnectionStateService {
// static variable instance of type Singleton
private static ConnectionStateService single_instance = null;
// private constructor restricted to this class itself
private ConnectionStateService() {
// some stuffs for initialize here
}
// static method to create instance of Singleton class
public static ConnectionStateService getInstance() {
if (instance == null)
instance = new ConnectionStateService();
return instance;
}
}
I think you are getting the bean when the context is not initialized
So actually be sure you are invoking this piece of code :
this.connectionStateService = ApplicationContextProviderService.getBean(ConnectionStateService.class);
after context is initialized
I have instances of the same class being created from config values such that I need them to be injected/autowired from that config value. I was doing it in guice like:
for (String s : config.getStrings()) {
bind(Foo.class).annotatedWith(Names.named(s)).toInstance(new Foo(s));
}
Is there any way to do something like this in Spring or is there a way to use something like a FactoryBean to create instances of a class given a qualifier?
public final class FLEXSyncFactory implements ApplicationContextAware {
private static AbstractApplicationContext context;
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context = (AbstractApplicationContext) applicationContext;
}
And to register alias of bean
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
Foo fooBean = beanFactory.getBean(Foo.class);
beanFactory.initializeBean(fooBean, "TheAliasForBeanNameYouNeed");
beanFactory.autowireBeanProperties(fooBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
I am working on a Spring Boot application wherein I am using that application to expose a SOAP webservice. I am using Apache CFX framework for SOAP impl in Spring boot app. I am using Annotation based approach.
I am facing issue in setting the Application Context from the Spring Boot Configuration file in one of the Beans. Below is my code.
#SpringBootApplication
#ComponentScan("com.test")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The configuration file is as below.
#Configuration
public class WebServiceConfiguration {
//All individual bean definitions should go here
#Autowired
ApplicationContext appContext;
#Bean
public ServletRegistrationBean cxfServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/soap-api/*");
}
#Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean(name="IValidator")
public IValidator getValidator(){
return new Validator();
}
#Bean(name="SOAPprocessImpl")
public IPSoap getService() {
return new SOAPprocessImpl();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), getService());
endpoint.publish("/WS_1.0");
endpoint.setWsdlLocation("process.wsdl");
return endpoint;
}
Now I have the bean SOAPprocessImpl implementation in which I need to get the Application Context so that I can get handle to the Validator bean. I have declared SOAPprocessImpl as a bean in the configuraton file. The code is as below
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap, ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
context = ac;
}
private static final Logger logger = Logger.getLogger(SOAPprocessImpl.class.getName());
private IValidator validator = (IValidator) context.getBean("IValidator"); // context is NULL here
public IRResponse GetBalance(TSSearchParams SearchParams) {
// Some processing logic
}
}
So the issue is that when I run the boot application by deploying to the embedded Tomcat then the Application Context is not getting set in the SOAPprocessImpl class even after implementing the ApplicationContextAware. I also tried Autowiring but that also is not working.
Strangely I tried to see if I can get the ApplicationContext in the Configuration file where all the bean are defined. Here it is getting setting properly.
Can anyone help me how to solve this issue. I am new to Spring Boot and may have missed some configutaion. Thanks in advance.
Option(1): To fix the issue, you need to use #Configuration to register your SOAPprocessImpl bean to the Spring container as shown below so that ApplicationContext object can be injected :
#Configuration
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap, ApplicationContextAware {
private static ApplicationContext context;
private IValidator validator;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
SOAPprocessImpl.context = ac;
}
#PostConstruct//use PostConstruct
public void init() {
validator = (IValidator) context.getBean("IValidator");
}
//add your current code
}
The important point is that you can't use the context object until the bean is prepared by the container, so you need to use #PostConstruct method as shown above to initialise your variables.
Option2 (recommended):
The best approach is that you can use #Autowired to inject IValidator object into SOAPprocessImpl as shown below so that you don't need your SOAPprocessImpl bean to be aware of ApplicationContextAware. Spring container will inject the instance for the implementation provided for the IValidator class (provided it is under the packages of #Componentscan).
#Component
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap {
private static final Logger logger = Logger.getLogger(SOAPprocessImpl.class.getName());
#Autowired //spring directly injects this object
private IValidator validator;
public IRResponse GetBalance(TSSearchParams SearchParams) {
// Some processing logic
}
}