Parsing the request body in HTTPServer

1,101 views
Skip to first unread message

rowa...@gmail.com

unread,
Jan 19, 2015, 12:11:12 PM1/19/15
to ve...@googlegroups.com
I'm trying to parse a JSON request body in Vert.x, then send it to the mod-mysql-postgresql mod. I'm wondering if my code is okay or that I'm missing some important piece of code to make it work.

somewhere in my routematching code:

JsonObject eventBusData = new JsonObject();
request.bodyHandler((Buffer buffer) -> {
JsonObject body = new JsonObject(buffer.toString());
eventBusData.putObject("body", body);
sendToController(controller, eventBusData, request);
}
public void sendToController(String controller, JsonObject eventBusData, HttpServerRequest request) {
        EventBus eb = vertx.eventBus();
        eb.send(controller, eventBusData, (Message<JsonObject> message) -> {
            request.response().end(message.body().toString());
        });
    }
then, in the controller:
eb.registerHandler("articles.insert", (Message<JsonObject> message) -> {
            JsonObject body = message.body().getValue("body");
            JsonArray fields = new JsonArray();
            JsonArray values = new JsonArray();
            for (String key : body.getFieldNames()) {
                fields.addString(key);
                values.add(body.getValue(key));
            }
                eb.send("mysql",
                    new JsonObject()
                        .putString("action", "insert")
                        .putString("table", "articles")
                        .putArray("fields", fields)
                        .putArray("values", values)
                    , (Message<JsonObject> data) ->
                            message.reply(data.body())
                    );
and my HTTP request body:
{
    "name": "pannekoek",
    "age": 150,
    "archived": true
}
gives me the following response:
Uncaught Exception for request {"action":"insert","table":"articles","fields":["name","age","archived"],"values":["pannekoek","150","true"]}
java.lang.ClassCastException: java.lang.String cannot be cast to org.vertx.java.core.json.JsonArray

the following piece of code does work, but it's rather static. I want the parsing to be dynamic, as in it shouldn't matter what's in the request body. The validation will be done later.
                eb.send("mysql",
                    new JsonObject()
                        .putString("action", "insert")
                        .putString("table", "articles")
                        .putArray("fields", new JsonArray().addString("name").addString("age"))
                        .putArray("values", new JsonArray().addArray(new JsonArray()
                            .addString(message.body().getObject("body").getString("name"))
                            .addNumber(message.body().getObject("body").getNumber("age")))), (Message<JsonObject> data) ->
                        message.reply(data.body())
                );
In the third code block from the beginning of the post, omitting .putArray("fields", fields) doesn't solve the problem.
Omitting .putArray("values", values) gives a nullpointerexception as the mysql mod expects it.

Could anyone point me to either an error in the Vert.x JSON API or more likely a parsing error in my code?

Julien Viet

unread,
Jan 20, 2015, 9:59:01 AM1/20/15
to ve...@googlegroups.com, rowa...@gmail.com
Hi,

it looks like you are creating a array of value for “values” and it is expecting an array of array of value:

values.add(body.getValue(key))

versus

putArray("values", new JsonArray().addArray(new JsonArray()
                            .addString(message.body().getObject("body").getString("name"))
                            .addNumber(message.body().getObject("body").getNumber("age"))

hope this helps

--
Julien Viet
www.julienviet.com


On 19 Jan 2015 at 18:11:16, rowa...@gmail.com (rowa...@gmail.com) wrote:
> I'm trying to parse a JSON request body in Vert.x, then send it to the
> mod-mysql-postgresql mod. I'm wondering if my code is okay or that I'm
> missing some important piece of code to make it work.
>
> somewhere in my routematching code:
>
> JsonObject eventBusData = new JsonObject();
> request.bodyHandler((Buffer buffer) -> {
> JsonObject body = new JsonObject(buffer.toString());
> eventBusData.putObject("body", body);
> sendToController(controller, eventBusData, request);
> }
>
> public void sendToController(String controller, JsonObject eventBusData, HttpServerRequest
> request) {
> EventBus eb = vertx.eventBus();
> eb.send(controller, eventBusData, (Message message) -> {
> request.response().end(message.body().toString());
> });
> }
>
> then, in the controller:
>
> eb.registerHandler("articles.insert", (Message message) -> {
> JsonObject body = message.body().getValue("body");
> JsonArray fields = new JsonArray();
> JsonArray values = new JsonArray();
> for (String key : body.getFieldNames()) {
> fields.addString(key);
> values.add(body.getValue(key));
> }
> eb.send("mysql",
> new JsonObject()
> .putString("action", "insert")
> .putString("table", "articles")
> .putArray("fields", fields)
> .putArray("values", values)
> , (Message data) ->
> message.reply(data.body())
> );
>
> and my HTTP request body:
>
> {
> "name": "pannekoek",
> "age": 150,
> "archived": true
> }
>
> gives me the following response:
>
> Uncaught Exception for request {"action":"insert","table":"articles","fields":["name","age","archived"],"values":["pannekoek","150","true"]}
> java.lang.ClassCastException: java.lang.String cannot be cast to org.vertx.java.core.json.JsonArray
>
>
> the following piece of code does work, but it's rather static. I want the
> parsing to be dynamic, as in it shouldn't matter what's in the request
> body. The validation will be done later.
>
> eb.send("mysql",
> new JsonObject()
> .putString("action", "insert")
> .putString("table", "articles")
> .putArray("fields", new JsonArray().addString("name").addString("age"))
> .putArray("values", new JsonArray().addArray(new JsonArray()
> .addString(message.body().getObject("body").getString("name"))
> .addNumber(message.body().getObject("body").getNumber("age")))), (Message
> data) ->
> message.reply(data.body())
> );
>
> In the third code block from the beginning of the post, omitting .putArray("fields",
> fields) doesn't solve the problem.
> Omitting .putArray("values", values) gives a nullpointerexception as the
> mysql mod expects it.
>
> Could anyone point me to either an error in the Vert.x JSON API or more
> likely a parsing error in my code?
>
> --
> You received this message because you are subscribed to the Google Groups "vert.x" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

rowa...@gmail.com

unread,
Jan 20, 2015, 11:22:09 AM1/20/15
to ve...@googlegroups.com, rowa...@gmail.com
I've tried the following:

for (String key : body.getFieldNames()) {
   fields
.addString(key);
   values
.add(body.getValue(key));
}

which gives me the cannot convert string to jsonarray within my controller,
when I try:

for (String key : body.getFieldNames()) {
   fields
.addString(key);

   values
.addArray(body.getValue(key));
}

so that it creates an array within a new array, as you said, the error exists within the mod-mysql module.
The owner of the mod-mysql suggested that the error was more likely to be within the JSON API within vert.x

Any suggestions?


Op dinsdag 20 januari 2015 15:59:01 UTC+1 schreef Julien Viet:

Julien Viet

unread,
Jan 20, 2015, 11:27:08 AM1/20/15
to ve...@googlegroups.com, rowa...@gmail.com, rowa...@gmail.com
how does

values.addArray(body.getValue(key));

compile ?

isn’t it:

values.addArray(new JsonArray().addString(body.getValue(key)));

?

--
Julien Viet
www.julienviet.com

rowa...@gmail.com

unread,
Jan 20, 2015, 12:29:14 PM1/20/15
to ve...@googlegroups.com, rowa...@gmail.com
I'm not sure if there's anything wrong with the code, but it now gives me a new error message.

java.lang.Integer cannot be cast to java.lang.String

because my request body contains a string, an integer and a boolean. Now it fails because of the addString as it expects a string, but sees an integer in the second value.

When I try this:
values.addArray(values.add(body.getValue(key)));

I get an incredibly long (too big to fit within a terminal window) error log about Jackson, it basically repeats this every few lines:

at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21)
at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:186)

rowa...@gmail.com

unread,
Jan 20, 2015, 12:31:17 PM1/20/15
to ve...@googlegroups.com, rowa...@gmail.com
If this adds anything, I managed to find out it gives me an java.lang.StackOverflowError in the mysql module. containing the errors listed above

Joern Bernhardt

unread,
Jan 21, 2015, 5:04:47 AM1/21/15
to ve...@googlegroups.com, rowa...@gmail.com
Wouldn't this work?

    values.addArray(new JsonArray().add(body.getValue(key)));

I guess you're getting the StackOverflow error as you add a reference to values inside of values and thus creating a circular structure...

rowa...@gmail.com

unread,
Jan 23, 2015, 9:08:58 AM1/23/15
to ve...@googlegroups.com, rowa...@gmail.com
This does indeed seem to fix it.

I'm now receiving a new error that's MySQL related.

Error 1136 - #21S01 - Column count doesn't match value count at row 1

I've printed the query below:

fields: ["name","age","archived"]

values: [["pannekoek"],[150],[true]]

query: {"action":"insert","table":"articles","fields":["name","age","archived"],"values":[["pannekoek"],[150],[true]]}

I'm not familiar with Scala, the language the mysql module is written in. I do understand the error I suppose, but I don't get why it's checking 'row 1' as it should just insert at the bottom.

rowa...@gmail.com

unread,
Jan 24, 2015, 5:40:41 PM1/24/15
to ve...@googlegroups.com, rowa...@gmail.com
Reply all
Reply to author
Forward
0 new messages