How can I tell if Spring has loaded my #Controller? - spring

Is there a way to tell if Spring has loaded my #Controller?
I'm requesting a URL but I'm not hitting my controller and I can't figure out why
I'm loading controllers by doing a component scan
<context:component-scan base-package="com.example.app.web"/>
Other controllers in the same package as my failing controller are working fine.
My controller code is:
#Controller
#RequestMapping(value = "/app/administration/ecosystem")
public class AppEcosystemController {
#Autowired
EcosystemManagerService ecosystemManagerService;
#RequestMapping(value = "/Foo", method = RequestMethod.GET)
public String getEcosystem() {
/* Implementation */
}
The first thing I'd like to do is to be sure that this controller is getting picked up by the component scan.
Any suggestions?

Just enable logging for your application, you can find this information at INFO level
For example in my application I have a controller named UserController.
The following log4j.properties does the trick.
log4j.rootLogger=INFO, FILE
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=../logs/rest-json.log
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
I can see in the log that RequestMappingHandlerMapping mapped my controller (scroll all the way to the right).
07:28:36,255 INFO RequestMappingHandlerMapping:182 - Mapped "{[/rest/**/users/{id}],methods=[GET],params=[],headers=[],consumes=[],produces=[text/xml || application/json],custom=[]}" onto public org..domain.User org.ramanh.controller.UserController.getUser(java.lang.String)
07:28:36,255 INFO RequestMappingHandlerMapping:182 - Mapped "{[/rest/**/users],methods=[POST],params=[],headers=[],consumes=[],produces=[text/xml || application/json],custom=[]}" onto public void org..controller.UserController.addUser(org...domain.User)
If you are still unsure I would suggest adding a method annotated with #PostConstruct.
You could easily look up the message in the log or place a break point in this method.
#PostConstruct
protected void iamAlive(){
log.info(“Hello AppEcosystemController”)
}
If you find that your controller is initialized correctly but still the url is not accessible.I would test the following
You are getting 404 error - maybe you are not pointing to the correct
url (do not forget to add the application as prefix to the url)
You are getting 404 error - Dispatcher servlet mapping in web.xml doesn't meet
the url above
You are getting 403/401 – maybe you are using
spring security and it’s blocking the url
You are getting 406 – your
content type definition is conflicting with your request
You are getting 50x – something is buggy in your code

I made an ApplicationContextDumper. Add it into application context, it will dump all beans and their dependencies in the current context and parent contexts (if any) into log file when the application context initialization finishes. It also lists the beans which aren’t referenced.
It was inspired by this answer.

You could start out with enabling debug logging for Spring as outlined here.
I'd also recommend leveraging the MVC testing support, which you'll find in the spring-test jar. Details on how to use it can be found here and here.

Related

Automatically finding Thymeleaf templates with Spring Boot

How can I get Spring Boot and Thymeleaf to automatically find and map template files to be processed when accessed by the browser?
src/main/resources/templates/index.xhtml
src/main/resources/templates/bar.xhtml
src/main/resources/application.properties contains spring.thymeleaf.suffix=.xhtml
FooController.java contains #RequestMapping("/foo") and a #PostMapping method that returns bar
If I enter http://localhost:8080/ in the browser, Thymeleaf processes and displays the index.xhtml page with no extra configuration needed. But http://localhost:8080/index, http://localhost:8080/index.xhtml, and http://localhost:8080/index.html all result in 404 Not Found.
My index view does a POST to foo; FooController is activated and returns bar; and Thymeleaf processes and shows bar.xhtml, even though bar.xhtml isn't mapped anywhere in the configuration. Yet accessing http://localhost:8080/bar, http://localhost:8080/bar.xhtml, and http://localhost:8080/bar.html in a browser all result in 404 Not Found.
Why does GET http://localhost:8080/ process the index.xhtml template, but GET http://localhost:8080/index does not?
How can Thymleaf use bar as a view, but I cannot access http://localhost:8080/bar directly?
How can I configure Thymeleaf so that I can add src/main/resources/templates/example.xhtml and have it processed automatically as a template that I can access via http://localhost:8080/example in the browser, with no explicit configuration specifically for the example.xhtml file?
If I absolutely have to configure controllers (see my answer below), is there a way that I can at least do this in some declarative file, outside of my code?
As noted in Spring in Action, Fifth Edition, I can do something like this in a #Configuration class that implements WebMvcConfigurer
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
registry.addViewController("/bar");
}
That will allow me to process bar.xhtml automatically. (I presume there is some default configuration registry.addViewController("/").setViewName("index"), which is why my index.xhtml file is getting processed by accessing the root path.
And I can even use the following to automatically pick up any template:
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
registry.addViewController("/**");
}
Unfortunately this removes the mapping from / to /index, and also prevents accessing any static resources from src/main/resources. I'm not sure how to tell Thymeleaf to use a template if it can, and fall back to a static file if not.

