I have a wildcard Spring MVC mapping that goes something like this:
#RequestMapping(value="**", method={RequestMethod.GET, RequestMethod.POST})
public void doSomething() {
}
However, defined in a Spring #Configuration file, I have this:
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(pushHandler(), "/websocket").withSockJS();
}
Unfortunately, Spring MVC's wildcard handler ignores the registration of /websocket, meaning my wildcard handler tries to handle my websocket as well.
I tried to change the wildcard pattern so that the #RequestHandler used a negating regex:
#RequestMapping(value="(?!websocket)", method={RequestMethod.GET, RequestMethod.POST}
public void doSomething() {
}
This now excludes the websocket path, but all other paths that I expect the wildcard to pick up now are no longer mapped.
Does anyone have a workable way to exclude a path from a #RequestMapping wildcard?
Jason
Related
I've one spring boot rest controller method which is mapped to multiple mappings. Please find the example code below.
#RestController
public class HomeController {
#RequestMapping( {"/", "/home"} )
public String home() {
return "Hello, World!";
}
}
I want to hide /home mapping from swagger documentation.
Can someone please help me to achieve this.
I also searched for a way to hide certain URLs from multi mapping methods. Unfortunately, I don't think it's possible when multi mapping it's defined like this #RequestMapping( {url1, url2} )
There are 2 alternative ways to do it:
Split your method into 2 methods that call the same function and annotate the one you want to hide with #Operation(hidden=true)
Define exceptions in your swagger config (for swagger 3 which uses open API):
#Configuration
public class SwaggerConfig {
#Bean
public GroupedOpenApi myApi()
{
return GroupedOpenApi.builder()
.pathsToMatch("/**")
.pathsToExclude("/home")
.build();
}
}
I am trying to set up a REST endpoint that allows querying a user by their email address. The email address is the last portion of the path so Spring is treating foo#example.com as the value foo#example and truncating the extension .com.
I found a similar question here Spring MVC #PathVariable with dot (.) is getting truncated
However, I have an annotation based configuration using AbstractAnnotationConfigDispatcherServletInitializer and WebMvcConfigurerAdapter. Since I have no xml configuration, this solution will not work for me:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="useDefaultSuffixPattern" value="false" />
</bean>
I have also tried this solution which uses regex but it has not worked either.
#RequestMapping(value = "user/by-email/{email:.+}")
Does anyone know how to turn off the suffix pattern truncation without xml?
The dot in the path variable at the end of the URI causes two unexpected behaviours (unexpected for the majority of users, except those familiar with the huge number of Spring configuration properties).
The first (which can be fixed using the {email:.+} regex) is that the default Spring configuration matches all path extensions. So setting up a mapping for /api/{file} will mean that Spring maps a call to /api/myfile.html to the String argument myfile. This is useful when you want /api/myfile.html, /api/myfile.md, /api/myfile.txt and others to all point to the same resource. However, we can turn this behaviour off globally, without having to resort to a regex hack on every endpoint.
The second problem is related to the first and correctly fixed by #masstroy. When /api/myfile.* points to the myfile resource, Spring assumes the path extension (.html, .txt, etc.) indicates that the resource should be returned with a specific format. This behaviour can also be very useful in some situations. But often, it will mean that the object returned by a method mapping cannot be converted into this format, and Spring will throw a HttpMediaTypeNotAcceptableException.
We can turn both off with the following (assuming Spring Boot):
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
// turn off all suffix pattern matching
configurer.setUseSuffixPatternMatch(false);
// OR
// turn on suffix pattern matching ONLY for suffixes
// you explicitly register using
// configureContentNegotiation(...)
configurer.setUseRegisteredSuffixPatternMatch(true);
}
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
}
More about Content Negotiation.
You have to add trailing slash at the end of the path variable after name like
#RequestMapping(value ="/test/{name}/")
The Request like
http://localhost:8080/utooa/service/api/admin/test/Takeoff.Java#gmail.com/
I've found the solution to this using the ContentNegotiationConfigurer bean from this article: http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc
I added the following configuration to my WebConfig class:
#EnableWebMvc
#Configuration
#ComponentScan(basePackageClasses = { RestAPIConfig.class })
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
}
By setting .favorPathExtension(false), Spring will no longer use the file extension to override the accepts mediaType of the request. The Javadoc for that method reads Indicate whether the extension of the request path should be used to determine the requested media type with the highest priority.
Then I set up my #RequestMapping using the regex
#RequestMapping(value = "/user/by-email/{email:.+}")
For the Java-Config folks:
With Spring 4 you can simply turn this feature off by:
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
Then in the whole application dots will treated as dots.
I am trying to do some validation on requests coming into my service using the ContainerRequestFilter. Everything is working fine, however there is one problem - every single request gets pass through the filters, even though some of the filters will never apply to them (one filter only validates on ResourceOne, another only on ResourceTwo etc.)
Is there a way to set a filter only to be invoked on a request under certain conditions?
While it is not a blocker or hindrance, it would be nice to be able to stop this kind of behaviour :)
I assume that You are using Jersey 2.x (implementation for JAX-RS 2.0 API).
You have two ways to achieve Your goal.
1. Use Name bindings:
1.1 Create custom annotation annotated with #NameBinding:
#NameBinding
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface AnnotationForResourceOne {}
1.2. Create filter with Your annotation:
#Provider
#AnnotationForResourceOne
public class ResourceOneFilter implements ContainerRequestFilter {
...
}
1.3. And bind created filter with selected resource method:
#Path("/resources")
public class Resources {
#GET
#Path("/resourceOne")
#AnnotationForResourceOne
public String getResourceOne() {...}
}
2. Use DynamicFeature:
2.1. Create filter:
public class ResourceOneFilter implements ContainerRequestFilter {
...
}
2.2. Implement javax.ws.rs.container.DynamicFeature interface:
#Provider
public class MaxAgeFeature implements DynamicFeature {
public void configure(ResourceInfo ri, FeatureContext ctx) {
if(resourceShouldBeFiltered(ri)){
ResourceOneFilter filter = new ResourceOneFilter();
ctx.register(filter);
}
}
}
In this scenario:
filter is not annotated with #Provider annotation;
configure(...) method is invoked for every resource method;
ctx.register(filter) binds filter with resource method;
When we use #NameBinding we need to remove #PreMatching annotation from the Filter. #PreMatching causes all the requests go through the filter.
#PreMatching does not work together with #NameBinding, because the resource class/method is not yet known in pre-matching phase.
I solved this issue by removing #PreMatching from the filter and using binding priority. See ResourceConfig.register(Object component, int bindingPriority).
Filters to be executed before the resource simply get a higher priority.
I am trying to specify a pre-matching filter that is only associated to some of my API calls, by following what the RESTeasy documentation suggests. Here is what my code looks like:
Name binding:
#NameBinding
public #interface ValidateFoo {}
Resource:
#Path("/foo/bar")
#Produces(MediaType.APPLICATION_JSON)
public class FooBar {
#GET
#ValidateFoo
public Object doStuff() {
//do stuff
}
#POST
public Object doAnotherStuff() {
//do another stuff
}
}
Filter:
#ValidateFoo
#Provider
#PreMatching
public class FooValidation implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext reqContext) throws IOException {
//validate stuff
}
}
Problem is: the FooValidation filter runs before every method call (e.g.: before GETs and POSTs to /foo/bar), not only the ones annotated with #ValidateFoo (seems a bug to me). If I remove the #Provider annotation from the filter, it won't run before any call (as expected).
I am seeing this behavior consistently, either using WebLogic or Tomcat. My dependency management is done through Maven, and the RESTeasy version is 3.0-beta-3.
Anyone experiencing/experienced the same behavior? I have seen another user with a similar problem on JBoss forums, with no luck so far.
UPDATE:
Still experiencing the same issue with RESTeasy 3.0.1-Final.
I had similar problem. For me the solution was to add following annotation configuration (to #ValidateFoo):
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(value = RetentionPolicy.RUNTIME)
#NameBinding
I just started working with spring and set up a simple spring project in NetBeans. By default it doesn't seem to use annotations.
In one of my controllers I'd like to handle different clicks on the form. I have looked at some solutions and it seems like adding a parameter check could work:
#RequestMapping(params = "someAction")
public ModelAndView doSomeAction() {
However it looks like all of the requests are going to:
public class SetupController implements Controller {
#Override
public org.springframework.web.servlet.ModelAndView handleRequest(
HttpServletRequest hsr, HttpServletResponse hsr1) throws Exception {
Is there a way I can achieve the same effect without RequestMapping annotation?
It seams that you mixed the old (implements Controller) style with the new one annotation based style.
You can't (or at least should not) mix them, at least not for one class.
If you use Spring 3.x then I strongly recommend to use the Annotation based style.
#Controller
#RequestMapping("/whatever")
public class DemoController() {
#RequestMapping(params="x");
public ModelAndView doX() {
}
#RequestMapping(params="y");
public ModelAndView doY() {
}
}
To enable the Annotation Based style, you need at least this configuration settings:
<!-- Turns on support for mapping requests to Spring MVC #Controller methods
Also registers default Formatters and Validators for use across all
#Controllers -->
<mvc:annotation-driven conversion-service="applicationConversionService" />