I want to create Fog architecture. I have 2 servers in cloud and client-server application where server is kinda fog server. Cloud servers are for comunicate with database. The problem is when I try to do registration in my application. I want to check if user exists in database in validation moment. When I invoke rest method it returns "404 null".
REST controller with method to check if users exist. When I invoke this method using http://localhost:8081/user/test it returns the JSON
{"userID":1,"username":"test","password":"test","events":[]}
UserController.java
@RestController
public class UserController {
@Autowired
private UserRepository userRepository;
@RequestMapping(value = "/user/{username}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> getUserByUsername(@PathVariable("username") String username) {
User user = userRepository.findByUsername(username);
if (user == null) {
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}
@RequestMapping(value = "/user/", method = RequestMethod.POST)
public ResponseEntity<Void> addUser(@RequestBody User user, UriComponentsBuilder ucBuilder) {
userRepository.save(user);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/user/{id}").buildAndExpand(user.getUserID()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
}
And now I try to get that user in fog server this way:
public boolean sendRequestIfUserExists(String username) {
CloudServer cloudServer = getAvailableServer();
if (cloudServer != null) {
ResponseEntity<User> userEntity = restTemplate.getForEntity(cloudServer.getURI() + "/user/" + username, User.class);
changeServerStatusToAvailable(cloudServer.getServerName());
HttpStatus status = userEntity.getStatusCode();
if (status == HttpStatus.NOT_FOUND) {
SpeechRecognitionApplication.logger.info("User: " + username + "does not exist");
return false;
}
}
return true;
}
And this line:
ResponseEntity<User> userEntity = restTemplate.getForEntity(cloudServer.getURI() + "/user/" + username, User.class);
Throws the exception:
org.springframework.web.client.HttpClientErrorException: 404 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:79) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:775) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:728) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:684) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:359) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at pl.speechrecognition.services.CloudService.sendRequestIfUserExists(CloudService.java:65) ~[classes/:na]
at pl.speechrecognition.controller.IndexController.postRegister(IndexController.java:53) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na]
Edit: Finally I found the solution for that exception. It was because I had wrong Contructor in User class.
User.java
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
private Long userID;
private String username;
private String password;
private List<Event> events;
public Long getUserID() {
return userID;
}
public void setUserID(Long userID) {
this.userID = userID;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Event> getEvents() {
return events;
}
public void setEvents(List<Event> events) {
this.events = events;
}
public User(String username) {
this.username = username;
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String toString() {
return "Username: " + username;
}
// Missing constructor
public User(Long userID, String username, String password, List<Event> events) {
this.userID = userID;
this.username = username;
this.password = password;
this.events = events;
}
}
But now it throws:
org.springframework.web.client.RestClientException: Error while extracting response for type [class pl.speechrecognition.model.User] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `pl.speechrecognition.model.User` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `pl.speechrecognition.model.User` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (PushbackInputStream); line: 1, column: 2]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:115) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1000) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:983) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:730) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
Finally I found solution. There was a problem with constructors. When I added constructor with all arguments I found information that to deserialize JSON Spring needs also zero-arg constructor
Did you try enabling logs to see where exactly is the call being initiated to ? Try adding : logging.level.org.springframework.web=DEBUG You should see the full URL.
Hopefully that helps you debug further..