Spring MVC 404 even though URL is mapped

I've been trying to setup a Spring MVC controller but when I try to make a GET request, I get a 404 error.
I created a working test example here: https://github.com/Jardo-51/zk-spring-mvc-test
When I run the application on Tomcat and try to make a GET request to: http://localhost:8080/zk-spring-mvc-test/api/v0/foo, I get a 404 error and the logs say:
WARNING: No mapping found for HTTP request with URI [/zk-spring-mvc-test/api/v0/foo] in DispatcherServlet with name 'dispatcher-api'`
I've been trying to fix it according to this answer, and found out that the controller is mapped correctly because the logs on startup say:
INFO: Mapped "{[/zk-spring-mvc-test/api/v0/foo],methods=[GET]}" onto public org.springframework.http.ResponseEntity<java.lang.String> com.jardoapps.zkspringmvctest.controllers.FooController.method()
The app uses ZK framework which needs its own servlets so maybe there is a conflict with the DispatcherServlet. Please see my example app for more details (it contains only the necessary code).
Here is the web.xlm (Spring context and MVC config are at the top).
Here is the controller class.
Simply replace #RequestMapping("zk-spring-mvc-test/api/v0/foo") with #RequestMapping("/v0/foo") in your FooController class.
The reason is that the path that you specify into the #RequestMapping annotation is the part of the request's URL beyond the part that called the servlet.
You defined DispatcherServlet's mapping as:
<servlet-mapping>
<servlet-name>dispatcher-api</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
So we have zk-spring-mvc-test that is the context root (this is deploy dependent), /api/ that calls the Spring DispatcherServlet, and finally /v0/foo that should be mapped by your controller:
#RestController
#RequestMapping("/v0/foo")
public class FooController {
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<String> method() {
return ResponseEntity.ok().body("OK");
}
}
You can see Spring MVC configure url-pattern for further information.

Unable to read values from external property file in Spring Boot

I have a running Spring Boot project. I want to read some environment specific properties from an external properties file.
I mentioned config files names and locations while starting the server as follows:
java -jar AllergiesConditions.jar --spring.config.name=application,metadata --spring.config.location=classpath:/,/APPS/SpringBoot/
The property files loads successfully(because i tried to log one of the external key values inside datasource bean and It printed successfully) But when i try to access a value using #Value annotation - It returns null.
My test Class is as follows:
#Component
public class testclass {
private Logger logger = LogManager.getLogger(testcla.class);
#Value("${sso.server}")
public String sso;
public void test(){
logger.info("sso url is: "+sso); //This sso is logged as null
otherStuff();
}
}
This test() function is called when a particular API is hit after server is running.
The external config file - metadata.properties contains this variable:
sso.server=1234test
Edit: As suggested in this apparently duplicate question I also tried adding #PropertySource(name = "general-properties", value = { "classpath:path to your app.properties"}) in main Application configuration class and It loaded the files, but still I get null value itself.
Can someone please help in what's going wrong here?? Does the testclass need some specific annotation OR it needs to be a bean or something??
Thanks in Advance :)
Thanks to M.Deinum for great input and saving my time
Just posting his comment as answer
Factually ${sso.server} cannot be null. If ${sso.server} couldn't be resolved, my application will break at startup itself.
So the obvious problem was that I was creating a new instance of testclass in my controller using
testclass obj = new testclass(); obj.test();
Rather I should be using spring managed instance by autowiring testclass in my controller.

CXF Interceptor phases being skipped for missing phase declaration

Been working on this one for a bit and haven't had any luck.
I'm in the process of upgrading from Spring 3.2.9 to 4.2.6. My first step was upgrading to cxf-core 3.1.6, which I did with no issues to the app.
When upgrading all spring dependencies I am running into an issue with the interceptor setup though. Here's the basics:
Interceptor
public class MyInterceptor extends AbstractPhaseInterceptor<Message>{
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
public MyInterceptor() {
super(Phase.PRE_INVOKE);
addAfter(HolderInInterceptor.class.getName());
}
#PostConstruct
public void display() {
logger.warn(this.getPhase());
}
#Override
public void handleMessage(Message message) throws Fault {
....
cxfContext.xml
<bean id="contentInInterceptor" class="com.MyInterceptor">
</bean>
<cxf:bus>
<cxf:inInterceptors>
<ref bean="contentInInterceptor"/>
</cxf:inInterceptors>
</cxf:bus>
as well as it being added in web.xml. When running I see the logged information showing the interceptor is created with a phase of pre-invoke (I added this to verify I'm not going crazy). But when calling the service, the PhaseInterceptor chain is skipping the interceptor for not declaring a phase:
Logs:
2016-05-31 16:08:28,208 [localhost-startStop-1] [] WARN
c.MyInterceptor - pre-invoke
2016-05-31 16:10:14,552
[http-bio-8080-exec-1] [] WARN o.a.c.p.PhaseInterceptorChain -
Skipping interceptor
com.MyInterceptor$$EnhancerBySpringCGLIB$$1afa70e1: Phase declaration
is missing.
This is intercepting a jaxws server call. Again, all I've changed that has caused the issues is updating to the latest version of Spring. It almost appears as though cxf is using a separate interceptor that was never generated from the bean.
EDIT
I believe I've found the issue, but again I'm not sure where the fix would be. Spring 4 proxy does not call the constructor twice when creating the proxy (i.e. it creates the raw bean using the constructor, but the CGLIB created proxy of the bean does not call the constructor). This causes the phase of the interceptor to be null.
I changed around my #PostContsruct on the class to confirm this:
#PostConstruct
public void display() {
logger.warn(this.getPhase());
MyInterceptor myInterceptor = (MyInterceptor) appContext.getBean("contentInInterceptor");
logger.warn("Bean phase is: " + myInterceptor.getPhase());
}
Logs show bean creation's phase versus proxy's phase:
2016-06-01 10:36:52,829 [localhost-startStop-1] [] WARN c.MyInterceptor - pre-invoke
2016-06-01 10:36:52,839 [localhost-startStop-1] [] WARN c.MyInterceptor - Bean phase is: null
Alright, I figured out a way around this for now, but it isn't the greatest implementation.
Basically what I ended up having to do was create an abstract class that implemented PhaseInterceptor and all of those implemented methods were set as abstract.
Then my interceptors extended from that class and had their own phase/id/before/after variables. It appears as though there may be an issue with Spring's bean proxy setup when variables are not available in the bean's direct class. At least that's what I'm finding in this case.
Again, not sure if it's the best solution, but this makes the interceptors work again.
You said that interceptor is intercepting jaxws server call. So my assumption is, it is outgoing call.
Phase.PRE_INVOKE is for incoming message. Use other phases like Phase.PRE_STREAM for outgoing message
For documentation of phases please see
http://cxf.apache.org/docs/interceptors.html

Spring boot - Serving static content

I have issues configuring Spring boot 1.2.0.M1 to serve static content.
As soon as I add a #RestController component in my application, the static content is not displayed and I get the whitelabel error page instead. My resources are in the src/main/resources/static folder.
I followed the instructions at http://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot and managed to have them displayed by setting the ResourceHandlerRegistry priority to -1. But i guess it is not the standard and right way to do it. It seems that the handler of the REST resources takes priority over the resource handler registry. Is there a possibility to configure the handler for rest resource to be used for a sub-context only like /api ?
Update:
I have put the DispatcherServlet in debug and I have better understanding on why this is happening but still not sure what would be the best way to deal with it.
I have noticed that the following handlers are registered in the Dispatch servlet in the respective order by default :
SimpleUrlHandlerMapping -> favico
RequestMappingHandlerMapping -> annotated #RestController methods registered
SimpleUrlHanderMapping -> / (home page handling ?)
BeanNameUrlHandlerMapping
SimpleUrlHandlerMapping -> handles resources configured in the resources registry
WebMVCConfigurationSupport handler
When I perform a POST on the REST resource 2. handles it.
When I perform a GET on a static resource 2. throws a HttpRequestMethodNotSupportedException because it cannot find the resource (in its handleNoMatch method).
If i change the priorities using ResourceHandlerRegistry#setOrder(Ordered.HIGHEST_PRECEDENCE); 5. is placed before 2. but in this case i cannot perform a POST /user/api intended for my REST resource, it is not matched as a resource (i have configured a /** pattern for the resource handler).
If i compare to what node.js/express does for instance is that you configure routes for your controllers and if none matches the request, the request is handled by the handler for static resources or templates.
Do you know how if it is possible through annotation to have the 2 (i.e RequestMappingHandlerMapping ) not throw an exception but just pass the request to the next handler in the chain in case of no-match ?
I'd like avoiding having a specific context (/static for static resources).
Update 2:
Actually it was just a misconfiguration of my annotated REST controller #RestController
I configured the path in the value attribute of the annotation that is not meant for that but to store the controller's name
I forgot to add the #RequestMapping therefore the handler RequestMappingHandlerMapping was enabled for any url path and the get request did not match any annotated methods, therefore it returned an error.

Resources