Problem parsing JSON
Haytam95 opened this issue ยท 52 comments
When parsing a received a JSON from Java (Spring) REST service it doesn't receive nothing. I thought it was because of nulls on Json, so i filled them with empty strings and arrays but still.
Java Entity
@Entity
public class Usuario implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
@NotNull
private String username;
@Column
@NotNull
private String contrasenia;
@Column
private String correo;
@Column
private Date fechaAlta;
@Column
private Float salud;
@Column
private Float blindaje;
@Column
private Integer energia;
@Column
private Integer saciedadHambre;
@Column
private Integer conectado;
@JoinColumn
@ManyToOne
private Crew crew;
@JoinColumn
@ManyToOne
private RangoCrew rangoCrew;
@JoinColumn
@OneToMany(fetch = FetchType.LAZY)
private List<Vehiculo> vehiculoList;
@JoinColumn
@OneToMany(fetch = FetchType.LAZY)
private List<Propiedad> propiedadList;
@JoinColumn
@OneToMany(fetch = FetchType.LAZY)
private List<ItemInventario> itemInventarioList;
@JoinColumn
@ManyToMany(fetch = FetchType.LAZY)
private List<Afeccion> afeccionList;
}
Java REST:
@PostMapping("findUsuarioByUsername")
public Usuario findUsuarioByUsername(@RequestBody Map<String, String> body) {
String username = body.get("username");
return usuarioRepository.findUsuarioByUsername(username);
}
JSON comming from service (Not null protected):
{
"username": "Elba_Nanero",
"contrasenia": "lala",
"correo": null,
"fechaAlta": null,
"salud": null,
"blindaje": null,
"energia": null,
"saciedadHambre": null,
"conectado": 1,
"crew": null,
"rangoCrew": null,
"vehiculoList": null,
"propiedadList": null,
"itemInventarioList": null,
"afeccionList": null
}
Json null protected
{
"username": "Elba_Nanero",
"contrasenia": "lala",
"correo": "asdasd",
"fechaAlta": "2018-11-22T13:11:30.996+0000",
"salud": 0,
"blindaje": 0,
"energia": 0,
"saciedadHambre": 0,
"conectado": 1,
"crew": {},
"rangoCrew": {},
"vehiculoList": [],
"propiedadList": [],
"itemInventarioList": [],
"afeccionList": []
}
SAMP - Request:
public OnGameModeInit()
{
client = RequestsClient("http://localhost:8080/", RequestHeaders(
"Content-Type", "application/json",
"Accept", "application/json"
));
new Node:node = JsonObject("username", JsonString("Elba_Nanero"));
RequestJSON(client, "usuario/findUsuarioByUsername", HTTP_METHOD_POST, "OnServerResponse", node, RequestHeaders("Content-Type", "application/json",
"Accept", "application/json"));
return 1;
}
SAMP - Process Response:
public OnServerResponse(id, status, node) {
new strResponse[512];
new strData[128];
JsonGetString(node, "contrasenia", strData);
format(strResponse, 512, "Recibi: '%s'", strData);
print(strResponse);
}
A little hand please?
Also, the status code is 2 (WTF)
Update
After some testing, i found out that only strings are the problem. Look at this:
Float and Integers work fine Neither float and integers are working, they come as "0" always
If you have curl
available, could you post the output of curl
ing that endpoint with the -v
flag? Since nothing seems to be working here, I suspect it's some edge case with the details of the response.
If you don't have curl
, instead modify your code to make use of the basic Request
function instead of RequestJSON
and simply print out the response body and check that it's actually the expected JSON payload.
Also, ensure your headers include a Content-Type: application/json
which I would assume they would since Spring should handle that automatically, but it's good to check just in case.
I just editted my code, i found something a little strange.
Strings after response data concatenation aren't showing. Maybe encoding problem?
Also, ensure your headers include a
Content-Type: application/json
which I would assume they would since Spring should handle that automatically, but it's good to check just in case.
Also at Spring, i have:
@RestController
@RequestMapping(value = "/usuario/", produces = "application/json;charset=UTF-8")
public class UsuarioController {
Edit
I just wrote the response in a file...
That first issue you noticed would be the culprit - the response contains invalid characters. If you open the output file in a hex viewer (Notepad++ can do this I think and Sublime has a plugin for it) you'll see the exact binary values.
But it seems like the problem is with the server, not the client.
Just to make sure: have you seen any error in OnRequestFailure
?
I was thinking, if there is a way in which we could debug the plugin locally with breakpoints (Using the source code)? Just to see what happens on the response.
I don't know how to program on C++ or develop SAMP Plugins, but if you give me a few hints i'm sure i'll be able to debug it and find out what's going on.
At this point, i'm pretty sure that:
- SAMP to Java data is getting fine
- Java response is correct and is encoded UTF-8 (tested with Postman)
- HTTP native SAMP is getting Java data fine
Do you have something in mind?
Or if you prefer, i can build a .war of my service, give you some endpoints and help you out whatever you need debugging. (It uses Hibernate & JPA, so there is no need to worry about creating databases or populate with data. Just run a Tomcat server and drop it there)
I noticed you used HTTP_METHOD_POST
in the code, but in the Postman and SA:MP standard HTTP call you used a GET method, is this intentional? Ensure your endpoint can deal with receiving data through a POST method if you need to send data to it. If this is the case, there is still something going wrong with the response not raising an error.
Another thing that probably won't help here but is good practice is to check the return value of Request
/RequestJSON
functions, a non-zero return value indicates an error.
If none of this helps, I'll do some digging tomorrow.
I noticed you used
HTTP_METHOD_POST
in the code, but in the Postman and SA:MP standard HTTP call you used a GET method, is this intentional? Ensure your endpoint can deal with receiving data through a POST method if you need to send data to it. If this is the case, there is still something going wrong with the response not raising an error.
Yeah, it was intentional when i tried default HTTP request SAMP.
Another thing that probably won't help here but is good practice is to check the return value of
Request
/RequestJSON
functions, a non-zero return value indicates an error.
RequestJson is returning 0 and Java service is getting data ok.
If none of this helps, I'll do some digging tomorrow.
As i say, if i can help you with anything just say it!
Just a quick update to keep you in the loop: I didn't get a chance to look at this at the weekend, took longer than usual to get my Windows laptop set up (not used it in months, had to install Visual Studio and dev tools etc). Will hopefully get time to do this soon.
Okay thanks for the update!
Waiting for it!
Any news? I know you're probably busy, but i'm depending on this to start a development of a gamemode
As i say, if you are too busy, just give me a hand to set up my development enviroment and i'll try to fix it
No progress yet - the reason this is taking a while is I build the plugin on a machine I don't own any more, and going through the process of setting up the build was something I neglected to document properly...
As far as I know, it should be a case of installing vcpkg, cpprestsdk, cmake and Visual Studio. I'm currently just awaiting the cpprestsdk installation then I shall try and get the source building.
If you can provide me with a .jar/.war/.exe to run a simple server with some endpoints, it will help with debugging!
Update: I have the environment set up and I'm ready to debug, hopefully we can get this bug fixed ASAP!
As far as I know, it should be a case of installing vcpkg, cpprestsdk, cmake and Visual Studio. I'm currently just awaiting the cpprestsdk installation then I shall try and get the source building.
That's what i tried, but... It didn't go so well, i couldn't make the IDE recognize the libraries and more mayhem.
If you can provide me with a .jar/.war/.exe to run a simple server with some endpoints, it will help with debugging!
Of course! Today i'm full, but i think tomorrow i'll be able to build a war
I'll try to make some room in an hour to build a war!
Update: I have the environment set up and I'm ready to debug, hopefully we can get this bug fixed ASAP!
Perhaps it's a good time to review the build environment documentation haha
Yep haha I'm doing that now so I don't forget for next time!
Documentation updated with development environment setup guide: https://github.com/Southclaws/pawn-requests/blob/master/README.md#development
So I've realised where the status code 2 is coming from, I encoded error values into the status field when calling OnRequestFailure
: https://github.com/Southclaws/pawn-requests/blob/master/src/impl.cpp#L116 but the strange thing is the log should display ERROR: General error: (cause)
I'm kind on a rush, so i could make a simple Spring application with some services (Couldn't build the war, tomorrow i have three exams at university and i think they're going to waste me !)
https://github.com/Haytam95/service_test
Just clone & put it to run in Intellij Idea
Anyway, tomorrow i'll build the war propertly, sorry!!!
Quick update!
I'm having some troubles building the war. For some reason, the service works when running from IDE, but i couldn't deploy the war in a Tomcat.
Did you see the repo (https://github.com/Haytam95/service_test) ? Or are waiting for the war?
I'll try harder to find a solution to the war problem
Yeah I cloned it and ran it in IntelliJ, I couldn't get it to run as it was throwing build errors (I did resolve them but after that, couldn't get it to run for some other reason. I'm at work currently so I can't give you any more details currently)
Don't worry.
It's my mess haha, i'll fix it and improve documentation to make it run.
Once i update everything, i'll leave a comment
Ready! So... In a perfect world, if you just pull from the repository, everything should work (At least in intellij. I'm still struggling making a war).
If you run in any trouble, let me know! (I messed up with the POM)
Thanks, works, I will run some tests on an evening this week (I can't tonight as I'm busy).
Here's a quick test I ran with curl
. First a call to httpbin which is used in the unit tests: https://github.com/Southclaws/pawn-requests/blob/master/test.pwn#L42
โ ~ curl -v http://httpbin.org/get
* Trying 34.206.253.53...
* TCP_NODELAY set
* Connected to httpbin.org (34.206.253.53) port 80 (#0)
> GET /get HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Server: gunicorn/19.9.0
< Date: Wed, 05 Dec 2018 09:22:48 GMT
< Content-Type: application/json
< Content-Length: 214
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< Via: 1.1 vegur
<
{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "91.217.237.56",
"url": "http://httpbin.org/get"
}
* Connection #0 to host httpbin.org left intact
Then a call to the Java app:
โ ~ curl -v localhost:8080/testGet
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /testGet HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 05 Dec 2018 09:08:29 GMT
<
* Connection #0 to host localhost left intact
{"id":"asd","name":"asdasdasd","moreData":[]}
Ignoring the request headers and response body, here's the difference between the response headers:
โ ~ diff -y <(curl -v localhost:8080/testGet 2>&1 | grep '< ') <(curl -v http://httpbin.org/get 2>&1 | grep '< ')
< HTTP/1.1 200 | < HTTP/1.1 200 OK
< Content-Type: application/json;charset=UTF-8 | < Connection: keep-alive
< Transfer-Encoding: chunked | < Server: gunicorn/19.9.0
< Date: Wed, 05 Dec 2018 09:22:02 GMT < Date: Wed, 05 Dec 2018 09:22:02 GMT
> < Content-Type: application/json
> < Content-Length: 214
> < Access-Control-Allow-Origin: *
> < Access-Control-Allow-Credentials: true
> < Via: 1.1 vegur
< <
I doubt the missing OK
on the status would break it. The keep-alive
I'm not sure about. Another thing I'm wondering is whether that Content-Type
with the charset
directive is something cpprestsdk isn't dealing with properly. There's also the missing Content-Length
header which cpprestsdk may require to properly decode the JSON response or something.
However, I still haven't had a chance to properly debug this on the plugin so these are all just assumptions. If there's an issue in cpprestsdk (the library that underpins the plugin) there may not be anything I can do other than wait for a fix.
Okay. So this is what i understand: Java is receiving data and cpprestsdk is receiving the response. BUT, it's going trough an exception because "it thinks" something failed, because the headers are different. Am i right?
If they can comunicate, maybe we could try:
- Match the headers adding annotations to Java server
- Insolate the exception and make it run anyway (if we are certain that the data is not corrupted. I think some information like the charset can be hardcoded, and the length could be scripted)
I'll search about how can i play a little with Spring headers and see how it goes.
I'll wait for more! Good job!
With Spring and cpprestsdk both being widely used libraries, I would expect both of them to conform to standards and work fine.
Another thing is I think the current binaries are using cpprestsdk v2.10.1 however the Linux builds use the latest pulled from GitHub so Linux vs Windows may behave differently. This may be worth investigating, if the issue doesn't occur on Linux then it's likely fixed in a later version of cpprestsdk.
Hi there! How's it going? Any news?
Unfortunately I can't get the demo server project to run on Windows: java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration.propertySourcesPlaceholderConfigurer
In the repo, there is the .jar compiled. https://github.com/Haytam95/service_test/tree/master/jar
Just install Java, open a CMD console and
java -jar demo.jar
Thanks, it's running now.
It seems to be working fine:
*** Test OnGetData
{"id":"asd","name":"asdasdasd","moreData":[]}
PASS!
Using the following code:
#define RUN_TESTS
#include <a_samp>
#include <YSI\y_testing>
#include "requests.inc"
new Request:OnGetData_ID;
main() {
new RequestsClient:client = RequestsClient("http://localhost:8080", RequestHeaders());
OnGetData_ID = Request(
client,
"testGet",
HTTP_METHOD_GET,
"OnGetData",
.headers = RequestHeaders()
);
}
forward OnGetData(Request:id, E_HTTP_STATUS:status, data[], dataLen);
public OnGetData(Request:id, E_HTTP_STATUS:status, data[], dataLen) {
print("*** Test OnGetData\n");
ASSERT(id == OnGetData_ID);
ASSERT(status == HTTP_STATUS_OK);
print(data);
print("\nPASS!");
}
public OnRequestFailure(Request:id, errorCode, errorMessage[], len) {
printf("Request %d failed with %d: '%s'", _:id, errorCode, errorMessage);
}
I suppose the latest build has some very minor changes then. I would put this down to a cpprestsdk bug that was fixed in a recent version.
I will provide new binaries for the updated version.
Thanks, i'll wait for your update. I hope we could close this issue, it has been a pain in the ass get to the bug hahahaha
There was any problems with the new release? Or should just download the lastest? (I don't use SAMPCTL)
Please let me know if this fixes the issue!
In case it's useful, vcpkg can wrap up a binary zip via the export command:
>vcpkg export --zip cpprestsdk zlib --triplet x64-windows
(other options include 7zip and nuget). The zip contains the cmake toolchain at the same relative path, so if you can build with a vcpkg repo, you can build with a vcpkg export :)
@Southclaws in the dependencies folder you left the old cpprest.dll file (cpprest_2_10). I think that's why i'm getting the error.
Could you provide the correct dll please?
Unfortunately I'm travelling at the moment and don't have my Windows laptop with me. I'm not going to be back until after the new year so maybe someone in the community can do a build for you if it's urgent, sorry!
I've updated the latest release for Windows - the one that didn't work was built using Boost 66 whereas the bug was fixed in Boost 67. The latest release includes Boost 68.
Happy new year! And nice new avatar, by the way
Now it's starting & the request reach fine to the service. BUT
It can't find the public function in the AMX to retrieve the info. It was working previously (When the data was coming corrupted). Something has changed?
I also tried using the native HTTP request (Just to check for misspelling) and it's calling the public.
When a request is created, the address of the
AMX it is called from is stored into the request object which is then
passed on to the response object when the request has finished.
There are no other changes between versions, all I did was recompile with newer dependencies: 0.8.4...0.8.5
The changes in #21 are on a different branch because it's a pull request, those changes were made later yesterday evening after releasing the binary. I can't reproduce this issue unfortunately but I'll have a look again later.
Great to hear! ๐