Build \ maven clean + install bizarreness - spring

In my project i made the following change:
from:
#RequestMapping(value = "/login/", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(value = HttpStatus.OK)
#ResponseBody
public long getLogin(#RequestBody UserLoginData userData, HttpServletRequest request) {
logger.info(String.format(
Constants.LogMessages.NEW_POST_REQUEST_FROM_IP,
request.getRemoteAddr()));
logger.info("/login/");
long result = userService.getUserByUsernameAndPassword("", "");
return result;
}
to:
#RequestMapping(value = "/login/", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(value = HttpStatus.OK)
#ResponseBody
public long getLogin(#RequestBody UserLoginData userData, HttpServletRequest request) {
logger.info(String.format(
Constants.LogMessages.NEW_POST_REQUEST_FROM_IP,
request.getRemoteAddr()));
logger.info("/login/");
long result = userService.getUserByUsernameAndPassword("", "");
return result;
}
(I change the mapping-requestMethod from POST to GET)
in one of my #controller
thing is - after i made the change, i restarted the tomcat.
and tried to call the controller GET method.
got an error: GET is not supported, but POST is supported.
meaning - the change didn't took place in my project build.
the bizarre thing is after i did project\maven\ run as maven-clean
and right afterwards - project\maven\ run as maven-install
the changes took place!
can anyone explain please why maven has anything to do with my project logic? i thought its for dependencies only...
p.s i got the "build automatically" options set to "true" and i use spring tool suite.
cheers

Related

Not working #PostMapping 404 path not found

The first request works, but on the second it gives 404, path not found
What can it be done with?
#PostMapping(value = "/postsViews", consumes = "application/json", produces = "application/json")
public Integer generateViews(#RequestBody PostViewsDTO requestDTO) throws IOException, JRException {
viewsService.generate(requestDTO.getFileName(), requestDTO.getProjectId());
return HttpServletResponse.SC_OK;
}
#PostMapping(value = "/favorite", consumes = "application/json", produces = "application/json")
public Integer generateFavorite(#RequestBody FavoriteDTO requestDTO) throws IOException, JRException {
favoriteService.generate(requestDTO);
return HttpServletResponse.SC_OK;
}
The problem is solved, gitlab uploaded not the last commit to the server
There's only two things that I can think of.
First, to make sure that you are running the code that you think you are, try shutting the app down, then "clean" the project, build and run it again.
If that doesn't work, it might be a mismatch between the data that you are posting and the definition of FavoriteDTO. Try commenting out the parameter and the line of code that uses it.

Spring's MockMvc picks up wrong handler method

I have a controller that contains 2+ methods:
#RequestMapping(method = RequestMethod.GET, value = "/{uuid}", produces = "application/json")
public MyObject findByUuid(
#PathVariable("uuid") String uuid) {
...
}
#RequestMapping(method = RequestMethod.POST, value = "/findByStringPropertyEquals", produces = "application/json")
public List<MyObject> findByStringPropertyEquals(
#RequestParam("type") String type,
#RequestParam("property") String property,
#RequestParam("value") String value) {
...
}
Now when I try to test the second method like
mvc.perform(get("/findByStringPropertyEquals?type={0}&property={1}&value={2}", "Person", "testPropInt", 42))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)));
then MockMvc picks up the findByUuid controller method unfortunately. Output is
MockHttpServletRequest:
HTTP Method = GET
Request URI = /api/v1/domain-entities/findByStringPropertyEquals
Parameters = {type=[Person], property=[testPropInt], value=[42]}
Headers = {}
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = com.example.MyObjectController
Method = public com.example.MyObject com.example.MyObjectController.findByUuid(java.lang.String)
However, accessing the REST API regularly when the web server is started is working fine. Is that a bug or do I do something wrong?
In your code you are invoking a GET:
mvc.perform(get("/findByStringPropertyEquals?type={0}&property={1}&value={2}", "Person", "testPropInt", 42))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)));
However the findByStringPropertyEquals method is declared for POST so your code cannot address that method with a GET. I'm not sure why the MockMVC layer has chosen findByUuid (perhaps because that is the only GET method on this controller) but the reason your code is not hitting findByStringPropertyEquals is that you have chosen the wrong HTTP method.
Try mvc.perform(post(...)) instead.

Ambiguous mapping error

