The #ModelAttribute methods in the controller are
#ModelAttribute("command")
public A getA() {
...
}
#ModelAttribute
public void prepareData(#ModelAttribute("command") A a) {
...
}
We are using Spring 4.2.6 version and As per Spring forum This issue has been resolved in 4.1.0 version of spring. When I deploy the project sometimes getA() is executing before prepareData and sometimes prepareData() is executing before getA(), but according to jira for above issue, it has been fixed in all the spring versions starting from 4.1.0. Could you please suggest am I missing anything here.
You should mark only 'preparedData' with #ModelAttribute not both. Marking so means it would get executed before any requests or controller method is called.
So if 'getA' is your controller method and you want to preprocess 'A' before it being called (at getA) your methods should be something like this
public A getA(#ModelAttribute("command") A a) { ... }
#ModelAttribute("command")
public A prepareData() {
return new A();//or some other way you want to populate values of A
}
Related
I have a service that has two classes and is very simple:
#ApplicationPath("/api")
public class HelloApplication extends Application {}
and
#Path("/hello-world")
public class HelloResource {
#GET
//#Produces("text/plain")
public Response hello() {
//return Response.ok().entity("This is JAX-RS").build();
return Response.ok().status(200).build();
//return "Hello, World!";
}
}
Commented lines are the ones that I tried to use. Every time I call "http://localhost:8080/api/hello-world" or "http://localhost:8080/api" the response is 404-Not Found. I use Tomcat 9.0.50.
What can be wrong with my usage of the classes or their calling from the outside?
The problem was - for some reason - in the usage of Tomcat. After moving to JBoss WildFly 24.0.0 the problem disappeared and the system started to work correctly.
If someone knows the reason of such an incompatibility - write a comment or an extra answer.
I know this is usually an issue that happens the other way around, so I am caught a little of guard here :D
I have built a user-management backend that provides a UI with data. When this architecture is deployed on our dev-server, everything works beautifully. However, as soon as I try to run the integration tests (which we do using a maven cargo tomcat) or if I use the war file in a local tomcat, the exception handlers aren't used at all. Spring simply displays a standard 500 response with the exception transformed into the body.
Perusing SO for similar issues has only resulted in the advice that I should use #EnableWebMVC, but that is neither applicable to what my backend is trying to accomplish, nor does it change anything.
How should I go about looking for the solution to this issue? Specifically, can I somehow observe if my controlleradvice is even scanned, and is there a reason why it might not be?
EDIT: These are the relevant files:
SpringConfiguration:
#Configuration
#ComponentScan(basePackageClasses = {UserManagementSpringConfiguration.class})
#EnableWebSecurity
public class UserManagementSpringConfiguration {
#Configuration
public static class ResourceMappingConfig implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/ui/*/usermanagement").setViewName("forward:/usermanagement-ui/index.html");
// registry.addViewController("/ui/*/*/generator/").setViewName("forward:/generator-ui/index.html");
registry.addViewController("/ui/*/usermanagement/*").setViewName("forward:/usermanagement-ui/index.html");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// cache setting, otherwise fonts are not loaded in IE over https
CacheControl cacheControl = CacheControl.noCache().mustRevalidate();
registry.addResourceHandler("/ui/**/*").addResourceLocations("/usermanagement-ui/")
.setCacheControl(cacheControl);
}
}
}
ControllerAdvice:
#ControllerAdvice
public class CustomResponseEntityExceptionHandler {
public static final Logger LOG = EISLoggerFactory.getLogger(CustomResponseEntityExceptionHandler.class);
#PostConstruct
public void postConstruct() {
LOG.debug("CustomExceptionHandler loaded and ready for use");
}
#ExceptionHandler(PasswordMismatchException.class)
public final ResponseEntity<ErrorDetails> handlePasswordChangeMismatch(
PasswordMismatchException ex,
WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(
new Date(),
ex.getMessage(),
request.getDescription(false),
MessageKeys.mismatchedPassword);
return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
}
}
It turns out that one of the modules that we wrote and that my project contains defines an ExceptionHandler for Throwable.class. On my machine, this ControllerAdvice is registered before my own ControllerAdvice, which causes Spring to look there first. Since Throwable fits the bill, Spring asks no further questions and just uses that handler.
The solution to my immediate problem was to add #Order(Ordered.HIGHEST_PRECEDENCE) to my ControllerAdvice. Since the exceptions I define within are quite specific, this will not cause any issues.
I have yet to find an explanation for why the order in which the two ControllerAdvice classes are registered is so consistently different between my machine and our dev server. Will update if I find anything. For now, I consider this issue to be answered.
This SO question was essential to solving this particular problem. Perhaps it helps someone in the future to link it here: Setting Precedence of Multiple #ControllerAdvice #ExceptionHandlers
Thanks to ValentinCarnu for pointing me to it!
I'm trying to configure a Spring interceptor for controllers only in the following way. For the beginning I want to exclude all the requests starting with /swagger. I try to do it in the following way:
registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/swagger**");
However, interceptor gets fired. Where is a mistake?
Maybe, there is an alternative solution with #ControllerAdvice. But I need to get request headers, so I guess it doesn't fit my needs.
Thanks for any help!
Try to use "/swagger*/**" or "/swagger*" instead of "/swagger**"
I solved the problem in the following way:
#ControllerAdvice
public class SomeAdvice {
#ModelAttribute
public void token(HttpServletRequest request) {
// getting headers and setting the attribute in the request
request.setAttribute("theAttribute", new SomeObject());
}
}
And then I get the request attribute in a controller this way:
public void someMethod(#RequestAttribute("theAttribute") SomeObject someObject) {
// some logic goes here
}
P.S. And one more note. If you're using Swagger you'll get into the trouble as Swagger will consider this attribute as controller method parameter. To ignore it you can use the following snapshot of configuration:
.ignoredParameterTypes(SomeObject.class);
I already opened an issue for that here. But also i want to ask it to stackoverflow people.
#Controller
#RequestMapping("/xxx")
public class MyController {
#RequestMapping("/**")
public ModelAndView getPage() {
//some code
}
#RequestMapping("/**/yyy/")
public ModelAndView getPageSecond() {
//some code
}
#RequestMapping("/**/yyy/{pathVariable}")
public ModelAndView getPageThird(#PathVariable("pathVariable") Integer num) {
//some code
}
}
Assume that we have a simple Controller like that, and I am sending these requests :
1) /xxx/aaa/bbb/yyy/ -->okay it will be mapped with getPageSecond method and will do his work.
2) /xxx/aaa/bbb/yyy/23 --> I think it must be mapped with getPageThird method, but it is strange that Spring is catching this request via getPage method.
I tried to dive into Spring codes to understand whats going on there, then i found AntPatternComparator. This comparator is giving result in order to bracket count, taking the lesser one for best match.
Why? Third one is more specific then others, is there something wrong ?
You could manually add your own version of RequestMappingHandlerMapping to your application context and set its patternMatcher property using setPathMatcher(PathMatcher pathMatcher) with your own implementation that will correct the issue you're having.
This is the code example from Spring 3.1 Spring Source Blog: From XML to #Configuration I'm trying to implement in my application (which was done in Spring 2.0 not by me so it's lot of learning).
#FeatureConfiguration
class MvcFeatures {
#Feature
public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
return new MvcAnnotationDriven().conversionService(conversionService)
.argumentResolvers(new CustomArgumentResolver());
}
// ...
}
However, I can't understand the point of .argumentResolvers(new CustomArgumentResolver()) and their CustomArgumentResolver looks like bellow. What's the point of it?
public class CustomArgumentResolver implements WebArgumentResolver {
#Override
public Object resolveArgument(MethodParameter param, NativeWebRequest request) throws Exception {
RequestAttribute attr = param.getParameterAnnotation(RequestAttribute.class);
if (attr != null) {
return request.getAttribute(attr.value(), WebRequest.SCOPE_REQUEST);
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
To add to #GaryF's answer, and to clarify some points, Spring 2.5 introduced annotated controllers, which replaced the old interface-style controllers of Spring 2.0. These new controllers have methods with no fixed parameters - the method declares the parameters that it needs to do its job, and nothing more.
For example, say a controller method needed one thing to do its job - a request parameter that contains the ID of an object from the database. In Spring 2.0, you would need to implement something like AbstractController.handleRequestInternal(), e.g
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
String id = request.getParameter("id");
MyThing obj = getObjById(id);
//... do stuff and return ModelAndView
}
Spring 2.5 made that easier:
#RequestMapping
public ModelAndView handle(String id) {
MyThing obj = getObjById(id);
//... do stuff and return ModelAndView
}
Here, we only declare parameters for the stuff we need.
So far so good, but this is where a custom WebArgumentResolver comes in. Say I want to remove the getObjById from my controller altogether, because maybe I think it clutters up the code, and maybe it's used across many other controller methods. Instead, I want to do this:
#RequestMapping
public ModelAndView handle(MyThing id) {
//... do stuff and return ModelAndView
}
It's even simpler, and has a bare minimum of boilerplate code. A custom WebArgumentResolver can be registered with the app-context which recognises parameters of type MyThing, and knows how to extract the information from the request. Spring invokes that resolver, and passes the result to the controller method.
Custom resolvers aren't commonly used, but can be very handy in the right situation.
The example in your question uses CustomArgumentResolver to resolve the example's custom RequestAttribute class. The resolver pulls out request attributes and binds them to RequestAttribute objects, so that they can be declared as controller method parameters.
WebArgumentResolvers are a way for you to specify how the parameters of MVC-mapped methods should be resolved. If you'd like to use a custom object as a parameter for an MVC-mapped method, Spring tries to figure out how make sense of it in it's own way. Typically this would happen through binding, where some http parameters you submit match up with the fields of the object and Spring matches them up and creates a new object for you.
If you ever have a situation where the submitted parameters don't match up quite so neatly with your method parameters, WebArgumentResolvers are there to fill in the gap: you provide custom logic so Spring doesn't have to figure it out.
In your example, param is one such parameter to be matched up. This piece of custom code first checks if the parameter has an #RequestAttribute annotation. If it does, then the custom code pulls the value from that object and looks it up as an attribute on the http request, returning it. It it does not have that annotation, then the method returns the UNRESOLVED value, which simply indicates that this WebArgumentResolver doesn't know anything about this particular parameter and Spring should try a different method (such as binding).