WCF REST JSON request: Formatter exception - json

I have a enum as one of the parameters in my Rest API.
End Point contract:
List<Transaction> GetTransactions(int employeeID, int recordOffset, int recordLimit, TransactionType transactionType = TransactionType.All);
InputJSON Request:
{
"employeeID":"123",
"recordOffset": 0,
"recordLimit": 80,
"transactionType":"All"
}
I'm getting a 400 bad request, when i pass this input JSON with transactionType key.
Please let me know how, i should be passing an ENUM value in the json request.
public enum TransactionType
{
All = 0,
Incoming = 1,
Outgoing = 2
}
Exception Message:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://Services/2015/03:transactionType. The InnerException message was 'There was an error deserializing the object of type Entities.TransactionType. The value 'All' cannot be parsed as the type 'Int64'.'. Please see InnerException for more details

The parameter expected is an int.
You should be passing an int value of 0, 1 or 2 in the JSON request here.
Depending on how you build up your JSON request, you could add the value of the Enum you want, e.g transactionType = TransactionType.All
This way, you can actually use your Enum when building up your request to ensure you use viable values.

Related

How do I serialize and deserialize a tuple in Rust using Serde?

I have a tuple consisting of an String and a Uuid that I serialize using serde_json:
let log_and_id = (String::from("Test string"), test_id);
let log_and_id_serialized = serde_json::to_string(&log_and_id)
.expect("Serialization failed");
//After serialization (debug print): "[\"Test string\",\"32a8e12d-69d2-421d-a52e-1ee76cc03ed5\"]"
Then I transfer this serialized value over the network and receive a BytesMut (serialized_tuple) on the other end, which I try to deserialize:
//Bytesmut value (debug print): b"\"[\\\"Test string\\\",\\\"32a8e12d-69d2-421d-a52e-1ee76cc03ed5\\\"]\""
let (log, operation_state_id) = serde_json::from_slice::<(String, Uuid)>(&serialized_tuple)?;
But I get the following error:
ERROR actix_http::response] Internal Server Error: SerdeError(Error("invalid type: string \"[\\\"Test string\\\",\\\"32a8e12d-69d2-421d-a52e-1ee76cc03ed5\\\"]\", expected a tuple of size 2", line: 1, column: 68))
(De)serializing single objects this way used to work in other parts of this code, so what could cause it to fail when used with tuples?
You don't have a serialized tuple, but a serialized serialized tuple.
I mean the serialization of the tuple, which was a JSON string, was again serialized.
You can check this with this code (playground):
let serialized_tuple = b"\"[\\\"Test string\\\",\\\"32a8e12d-69d2-421d-a52e-1ee76cc03ed5\\\"]\"";
let serialized_tuple: String = serde_json::from_slice(serialized_tuple).unwrap();
let (log, operation_state_id) = serde_json::from_slice::<(String, String)>(serialized_tuple.as_bytes()).unwrap();
which produces the desired tuple.
Of course, rather than deserializing twice, you should remove the unnecessary serialization from your application (it's not in the code you've shown).

How can I parse a JSON object with an empty value in Java?

I'm building a test suite to test my Vert.x API that implements a couple of sorting algorithms. One of the test cases that I'd like to cover is to handle null or empty values in the unsorted array:
The request body is a JSON string that I create like this:
final String json = "{\"arr\": [99, [2, 4, ], [[55]], 0]}";
Currently I'm parsing the JSON in the request handler using Vert.x JsonObject and JsonArray.
import io.vertx.core.json.JsonObject;
import io.vertx.core.json.JsonArray;
private void doBubbleSort(RoutingContext routingContext) {
JsonObject json = routingContext.getBodyAsJson();
JsonArray jsonArray = json.getJsonArray("arr");
....
}
This is the error I'm getting
SEVERE: Unexpected exception in route
io.vertx.core.json.DecodeException: Failed to decode:Unexpected character (',' (code 44)): expected a value
at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 49]
at io.vertx.core.json.Json.decodeValue(Json.java:172)
at io.vertx.core.json.JsonObject.fromBuffer(JsonObject.java:960)
at io.vertx.core.json.JsonObject.<init>(JsonObject.java:73)
at io.vertx.ext.web.impl.RoutingContextImpl.getBodyAsJson(RoutingContextImpl.java:263)
at io.vertx.ext.web.impl.RoutingContextDecorator.getBodyAsJson(RoutingContextDecorator.java:123)
at za.co.offerzen.SortVerticle.doBubbleSort(SortVerticle.java:80)
at io.vertx.ext.web.impl.BlockingHandlerDecorator.lambda$handle$0(BlockingHandlerDecorator.java:48)
at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$2(ContextImpl.java:272)
at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
How can I parse the request when there is an empty value in the json? Ideally, I only want all the int values from the request body and ignore or strip out empty, null or missing values. Do I need to iterate over the request body before parsing it to json, and check whether each value instanceof int? Or is there another way?
Apart from JsonObject and JsonArray, I can get the request body as a Buffer or as a String
Thanks.
If you really mean that:
ideally, I only want all the int values from the request body
you can simply do the following:
final String json = "{\"arr\": [99, [2, 4, ], [[55]], 0]}";
final String regularExpression = "([^\\d])+";
Pattern pattern = Pattern.compile(regularExpression);
String[] results = pattern.split(json);
List<Integer> numbers = new ArrayList<>();
for (String result : results) {
try {
numbers.add(Integer.valueOf(result));
} catch (NumberFormatException e) {
}
}
for (int number : numbers) {
System.out.println(number);
}
This would output:
99
2
4
55
0
But this really doesn't give a damn about this being a json. It's just extracting numbers from a string.

