Spring MVC - Hit to URL with RequestParam failing with 404 Not Found Error - spring

I am using Spring MVC in my project and while mapping user request to a URI, I get the 404 error. Here is my function skeleton which I want to be invoked:
#RequestMapping(value="/inventory/discovery", method = RequestMethod.GET, params = {"discoveryType"}, produces = {"application/json"})
public String getDiscoveryByType(#RequestParam("discoveryType") String discoveryType)
{
return discoveryType;
}
I am expecting this method to be called when I give the URL
http://<some-ip>/inventory/discovery/discoveryType?=DMVPN
However, when I test the code using Chrome's Advanced Rest Client I see that the URI it is trying to access is "/inventory/DMVPN" and not the "/inventory/discovery?discoveryType=DMVPN".
Am I missing something here? I don't see anything wrong with my URL syntax
I have another function in my code (but I don't think it is causing the problem) which has same request-mapping value, but has no params attribute.
#RequestMapping(value = "/inventory/discovery", method = RequestMethod.GET, produces = { "application/json" })
public ResponseEntity<DiscoveryNIOListResult> getAllDiscovery() {
logger.trace("getAllDiscovery");
List<DiscoveryNIO> listDiscoveryNIO = discoveryDasClient.getDiscoveryList();
DiscoveryNIOListResult result = new DiscoveryNIOListResult();
result.setResponse(listDiscoveryNIO);
return new ResponseEntity<DiscoveryNIOListResult>(result, HttpStatus.OK);
}

Ok, so a second look at your URL:
http://<some-ip>/inventory/discovery/discoveryType?=DMVPN
This is NOT passing discoveryType as a request GET parameter. For that you would need to do:
http://<some-ip>/inventory/discovery&discoveryType?=DMVPN
If you want to use path variables instead, you could do something like:
http://<some-ip>/inventory/discovery/DMVPN
And change your handler to something like:
#RequestMapping(value="/inventory/discovery/{discoveryType}", method = RequestMethod.GET, produces = {"application/json"})
public String getDiscoveryByType(#PathVariable("discoveryType") String discoveryType)
{
return discoveryType;
}
It looks like you were trying to mix these two methods, and that wont work.

Try changing your URL to:
http://<some-ip>/inventory/discovery?discoveryType=DMVPN

Related

How to pass 2 or more variables using #PathParam in spring mvc? and suppose if I want to test it out using postman how to do that?

I'm trying to fetch value from db using JPA repository method
product findByIdNumberOrCifNumber(String idNumber , String cifNumber);
service class logic:-
public ResponseModel FindByCivIDOrCifNumber(String idNumber,String cifNumber) {
ResponseModel responseModel = new ResponseModel();
Optional<product> civId = Optional.ofNullable(productRepos.findByIdNumber(idNumber));
if (civId.isPresent()) {
responseModel.setResponse(productRepos.findByIdNumberOrCifNumber(idNumber,cifNumber));
} else {
errorModel errorModel1 = new errorModel();
enter image description here errorModel1.setErrorCode(productConstant.INVALID_REQUEST);
errorModel1.setErrorDescription("Requested Civil Id or CifNUmber is not present");
responseModel.setErrorModel(errorModel1);
}
return responseModel;
}
controller class:-
#GetMapping("/getByCifNoOrGetByIdNo")
public ResponseModel getProductByCifNoOrGetByIdNo(#RequestParam String idNumber,#RequestParam String cifNumber ) {
return productService.FindByCivIDOrCifNumber(idNumber,cifNumber);
}
post man:-
kindly help me out how to make it work:)
If you are looking for an answer to pass two or more path variables and test it with postman, you can try this.
#GetMapping("/api/mapping-name/{variable1}/{variable2}")
Here you will be getting two path variables which you can access by the syntax
#PathVariable("variable1") datatype variableName
Now in postman request url you can simply give the respective url, lets say:
https://localhost8080/api/mapping-name/:variable1/:variable2
which automaticaly will give you a key value section in the path variables section in the params with prepopulated key names as per the name you have given. In this case variable1 & variable2.
Give the respective value and it should work.

Is there any situation QueryString is present but HttpServletRequest.getParameterMap() is empty?

I have encouterd an odd situation while we are doing press testing in our test env. When the app load is high, the Query String will missing occasionally and the Spring will throw MissingServletRequestParameterException.
In order to find the root cause , I add some logs at the foremost Filter(code is shown below), and something weired happened.
public static void printRequestParameter(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
log.info("Request URI : {}, method = {} , query string = {}", request.getRequestURI(), request.getMethod(), request.getQueryString());
if (MapUtils.isNotEmpty(parameterMap)) {
parameterMap.forEach((k, v) -> {
log.info("Request parameter name = {}, value = {}", k, ArrayUtils.isEmpty(v) ? Strings.EMPTY : Arrays.stream(v).collect(Collectors.joining(COMMA)));
});
}
}
The request.getParameterMap() is empty, but , the query string is not empty , and I got a log like :
Request URI : /a/b/c, method = POST , query string = foo=bar.
But no logs like:
Request parameter name = foo , value = bar
And our Controller use #RequestParam() String foo to receivce the parameter , finally , the Spring throws
MissingServletRequestParameterException Handler org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'foo' is not present
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:204)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:114)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)
at org.springframework.web.method.support.InvocableH
I just wonder, why the parameter in query string is not contained in parameterMap?
Note:
The odd behavior is only happened occasionally, at most time it's just works.
My spring boot version is 2.3.9.RELEASE and the embedded tomcat version is 9.0.43.
Any help is appreciated!
Since the specification does not allow ServletRequest.getParameterMap to throw any exception, any failure in parameter parsing will cause the parameter list to be empty.
To detect this situation you can log the "org.apache.catalina.parameter_parse_failed_reason" attribute of your request.
Examples of query strings that should fail:
?=noname,
?urlEncoding=%ue

