Reputation: 387
I am creating an API that will take HTTP requests and return JSON reports. I have been testing the requests in both Java (using HTTPUrlConnection) and Python (using requests). The API is written in Java Spark. I am doing some testing in Python since requests is a little easier to play with. The Python code I've used is provided for insight into what I'm trying to do, since that works.
Some of the parameters of my request are being passed as a string representation of a JSON object. What I am finding is that when a JSON object string is passed to my API and parsed, the object is treated differently depending on where it comes from, specifically when the data in question is an int.
In Python:
report_dict = {
"client_name": "Wayne_Enterprises",
"client_id": 123,
"report_type": "test_report",
"timestamp_generated": "2015-08-11T11:00:00Z",
"report_data": {"revenue": 40000}
}
response = requests.post(myurl, data=json.dumps(report_dict))
In Java:
JSONObject testData = new JSONObject();
JSONObject content = new JSONObject();
content.put("revenue", 40000);
testData.put("client_name","Wayne_Enterprises");
testData.put("client_id",123);
testData.put("report_type","test_report");
testData.put("timestamp_generated","2015-08-11T11:00:00Z");
testData.put("report_data",content.toString());
URL url = new URL("http","127.0.0.1",8080,"/reports/");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setDoOutput(true);
System.out.println(testData.toString());
DataOutputStream wr = new DataOutputStream (connection.getOutputStream());
wr.writeBytes(testData.toString());
wr.close();
The JSON String is handled in the API like so:
120> JSONParser parser = new JSONParser();
121> JSONObject report = (JSONObject) parser.parse(request.body());
122> String reportType = (String) report.get("report_type");
123> String clientName = (String) report.get("client_name");
124> int clientId = (int)(long) report.get("client_id");
125> JSONObject data = (JSONObject)parser.parse((String)report.get("report_data"));
126> String dateStr = (String) report.get("timestamp_generated");
When I run the test in Python, the data is posted successfully. However, when I run the java test, I get a ClassCast Exception: java.lang.String cannot be cast to java.lang.long
when I set the clientID int. Well, that's easy enough to fix. So that line now becomes:
int clientId = (int)(long) Long.parseLong((String) report.get("client_id"));
Not only is this ugly, it creates the opposite issue. Now i have 'java.lang.Long cannot be cast to java.lang.String!
Am I doing something wrong with my object creation in Java? Or am I handling the request incorrectly?
Edit: I am using org.json.simple
The string outputs: Java
{"report_data":"{\"revenue\":123}","timestamp_generated":"2000-01-01T12:00:00Z","report_type":"api_testing","client_name":"Wayne_Enterprises","client_id":123}
Python
{'client_name': 'test_client', 'report_data': '{"revenue": 4000}', 'report_type': 'transparency', 'client_id': 123, 'timestamp_generated': '2015-07-29T11:00:00Z'}
Stack Trace:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
at com.simplerelevance.Main.lambda$init$1(Main.java:124)
at com.simplerelevance.Main$$Lambda$2/449105069.handle(Unknown Source)
at spark.SparkBase$1.handle(SparkBase.java:311)
at spark.webserver.MatcherFilter.doFilter(MatcherFilter.java:159)
at spark.servlet.SparkFilter.doFilter(SparkFilter.java:131)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(Servlet
Handler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java
:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.j
ava:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.jav
a:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandl
er.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandl
er.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:
515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandle
r.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandle
r.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.j
ava:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(Cont
extHandlerCollection.java:215)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerColl
ection.java:110)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper
.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:497)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.jav
a:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java
:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPoo
l.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool
.java:555)
at java.lang.Thread.run(Thread.java:745)
Upvotes: 1
Views: 192
Reputation: 2185
report.get("client_id”);
will give you a String
object, which cannot just be casted to long
or int
. Use report.getLong
or report.getInt
instead.
Upvotes: 1
Reputation:
Why not just use:
int clientId = (int) report.getLong("client_id");
The getLong returns a long based on a key. Then you cast from long to int.
Alternatively, you could change declaration of clientId in Java to type long, instead of int. Then no casting is required.
Upvotes: 2