kotlin data class HttpMessageNotReadableException

I'm trying this code with postman, but nothing works, why ?
What i send :
{
"name":"front_msel",
"gitlabId": "83",
"fichierVersion":"VERSION"
}
My spring controller :
#RestController
#RequestMapping("/projects")
class ProjectController(val projectRepository: ProjectRepository) {
private val log = LoggerFactory.getLogger(ProjectController::class.java)
#PostMapping()
fun saveProject(#RequestBody payload: Project): String {
log.info("project: '{}'", payload.toString())
return projectRepository.save(payload).gitlabId?:"-1"
}
}
What i get :
{
"timestamp": 1505917417221,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.http.converter.HttpMessageNotReadableException",
"message": "JSON parse error: Can not construct instance of com.......model.Project: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.......model.Project: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)\n at [Source: java.io.PushbackInputStream#66ba61d9; line: 2, column: 2]",
"path": "/projects"
}
My project data class :
data class Project(val name:String?, val gitlabId: String?, val fichierVersion: String?)
I doubled check params, it's not a wording mistake, what does this things doesn't works ?
EDIT :
Thanks to Todd, the problem was resolve by adding null value to my param, to generate a zero argument constructor. Thanks !
data class Project(val name:String? = null, val gitlabId: String? = null, val fichierVersion: String? = null)
I got this to work by making two slight changes.
First, since all your Project fields are nullable, provide default values so the compiler will generate a zero argument constructor:
data class Project(val name:String? = null, val gitlabId: String? = null, val fichierVersion: String? = null)
Second, it seems that Spring wants your fields to be in snakey_case rather than camelCase, so change your payload to this:
{
"name":"front_msel",
"gitlab_id": "83",
"fichier_version":"VERSION"
}

JSON.parse Map want String get integer

