#Bean Controller not getting picked up by #EnableMVC - spring

Most of my #Controllers are picked up through component scanning. However, a few, such as those I use with Spring Social are created as #Beans. I just migrated from mostly xml to JavaConfig only and upgraded to Spring 4.1.9.
However, the Controller endpoints that are created as #Beans are creating 404s.
Any ideas?
package nl.project.webapp.config;
#Order(1)
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{WebAppConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{ServletConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
[...]
}
package nl.project.webapp.config;
#Configuration
#ComponentScan(basePackages = {"nl.project.webapp"},excludeFilters={
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=Controller.class),
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=RestController.class)
})
#Import({AppConfig.class,JPAConfig.class})
#PropertySource("classpath:msa.properties")
public class WebAppConfig {
[...]
}
package nl.project.webapp.config;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"nl.project.webapp.controller"},includeFilters={
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=Controller.class),
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=RestController.class)
})
public class ServletConfig extends WebMvcConfigurerAdapter{
[...]
}
package nl.project.webapp.social.config;
#Configuration
public class SocialConfig{
#Bean
public MyConnectController connectController(MessageSource messages, UsorManager userMgr, PhotoManager photoMgr) {
MyConnectController connectController = new MyConnectController(connectionFactoryLocator, connectionRepository);
connectController.setConnectInterceptors(Arrays.asList(new ConnectInterceptor<?>[]{
new TwitterConnectInterceptor(userMgr, photoMgr, messages),
new FacebookConnectInterceptor(userMgr, photoMgr, messages),
new LinkedInConnectInterceptor(userMgr, photoMgr, messages),
new GoogleConnectInterceptor(userMgr, photoMgr, messages),
}));
return connectController;
}
#Bean
public MySignInController signinController(MessageSource messages, UsorManager userMgr, PhotoManager photoMgr){
MySignInController signinController = new MySignInController(connectionFactoryLocator, usersConnectionRepository, new SimpleSigninAdapter(userMgr));
signinController.setSignInInterceptors(Arrays.asList(new ProviderSignInInterceptor<?>[]{
new FacebookSigninInterceptor(userMgr, photoMgr, messages),
new LinkedInSigninInterceptor(userMgr, photoMgr),
new GoogleSigninInterceptor(userMgr, photoMgr)
}));
return signinController;
}
}
package nl.project.webapp.social.controller;
#Controller
#RequestMapping("/signin")
public class MySignInController extends ProviderSignInController {
public MySignInController(
ConnectionFactoryLocator connectionFactoryLocator,
UsersConnectionRepository usersConnectionRepository,
SignInAdapter signInAdapter) {
super(connectionFactoryLocator, usersConnectionRepository, signInAdapter);
this.connectionFactoryLocator = connectionFactoryLocator;
}
[...]

The problem was caused by SocialConfig being imported by the WebAppConfig in stead of the ServletConfig. Although the documentation suggests that any Controller bean available in the context will be picked up by using '#EnableWebMVC', it is not very clear that this does not apply to Controller beans loaded through the webapp context.

Related

Spring MVC - Dispatcher Servlet can't find any page

I do really simple demo web app using Spring mvc, Java class annotations and .jsp instead of .html.
When I start Tomcat on localhost - I always get 404 error. Where do I do mistake?
Config.class
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.mylov.springsecurity.demo.config")
public class Config {
//Define bean for ViewResolver
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
Dispatcher Servlet Initialization
public class DispatcherServletInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{Config.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Controller
#Controller
public class DemoController {
#GetMapping({"", "/"})
public String showHome() {
return "home";
}
}
Project Structure:
You need to scan packages under demo package. So Spring will find your Controllers and Config classes. But now you point to only config. So package 'controller' won't be scan.
Try to do this:
#ComponentScan(basePackages = "com.mylov.springsecurity.demo")
Try providing the mapping as below so that all url's are mapped with the servlet:
public class DispatcherServletInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{Config.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/*"};
}
}
Also change the base packages to as below so that the controller class is also picked up for component scanning :
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.mylov.springsecurity.demo")
public class Config {
..........
}

Controller are not working in Spring

I unable to understand why my controller are not redirecting to my html. Anyone can help me please?
WebConfig.java
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.udemy.controller" })
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix("");
return resolver;
}
}
HelloWorldController.java
#Controller
#RequestMapping("/example")
public class HelloWorldController {
public static final String EXAMPLE_VIEW = "example.html";
#GetMapping("/")
public String fileUploadForm(Model model) {
return "fileDownloadView";
}
#GetMapping("/helloworld")
public String helloWorld(){
return "helloworld";
}
// #RequestMapping(value="/exampleString", method=RequestMethod.GET)
#GetMapping("/exampleString")
public String exampleString(Model model){
model.addAttribute("name","John");
return EXAMPLE_VIEW;
}
// #RequestMapping(value="/exampleMAV", method=RequestMethod.GET)
#GetMapping("/exampleMAV")
public ModelAndView exampleMAV() {
ModelAndView mav= new ModelAndView(EXAMPLE_VIEW);
mav.addObject("name", "Mike");
return mav;
}
AppInitializer
public class MyWebAppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
My project structure is well done. So my html and jsps, are inside of the root WEB-INF/views. Also, the anotation #ComponentScan, are detecting the controller. So, its not a problem of root. Anyone can tell me, why im am not redirecting to the .html , please..
Error says:
ADVERTENCIA: No mapping found for HTTP request with URI [/spring-mvc-download-example/WEB-INF/views/example.html] in DispatcherServlet with name 'dispatcher'
In your controller class, above the
#RequestMapping("/example")
Insert:
#Controller
Gonna be:
#Controller
#RequestMapping("/example")
you have to annotate class HelloWorldController with #Controller or #RestController, only then it will be picked by #Componentscan annotation.

unable to use #AspectJ with Spring-Apache CXF services

I am new to spring and am working on a rest service written using Spring and Apache CXF with Java Configurations. I have the following rest service.
#Path("/release/")
#Component
#RestService
#Consumes({ MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ReleaseResource extends AbstractService implements IResource {
#Override
#CustomLogger
#GET
public Response get() {
//Some Logic
return Response.ok("Success!!").build();
}
}
I have created an aspect using #AspectJ for logging. However, the aspect is not working on the services written in CXF. I did a bit of searching in net and found that Spring needs proxy beans for the aspects to work. Then I tried few approaches such as
Making the service class implement an interface
Using CGLIB library and scope proxy mode TARGET_CLASS
Extending a class with method
#Override
public void setMessageContext(MessageContext context) {
this.context = context;
}
But none of them worked.
Any idea if it is possible to run the aspect around the services?
If yes, can someone please tell me how to.
I have read that this can be achieved by bytecode weaving the aspectj manually instead of using spring aspectj autoproxy (not sure how to do it though). Can someone tell me if this is a good option and how to do it?
EDIT:
Sorry for the incomplete info provided. Attaching the other classes
#Aspect
#Configuration
public class LoggerAspect {
#Pointcut(value = "execution(* *(..))")
public void anyPublicMethod() {
}
#Around("anyPublicMethod() && #annotation(CustomLogger)")
public Object logAction(ProceedingJoinPoint pjp, CustomLogger customLogger) throws Throwable {
//Log Some Info
return pjp.proceed();
}
}
Web Initializer class:
#Configuration
public class WebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(new ContextLoaderListener(createWebAppContext()));
addApacheCxfServlet(servletContext);
}
private void addApacheCxfServlet(ServletContext servletContext) {
CXFServlet cxfServlet = new CXFServlet();
ServletRegistration.Dynamic appServlet = servletContext.addServlet("CXFServlet", cxfServlet);
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/*");
}
private WebApplicationContext createWebAppContext() {
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(TestConfig.class);
return appContext;
}
}
Config Class:
#Configuration
#ComponentScan(basePackages = "com.my.package")
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class TestConfig {
private static final String RESOURCES_PACKAGE = "com.my.package";
#ApplicationPath("/")
public class JaxRsApiApplication extends Application {
}
#Bean(destroyMethod = "shutdown")
public SpringBus cxf() {
return new SpringBus();
}
#Bean
public JacksonJsonProvider jacksonJsonProvider() {
return new JacksonJsonProvider();
}
#Bean
public LoggerAspect getLoggerAspect() {
return new LoggerAspect();
}
#Bean
IResource getReleaseResource() {
return new ReleaseResource();
}
#Bean
#DependsOn("cxf")
public Server jaxRsServer(ApplicationContext appContext) {
JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint(jaxRsApiApplication(),
JAXRSServerFactoryBean.class);
factory.setServiceBeans(restServiceList(appContext));
factory.setProvider(jacksonJsonProvider());
return factory.create();
}
private List<Object> restServiceList(ApplicationContext appContext) {
return RestServiceBeanScanner.scan(appContext, TestConfig.RESOURCES_PACKAGE);
}
#Bean
public JaxRsApiApplication jaxRsApiApplication() {
return new JaxRsApiApplication();
}
}
RestServiceBeanScanner class
public final class RestServiceBeanScanner {
private RestServiceBeanScanner() {
}
public static List<Object> scan(ApplicationContext applicationContext, String... basePackages) {
GenericApplicationContext genericAppContext = new GenericApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(genericAppContext, false);
scanner.addIncludeFilter(new AnnotationTypeFilter(RestService.class));
scanner.scan(basePackages);
genericAppContext.setParent(applicationContext);
genericAppContext.refresh();
List<Object> restResources = new ArrayList<>(
genericAppContext.getBeansWithAnnotation(RestService.class).values());
return restResources;
}
}

Change main endpoint in Spring Data Rest (usind Spring Boot)

Im building a small application using Spring (Boot, Data, Data Rest).
I have some JpaRepositories that aumotatically are exported as Rest endpoints.
What i want to do is to change the base path from / to /api.
Now to list all people for example i do a GET to http://localhost:8080/people and i want the url to be http://localhost:8080/api/people.
I tried adding this config class but nothing happened (it seems that Spring Boot overrides this config):
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses()
{
return new Class<?>[] { Application.class};
}
#Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[] { RestExporterRestConfig.class, RepositoryRestMvcConfiguration.class };
}
#Override
protected String[] getServletMappings()
{
return new String[] { "/api/*" };
}
}
My Application.java:
#Configuration
#ComponentScan
#Import(RestExporterRestConfig.class)
#EnableJpaRepositories
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and RestExporterRestConfig:
#Configuration
public class RestExporterRestConfig extends RepositoryRestMvcConfiguration {
#Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
#Override
protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", validator());
}
#Bean
#Qualifier
public DefaultFormattingConversionService defaultConversionService() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(StringToDate.INSTANCE);
return conversionService;
}
#Bean
public DomainClassConverter<?> domainClassConverter() {
return new DomainClassConverter<DefaultFormattingConversionService>(defaultConversionService());
}
}
Well i figured it out. SpringWebAppInitializer is not necesary in this case. I just added this code to Application.java:
#Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
ServletRegistrationBean reg = new ServletRegistrationBean(dispatcherServlet);
reg.addUrlMappings("/api/*");
return reg;
}
I think this is the correct way to modify (add, change mappings, etc) servlets using Spring Boot.

Overriding default ValidationMessages.properties from hibernate-validation

I'm trying to override the ValidationMessages.properties from default hibernate-validation (5.0.2 version) in a Spring MVC application.
But it keeps using the internal ValidationMessages.properties from jar.
UPDATE: it works (but it should be another way) when I copy the *.properties files to org\hibernate\validator ...
This is my configuration:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.blueliv.search.*"} )
public class WebConfig extends WebMvcConfigurerAdapter {
static Logger log =LoggerFactory.getLogger(WebMvcConfigurerAdapter.class);
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new GsonHttpMessageConverter());
//converters.add(new MappingJackson2HttpMessageConverter());
}
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
#Bean
public ExceptionHandlerExceptionResolver exceptionResolver() {
return new ExceptionHandlerExceptionResolver();
}
#Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean validatorFactoryBean = new LocalValidatorFactoryBean();
validatorFactoryBean.setValidationMessageSource(getBundle());
return validatorFactoryBean;
}
public ReloadableResourceBundleMessageSource getBundle(){
log.debug("get bundle!");
ReloadableResourceBundleMessageSource bundle = new ReloadableResourceBundleMessageSource();
bundle.setBasenames("classpath:/i18n/validation/ValidatonMessages");
return bundle;
}
#Override
public Validator getValidator() {
return validator();
}

Resources