In my controller I am having if condition and two different response type. I will get response in JSON format from "if" condition, but I am getting response from else condition like unexpected '0 , instead I need to get my error message'.
My controller code snippet
#RequestMapping(value = "/saveuser", produces = { "application/json" }, consumes = { "application/json" }, method = RequestMethod.POST)
public ResponseEntity<?> addUser(#RequestBody TestUser user)
throws NotFoundException {
System.out.println(user.getAnswer().size());
if(questioncount == user.getAnswer().size())
{
return new ResponseEntity<TestUser>(service.addUser(user),
HttpStatus.OK);
}else {
String one="one";
String erromessage = "Only" + questioncount +" questions are allowed";
System.out.println(erromessage);
return new ResponseEntity<String>(erromessage,HttpStatus.NOT_ACCEPTABLE);
}
}
Related
I am trying to use swagger with java.
Using NSwag studio I am able to generate all my endpoints except one that returns a list of objects.
Here is my action in controller:
#ApiOperation(value = "getAll", nickname = "getAll", responseContainer = "List", response = DiakEntity.class)
#GetMapping("/api/diakok")
#ResponseBody
#PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
public List<DiakEntity> GetDiakok() throws Exception
{
ServiceObjectResponse<List<DiakEntity>> request = _diakService.getAll();
if(!request.getIsSuccess())
{
throw new Exception(request.getMessage());
}
return request.getObject();
}
I am using swagger-annotations 1.5.23, springfox-swagger-ui 2.9.2, springfox-swagger2 2.9.2.
If I test from Postman it works.
Also tried like this:
#ApiOperation(value = "getAll", nickname = "getAll")
#ApiResponse(code = 200, responseContainer="List", response=DiakEntity.class, message = "Gets all diak objects")
#GetMapping("/api/diakok")
#ResponseBody
#PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
public ResponseEntity<List<DiakEntity>> GetDiakok() throws Exception
{
ServiceObjectResponse<List<DiakEntity>> request = _diakService.getAll();
if(!request.getIsSuccess())
{
throw new Exception(request.getMessage());
}
return new ResponseEntity<>(request.getObject(), HttpStatus.OK);
}
thnx
Please try with the following annotation for swagger.
#ApiOperation(value = "getAll", nickname = "getAll")
#ApiResponse(code = 200, responseContainer="List", response=DiakEntity.class)
At the end I changed my action as below, and it started to work
#ApiOperation(value = "all", nickname = "all")
#PostMapping("/api/diak/all")
#ResponseBody
#PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
public List<DiakEntity> GetAll(#RequestBody #Valid RequestDiakByName data) throws Exception
{
ServiceObjectResponse<List<DiakEntity>> request = _diakService.getAll();
if(!request.getIsSuccess())
{
throw new Exception(request.getMessage());
}
return request.getObject();
}
I have one GET Rest-endpoint in my sample app which returns some data based on criteria it can also return null if no data is available with HTTP status as 204 else 200 OK if data is available.
#GetMapping("/homepage")
public ResponseEntity getHomePageCollections(#RequestHeader(value = HEADER_APP_TOKEN) String headerAppToken) {
CollectionObject homepageCollections = null;
String errorMessage = null;
HttpStatus httpStatus;
try {
homepageCollections = collectionService.getHomePageCollections();
if (nonNull(homepageCollections)) {
httpStatus = HttpStatus.OK;
LOGGER.info("{} Response Status from CollectionController -- getHomePageCollections !! {}", TRANSACTION_SUCCESS_CODE, TRANSACTION_SUCCESS);
} else {
httpStatus = HttpStatus.NO_CONTENT;
LOGGER.info("{} Response Status from CollectionController -- getHomePageCollections !! {}", NO_CONTENT_CODE, NO_CONTENT);
}
} // catch logic
return ResponseEntity.status(httpStatus).contentType(MediaType.APPLICATION_JSON).body(httpStatus == HttpStatus.OK || httpStatus == HttpStatus.NO_CONTENT ? homepageCollections : errorMessage);
}
I have 2 questions, first is how to assert the content type is
set by the controller in my unit test
Unit Test
#Test
public void testGetHomePageCollection() {
when(collectionService.getHomePageCollections()).thenReturn(null);
ResponseEntity responseEntity = collectionController.getHomePageCollections(HEADER_APP_TOKEN);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
}
When the homepageCollections is null spring auto-sets the content type as octet-stream, is there a reason behind it?
The ContentType is present in the headers of the response, so you can test the same by accessing it as below:
#Test
public void testGetHomePageCollection() {
when(collectionService.getHomePageCollections()).thenReturn(null);
ResponseEntity responseEntity = collectionController.getHomePageCollections(HEADER_APP_TOKEN);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
assertThat(responseEntity.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON_VALUE);
}
I'm writing my first spring application, and would like to get experience to make an optimal and attractive code on spring.
I've some restcontrollers which have the big part of similar code
#RequestMapping(path = "/1154",
method = RequestMethod.POST,
headers = {"Content-Type=application/json"},
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public CreateUserResp processRequest(#RequestBody #Valid CreateUserReq request, BindingResult bindingResult) {
CreateUserResp response = new CreateUserResp();
if (bindingResult.hasErrors()){
response.setResultCode(102); // Validation error
response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");
} else {
// main service
request = UserService.doSomething();
}
return response;
}
#RequestMapping(path = "/1155",
method = RequestMethod.POST,
headers = {"Content-Type=application/json"},
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ChangeUserResp processRequest(#RequestBody #Valid ChangeUserReq request, BindingResult bindingResult) {
ChangeUserResp response = new ChangeUserResp();
if (bindingResult.hasErrors()){
response.setResultCode(102); // Validation error
response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");
} else {
// main service
request = ChangeService.doSomething();
}
return response;
}
#RequestMapping(path = "/1156",
method = RequestMethod.POST,
headers = {"Content-Type=application/json"},
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public AddUserResp processRequest(#RequestBody #Valid AddUserReq request, BindingResult bindingResult) {
AddUserResp response = new AddUserResp();
if (bindingResult.hasErrors()){
response.setResultCode(102); // Validation error
response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");
} else {
// main service
request = AddService.doSomething();
}
return response;
}
#RequestMapping(path = "/1157",
method = RequestMethod.POST,
headers = {"Content-Type=application/json"},
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ModifyUserResp processRequest(#RequestBody #Valid ModifyUserReq request, BindingResult bindingResult) {
ModifyUserResp response = new ModifyUserResp();
if (bindingResult.hasErrors()){
response.setResultCode(102); // Validation error
response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");
} else {
// main service
request = ModifyService.doSomething();
}
return response;
}
etc ....
The only differences in (path, #RequestBody and Responce objects, and called service ). So, I'll have 10-12 controllers like this one. Is it the way to make this code more optimal and not to write this repeatable blocks of code 10 times (spring methods or may be using generic class or methods). It's just example, not real code. Thx
Especial thanks to people who are very busy to answer but have time to put minus.
I have something quite similar in my application.
For example this is how my editProfile method from the User controller looks like:
#PostMapping(value = EDIT_CONTACT_INFO)
public ResponseEntity<?> editContactInfo(
#Autowired HttpServletRequest httpServletRequest,
#RequestBody #Valid ContactInfoDTO.Req requestBody,
BindingResult bindingResult
)
{
if (bindingResult.hasErrors())
// 400 - BAD REQUEST
return ErrorsDTO.from(bindingResult).responseEntity();
String userName = ControllerUtils.getUserName(httpServletRequest);
User user = userService.findByUserName(userName);
ContactInfo contactInfo = modelMapper.map(requestBody, ContactInfo.class);
if (!userService.editContactInfo(user, contactInfo))
// 500 - INTERNAL SERVER ERROR
return ErrorsDTO.from(INTERNAL_SERVER_ERROR).responseEntity();
// 200 - OK
return ResponseEntity.ok(null);
}
The majority of my API looks quite similar to yours. I've just written my custom mechanism to report errors, and I use a ResponseEntity instance to return data.
Also I have a library to pass data from DTOs to my Model and back (it's called ModelMapper).
edit: it looks like this blogpost covers your question:
http://blog.codeleak.pl/2013/09/request-body-validation-in-spring-mvc-3.2.html
If you really want to get down and dirty, you could write an interceptor, with a pointcut on a new annotation ValidateBinding and an argument of BindingResult. It would probably look something like:
#Around("#annotation(ValidateBinding) && execution(* *(..)) && args(bindingResult)
public Object handleInvalidBindings(ProceedingJoinPoint p, BindingResult bindingResult) {
if (bindingResult.hasErrors()){
GenericResponse response = createTypedResponse(p);
response.setResultCode(102); // Validation error
response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");
return response;
}
return pjp.proceed();
}
private GenericResponse createTypedResponse(ProceedingJoinPoint p) {
MethodSignature signature = (MethodSignature) p.getSignature();
Method method = signature.getMethod();
Class responseClass = method.getReturnType();
if(!GenericResponse.class.isAssignableFrom(responseClass)) {
throw new IllegalArgumentException("Could not create proper response class - it should implement the GenericResponse interface");
return (GenericResponse) responseClass.newInstance();
}
But I'm not guaranteeing the expression or the code works. This is more a rough guess on how it could look.
To do this, you'd need an interface GenericResponse which is implemented by your responseclasses, and has a setResultCode and setErrMsg.
I have built an application with Spring-boot and AngularJS with the REST End Point application. I got a little stuck with #RequesMapping in Spring Controller I've made. The problem is, I have the example url:
"localhost:8080/foo/bar/api/cardGenerated/0102".
'01' is first parameter and '02' is second parameter. How can I mapped into #RequestMapping Spring controller to get a url above.
Here's my controller :
#RestController
#RequestMapping("/api")
public class CardGeneratedResource {
#RequestMapping(value = "/cardGenerated/{branchCode}{cardType}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<CardGenerated> get(#PathVariable("branchCode") String branchCode,
#PathVariable("cardType") String cardType,
HttpServletResponse response) {
log.debug("REST request to get CardGenerated : " + branchCode + " and " + cardType);
CardGenerated cardGenerated = cardGeneratedRepository.
findTopByBranchCodeAndCardTypeOrderByCardNumberDesc(branchCode, cardType);
if (cardGenerated == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(cardGenerated, HttpStatus.OK);
}
}
so this is my AngularJS $resource:
'use strict';
angular.module('itmApp')
.factory('CardGenerated', function ($resource) {
return $resource('api/cardGenerated/:branchCode:cardType', {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
data = angular.fromJson(data);
return data;
}
}
});
});
I always got 'Failed to load resource: the server responded with a status of 404 (Not Found)'.
Here you are missing / .
You have two path variable here.so default url is
localhost:8080/foo/bar/api/cardGenerated/FIRST_PATH_VARIABLE/SECOND_PATH_VARIABLE
branchCode (First path variabel)
cardType (Second path variable)
#RequestMapping(value = "/cardGenerated/{branchCode}/{cardType}"
And in frontend side too the same mistake while registering factory definition.
api/cardGenerated/:branchCode/:cardType'
All method is like
#RestController
#RequestMapping("/api")
public class CardGeneratedResource {
#RequestMapping(value = "/cardGenerated/{branchCode}/{cardType}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<CardGenerated> get(#PathVariable("branchCode") String branchCode,
#PathVariable("cardType") String cardType,
HttpServletResponse response) {
log.debug("REST request to get CardGenerated : " + branchCode + " and " + cardType);
CardGenerated cardGenerated = cardGeneratedRepository.
findTopByBranchCodeAndCardTypeOrderByCardNumberDesc(branchCode, cardType);
if (cardGenerated == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(cardGenerated, HttpStatus.OK);
}
}
and angular factory is like
'use strict';
angular.module('itmApp')
.factory('CardGenerated', function ($resource) {
return $resource('api/cardGenerated/:branchCode/:cardType', {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
data = angular.fromJson(data);
return data;
}
}
});
});
NOTE: First try with any rest client or postman and make sure backend api is working properly also angular side check parameters are being passed correctly.
My requirement is simple i.e i want to write a common methods which suppose to have auto intelligence based on user request it will generate response, like if i submit as a html it should produce html . if i submit as a Json it should produce Json.
Below is 2 sample code ,If i write 2 separate method it works fine but i want to write it to one common method.
1)below is sample code which works for html
#Controller
public class Program1Controller {
#RequestMapping("/helloworld")
public #ResponseBody ModelAndView helloWord(){
String message = "Welcome to TEST";
return new ModelAndView("Test1", "message",message);
}
}
2)below is sample code which work for json
#RequestMapping(value = DUMMY_EMP, method = RequestMethod.GET)
public #ResponseBody String getDummyEmployee() {
String message = "Welcome to TEST";
return message;
}
Instead writing 2 separate method i want to write one method which should have auto intelligence to send a response based on user request.
Above Query for GET ,Same also how can i do for POST.
You can handle that one in ajax. In your controller you have 2 different methods returning JSON, POST and GET and it can have the same value for its RequestMapping. Example:
#RequestMapping(value = "/returnJSON", method = RequestMethod.GET)
public #ResponseBody String getDummyEmployee() {
String message = "Welcome to TEST";
return message;
}
#RequestMapping(value = "/returnJSON", method = RequestMethod.POST)
public #ResponseBody String getDummyEmployee2() {
String message = "Welcome to TEST";
return message;
}
This should also be done for the one returning the HTML Object:
#RequestMapping(value = "/helloworld", method = RequestMethod.GET)
public #ResponseBody ModelAndView helloWord(){
String message = "Welcome to TEST";
return new ModelAndView("Test1", "message",message);
}
}
#RequestMapping(value = "/helloworld", method = RequestMethod.POST)
public #ResponseBody ModelAndView helloWord2(){
String message = "Welcome to TEST";
return new ModelAndView("Test1", "message",message);
}
}
Now, before going to the jquery ajax call, pass as parameter the url and type:
$.ajax({
type: type,
url: url,
data: { name: "John", location: "Boston" }
})
.done(function( msg ) {
alert( "Data Saved: " + msg );
});