ResponseEntity return type wildcard with swagger generated interface

I want to know the difference between returning ResponseEntity<?> with wildcard VS ResponseEntity<ABC.class> as return type when Swagger generated API interface contains 2 different classes as return types, i.e one for an exception and another for normal flow.
My controller interface is :-
#Operation(summary = "Get user by user name", tags = { "user" })
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "successful operation", content = #Content(schema = #Schema(implementation = User.class))),
#ApiResponse(responseCode = "400", description = "Invalid username supplied", content = #Content(schema = #Schema(implementation = Error.class)))
})
#GetMapping(value = "/user/{username}", produces = { "application/xml", "application/json" })
ResponseEntity<?> getUserByName(#PathVariable("username") String username);
the #Schema defines return type.
Can I use ResponseEntity<User> instead of the <?> for the getUserByName method ?
I have the the global exception handler #ControllerAdvice in my application which returns ResponseEntity<Error> .
Answer for your question is simply Yes. Since you are using a Controller Adviser, you can directly define the endpoint return type as User in ResponseEntity
Using a Wildcard(ResponseEntity<?>) as a return type, the symbol ? defines that the return value of the controller method can be any type of ResponseEntity.
Using as ResponseEntity<?> or simply keep it as ResponseEntity<> are considered as raw type of its usage.
But really it is not a good practice to do so. So, you have to declare the exact return type of the controller method in this format ResponseEntity<ABC>.
Let's take this example java of method returning a list of objects(List<Object>).
It is possible on this list to add a Car.class type, a Van.class type. But how ever the consumer of a method should not have to deal with such disruptive questions and we have to define an exact type.
Yes you can use ResponseEntity<User> if your method returns a User type ResponseEntity.
I hope this'll help you to solve the issue :)

Why am I getting "400 Bad Request" for this URL in Spring MVC?

The following URL results in a "400 Bad Request":
http://localhost:8080/springdata_web/rest/errors/test?from=2014-05-25T00:00:00.000Z&to=2014-05-27T00:00:00.000Z
The matching #RequestMapping is below. I can see I am definitely hitting this method because I see the Sysout line in the console using the following URL for example:
http://localhost:8080/springdata_web/rest/errors/test?from=&to=
So I guess it's to do with the Date type and Spring not accepting the format I'm passing in the request params but I don't see why.
#RequestMapping(value = "/test",
method = RequestMethod.GET,
produces = "application/json")
#ResponseBody
public Resource<List<ErrorsDTOEntity>> getAllErrors(
#RequestParam(value = "from", required = true) #DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Date from,
#RequestParam(value = "to", required = true) #DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Date to) {
System.out.println("getAllErrors(Date, Date);");
List<ErrorsDTOEntity> services = errorsDAO.getAllErrors(from, to);
Resource<List<ErrorsDTOEntity>> toReturn = new Resource<List<ErrorsDTOEntity>>(services);
toReturn.add(linkTo(methodOn(ErrorsController.class).getAllErrors(from, to)).withSelfRel());
return toReturn;
}
It was the format of the date in the URL. This URL-encoded request works:
http://localhost:8080/springdata_web/rest/errors/test?from=2014-05-25T00%3A00%3A00.000%2B0000&to=2014-05-27T00%3A00%3A00.000%2B0000
The date pattern you are passing for ( from / to) is not matching. Underltying pattern for is DateTimeFormat.ISO DATE_TIME:
yyyy-MM-dd'T'hh:mm:ss.SSSZ
so example time is as below :
2000-10-31T01:30:00.000-05:00
try whether following request work:
test?from=2000-10-31T01:30:00.000-05:00&to=2000-10-31T01:30:00.000-05:00
Spring Docs says :

