I'm having a problem with response entity exception handling. as it is seen, my response entity error is not changing the HTTP response.
My Codes
public ResponseEntity<User> retriveUser(#PathVariable int id){
Optional<User> foundUser;
foundUser= userRepo.findById(id);
if(foundUser.get()==null) {
return new ResponseEntity<>(foundUser.get(),HttpStatus.HttpStatus.NOT_FOUND);
}
else {
return new ResponseEntity<>(foundUser.get(),HttpStatus.OK);
}
}
There are a few errors in your code, first of all the foundUser.get()==null part does not enter the if block because it throw an error. You can check the java document to find out why you throw an error.
It also needs to be HttpStatus.NOT_FOUND instead of HttpStatus.HttpStatus.NOT_FOUND.
In the "Not Found" line, so that the optionalUser.get() method does not give an error; you have to remove it too.
#GetMapping("/user/{id}")
public ResponseEntity<User> retrieveUser(#PathVariable int id) {
Optional<User> optionalUser = userRepo.findById(id);
if (!optionalUser.isPresent()) {
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
} else {
return new ResponseEntity<>(optionalUser.get(), HttpStatus.OK);
}
}
You should not call get() method if value is not present. can you try like below
public ResponseEntity<User> retriveUser(#PathVariable int id){
Optional<User> foundUser = userRepo.findById(id);
if(foundUser.isPresent()) {
return new ResponseEntity<>(foundUser.get(),HttpStatus.HttpStatus.OK);
}else {
return new ResponseEntity<>(null,HttpStatus.NOT_FOUND);
//or just return not found status code
//return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
Although the current accepted answer has all the details it needs, i have added my suggestions here please take a look.
you can get rid of if else block
#RestController
#RequestMapping(path = "users")
static class UserController {
private final Map<Long, UserInfo> users = new HashMap<>();
UserController() {
users.put(1L, new UserInfo(1L, "User 1"));
users.put(2L, new UserInfo(1L, "User 2"));
}
#GetMapping(path = "{id}")
public ResponseEntity<UserInfo> get(#PathVariable("id") Long id) {
return findUserById(id)
.map(ResponseEntity::ok)
.orElse(new ResponseEntity<>(UserInfo.notFoundUser(), HttpStatus.NOT_FOUND));
}
Optional<UserInfo> findUserById(#NonNull Long id) {
return Optional.ofNullable(users.get(id));
}
static class UserInfo {
Long id;
String name;
public UserInfo() {
}
public UserInfo(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
static UserInfo notFoundUser() {
return new UserInfo(-1L, null);
}
}
}
change your code to below
if(foundUser.isPresent()) {
return new ResponseEntity<>(foundUser.get(),HttpStatus.OK);
} else {
return new ResponseEntity<>(foundUser.get(),HttpStatus.HTTP_VERSION_NOT_SUPPORTED);
}
Related
I have a service, that gets an xml/json string, tries to read it as an pojo, then returns it. Then, I want to show the result in thymeleaf. I did that successfully, but - in the model I have validation annotations, but if I submit invalid information it accepts the value, although I validated the method. Here is my code:
Controller:
#Controller
public class ConvertController implements WebMvcConfigurer {
#Autowired
PrintJSON printJSON;
#Autowired
PrintXML printXML;
#Autowired
ReadJSON readJSON;
#Autowired
ReadXML readXML;
#GetMapping("/read")
public String showReadForm() {
return "read";
}
#PostMapping("/read")
public String read(#RequestParam(value = "convertFrom") String
convertFrom, String text, Model model){
if("json".equals(convertFrom)){
Book newBook = readJSON.read(text);
model.addAttribute("result", newBook);
return "converted";
}else if("xml".equals(convertFrom)){
Book newBook = readXML.read(text);
model.addAttribute("result", newBook);
return "converted";
}
return "read";
}
#GetMapping("/print")
public String showPrintForm(Book book){
return "convert";
}
#PostMapping("/print")
public String convert(#RequestParam(value = "convertTo") String
convertTo, #Valid Book book, Errors errors, Model model) {
if(errors.hasErrors()){
return "convert";
}
if("json".equals(convertTo)){
model.addAttribute("result", printJSON.getJSON(book));
return "converted";
}
if("xml".equals(convertTo)){
model.addAttribute("result", printXML.getXML(book));
return "converted";
}
return "convert";
}}
Service
public class ReadXML {
#Autowired
#Qualifier("XmlMapper")
XmlMapper xmlMapper;
#Valid
public Book read(String xml){
try{
#Valid Book book = xmlMapper.readValue(xml, Book.class);
return book;
}
catch(JsonProcessingException e){
e.printStackTrace();
return new Book();
}
}
}
Model
public class Book {
#NotEmpty
private String title;
private String description;
private Date publishDate;
private int ISBN;
private List<#Valid Author> authors;
#Override
public String toString(){
String bookString = String.format("Title: %s\nDescription: %s\nPublish Date: %s\nISBN: %s\nAuthor", title, description, publishDate, ISBN);
for(Author a : authors){
bookString += a.toString();
}
return bookString;
}
public String getTitle() {
return title;
}
public void setTitle(String title){
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description){
this.description = description;
}
public Date getPublishDate() {
return publishDate;
}
public void setPublishDate(String newPublishDate) throws ParseException {
Date publishDate = new SimpleDateFormat(Constants.dateFormat).parse(newPublishDate);
this.publishDate = publishDate;
}
public int getISBN() {
return ISBN;
}
public void setISBN(int ISBN){
this.ISBN = ISBN;
}
public void addAuthor(Author author) {
authors.add(author);
}
public List<Author> getAuthors(){
return authors;
}
}
Where is my problem???
Thank you!
i have below resttempalte which invokes rest controller of another service..
#Override
public ResponseEntity<String> callRestAPI(APIReqDataMO apiReqDataMO) {
String apiURL = URIGenerator.getAPIURL(apiReqDataMO);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> request = new HttpEntity<>(apiReqDataMO.getRequestObject(), headers);
ResponseEntity<String> httpRes = restTemplate.postForEntity(apiURL, request, String.class);
return httpRes;
}
and in my service i have controller, which consumes above request..
#RequestMapping(value = "/targetService/createUser", method = RequestMethod.POST, consumes = "application/json")
public String fuzzerServiceAge(UserMO userMO) {
System.out.println("---------------------age is -------------------------" + userMO.getAge());
if (userMO.getAge() > 0) {
System.out.println("error age greater than 0 ");
return "invalid user age";
} else if (userMO.getAge() == 0) {
return "invalid user age";
}
return "user added successfully";
}
when i try my test.. the age which i am pushing through rest template is not getting mapped..and i am getting age as 0 always in my system.out.. what could be wrong in my code... and is there anything missing from configuration perspective..
EDIT -
public class APIReqDataMO {
private String restAPIURL;
private Object[] pathParam;
private Object[] requestParam;
private String requestType;
private String paramType;
private Object requestObject;
public String getParamType() {
return paramType;
}
public void setParamType(String paramType) {
this.paramType = paramType;
}
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
public Object getRequestObject() {
return requestObject;
}
public void setRequestObject(Object requestObject) {
this.requestObject = requestObject;
}
public String getRestAPIURL() {
return restAPIURL;
}
public void setRestAPIURL(String restAPIURL) {
this.restAPIURL = restAPIURL;
}
public Object[] getPathParam() {
return pathParam;
}
public void setPathParam(Object[] pathParam) {
this.pathParam = pathParam;
}
public Object[] getRequestParam() {
return requestParam;
}
public void setRequestParam(Object[] requestParam) {
this.requestParam = requestParam;
}
}
controller
#PostMapping("/targetService/createUser")
public String fuzzerServiceAge(UserMO userMO) {
System.out.println("--------------------- age is -------------------------" + userMO.getAge());
if (userMO.getAge() > 0) {
// return ResponseEntity.ok("Hello World!");
} else if (userMO.getAge() == 0) {
System.out.println(" it is else block");
// return ResponseEntity.badRequest().build();
}
// return ResponseEntity.ok("user added successfully!");
return "user added successfully";
}
usermo
public class UserMO {
#JsonProperty("name")
private String name;
#JsonProperty("age")
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Issue
There is an issue in API implementation. You are creating POST API and when the user will invoke this API by passing UserMO in the request body then mapping won't happen because the #RequestBody annotation is missing.
#PostMapping("/targetService/createUser")
public String fuzzerServiceAge(UserMO userMO) {
System.out.println("--------------------- age is -------------------------" + userMO.getAge());
if (userMO.getAge() > 0) {
// return ResponseEntity.ok("Hello World!");
} else if (userMO.getAge() == 0) {
System.out.println(" it is else block");
// return ResponseEntity.badRequest().build();
}
// return ResponseEntity.ok("user added successfully!");
return "user added successfully";
}
Solution
If you are using #RestController annotation on top of the controller class then add #RequestBody annotation before UserMO userMO and try again.
Like this
#PostMapping("/targetService/createUser")
public String fuzzerServiceAge(#RequestBody UserMO userMO) {
//logic
}
if you are using #Controller annotation on top of the controller class then add #ResponseBody annotation on top of method fuzzerServiceAge() and #RequestBody annotation before UserMO userMO and try again.
Like this
#PostMapping("/targetService/createUser")
#ResponseBody
public String fuzzerServiceAge(#RequestBody UserMO userMO) {
//logic
}
#Component
public class JsonData {
#JsonProperty("id")
private Integer id;
#JsonProperty("createdAt")
private Date cratedAt;
#JsonProperty("name")
private String name;
#JsonProperty("email")
private String email;
#JsonProperty("imageUrl")
private String url;
public JsonData() {
}
public JsonData(Integer id, Date cratedAt, String name, String email, String url) {
this.id = id;
this.cratedAt = cratedAt;
this.name = name;
this.email = email;
this.url = url;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Date getCratedAt() {
return cratedAt;
}
public void setCratedAt(Date cratedAt) {
this.cratedAt = cratedAt;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Controller
#RestController
public class JsonDataController {
#RequestMapping(value = "/template/products")
public void getAllData() {
RestTemplate template = new RestTemplate();
String url = "https://5ef99e4bbc5f8f0016c66d42.mockapi.io/testing/data";
ResponseEntity < JsonData[] > response = template.exchange(url, JsonData[].class);
for (JsonData jsonData: response.getBody()) {
System.out.println(jsonData.getName());
System.out.println(jsonData.getEmail());
}
}
}
I am trying to print json data that is array using rest template but I am getting error in this line "ResponseEntity < JsonData[] > response = template.exchange(url, JsonData[].class);" my error is "cannot resolve method" Can anyone tell me correct way of doing this .I am new to spring I do not have proper understanding it would be helpful if some one can give their suggeestion in this code
RestTemplate does not have any method with signature exchange(String, Class<T>).
That is why you are getting "cannot resolve method" error for template.exchange(url, JsonData[].class);.
Here is an example of correct usage of one of the methods from RestTemplate.exchange API:
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<JsonData[]> response = restTemplate.exchange(url, HttpMethod.GET, null, JsonData[].class);
RestTemplate also has another method - getForEntity that makes a GET call with the given URL and expected return type. (without need for passing null for not required fields)
RestTemplate template = new RestTemplate();
String url = "https://5ef99e4bbc5f8f0016c66d42.mockapi.io/testing/data";
ResponseEntity <JsonData[]> response = template.getForEntity(url, JsonData[].class);
we need to make a spring boot project that works with spring ldap.
every things is good.But when we remove a member from a group,the member deleted form group (i see it in debug mode in a Setmembers) but, in ldap(Oracle Internet Directory) that member exists!
Please help me!
//Group Entry
#Entry(objectClasses = {"top", "groupOfUniqueNames", "orclGroup"}, base = "cn=Groups")
public final class Group {
#Id
private Name dn;
#Attribute(name = "cn")
private String name;
private String description;
private String displayName;
#Attribute(name = "ou")
private String ou;
#Attribute(name = "uniqueMember")
private Set<Name> members;
public void addMember(Name newMember) {
members.add(newMember);
}
public void removeMember(Name member) {
members.remove(member);
}
//Custom LdapUtils
public class CustomLdapUtils {
private static final String GROUP_BASE_DN = "cn=Groups";
private static final String USER_BASE_DN = "cn=Users";
public Name buildGroupDn(String name) {
return LdapNameBuilder.newInstance(GROUP_BASE_DN)
.add("cn","Charts")
.add("cn",name)
.build();
}
private static final CsutomLdapUtils LDAP_UTILS = new CsutomLdapUtils ();
private CsutomLdapUtils () {
}
public Name buildPersonDn(String name) {
return LdapNameBuilder.newInstance(USER_BASE_DN)
.add("cn", name)
.build();
}
}
//Controller
#DeleteMapping(value = "/memberOfGroup", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> removeMemberFromGroup(#RequestBody Map<String,String> map) throws NamingException {
List<Group> groupToFind = ldapSearchGroupsService.getGroupByCn(map.get("groupName"));
List<User> userToFind = ldapSearchUserService.getAllUserByUserName(map.get("userName"));
if (groupToFind.isEmpty()) {
//TODO : Group no found!
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
for (Group group1 : groupToFind) {
group1.removeMember(userToFind.stream().findAny().get().getDn());
//ldapBindGroupService.deleteMemberFromGroup(group1);
DirContextOperations ctx = ldapTemplate.lookupContext(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")));
ctx.removeAttributeValue("uniqueMember",map.get("userName"));
ctx.rebind(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")),map.get("groupName"));
ldapTemplate.modifyAttributes(ctx);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}
Is some problem in code? or need some methods?
Finally after several search and debug,i found the problem!
In each ldap env,after every changes,the directory must be commit and apply.
In above code,i implemented that,but not in true way!
Best way is here:
#DeleteMapping(value = "/membersOfGroup", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> removeMemberFromGroup(#RequestBody Map<String,String> map) {
List<Group> groupToFind = ldapSearchGroupsService.getGroupByCn(map.get("groupName"));
List<User> userToFind = ldapSearchUserService.getAllUserByUserName(map.get("userName"));
if (groupToFind.isEmpty()) {
//TODO : Group no found!
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
for (Group group1 : groupToFind) {
group1.removeMember(userToFind.stream().findAny().get().getDn());
DirContextOperations ctx = ldapTemplate.lookupContext(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")));
ctx.removeAttributeValue("member",CustomLdapUtils.getInstance().buildPersonDn(map.get("userName")));
//True way
ldapTemplate.update(group1);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}
I'm trying to build a Spring WebFlux project and realize the follow business logic:
1 - Call an external REST Api using WebClient and parse the Json results using the Models below. It is working OK
2 - To show the Mono results Mono<DeviceList> devices, I'm using the ResponseApi class and returning it, but it is NOT working
I'm getting the follow error:
Response status 406 with reason "Could not find acceptable representation"
Thanks
# Json Result
{
"data": [
{
"id": "5bc3c0efe833d93f401bafa8",
"name": "XXXXX",
"group": "5b8fd1fa0499f54cfa7febb8",
"description": "Geolocalizacao gps",
"payloadType": "None",
"contract": "5bc08be5e833d93f40e1f936",
"keepAlive": 0
}
]
}
# Controller
public class DeviceController{
...
...
#RequestMapping(value = V1 + BASE_URL + "/devices/types", method = GET, produces = APPLICATION_JSON)
public Mono<ServerResponse> getDeviceTypes(){
Mono<DeviceList> devices = deviceService.findDeviceTypes();
ResponseApi r = new ResponseApi();
r.setMessage("Test");
r.setCode("200");
r.setStatus(200);
r.setData(devices);
return ok().body(Mono.just(r), ResponseApi.class);
}
}
# Repository
public Mono<DeviceList> findDeviceTypes() {
return webClient.get()
.uri(DEVICE_TYPES_URL)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(DeviceList.class);
}
# Model
public class DeviceList{
#JsonProperty("data")
private List<Device> data;
public List<Device> getData() {
return data;
}
public void setData(List<Device> data) {
this.data = data;
}
}
public class Device{
#JsonProperty("id")
private String id;
#JsonProperty("name")
private String name;
#JsonProperty("group")
private String group;
#JsonProperty("description")
private String description;
#JsonProperty("keepAlive")
private Integer keepAlive;
#JsonProperty("payloadType")
private String payloadType;
#JsonProperty("contract")
private String contract;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getKeepAlive() {
return keepAlive;
}
public void setKeepAlive(Integer keepAlive) {
this.keepAlive = keepAlive;
}
public String getPayloadType() {
return payloadType;
}
public void setPayloadType(String payloadType) {
this.payloadType = payloadType;
}
public String getContract() {
return contract;
}
public void setContract(String contract) {
this.contract = contract;
}
}
#JsonRootName("data")
public class ResponseApi{
#JsonProperty("status")
private Integer status;
#JsonProperty("code")
private String code;
#JsonProperty("message")
private String message;
#JsonProperty("data")
private Object data;
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
You can get devices, then in non blocking way, map them to the ResponseApi like that:
#RequestMapping(value = V1 + BASE_URL + "/devices/types", method = GET, produces = APPLICATION_JSON)
public Mono<ServerResponse> getDeviceTypes(){
return deviceService.findDeviceTypes()
.flatMap(devices -> {
ResponseApi r = new ResponseApi();
r.setMessage("Test");
r.setCode("200");
r.setStatus(200);
r.setData(devices);
return ok().body(Mono.just(r), ResponseApi.class);
});
}