I am consuming a restful with spring but I do not achieve get all data successfully.
RESTful response detail:
{
"errorCode": "0",
"errorMessage": "OK",
"transactionUUID": "2e48d6e7-f1fb-4271-b282-d74d3df1ef23",
"data":{
"price": "123",
"quantity" : "1",
"productname" : "Anystuff"}
}
My classes:
public class ResponseRest{
private String errorCode;
private String errorMessage;
private String transactionUUID;
private ResponseDetail data;
//get and set methods
}
public class ResponseDetail {
private String price;
private String quantity;
private String productname;
//get and set methods
}
Piece of my method in my controller class:
HttpHeader headers;
//headers.set....
String jsonParam = "{\"transactionToken\":\""+transactionToken+"\","
+ "\"sessionToken\":\""+sessionToken+"\"}";
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> entity = new HttpEntity<String>(jsonParam, headers);
response = restTemplate.exchange(URL_API_AUTH, HttpMethod.POST, entity, ResponseRest.class);
When I got result by console, I only get the properties from the ResponseRest class but not their detail from class ResponseDetail, console result:
System.out.println("-> Result - status ("+ response.getStatusCode() + ") has body with: " + (response.getBody().toString()));
Result - status (200) has body with: ResponseRest[errorCode="0", errorMessage="OK",transactionUUID="2e48d6e7-f1fb-4271-b282-d74d3df1ef23", data[price=null,quantity=null,productname=null]]
What I doing wrong?
Thanks a lot for their time.
Related
The first request is sent asynchronously, then the id value is taken from the response to the first request and used in the second asynchronous request. And then both responses to request 1 and request 2 are combined. The example below works, but is not asynchronous because .get() is used. Is there a way to do this asynchronously?
The process in short - everything should happen asynchronously:
Send POST request 1
Use the id value from response 1 for request 2
Send POST request 2
Combine response 1 and response 2 to the final response of the REST controller
This body is sent to the REST controller endpoint "/combine" via POST method:
{
"userid": 1,
"id": 2,
"title": "3",
"body": "4" }
#RestController
public class CombinationController {
#Autowired
CombinationService combinationService;
#PostMapping("/combine")
public CompletableFuture<CombinationBothResponses> combine(#RequestBody RequestBodyOne requestBodyOne) {
return combinationService.combine(requestBodyOne);
}
}
#Service
public class CombinationService {
private final Jsonb jsonb = JsonbBuilder.create();
private final HttpClient httpClient = HttpClient.newBuilder().build();
public CompletableFuture<CombinationBothResponses> combine(RequestBodyOne requestBodyOne) {
// 1. Send POST request 1
HttpRequest httpRequestOne =
HttpRequest.newBuilder(URI.create("https://jsonplaceholder.typicode.com/posts"))
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.POST(HttpRequest.BodyPublishers.ofString(jsonb.toJson(requestBodyOne)))
.build();
return httpClient
.sendAsync(httpRequestOne, HttpResponse.BodyHandlers.ofString())
.thenApply(
httpResponse -> {
if (HttpStatus.valueOf(httpResponse.statusCode()).is2xxSuccessful()) {
CombinationBothResponses combinationBothResponses =
jsonb.fromJson(httpResponse.body(), CombinationBothResponses.class);
// 2. Use one value from response 1 for request 2
int valueToBeUsedInRequestBody2 = combinationBothResponses.getId();
// 3. Send POST request 2
CompletableFuture<CombinationBothResponses> completableFuture2 =
sendSecondPostRequest(valueToBeUsedInRequestBody2);
// 4. Combine response 1 and response 2 to the final response of REST controller
try {
CombinationBothResponses responseBodyRequestTwo =
completableFuture2.get(); // Not asynchronous
combinationBothResponses.setSuccess(responseBodyRequestTwo.getSuccess());
return combinationBothResponses;
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
throw new RuntimeException();
});
}
private CompletableFuture<CombinationBothResponses> sendSecondPostRequest(
int valueToBeUsedInRequestBody2) {
RequestBodyTwo requestBodyTwo = new RequestBodyTwo(valueToBeUsedInRequestBody2, "request 2");
HttpRequest httpRequest =
HttpRequest.newBuilder(URI.create("https://reqbin.com/echo/post/json"))
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.POST(HttpRequest.BodyPublishers.ofString(jsonb.toJson(requestBodyTwo)))
.build();
return httpClient
.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
.thenApply(
httpResponse -> {
if (HttpStatus.valueOf(httpResponse.statusCode()).is2xxSuccessful()) {
CombinationBothResponses responseBodyRequestTwo =
jsonb.fromJson(httpResponse.body(), CombinationBothResponses.class);
return responseBodyRequestTwo;
}
throw new RuntimeException();
});
}
}
#Data
#NoArgsConstructor
public class RequestBodyOne {
private int userId;
private int id;
private String title;
private String body;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
public class RequestBodyTwo {
private int id;
private String key;
}
#Data
#NoArgsConstructor
public class CombinationBothResponses {
private int userId;
private int id;
private String title;
private String body;
private String success;
}
Response to request 1:
{ "userId": 0, "id": 101, "title": "3", "body": "4" }
Response to request 2:
{"success":"true"}
Combined responses; response of REST controller:
{
"userId": 0,
"id": 101,
"title": "3",
"body": "4",
"success": "true" }
return httpClient
.sendAsync(httpRequestOne, HttpResponse.BodyHandlers.ofString())
.thenCompose(httpResponse -> {
if (HttpStatus.valueOf(httpResponse.statusCode()).is2xxSuccessful()) {
final CombinationBothResponses combinationBothResponses = jsonb.fromJson(httpResponse.body(), CombinationBothResponses.class);
// 2. Use one value from response 1 for request 2
int valueToBeUsedInRequestBody2 = combinationBothResponses.getId();
// 3. Send POST request 2
return sendSecondPostRequest(valueToBeUsedInRequestBody2)
.thenApply(responseBodyRequestTwo -> {
// 4. Combine response 1 and response 2 to the final response of REST controller
combinationBothResponses.setSuccess(responseBodyRequestTwo.getSuccess());
return combinationBothResponses;
});
}
return CompletableFuture.failedFuture(new RuntimeException());
});
I have this class in my .NET application to send some data from client(.NET) to server(Spring) :
class NetworkController
{
private static readonly HttpClient client = new HttpClient();
public static async Task SendUserDataAsync()
{
var values = new Dictionary<string, string>
{
{ "firstName", "sunny" },
{ "lastName", "leone" },
{ "timeStamp", "test" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://localhost:8080/user", content);
var responseString = await response.Content.ReadAsStringAsync();
}
}
Reference
And in my Spring Boot application, I a class called User :
#Entity
public class User
{
#Id
private String firstName;
private String lastName;
private String timeStamp;
public User(){}
#Override
public String toString() {
return "firstName : "+this.firstName + "\n"+"lastName : " + this.lastName;
}
}
In my rest-controller I have this method to insert User :
#PostMapping("/user")
User addUser(#RequestBody User user)
{
System.out.println(user);//this always prints an empty line, maybe receiving nothing
return userRepository.save(user);
}
I get this warning Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported]
I have created this class(with the concept of Spring) in .NET, but it seems no use :
class User
{
String firstName;
String lastName;
String timeStamp;
public User()
{
firstName = "1"
lastName = "2"
timeStamp = "test"
}
}
Wouldn't sending an object instead of dictionary be more gentle and tidy ? How to do so ?
How can I resolve this problem ?
In your .NET application, the line var content = new FormUrlEncodedContent(values); indicates that the request will have a HTTP header Content-Type set to application/x-www-form-urlencoded.
It means the data stored in var values = new Dictionary... will be formatted by .NET as a query string such as firstName=sunny&lastName=leone&timeStamp=test.
That is what your Sprint server receives. However it wants to receive JSON data, not a query string. So it complains.
In order to get rid of the miscommunication, your .NET application should send JSON data, such as
{"firstName": "sunny", "lastName": "leone", "timeStamp": "test"},
as expected by the Spring server.
Here is an example code:
HttpClient client = new HttpClient();
object anonymousObject = new
{
firstName = "sunny",
lastName = "leone",
timeStamp = "test"
};
string jsonContent = JsonConvert.SerializeObject(anonymousObject);
var request = new HttpRequestMessage(HttpMethod.Post, "http://127.0.0.1:8080/user");
request.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
You need to install the package Newtonsoft.Json in order to call JsonConvert.SerializeObject(anonymousObject), as pointed by this SO answer mentionned by #alfcope.
We have an REST endpoint that will add a new empty ingredient to an existing meal:
#RequestMapping(value = "/add", method = RequestMethod.PUT, consumes = "application/json;charset=UTF-8")
public ResponseEntity<Object> add(#RequestBody final Meal meal) throws URISyntaxException
{
Optional<Meal> optionalMeal = mealRepository.findById(meal.getId());
if (!optionalMeal.isPresent()) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(MessageUtil.parse(MSG_404_MEAL, meal.getId() + ""));
}
Ingredient ingredient = new Ingredient();
ingredient.setMeal(optionalMeal.get());
ingredientRepository.saveAndFlush(ingredient);
ResponseEntity re = ResponseEntity
.created(RequestUtil.getResourceURI(ingredient.getId()))
.body(ingredient);
return re;
}
Ingredient is an entity class with some fields:
public class Ingredient implements Serializable
{
#Id
private Integer id;
private Meal meal;
private Grocery grocery;
private Float amount;
...
}
RequestUtil takes care of creating the URI where the newly created resource is to be found:
public class RequestUtil
{
public static URI getResourceURI(int id) throws URISyntaxException
{
final String url = RequestUtil.getCurrentRequest().getRequestURL().toString();
final String req = RequestUtil.omitLast(url);
return new URI(req + "get/" + id);
}
public static HttpServletRequest getCurrentRequest()
{
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return ((ServletRequestAttributes) requestAttributes).getRequest();
}
public static String omitLast(final String url) {
return url.substring(0, url.lastIndexOf("/") + 1);
}
}
The http status code and resource URI end up correctly in the response headers, but the body contains two JSONs:
{
"id": 407,
"meal": {
"id": 99,
"name": "New Meal",
"active": true
},
"grocery": null,
"amount": null,
"bought": false
} {
"timestamp": "2018-08-29T19:25:31.466+0000",
"status": 201,
"error": "Created",
"message": "No message available",
"path": "/ingredient/add"
}
Our javascript code does not expect this extra data and fails with
SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data at line 1 column 114 of the JSON data
Using a debugger, we can see that by the time the code reaches the return statement in add(), the ResponseEntity does not contain this extra data. Can someone explain where it comes from, and how we stop it from polluting the response?
Thanks for any help!
I am trying to call REST service by passing object as parameter which contains list of other custom objects. I am getting "Error 405: Request method POST not supported" error.
Client side code-
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(SSLConnectionSocketFactory.getSystemSocketFactory()).build();
httpPost = new HttpPost("http://api100.abc.xyz.com:9080/abcd/api/sscws/v1/saveContributions");
httpPost.addHeader(WebAppConstants.CONTENT_TYPE, WebAppConstants.APPLICATION_JSON);
httpPost.addHeader(WebAppConstants.ACCEPT, WebAppConstants.APPLICATION_JSON);
httpPost.addHeader(WebAppConstants.X_USERNAME, userContext.getUserID());
httpPost.addHeader(WebAppConstants.X_ENTERPRISE_ID, "123456");
httpPost.addHeader(WebAppConstants.X_UNIQUE_ID, "A548742ATG"); //to do
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String requestParamJson = ow.writeValueAsString(contribRequestParamDto);
httpPost.setEntity(new StringEntity(contribRequestParamDto, WebAppConstants.UTF_8));
In above code contribRequestParamDto is a object of ContributionsRequestParamDto class which will look this-
public class ContributionsRequestParamDto {
private String tokenID;
private String taxID;
private String affiliateID;
private long planID;
private String accountNumber;
private String bankAccountNumber;
private String transitId;
private BigDecimal eftAmt;
private Date ppeDate;
private String taxYear;
private Short planType;
private List<ParticipantsDeferralDto> participantsDeferrals;
private List<EmployersContributionDto> employersContributions;
}
REST endpoint will look like this-
#Transactional
#RestController
#RequestMapping("/v1")
#Api(value="v1", description="")
public class SscRestController {
#RequestMapping(value="/saveContributions",
method=RequestMethod.POST, produces={MediaType.APPLICATION_JSON_VALUE}, consumes={MediaType.APPLICATION_JSON_VALUE})
#ApiOperation(value="Returns the saved contributions object")
public String saveContributions(#RequestBody ContributionsRequestParam contributionsParam) throws Exception {
return "success";
}
}
Json request body is-
{
"tokenID" : "123456789",
"taxID" : "123456",
"affiliateID" : "123456789",
"planID" : 123456,
"ppeDate" : "2017-10-24",
"taxYear" : "2017",
"planType" : 1,
"participantsDeferrals" : [ {
"taxId" : "555555",
"participantDeferralAmt" : 22.00
} ],
"employersContributions" : [ {
"taxId" : "555555",
"employerContributionAmt" : 22.00
} ]
}
This is not working as I am getting "Error 405: Request method POST not supported" error. It will work if remove list fields for 'participantsDeferrals' and 'employersContributions' from JSON request body by removing those list fields from 'ContributionsRequestParamDto' object. So I am sure that there is something wrong with list of custom objects and its corresponding JSON request body. Am I missing something here? Please help. Thanks!
I have changed the type of the Date. Now it is normal String and not SQL date. After changing its type to string in object, it is working fine
I hava a problem with my one controller. When i send (POST) data from angular to java controller using ( jason content type ) i see error which is visible in the topic. So I can't catch response from server. Controller catch this request good so in this case book is added to database correctly. Firebug show 404 error but when I checked in Postman I saw 415 Unsupported Media Type. Why there is such an exception if the controller is working properly.
This is example JSON:
{"title":"fgthbfgd","authors":[{"author_id":24,"author":"danielle steel"}],"genres":[{"genre_id":1,"genre":"Dramat"}],"description":"rthg","path_image":"19296.png"}
and this is controller:
#SuppressWarnings("finally")
#RequestMapping(value = "/rest/book", consumes = "application/json", produces = "application/json", method = RequestMethod.POST)
public MessageDTO addNewBook(#RequestBody BookDTO newBook) {
MessageDTO message = new MessageDTO();
try {
bookService.addNewBook(newBook);
message.setCheck(true);
} catch (BookTitleException e) {
message.setCheck(false);
message.setDescription("Ksiązka o tym tytule juz istnieje.");
e.printStackTrace();
} finally {
return message;
}
}
This is BookDTO
public class BookDTO implements Serializable{
private static final long serialVersionUID = -5057364006691079475L;
private Integer id;
private AuthorEntity [] authors;
private String description;
private GenreEntity [] genres;
private String title;
private String path_image;
private double rate;
private Integer progressBar;
private boolean flagRate;
private double userRate;
/* geters and seters */
}
This is Angular code:
var bookResource = $resource( $rootScope.restUrl + 'book');
var book = {
title : $scope.title,
authors : $scope.author,
genres : $scope.genre,
description : $scope.description,
path_image: null
}
service.addNewBook = function(book){
var deferred = $q.defer();
bookResource.save(book)
.$promise.then( function(data){
deferred.resolve( data );
}, function(){
deferred.reject("Error during adding new book.");
});
return deferred.promise;
}
This is only a problem in my aplication. In another case all working correctly.
You have a 415 error because you send your request without the right content-type header
var bookResource = $resource( $rootScope.restUrl + 'book',{}, {
save:{
method:"POST",
headers:{'Content-Type':'application/json; charset=UTF-8'}
}
});
I hope it will solve your problem