Did ComponentScan work in my SpringMVCproject? - java

I have a project based on SpringMVC 5 and an error happened when I tried to run it on JBoss EAP 7.3.
14:33:14,134 DEBUG
[org.springframework.beans.factory.support.DefaultListableBeanFactory]
(ServerService Thread Pool -- 99) Creating shared instance of
singleton bean 'userDetailsService'
14:33:14,140 ERROR [org.springframework.web.context.ContextLoader]
(ServerService Thread Pool -- 99) Context initialization failed:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'springSecurityFilterChain' defined in
org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration:
Bean instantiation via factory method failed;......nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'com.aaa.bbb.security.service.UserService'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here's the code of class "UserDetailsServiceImpl":
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserService userService;
#Autowired
private SessionUtils sessionUtils;
#Override
public UserDetails loadUserByUsername(String userID) throws UsernameNotFoundException {
User user = userService.get(userID);
if (user == null) throw new UsernameNotFoundException("Could not find user");
sessionUtils.expireUserSessions(user.getUser_name()); // Force expire other session
return new UserDetailsInfo(user);
}
}
And here's the code of class "UserService":
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
public User get(String id) {
return userRepository.findById(id).get();
}
public User getuUserByUsername(String user_name) {
return userRepository.getuUserByUsername(user_name);
}
public int incLoginErrorCount(String id) {
return userRepository.incLoginErrorCount(id);
}
public int resetLoginErrorCount(String id) {
return userRepository.resetLoginErrorCount(id);
}
public int lockCount(String id) {
return userRepository.lockCount(id);
}
public int changeUPassword(String id, String password) {
return userRepository.changeUPassword(id, password);
}
}
And I'm using "WebAppInitializer":
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
private String TMP_FOLDER = "/tmp";
private int MAX_UPLOAD_SIZE = 5 * 1024 * 1024;
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { WebSecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebMvcConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Filter[] getServletFilters() {
return new Filter[] { new HiddenHttpMethodFilter(), new MultipartFilter(),
new OpenEntityManagerInViewFilter() };
}
#Override
protected void registerDispatcherServlet(ServletContext servletContext) {
super.registerDispatcherServlet(servletContext);
servletContext.addListener(new HttpSessionEventPublisher());
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
MultipartConfigElement multipartConfigElement = new MultipartConfigElement(TMP_FOLDER, MAX_UPLOAD_SIZE,
MAX_UPLOAD_SIZE * 2, MAX_UPLOAD_SIZE / 2);
registration.setMultipartConfig(multipartConfigElement);
}
}
To call "WebMvcConfig":
#ComponentScan(basePackages = {"com.aaa.bbb"})
public class WebMvcConfig implements WebMvcConfigurer {
#Bean(name = "viewResolver")
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(100000);
return multipartResolver;
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**", "/resources/**", "/resources/**", "/webjars/**", "/log/**")
.addResourceLocations("classpath:/css/", "classpath:/js/", "classpath:/json/", "/webjars/", "/META-INF/");
}
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasenames("message/messages");
source.setUseCodeAsDefaultMessage(true);
source.setDefaultEncoding("UTF-8");
return source;
}
}
If #ComponentScan worked, this error should not happen.
Thank you!

I think you should use #Service annotation on the UserDetailsServiceImpl class too. Since it is not annotated, componentScan doesn't know that it should autowire the services inside it. So UserDetailsServiceImpl class should look like this.
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserService userService;
#Autowired
private SessionUtils sessionUtils;
#Override
public UserDetails loadUserByUsername(String userID) throws UsernameNotFoundException {
User user = userService.get(userID);
if (user == null) throw new UsernameNotFoundException("Could not find user");
sessionUtils.expireUserSessions(user.getUser_name()); // Force expire other session
return new UserDetailsInfo(user);
}
}

Related

Spring configuration without Spring Boot

I've been trying to configure Spring without Spring Boot.
I added a Tomcat, created the MainController class, and configured the Dispatcher Servlet
but in an endpoint 'http://localhost:8080/main/hello I receive 404.
I think it is problem in the ServletDispatcherConfig.
This is my  ServletDispatcherConfig  class
#Component
public class ServletDispatcherConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {SpringConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
and this is my SpringConfig class
#Configuration
#ComponentScan("example.test")
#EnableWebMvc
public class SpringConfig {
private final ApplicationContext applicationContext;
#Autowired
public SpringConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
var resolver = new SpringResourceTemplateResolver();
resolver.setCacheable(true);
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
resolver.setApplicationContext(applicationContext);
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
var engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
engine.setEnableSpringELCompiler(true); // delete if any bugs will be
return engine;
}
#Bean
public ThymeleafViewResolver viewResolver() {
var templateResolver = new ThymeleafViewResolver();
templateResolver.setTemplateEngine(templateEngine());
return templateResolver;
}
}
my MainController class
#Controller
#RequestMapping("/main")
public class MainController {
#GetMapping("/first")
public String main() {
return "/main";
}
#GetMapping("/hello")
public String hello() {
return "/main";
}
}

Unsatisfied dependency expressed through field 'userDetailsService'; NoSuchBeanDefinitionException: 'org.springframework.securityUserDetailsService'

It seems that Spring can't autowire the UserDetailsService. I don't understand why.
WebConfig.java:
#Configuration
#ComponentScan("testproject")
#EnableWebMvc
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "testproject",
entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setViewClass(JstlView.class);
bean.setPrefix("/WEB-INF/view/");
bean.setSuffix(".html");
return bean;
}
#Bean
public UserDetailsService userDetailsService() {
UserDetailsService userDetailsService =
new UserDetailsServiceImpl();
return userDetailsService;
}
}
MyAppInitializer.java:
public class MyAppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
public void onStartup(final ServletContext sc) throws ServletException {
System.out.println("onStartup!");
AnnotationConfigWebApplicationContext root =
new AnnotationConfigWebApplicationContext();
root.register(WebConfig.class);
root.setServletContext(sc);
root.scan("testproject");
sc.addListener(new ContextLoaderListener(root));
ServletRegistration.Dynamic appServlet =
sc.addServlet("dispatcher", new DispatcherServlet(new GenericWebApplicationContext()));
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/");
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {SecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
SecurityConfig.java:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Bean
DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider =
new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(this.userDetailsService);
return daoAuthenticationProvider;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
// dont authenticate this particular request
// .authorizeRequests().antMatchers("/login").permitAll()
// all other requests need to be authenticated
.authorizeRequests().anyRequest().authenticated().and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
SecurityWebApplicationInitializer.java:
public class SecurityWebApplicationInitializer extends
AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(SecurityConfig.class);
}
}
Full error:
Error creating bean with name 'securityConfig':
Unsatisfied dependency expressed through field 'userDetailsService'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type
'org.springframework.security.core.userdetails.UserDetailsService'
available: expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Any help is appreciated!
EDIT:
UserDetailsServiceImpl.java:
#Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user != null) {
return new UserDetailsImpl(user);
} else {
throw new UsernameNotFoundException("User not found.");
}
}
}
Your #ComponentScan should point to the package of the classes, I'm assuming testproject is not the package name.

I can not Inject Spring Beans into Test using TestNG launcher (Multithreading)

#TransactionConfiguration
#Transactional
#ContextConfiguration(classes=AnnotationConfigContextLoaderUtils.class)
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
public class AnyTest extends TestMachine {
#Inject
private AccountDao accDao; //ALLWAYS NULL
I run the test with:
TestNG testNG = new TestNG();
AppConfig.java
#Bean
public SessionScope sessionScope(){
return new SessionScope();
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public JdbcTemplate jdbcTemplate() throws ConfigurationException {
return new JdbcTemplate(dataSource());
}
#Bean
public DataSource dataSource() throws ConfigurationException {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
//DB INITIALIZE
}
#Bean(name = "sessionFactory")
public LocalSessionFactoryBean sessionFactory() throws ConfigurationException {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan("package.model");
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
#Bean
public HibernateTransactionManager transactionManager() throws ConfigurationException {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put("hibernate.hbm2ddl.auto", hibernateAuto);
properties.put("hibernate.dialect", hibernateDialect);
properties.put("hibernate.show_sql", showSQL);
return properties;
}
SpringMVCInitializer.java
public class SpringMVCInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {AppConfig.class, SpringMVCConfiguration.class, SimpleCORSFilter.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Maven dependency versions:
<spring-version>4.0.3.RELEASE</spring-version>
<spring-test>4.0.3.RELEASE</spring-test>
<testNG-Version>6.9.4</testNG-Version>
<hibernate.version>4.1.5.Final</hibernate.version>
<hibernate-validator>4.2.0.Final</hibernate-validator>
<mysql.connector.version>5.1.32</mysql.connector.version>
<dbcp.version>1.4</dbcp.version>
Why I can't inject any bean to a test?
Note: I used #Autowired and it did not work too.
One sugestion is inject the session in the main method I used to run the test.
Is any way to make this?
I resolved this problem creating a Static Class and injecting the dependencies into this class in a controller.
Controller:
#Controller
public class InitController {
#Inject
public InitController(TestDao testDao, InsynctivePropertyDao propertyDao, ServletContext servletContext, AccountDao accDao, CrossBrowserAccountDao crossDao, CreatePersonFormDao createPersonFormDao, TestSuiteDao testSuiteDao) {
HibernateUtil.init(testDao, propertyDao, servletContext, accDao, crossDao, createPersonFormDao, testSuiteDao);
}
}
HibernateUtil.java
public class HibernateUtil {
public static CrossBrowserAccountDao crossDao;
public static TestDao testDao;
public static synchronized void init(TestDao testDao, InsynctivePropertyDao propertyDao, ServletContext servletContext, AccountDao accDao, CrossBrowserAccountDao crossDao, CreatePersonFormDao createPersonFormDao, TestSuiteDao testSuiteDao){
HibernateUtil.crossDao = crossDao;
HibernateUtil.testDao = testDao;
}
}

Use #Autowired in Spring MVC and JavaConfig

I have spring mvc project and i don't use #Autowired because my object always is null. How me load JavaConfig for using #Autowired, i do not use any *.xml file.
This is my controller with #Autowired field for service.
#Controller
public class WebController {
#Autowired
private ServiceWeb serviceWeb;
public void setServiceWeb(ServiceWeb serviceWeb) {
this.serviceWeb = serviceWeb;
}
...
}
This is my AbstractAnnotationConfigDispatcherServletInitializer
public class ServletInit extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SpringRootConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SpringWebConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
SpringRootConfig & SpringWebConfig
#Configuration
#ComponentScan({"web.controller"})
public class SpringRootConfig {
}
#EnableWebMvc
#Configuration
#ComponentScan({ "web.controller"})
#Import({SecurityConfig.class})
public class SpringWebConfig extends WebMvcConfigurerAdapter{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver
= new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
Class for #Autowiring
#Configuration
public class ConfigurationBean {
#Bean
public ServiceWeb serviceWeb(){
return new ServiceWebImpl();
}
}
Register context for spring, but where need write Init.class for loading this config ?
public class Init implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ConfigurationBean.class);
servletContext.addListener(new ContextLoaderListener(ctx));
ctx.setServletContext(servletContext);
}
}
Pls try this...
#Service
public class ServiceWebImpl implements ServiceWeb {
}
ServiceWeb bean is created inside ConfigurationBean class and its not visible at spring context level for autowiring.

Duplicate Filter registration for 'springSecurityFilterChain'

So I have looked around and everywhere says that I need to check my configuration but what doesn't make sense to me is that my app will run on a different computer but the one I use for development. Just to provide some context, this app is purely restful with token authentication. Here's what my config looks like:
Security Init:
#Order(1)
public class SecurityWebappInitializer extends AbstractSecurityWebApplicationInitializer
{
}
App Init:
#Order(2)
public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
#Override
protected Class<?>[] getRootConfigClasses()
{
return new Class[]{RootConfiguration.class, SecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[]{WebConfiguration.class};
}
#Override
protected String[] getServletMappings()
{
return new String[]{"/", "/rest/*"};
}
#Override
protected Filter[] getServletFilters()
{
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return new Filter[] {characterEncodingFilter};
}
}
SecurityConfig:
#EnableWebSecurity
#EnableGlobalMethodSecurity(jsr250Enabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private NoOpAuthProvider noOpAuthenticationProvider;
#Autowired
private TokenFilter tokenFilter;
public SecurityConfig()
{
super(true);
}
#Override
public void configure(WebSecurity web) throws Exception
{
web
.ignoring()
.antMatchers("/rest/authentication/login")
.antMatchers("/services/**")
.antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("**").hasRole("RUN").and()
.addFilterAfter(tokenFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling().and()
.logout();
}
#Bean
public AuthenticationManager authenticationManager() throws Exception
{
List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>();
authenticationProviders.add(noOpAuthenticationProvider);
return new ProviderManager(authenticationProviders);
}
}
WebConfig:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.example.tinker.web")
public class WebConfiguration extends WebMvcConfigurerAdapter
{
#Autowired
private PrincipalRetrievalService principalRetrievalService;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/resources/**").addResourceLocations("resources/").setCachePeriod(31556926);
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers)
{
argumentResolvers.add(new WebArgumentResolver(principalRetrievalService));
super.addArgumentResolvers(argumentResolvers);
}
}
Any idea what would be causing my problems?
There is no need to implement AbstractSecurityWebApplicationInitializer.
Security is initialized via ApplicationInitializer/RootConfiguration/#ComponentScan/SecurityConfig. Also there si no need to add SecurityConfig in getRootConfigClasses.

Categories