I am working on a Spring MVC project in IntelliJ, hosted on Tomcat 6.0.44, using JDK 1.8.0_60. My whole team is running our application without any issues. On my machine, when I try to run the latest code from Git, the same code the rest of the team is running, I get this error:
Context initialization failed Ambiguous mapping. Cannot map 'CartValidate' method.
There are 2 CartValidate methods (one POST, one GET), and a view method in the same controller that seem to be causing this issue.
If I change the request mappings for these 3 methods (I don't have to change the method names, just the request mappings), then it works fine.
I've searched the full codebase for the request mapping values, and they don't occur anywhere else, so I can't understand why there would be a problem with the original request mappings. The original request mappings are cart/validate.json and cart/view.json.
Does anyone have any idea what might be going on?
Here is the code for the 3 methods for which I need to change the request mapping to make the code run:
#ResponseBody
#RequestMapping(value = "/cart/view.json", method = RequestMethod.GET, produces = "application/json", consumes = "application/json")
public Order view(#RequestParam(value = "orderId") Long orderId,
HttpServletRequest aRequest, HttpServletResponse aResponse) {
Order order = orderService.orderGet(aRequest, aResponse, orderId);
return order;
}
#ResponseBody
#RequestMapping(value = "/cart/validate.json", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
public OrderWeb CartValidate(#RequestBody OrderWeb aModel,
HttpServletRequest aRequest, HttpServletResponse aResponse) {
String orderId = aModel.getOrderId().toString();
OrderWeb order = orderService.orderValidatePost(aModel, orderId,
aRequest, aResponse);
return order;
}
#ResponseBody
#RequestMapping(value = "/cart/validate.json", method = RequestMethod.GET, consumes = "application/json", produces = "application/json")
public OrderWeb CartValidate(#RequestParam(value = "orderId", required = true) Long orderId,
HttpServletRequest aRequest, HttpServletResponse aResponse) {
OrderWeb aModel = (OrderWeb) orderService.orderGet(aRequest, aResponse, orderId);
OrderWeb order = orderService.orderValidatePost(aModel, orderId.toString(),
aRequest, aResponse);
return order;
}

When use ResponseEntity<T> and #RestController for Spring RESTful applications

I am working with Spring Framework 4.0.7, together with MVC and Rest
I can work in peace with:
#Controller
ResponseEntity<T>
For example:
#Controller
#RequestMapping("/person")
#Profile("responseentity")
public class PersonRestResponseEntityController {
With the method (just to create)
#RequestMapping(value="/", method=RequestMethod.POST)
public ResponseEntity<Void> createPerson(#RequestBody Person person, UriComponentsBuilder ucb){
logger.info("PersonRestResponseEntityController - createPerson");
if(person==null)
logger.error("person is null!!!");
else
logger.info("{}", person.toString());
personMapRepository.savePerson(person);
HttpHeaders headers = new HttpHeaders();
headers.add("1", "uno");
//http://localhost:8080/spring-utility/person/1
headers.setLocation(ucb.path("/person/{id}").buildAndExpand(person.getId()).toUri());
return new ResponseEntity<>(headers, HttpStatus.CREATED);
}
to return something
#RequestMapping(value="/{id}", method=RequestMethod.GET)
public ResponseEntity<Person> getPerson(#PathVariable Integer id){
logger.info("PersonRestResponseEntityController - getPerson - id: {}", id);
Person person = personMapRepository.findPerson(id);
return new ResponseEntity<>(person, HttpStatus.FOUND);
}
Works fine
I can do the same with:
#RestController (I know it is the same than #Controller + #ResponseBody)
#ResponseStatus
For example:
#RestController
#RequestMapping("/person")
#Profile("restcontroller")
public class PersonRestController {
With the method (just to create)
#RequestMapping(value="/", method=RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void createPerson(#RequestBody Person person, HttpServletRequest request, HttpServletResponse response){
logger.info("PersonRestController - createPerson");
if(person==null)
logger.error("person is null!!!");
else
logger.info("{}", person.toString());
personMapRepository.savePerson(person);
response.setHeader("1", "uno");
//http://localhost:8080/spring-utility/person/1
response.setHeader("Location", request.getRequestURL().append(person.getId()).toString());
}
to return something
#RequestMapping(value="/{id}", method=RequestMethod.GET)
#ResponseStatus(HttpStatus.FOUND)
public Person getPerson(#PathVariable Integer id){
logger.info("PersonRestController - getPerson - id: {}", id);
Person person = personMapRepository.findPerson(id);
return person;
}
My questions are:
when for a solid reason or specific scenario one option must be used mandatorily over the other
If (1) does not matter, what approach is suggested and why.
ResponseEntity is meant to represent the entire HTTP response. You can control anything that goes into it: status code, headers, and body.
#ResponseBody is a marker for the HTTP response body and #ResponseStatus declares the status code of the HTTP response.
#ResponseStatus isn't very flexible. It marks the entire method so you have to be sure that your handler method will always behave the same way. And you still can't set the headers. You'd need the HttpServletResponse.
Basically, ResponseEntity lets you do more.
To complete the answer from Sotorios Delimanolis.
It's true that ResponseEntity gives you more flexibility but in most cases you won't need it and you'll end up with these ResponseEntity everywhere in your controller thus making it difficult to read and understand.
If you want to handle special cases like errors (Not Found, Conflict, etc.), you can add a HandlerExceptionResolver to your Spring configuration. So in your code, you just throw a specific exception (NotFoundException for instance) and decide what to do in your Handler (setting the HTTP status to 404), making the Controller code more clear.
According to official documentation: Creating REST Controllers with the #RestController annotation
#RestController is a stereotype annotation that combines #ResponseBody
and #Controller. More than that, it gives more meaning to your
Controller and also may carry additional semantics in future releases
of the framework.
It seems that it's best to use #RestController for clarity, but you can also combine it with ResponseEntity for flexibility when needed (According to official tutorial and the code here and my question to confirm that).
For example:
#RestController
public class MyController {
#GetMapping(path = "/test")
#ResponseStatus(HttpStatus.OK)
public User test() {
User user = new User();
user.setName("Name 1");
return user;
}
}
is the same as:
#RestController
public class MyController {
#GetMapping(path = "/test")
public ResponseEntity<User> test() {
User user = new User();
user.setName("Name 1");
HttpHeaders responseHeaders = new HttpHeaders();
// ...
return new ResponseEntity<>(user, responseHeaders, HttpStatus.OK);
}
}
This way, you can define ResponseEntity only when needed.
Update
You can use this:
return ResponseEntity.ok().headers(responseHeaders).body(user);
A proper REST API should have below components in response
Status Code
Response Body
Location to the resource which was altered(for example, if a resource was created, client would be interested to know the url of that location)
The main purpose of ResponseEntity was to provide the option 3, rest options could be achieved without ResponseEntity.
So if you want to provide the location of resource then using ResponseEntity would be better else it can be avoided.
Consider an example where a API is modified to provide all the options mentioned
// Step 1 - Without any options provided
#RequestMapping(value="/{id}", method=RequestMethod.GET)
public #ResponseBody Spittle spittleById(#PathVariable long id) {
return spittleRepository.findOne(id);
}
// Step 2- We need to handle exception scenarios, as step 1 only caters happy path.
#ExceptionHandler(SpittleNotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public Error spittleNotFound(SpittleNotFoundException e) {
long spittleId = e.getSpittleId();
return new Error(4, "Spittle [" + spittleId + "] not found");
}
// Step 3 - Now we will alter the service method, **if you want to provide location**
#RequestMapping(
method=RequestMethod.POST
consumes="application/json")
public ResponseEntity<Spittle> saveSpittle(
#RequestBody Spittle spittle,
UriComponentsBuilder ucb) {
Spittle spittle = spittleRepository.save(spittle);
HttpHeaders headers = new HttpHeaders();
URI locationUri =
ucb.path("/spittles/")
.path(String.valueOf(spittle.getId()))
.build()
.toUri();
headers.setLocation(locationUri);
ResponseEntity<Spittle> responseEntity =
new ResponseEntity<Spittle>(
spittle, headers, HttpStatus.CREATED)
return responseEntity;
}
// Step4 - If you are not interested to provide the url location, you can omit ResponseEntity and go with
#RequestMapping(
method=RequestMethod.POST
consumes="application/json")
#ResponseStatus(HttpStatus.CREATED)
public Spittle saveSpittle(#RequestBody Spittle spittle) {
return spittleRepository.save(spittle);
}

Ignore / from #requestmapping value in MVC Spring

My file path or directory like a/b/c/d
I am triggered this in rest but i am getting HTTP Status 404 error.
i want to ignore / from filepath and want to print like a/b/c/d without 404 error.
#RequestMapping(value = "/TEST/{filepath:./*}", method = RequestMethod.GET)
public void DownloadFile(#PathVariable("filepath") String filePath) {
System.out.println(filePath);
}
This is what i am triggered in rest TEST/a/b/c/d
Please Help..
This solution does not use PathVariable:
#RequestMapping(value = "/TEST/**", method = RequestMethod.GET)
public void DownloadFile(HttpServletRequest request) {
String filePath = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
System.out.println(filePath.substring(filePath.indexOf("TEST")));
}

Resources