Spring Matrix Variables require at least one template variable to work?

I've been trying to get a simple REST API to list contents of a collection and I'm using matrix variables to control the pagination.
My controller has the following method to list contents of a collection:
#RequestMapping(
value = "articles",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ArticlePageRestApiResponse listArticles(
#MatrixVariable(required = true, defaultValue = 100, value = "resultsPerPage") int resultsPerPage,
#MatrixVariable(required = true, defaultValue = 0, value = "pageNumber") int pageNumber) {
// some logic to return the collection
}
If I then do a GET http://example.com/articles;resultsPerPage=22;pageNumber=33 it fails to find a request mapping. I have enabled matrix variables support by adding the following:
#Configuration
public class EnableUriMatrixVariableSupport extends WebMvcConfigurationSupport {
#Override
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping hm = super.requestMappingHandlerMapping();
hm.setRemoveSemicolonContent(false);
return hm;
}
}
What I've found is that if the matrix variables are prefixed with at least one template variable then the matrix variables are correctly assigned. The following works but is ugly where I've had to make part of the URI path a template variable that is always going to be "articles" to trick the Request Mapping Handler into thinking there is at least one URI template variable :
#RequestMapping(
value = "{articles}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ArticlePageRestApiResponse listArticles(
#PathVariable("articles") String ignore,
#MatrixVariable(required = true, defaultValue = 100, value = "resultsPerPage") int resultsPerPage,
#MatrixVariable(required = true, defaultValue = 0, value = "pageNumber") int pageNumber) {
// some logic to return the collection
}
Have I found a bug or am I mis-understanding matrix variables?
According to Spring documentation
If a URL is expected to contain matrix variables, the request mapping
pattern must represent them with a URI template. This ensures the
request can be matched correctly regardless of whether matrix
variables are present or not and in what order they are provided.
In your first example you use no templates (like {articles}) in URL mapping, so Spring is unable to detect matrix parameters.
I'd rather call it not a bug, but an implemnetation side effect. We have it just because #MatrixVariable support is build on the top of the old #PathVariable parsing mechanism.

Resources