400 Error When Sending JSON to Controller - javascript

I try to send a JSON object from JavaScript to Controller. I get 400 status code when sending the object. I tried many methods, but my last approach is below. Do I miss something? Why do I keep getting 400?
ajax post call:
$.ajax({
type: "POST",
url: "http://localhost:8080/services/saveReservation",
cache: false,
data: saveReservation,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
console.debug("After success");
}
});
my object looks like this:
{
"accommodaion":"a0d8185c-a238-5qe7-aa48-5c196b108aba",
"totalOutputPrice":90,
"bookerInfo":{
"country":"xa",
"homeAddress":"",
"phoneNumber":"0019382663773",
"contactChoice":"phone",
"name":"test name",
"id":"87"
},
"creditCard":{
"holderName":"holder test",
"cardType":"discover",
"cardNumber":"6011303031648258",
"expMonth":"01",
"expYear":"2017",
"cvc":"123"
},
"checkIn":"2016-11-16 06:43:19.77",
"checkOut":"2017-03-16 06:43:19.77",
"totalTax":4,
"totalVat":13,
"roomOutputPrice":"77"
}
Controller:
#RequestMapping(value = "/saveReservation", method = RequestMethod.POST)
public test saveReservation(
#RequestBody test saveReservation) {
System.out.println(saveReservation.getAccommodaion());
System.out.println(saveReservation.getBookerInfo().getName());
System.out.println(saveReservation);
return saveReservation;
}
Classes:
private class bookerInfo {
private String country;
private String homeAddress;
private String phoneNumber;
private String contactChoice;
private String name;
private String id;
//getters setters
}
private class creditCard {
private String holderName;
private String cardType;
private String expMonth;
private String expYear;
private String cvc;
//getters setters
}
private class test {
private String accommodaion;
private Float totalOutputPrice;
private bookerInfo bookerInfo;
private creditCard creditCard;
private String checkIn;
private String checkOut;
private Float totalTax;
private Float totalVat;
private Float roomOutputPrice;
//getters setters
}
Error in framework:
16:12:14,096 DEBUG ExceptionHandlerExceptionResolver:134 - Resolving exception from handler [public ba.projectService.controller.test ba.projectService.controller.G2BController.saveReservation(ba.projectService.controller.test)]: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unrecognized field "cardNumber" (class ba.projectService.controller.creditCard), not marked as ignorable (5 known properties: , "cvc", "expMonth", "holderName", "cardType", "expYear"])
at [Source: org.apache.catalina.connector.CoyoteInputStream#793ea01d; line: 1, column: 287] (through reference chain: ba.projectService.controller.test["creditCard"]->ba.projectService.controller.creditCard["cardNumber"]); nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "cardNumber" (class ba.projectService.controller.creditCard), not marked as ignorable (5 known properties: , "cvc", "expMonth", "holderName", "cardType", "expYear"])
at [Source: org.apache.catalina.connector.CoyoteInputStream#793ea01d; line: 1, column: 287] (through reference chain: ba.projectService.controller.test["creditCard"]->ba.projectService.controller.creditCard["cardNumber"])
16:12:14,099 DEBUG ResponseStatusExceptionResolver:134 - Resolving exception from handler [public ba.projectService.controller.test ba.projectService.controller.G2BController.saveReservation(ba.projectService.controller.test)]: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unrecognized field "cardNumber" (class ba.projectService.controller.creditCard), not marked as ignorable (5 known properties: , "cvc", "expMonth", "holderName", "cardType", "expYear"])
at [Source: org.apache.catalina.connector.CoyoteInputStream#793ea01d; line: 1, column: 287] (through reference chain: ba.projectService.controller.test["creditCard"]->ba.projectService.controller.creditCard["cardNumber"]); nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "cardNumber" (class ba.projectService.controller.creditCard), not marked as ignorable (5 known properties: , "cvc", "expMonth", "holderName", "cardType", "expYear"])
at [Source: org.apache.catalina.connector.CoyoteInputStream#793ea01d; line: 1, column: 287] (through reference chain: ba.projectService.controller.test["creditCard"]->ba.projectService.controller.creditCard["cardNumber"])
16:12:14,099 DEBUG DefaultHandlerExceptionResolver:134 - Resolving exception from handler [public ba.projectService.controller.test ba.projectService.controller.G2BController.saveReservation(ba.projectService.controller.test)]: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unrecognized field "cardNumber" (class ba.projectService.controller.creditCard), not marked as ignorable (5 known properties: , "cvc", "expMonth", "holderName", "cardType", "expYear"])
at [Source: org.apache.catalina.connector.CoyoteInputStream#793ea01d; line: 1, column: 287] (through reference chain: ba.projectService.controller.test["creditCard"]->ba.projectService.controller.creditCard["cardNumber"]); nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "cardNumber" (class ba.projectService.controller.creditCard), not marked as ignorable (5 known properties: , "cvc", "expMonth", "holderName", "cardType", "expYear"])
at [Source: org.apache.catalina.connector.CoyoteInputStream#793ea01d; line: 1, column: 287] (through reference chain: ba.projectService.controller.test["creditCard"]->ba.projectService.controller.creditCard["cardNumber"])

You need to serialize your javascript object with JSON.stringify.
Try:
$.ajax({
type: "POST",
url: "http://localhost:8080/services/saveReservation",
cache: false,
data: JSON.stringify(saveReservation),
contentType: "application/json; charset=utf-8",
dataType: "json",
processData: false,
success: function(data) {
console.debug("After success");
}
});
And add the content type to the request mappging:
#RequestMapping(value = "/saveReservation", method = RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
Make sure you have defined the json message converters. If you have Jackson as dependecy Spring do it for you.
Your new message is clear. You are sending a property from javascript that does not exist in your class. I am not sure whether you made a mistake or it is what you want. The property "cardNumber" does not exist at your CreditCard bean.
You can configure Jackson to ignore the unknown properties without throwing an exception using the annotation #JsonIgnoreProperties at the top of your class.
#JsonIgnoreProperties(ignoreUnknown = true)
private class creditCard {
private String holderName;
private String cardType;
private String expMonth;
private String expYear;
private String cvc;
//getters setters
}
If you want to send more than one credit card you could use a list. So, just changing your test bean to be able to work with a list of cards
private class test {
...
private List<creditCard> creditCards;
...
//getters setters
}
and at your javascript object, it should be now an array
{
... here all your properties
"creditCards":[{
"holderName":"card 1",
"cardType":"discover",
"cardNumber":"6011303031648258",
"expMonth":"01",
"expYear":"2017",
"cvc":"123"
},{
"holderName":"card 2",
"cardType":"discover",
"cardNumber":"6011303031648258",
"expMonth":"01",
"expYear":"2017",
"cvc":"123"
},{
"holderName":"card 3",
"cardType":"discover",
"cardNumber":"6011303031648258",
"expMonth":"01",
"expYear":"2017",
"cvc":"123"
}],
... more properties
}
should be enough. I hope you get the idea.

Related

Can't get array from JS to my Spring boot controller?

I am having a little problem while sending data from my React app to my Spring Boot Controller, I am sending the data via a put method, but I get 400, error, and an error in eclipse pops up, so What I did is :
export const changeContratTypes = (idContrat, items, declaration) => {
const endpoint = template(CONTRAT_TYPES_CHANGE);
return instance // just an axios instance
.put(endpoint({ idContrat }), { items, declaration })
.then(values => values)
.catch(err => err.response);
};
My endpoint constant is the url, simple is that, and I send declaration which is an integer and items which is an array of object, my object structure is :
{
id: 1, // or 2, 3, ....
isSelected: true, // or false
title: "a String here"
}
To get this in Spring boot I created this method in my controller :
#CrossOrigin(origins = "*")
#ApiOperation(value = "${contrat.recuperation}", notes = "${contrat.recuperation.notes}", response = ContratDetailDto.class)
#PutMapping(value="/{idContrat}/trtype")
#ApiModelProperty(example = "4000004")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Enrigistrer Les types de contrats ") })
public ResponseEntity enrigistrerTypesDeContrat(#ApiParam(value = "${contrat.recuperation.param.id}") #PathVariable long idContrat, #RequestBody TypesConformites tcf) {
if (log.isDebugEnabled()) {
log.debug("appel de la méthode enrigistrerTypesDeContrat");
}
System.out.println("Voila "+tcf.getDeclaration());
return ResponseEntity.ok(HttpStatus.OK);
}
This controller is well mapped and other methods in it works fine, but all methods I used are Get Methods.
What I did before that is creating a class used as a RequestBody :
#Getter #Setter
public class TypesConformites {
private int declaration;
private ArrayList<Item> items;
public TypesConformites() {
}
}
and Here is my Item class :
#Getter #Setter
public class Item {
private int id;
private String title;
private boolean isSelected;
public Item() {
}
}
I get this error in Java :
Blockquote
JSON parse error: Unrecognized field "isSelected" (class com.apicil.cosy.contrat.controller.api.impl.external.Item), not marked as ignorable; nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "isSelected" (class com.apicil.cosy.contrat.controller.api.impl.external.Item), not marked as ignorable (3 known properties: "title", "id", "selected"])
at [Source: (PushbackInputStream); line: 1, column: 66] (through reference chain: com.apicil.cosy.contrat.controller.api.impl.external.TypesConformites["items"]->java.util.ArrayList[0]->com.apicil.cosy.contrat.controller.api.impl.external.Item["isSelected"])
What's wrong with that code, Any help would be much appreciated.
Generally the Item is deserialised by jackson like this :-
public void setId(String firstName) {
public void setTitle(String lastName) {
public void setSelected(boolean isActive) {
To avoid this you can just changed the mapping name in the Item and request body.. or annotated your isSelected with #JsonProperty

Instantiate typescript class

I'm new to Typescript and started using it to play with Ionic. I come from a Java background and I'm experiencing some trouble getting accustomed to it's syntax and way of doing things. Specifically creating new object instances and getting them initialized.
Recently I came across this issue which I cannot explain. I'm sending a HTTP GET request and getting it's response in a Javascript Object.
To work with this response, I'm trying to map this Javascript Object I received to a typescriptclass of mine which I called HttpResponse, creating a new instance of it when I receive the response. To make things easier I created a simple fiddle which ilustrates my problem.
You can find the quick written fiddle on this link
As you can see on the output, object data is there but when I invoke the HttpResponse it just creates an empty instance, it contains nothing, and I don't understand why it does so.
Any help appreciated! Here's the code:
class HttpResponse {
constructor(status: number = 0,
data: string = '',
headers: Object = '',
error: string = ''){}
}
class Page {
response: HttpResponse;
retrieveData(): void {
document.body.innerHTML += 'inside retrieveData()<br>';
let data = {
status: 200, data: "this is some fake data",
headers: { foo: 'foo', bar: 'bar', baz: 'baz' }
}
document.body.innerHTML +='Data: ' + JSON.stringify(data) + '<br>';
this.response = new HttpResponse(data.status, data.data, data.headers);
document.body.innerHTML += JSON.stringify(this.response);
}
}
new Page().retrieveData();
In the constructor of your HttpResponse class, you are not setting the properties of the class with the passed arguments. You can do so by using the public qualifier in the parameters.
class HttpResponse {
constructor(public status: number = 0,
public data: string = '',
public headers: Object = '',
public error: string = ''){ }
}
See the updated Fiddle.
Alternatively, you can declare the properties in your class and set them in the constructor like this.data = data; assignments.
Because your HttpResponse does not actually have any properties. You only have constructor parameters and nothing else. If you want to automatically convert your constructor parameters into properties, you can do so by using parameter properties:
class HttpResponse {
constructor(
public status: number = 0,
public data: string = '',
public headers: Object = '',
public error: string = ''){}
}
You must have to declare constructor parameters using qualifiers i.e. private public protected
class HttpResponse {
constructor(
private status: number = 0,
private data: string = '',
private headers: Object = '',
private error: string = ''){}
}

Cast int to enum strings in Typescript

I get from a RESTful Service the following data:
[
{
"id": 42,
"type": 0,
"name": "Piety was here",
"description": "Bacon is tasty, tofu not, ain't nobody like me, cause i'm hot...",
}...
And I'm mapping with this class:
export enum Type {
Info,
Warning,
Error,
Fatal,
}
export class Message{
public id: number;
public type: Type:
public name: string;
public description: string;
}
But when I access 'type' in Angular2 I get only a int value. But I'd like to get a string value.
e.g:
'message.type=0'
{{message.type}} => should be Info
'message.type=1'
{{message.type}} => should be Warning
Enums in TypeScript are numbers at runtime, so message.type will be 0, 1, 2 or 3.
To get the string value, you need to pass that number into the enum as an index:
Type[0] // "Info"
So, in your example, you'll need to do this:
Type[message.type] // "Info" when message.type is 0
Docs
Enums in TypeScript are objects at runtime that have properties that go from int -> string and from string -> int for all possible values.
To access the string value you will need to call:
Type[0] // "Info"
Make sure that you are passing the correct type into the property accessor though because chained calls can result in the following:
Type[Type.Info] // "Info"
Type[Type[Type.Info]] // 0
Type["Info"] // 0
Type[0] // "Info"
I think with
{{message.type}}
you just get the mapped value and not the enum.
Please try following code.
{{TYPE[message.type]}}
This is how enum works in the typescript:
enum PrintMedia {
Newspaper = 1,
Newsletter,
Magazine,
Book
}
PrintMedia.Magazine; // returns 3
PrintMedia["Magazine"]; // returns 3
PrintMedia[3]; // returns Magazine
PrintMedia[PrintMedia.Magazine];// returns Magazine

AngularJS and Spring MVC - $http 400 Bad Request

I'm trying to post a object that includes an id (int) and a array, but I get a http 400 Bad request response from the server side. This is what I have so far...
Java Bean Object for Request:
public class GuardarVentaRequest {
private Integer idCliente;
private List<Venta> venta; ... (Getters and Setters code)
Java Object:
public class Venta {
private Integer id;
private String nombre;
private Integer precio;
private Integer cantidad;
private Integer total; ... (Getters and Setters code)
Java Controller:
#RequestMapping(value = "/guardarVenta", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody void venta(#RequestBody GuardarVentaRequest factura){
System.out.println(factura);
}
AngularJS Service:
function guardarVenta(array){
let factura = {
idCliente : parseInt($('#cliente').val()),
venta : array,
};
console.log(factura);
$http({
method: 'POST',
url: '/blue/guardarVenta',
contentType: 'application/json',
data: factura
}).then(
function successCallback(response){
console.log(response.statusText);
},
function errorCallback(response){
console.log(response.statusText);
}
);
}
Array:
$scope.productos = new Array();
let productoInfo = {
id: $scope.producto.id,
nombre: $scope.producto.nombre,
precio: $scope.producto.precio,
cantidad: $scope.cantidadProducto,
total: $scope.producto.precio * $scope.cantidadProducto
}
$scope.productos.push(productoInfo);
Output:
ADVERTENCIA: Failed to read HTTP message:
org.springframework.http.converter.HttpMessageNotReadableException: Could
not read document: Can not construct instance of com.blue.beans.Venta: no
suitable constructor found, can not deserialize from Object value (missing
default constructor or creator, or perhaps need to add/enable type
information?)
at [Source: java.io.PushbackInputStream#663359f3; line: 1, column: 28]
(through reference chain: com.blue.beans.GuardarVentaRequest["venta"]-
>java.util.ArrayList[0]); nested exception is
com.fasterxml.jackson.databind.JsonMappingException: Can not construct
instance of com.blue.beans.Venta: no suitable constructor found, can not
deserialize from Object value (missing default constructor or creator, or
perhaps need to add/enable type information?)
at [Source: java.io.PushbackInputStream#663359f3; line: 1, column: 28]
(through reference chain: com.blue.beans.GuardarVentaRequest["venta"]-
>java.util.ArrayList[0])
Chrome's Network Tab Output
Any ideas?
Try these 3 things.
Add the default constructor to GuardarVentaRequest and Venta.
GuardarVentaRequest(){} &
Venta(){}
Check if a HTTPMessageConverter has been added to your spring config. Eg: MappingJackson2MessageConverter (Check for compatibility with your spring version).
Try serializing the request payload by using angular.toJson
Hope that helps!

Error sending JSON to WebMethod

I am having trouble sending JSON to a WebMethod. Here is the way that I am trying to do it. If there is a better way to do this please let me know. What I am trying to do is save the JSON object off in a database.
JavaScript
function TEST() {
var str = '[{
"Key": 6311,
"Start": "123 Start",
"End": "456 End ",
"Date": "2/2/2012",
"Order": null,
"EstMiles": 0,
"Stops": [
{"StopAddy": "123 Stop Addy "},
{"StopAddy": "456 Stop Addy"},
{"StopAddy": "789 Stop Addy"}
]
}]'; // Whitespace added for clarity
$.ajax({
type: "POST",
url: "WebService1.asmx/Test",
data: str,
//contentType: "plain/text",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
alert(msg.d);
},
error: function(e) {
alert(e.responseText);
}
});
}
VB.NET
Public Function Test(ByVal o As Object()) As String
'do your processing
Return "success"
End Function
Public Class [Stop]
Public Property StopAddy() As String
Get
Return m_StopAddy
End Get
Set(ByVal value As String)
m_StopAddy = value
End Set
End Property
Private m_StopAddy As String
End Class
Public Class RootObject
Public Property Key() As Integer
Get
Return m_Key
End Get
Set(ByVal value As Integer)
m_Key = value
End Set
End Property
Private m_Key As Integer
Public Property Start() As String
Get
Return m_Start
End Get
Set(ByVal value As String)
m_Start = value
End Set
End Property
Private m_Start As String
Public Property [End]() As String
Get
Return m_End
End Get
Set(ByVal value As String)
m_End = value
End Set
End Property
Private m_End As String
Public Property [Date]() As String
Get
Return m_Date
End Get
Set(ByVal value As String)
m_Date = value
End Set
End Property
Private m_Date As String
Public Property Order() As Object
Get
Return m_Order
End Get
Set(ByVal value As Object)
m_Order = value
End Set
End Property
Private m_Order As Object
Public Property EstMiles() As Integer
Get
Return m_EstMiles
End Get
Set(ByVal value As Integer)
m_EstMiles = value
End Set
End Property
Private m_EstMiles As Integer
Public Property Stops() As List(Of [Stop])
Get
Return m_Stops
End Get
Set(ByVal value As List(Of [Stop]))
m_Stops = value
End Set
End Property
Private m_Stops As List(Of [Stop])
End Class
The error I am getting is
{"Message":"Type \u0027System.Collections.Generic.IDictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\u0027 is not supported for deserialization of an array.","StackTrace":"
   at System.Web.Script.Serialization.ObjectConverter.ConvertListToObject(IList list, Type type, JavaScriptSerializer serializer, Boolean throwOnError, IList& convertedList)
   at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeInternal(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n
   at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeMain(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n
   at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToType(Object o, Type type, JavaScriptSerializer serializer)\r\n
   at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit)\r\n
   at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String input)\r\n
   at System.Web.Script.Services.RestHandler.GetRawParamsFromPostRequest(HttpContext context, JavaScriptSerializer serializer)\r\n
   at System.Web.Script.Services.RestHandler.GetRawParams(WebServiceMethodData methodData, HttpContext context)\r\n
   at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)",
"ExceptionType":"System.InvalidOperationException"}
Based on your stack trace, I assume you are using Asp.net on the server side?
If so, I believe Asp.net requires you to have a main object that wraps list of objects for json data. So, please change your input to the following, and change your server code a bit to handle the extra wrapping layer:
var str = '{
"data":
[
{
"Key": 6311,
"Start": "123 Start",
"End": "456 End ",
"Date": "2/2/2012",
"Order": null,
"EstMiles": 0,
"Stops": [
{
"StopAddy": "123 Stop Addy "
},
{
"StopAddy": "456 Stop Addy"
},
{
"StopAddy": "789 Stop Addy"
}
]
}
]
}'

Categories

Resources