Dart is great, it's like, well, programming. Also the IDE is great.
I have encountered what appears to me to be a problem (for me) with the Dart
JSON.parse function. The problem appears to me to be that if a string
is an integer, it creates an integer in the Map. This may not be desirable
because there could be situations where string fields contain numeric.
eg. an address that contains just the street number. Or, perhaps I am
simply doing something wrong.
The line of code that exposes the possible problem is :
String sId = mAcctData['I_Id'];
I presume that there is a logical solution to this, and if so I would
appreciate being advised
httpSubmitAccountNrLoadEnd(HttpRequest httpReq) {
String sResponse = null;
if (httpReq.status != 200) {
print('On Http Submit Account Nr. There was an error : status = ${httpReq.status}');
} else {
print("On Return from Http Submit Account Nr. no error - status = ${httpReq.status}");
sResponse = httpReq.responseText;
}
print("Response From Submit Account Nr. = ${sResponse}"); // print the received raw JSON text
Map mAcctData = JSON.parse(sResponse);
print ("Json data parsed to map");
print ("Map 'S_Custname' = ${mAcctData['S_Custname']}");
String sCustName = mAcctData['S_Custname'];
print ("About to extract sId from Map data");
String sId = mAcctData['I_Id'];
print ("sId has been extracted from Map data");
String sAcctNr = mAcctData['I_AcctNr'];
String sAcctBal = mAcctData['I_AcctBal'];
The following is the console output.
The line that shows the problem that I have is:
Exception: type 'int' is not a subtype of type 'String' of 'sId'.
About to send http message
On Return from Http Submit Account Nr. no error - status = 200
Response From Submit Account Nr. = {"S_Custname":"James Bond","I_Id":1,"I_Acctnr":123456789,"I_AcctBal":63727272,"I_AvailBal":0}
Json data parsed to map
Map 'S_Custname' = James Bond
About to extract sId from Map data
Exception: type 'int' is not a subtype of type 'String' of 'sId'.
Stack Trace: #0 httpSubmitAccountNrLoadEnd (http://127.0.0.1:3030/C:/Users/Brian/dart/transact01/transact01.dart:75:31)
1 submitAccountNr.submitAccountNr. (http://127.0.0.1:3030/C:/Users/Brian/dart/transact01/transact01.dart:33:59)
Exception: type 'int' is not a subtype of type 'String' of 'sId'.
Stack Trace: #0 httpSubmitAccountNrLoadEnd (http://127.0.0.1:3030/C:/Users/Brian/dart/transact01/transact01.dart:75:31)
1 submitAccountNr.submitAccountNr. (http://127.0.0.1:3030/C:/Users/Brian/dart/transact01/transact01.dart:33:59)
Questions:
Is there a solution to this? (eg. force JSON.parse to create strings)
Is there a better way to handle this? (eg. extract data directly from the JSON string)
From what I see in your sResponse mAcctData['I_Id'] is really an int :
{
"S_Custname": "James Bond",
"I_Id": 1,
"I_Acctnr": 123456789,
"I_AcctBal": 63727272,
"I_AvailBal": 0
}
So if you want to get a String for mAcctData['I_Id'] you can use int.toString() :
String sId = mAcctData['I_Id'].toString();
Just turn your integers into strings if you want them to be like that:
{
"S_Custname": "James Bond",
"I_Id": "1",
"I_Acctnr": "123456789",
"I_AcctBal": "63727272",
"I_AvailBal": "0"
}
Now it should work fine. Alternatively, use .toString() to convert the integers into strings.

Grails unable to unmarshall date/time from JSON back into joda DateTime

I'm having trouble using the JodaTime plugin for Grails. The plugin seems to be correctly converting to JSON for the output, but it does not seem to be able to accept the outputted date format again as input when the same JSON object is sent back in.
These are the errors I get:
Field error in object 'server.Session' on field 'lastUpdated': rejected value [2011-12-19T14:15:03-06:00]; codes [typeMismatch.server.Session.lastUpdated,typeMismatch.lastUpdated,typeMismatch.org.joda.time.DateTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [server.Session.lastUpdated,lastUpdated]; arguments []; default message [lastUpdated]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'org.joda.time.DateTime' for property 'lastUpdated'; nested exception is java.lang.IllegalArgumentException: Invalid format: "2011-12-19T14:15:03-06:00" is malformed at "11-12-19T14:15:03-06:00"]
Field error in object 'server.Session' on field 'dateCreated': rejected value [2011-12-19T14:15:03-06:00]; codes [typeMismatch.server.Session.dateCreated,typeMismatch.dateCreated,typeMismatch.org.joda.time.DateTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [server.Session.dateCreated,dateCreated]; arguments []; default message [dateCreated]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'org.joda.time.DateTime' for property 'dateCreated'; nested exception is java.lang.IllegalArgumentException: Invalid format: "2011-12-19T14:15:03-06:00" is malformed at "11-12-19T14:15:03-06:00"] id=33 version=0>
Here's the very basic domain model:
package server
import org.joda.time.DateTime
class Session {
DateTime dateCreated
DateTime lastUpdated
String ip
static constraints = {
ip blank: false
}
}
And here are the show and update methods (send and receive JSON respectively):
def show() {
def sessionInstance = Session.get(params.id)
if (!sessionInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'session.label', default: 'Session'), params.id])
redirect(action: "list")
return
}
def response = [sessionInstance: sessionInstance]
withFormat {
html response
json {render response as JSON}
xml {render response as XML}
}
}
def update() {
def sessionInstance = Session.get(params.id)
if (!sessionInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'session.label', default: 'Session'), params.id])
redirect(action: "list")
return
}
if (params.version) {
def version = params.version.toLong()
if (sessionInstance.version > version) {
sessionInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
[message(code: 'session.label', default: 'Session')] as Object[],
"Another user has updated this Session while you were editing")
render(view: "edit", model: [sessionInstance: sessionInstance])
return
}
}
sessionInstance.properties = params // <----- This is what causes the errors
log.info("instance: ${sessionInstance.dump()}") // <------ This is where I'm seeing the error messages
if (!sessionInstance.save(flush: true)) {
render(view: "edit", model: [sessionInstance: sessionInstance])
return
}
flash.message = message(code: 'default.updated.message', args: [message(code: 'session.label', default: 'Session'), sessionInstance.id])
redirect(action: "show", id: sessionInstance.id)
}
I'm not sure what I need to do to correct this, or even if I'm doing things correctly, since I'm very new to Grails. In all reality, the two date fields that are causing issues should be handled 100% internally by GORM and I would rather the controller ignore them completely, but there will be other date fields like them that will need to be updated once the domain model gets filled in.
How can I get the automatic JSON unmarshalling to correctly convert back into joda time DateTime objects?
Note: This is currently a proof-of-concept for a client-server application.
I'm not sure of the cause, nor why this fix works, but adding jodatime.format.html5 = true to the Config.groovy file makes everything work.
As far as I can tell, there is no change in the JSON output, but for whatever reason, it makes the JSON input handling and data binding work.
The only semblance of documentation that even hints at this is here.
Trying to set the format for DateTime via something like jodatime.format.org.joda.time.DateTime = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ" had no effect at all.