When request is processed by spring controller, the service is not wired:
#Controller
#RequestMapping(value = "/login")
public class LoginController {
#Inject
private AccountService accountService;
#RequestMapping(method = RequestMethod.POST)
public String handleLogin(HttpServletRequest request, HttpSession session){
try {
...
//Next line throws NullPointerException, this.accountService is null
Account account = this.accountService.login(username, password);
} catch (RuntimeException e) {
request.setAttribute("exception", e);
return "login";
}
}
}
AccountService and its only implementation are defined in module service as:
package com.savdev.springmvcexample.service;
...
public interface AccountService {
...
package com.savdev.springmvcexample.service;
#Service("accountService")
#Repository
#Transactional
public class AccountServiceImpl implements AccountService {
The web configuration is loaded by files, located in web module:
package com.savdev.springmvcexample.web.config;
public class SpringMvcExampleWebApplicationInitializer implements WebApplicationInitializer
{
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerDispatcherServlet(servletContext);
}
private void registerDispatcherServlet(final ServletContext servletContext) {
WebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class);
...
}
private WebApplicationContext createContext(final Class<?>... annotatedClasses) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
return context;
}
The WebMvcContextConfiguration file that scans packages to discovery beans:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.savdev.springmvcexample.web", "com.savdev.springmvcexample.service" })
public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setOrder(1);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
This class is loaded, cause view resolving is used according to InternalResourceViewResolver logic. As a result the "com.savdev.springmvcexample.web" is scanned cause controller that processes request is found.
The "com.savdev.springmvcexample.service" is scanned, but it is in another module, I don't know can it be an issue or not, but I don't get any errors.
UPDATED:
#JBNizet, module - means module in maven multimodule project. I've removed #Repository and now I'm getting an error in test:
NoSuchBeanDefinitionException: No qualifying bean of type
[javax.sql.DataSource] found for dependency.
That means, that means the spring profile is not activated. DataSource is loaded only for profiles.
In web infrastructure I manage profiles with:
public class SpringMvcExampleProfilesInitializer implements ApplicationContextInitializer<ConfigurableWebApplicationContext> {
#Override
public void initialize(ConfigurableWebApplicationContext ctx) {
ConfigurableEnvironment environment = ctx.getEnvironment();
List<String> profiles = new ArrayList<String>(getProfiles());
if( profiles == null || profiles.isEmpty() )
{
throw new IllegalArgumentException("Profiles have not been configured");
}
environment.setActiveProfiles(profiles.toArray( new String[0]));
}
//TODO add logic
private Collection<String> getProfiles() {
return Lists.newArrayList("file_based", "test_data");
}
}
If I'm not wrong SpringMvcExampleProfilesInitializer is used before Spring ApplicationContext is loaded. And it is made automatically. Nothing additional has to be configured for this. But it's not working. Please fix me, if I'm wrong.
Please note, the initializer has the following signature:
SpringMvcExampleProfilesInitializer implements ApplicationContextInitializer<ConfigurableWebApplicationContext>
At the moment when DispatcherServlet is configured I can setup it using:
setContextInitializers(ApplicationContextInitializer<ConfigurableApplicationContext>... contextInitializers)
How can I setup setContextInitializers but pass something that implements ApplicationContextInitializer<ConfigurableWebApplicationContext>, but not ApplicationContextInitializer<ConfigurableApplicationContext>
#Inject requires the presence of the JSR 330 jar on the classpath. It could be that it's visible at compile time but not at runtime.
Try this:
#Autowired(required=true)
private AccountService accountService;
If this does not work, it means that the bean AccountServiceImpl is not being scanned correctly.
If it does work, it means that there is a problem with #Inject support (maybe a missing jar at runtime).
If the scanning is not working, try to do the scanning via xml:
<context:component-scan base-package="com.savdev.springmvcexample.service" />
Can you post back:
If #Autowired(required=true) works
if and how the JSR-330 is added in the poms (output of mvn dependency:tree)
did the scanning via xml worked
Related
I have this project hierarchy:
A SpringConfiguration.java file with one Bean (SoapServiceBean).
A LoggerUtilsConfiguration.java with two beans (ConfigManager and LoggerManager).
SpringConfiguration imports LoggerUtilsConfigueration with an #Import.
The code:
#Configuration
#Import({com.myApp.LoggerUtilsConfiguration.class})
public class SpringConfiguration {
#Lazy
#Bean(name = "soapServiceBean")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit(
#Qualifier("configManager") ConfigManager configManager ,
#Qualifier("loggerManager") LoggerManager loggerManager)
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
}
#Configuration
public class LoggerUtilsConfiguration {
#Bean(name = "configManager")
#Scope(BeanDefinition.SINGLETON)
public ConfigManager configManagerInit() {
ConfigManager cManager = new ConfigManager();
return cManager;
}
#Bean(name = "loggerManager")
#Scope(BeanDefinition.SINGLETON)
public LoggerManager loggerManagerInit() {
LoggerManager cManager = new LoggerManager();
return cManager;
}
}
My problema is that, "configManager" is a valid bean, but loggerManager throws this Exception:
No qualifying bean of type [com.myApp.LoggerManager] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Qualifier(value=loggerManager)}
Is very Strange, because If I copy the loggerManager Bean method into the main #Configuration class, the app starts with no problem and loggerManager is started with no problem.
"LoggerUtilsConfiguration" is not part of my App, is a Maven dependency external jar from another dev team. I have decompiled it and I cannot see anything strange, "configManager" and "loggerManager" has the same annotations with the same values except the bean name.
Any idea?
Solved.
My problem is the WebSphere, that store an old version of the third party JAR.
\was\wasprofiles\wp_profile80\installedApps\GUUPZN00Cell\MY-APP.ear\lib\LOGGER-LIB-1.0.0.jar
\was\wasprofiles\wp_profile80\installedApps\GUUPZN00Cell\MY-APP.ear\lib\LOGGER-LIB-1.0.1.jar
The version "1.0.0" LOGGER-LIB doesn't contains the bean "loggerManager" and WebSphere is loading this version of the library.
It seems that the file was blocked when websphere try to delete it. I had to stop the server to delete it properly.
If the 2 managers are singletons you can #Autowired them in.
If there is an existing bean called loggerManager of a different type then it wouldn't find yours, but it depends on how your classpath is set up.
#Configuration
#Import({com.myApp.LoggerUtilsConfiguration.class})
public class SpringConfiguration {
#Autowired
ConfigManager configManager;
#Autowired
LoggerManager loggerManager;
#Lazy
#Bean(name = "soapServiceBean")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit()
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
}
Try to use #DependsOn:
#Lazy
#Bean(name = "soapServiceBean")
#DependsOn({ "configManager", "loggerManager" })
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit(
#Qualifier("configManager") ConfigManager configManager ,
#Qualifier("loggerManager") LoggerManager loggerManager)
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
Try providing autowire annotation to properly enable constructor injection like :
#Configuration
#Import({com.myApp.LoggerUtilsConfiguration.class})
public class SpringConfiguration {
#Lazy
#Autowired
#Bean(name = "soapServiceBean")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit(
#Qualifier("configManager") ConfigManager configManager ,
#Qualifier("loggerManager") LoggerManager loggerManager)
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
}
The #Qualifier annotation is used to resolve the bean based on names while the #Autowired annotation provides constructor injection of beans. The #Bean annotation should support constructor injection without the need for #Autowired
In my non-Boot Spring 5 project I need to manually register and initialize some beans. After that I want to add a #Configuration class to context, that imports a config from an external lib:
#Configuration
#Import(ExtLibConfig.class)
public class MyExtLibConfig {
#Bean
public ExtLibBean extLibBean() {
return ExtLibBean.builder().build();
}
}
ExtLibConfig has many of its own #ComponentScan and #Import, and I wish them all to be configured automatically, including my ExtLibBean.
Is it possible to do so in runtime? External lib scans ApplicationContext, and I need it to do so, when my manually registered beans are added.
UPD:
The problem is not actual about beans register order. The ext lib is scanning ApplicationContext after its refresh, so I need my beans to be there at this time
The solution was to implement BeanDefinitionRegistryPostProcessor
public class MyMockBeanDefinitioRegistrynPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// registry.registerBeanDefinition(mockBeanClass, mockBeanDefinition);...
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// nothing to do
}
Then declare it as a Bean:
#Configuration
public class MockBeanConfig {
#Bean
public MyMockBeanDefinitioRegistrynPostProcessor mockBeanDefinitionPp() {
return new MyMockBeanDefinitioRegistrynPostProcessor();
}
}
And add it to context:
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MockBeanConfig.class);
context.register(MyExtLibConfig.class);
context.refresh();
I know there are lot of questions on this topic. I have read the spring boot doc and all of the solutions here. According spring boot doc, #ServerEndpoint is a Javax annotation and #Autowired components are spring-boot managed. These two cannot be used together. The solution to this would be to add SpringConfigurator as configurator of the ServerEndpoint. When I tried this I do get the following error:
Failed to find the root WebApplicationContext. Was ContextLoaderListener not used?
There is no example in the spring-boot websocket page to use ContextLoaderListener. How can use ContextLoaderListener so that components can be injected into #ServerEndpoint annotated controllers?
The following is my code.
Websocket controller
#ServerEndpoint(value = "/call-stream", configurator = SpringConfigurator.class)
public class CallStreamWebSocketController
{
#Autowired
private IntelligentResponseService responseServiceFacade;
// Other methods
}
Websocket configurations
#Configuration
public class WebSocketConfiguration
{
#Bean
public CallStreamWebSocketController callStreamWebSocketController()
{
return new CallStreamWebSocketController();
}
#Bean
public ServerEndpointExporter serverEndpointExporter()
{
return new ServerEndpointExporter();
}
}
Edit:
This has been tagged as a duplicate of this question. I have tried the solution specified in the answers. The solution is to add SpringConfigurator as configurator of the #ServerEndpoint. After adding this I still do get the error mentioned in the details.
After some research I found a way to force spring-boot to inject a component into an externally managed/instantiated class.
1) Add a generic method to your class extending ApplicationContextAware to return a bean.
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringContext.context = context;
}
public ApplicationContext getApplicationContext() {
return context;
}
// Generic method to return a beanClass
public static <T> T getBean(Class<T> beanClass)
{
return context.getBean(beanClass);
}
}
2) Use this method to initialize the class object you want to be injected
private IntelligentResponseService responseServiceFacade = SpringContext.getBean(IntelligentResponseService.class);
So after the above changes my websocket controller would look like this
#ServerEndpoint(value = "/call-stream", configurator = SpringConfigurator.class)
public class CallStreamWebSocketController
{
private IntelligentResponseService responseServiceFacade = SpringContext.getBean(IntelligentResponseService.class);
// Other methods
}
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
}
}
I have a problem setting Spring Security up.
So to start with, I have a Configuration class, something like this:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity
#ComponentScan("com.boardviewer")
public class BoardviewerConfiguration extends WebSecurityConfigurerAdapter {
#Inject
private BoardviewerSecurityService boardviewerSecurityService;
#Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean /* The "${props} can now be parsed before runtime with this bean declaration */
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
/* Spring Sec */
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider dao = new DaoAuthenticationProvider();
dao.setUserDetailsService(boardviewerSecurityService);
return dao;
}
#Bean
public ProviderManager providerManager() {
List<AuthenticationProvider> list = new ArrayList<AuthenticationProvider>();
list.add(daoAuthenticationProvider());
return new ProviderManager(list);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth.authenticationProvider(daoAuthenticationProvider());
auth.userDetailsService(boardviewerSecurityService);
}
}
Basically some basic WebSecurity configs...
I'm not getting ANY errors, but I can browse around the site normally without any restrictions.
For instance, I have a controller with the #PreAuthorize annotation, and I get straight through it.
I'm running Spring Security 3.2.0 RC2 to be able to get an annotation configuration going... But so far no luck.
Is there any additional config in the web.xml needed? Or am I missing something?
Anyone got an example of a working Spring Security annotation config?
Also, I'm using hibernate to fetch User accounts etc, and my boardviewerSecurityService looks like this:
#Service
public class BoardviewerSecurityService implements UserDetailsService {
#Inject
private UserDAO userDAO;
#Inject
private BoardviewerTransformer transformer;
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User u = userDAO.getByUsername(s);
if(u == null) {
throw new UsernameNotFoundException("Couldn't find a user with that username");
} else {
return transformer.userToSpringUser(u);
}
}
}
And the transformer simply remaps the entity to a Spring UserDetails User object (org.springframework.security.core.userdetails.User)
Am I missing something? (A part from setting up the login page and url interceptors? I thought I won't need those since I only want to control access on class / method level)
Would appreciate any help!
Regards