0

Im learning how to produce and consume JSON in rest services, but I wanna learn it well so im trying all possible cases of objects, one of them is an object that has an List attribute like this class:

import java.util.List;

public class PruebaJSON {

    private String nombre;
    private List atributos;
    private String descripcion;
    public String getNombre() {
        return nombre;
    }
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
    public List getAtributos() {
        return atributos;
    }
    public void setAtributos(List atributos) {
        this.atributos = atributos;
    }
    public String getDescripcion() {
        return descripcion;
    }
    public void setDescripcion(String descripcion) {
        this.descripcion = descripcion;
    }   
}

Then all what im doing on my rest service method is this:

@POST
@Path("/prueba")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public PruebaJSON prueba(String data) {

    try {

        JSONObject json = new JSONObject(data);


        Gson convertir = new GsonBuilder().create();
        PruebaJSON pruebaJson = convertir.fromJson(json.toString(), PruebaJSON.class);

        return pruebaJson;
    } catch (Exception e) {
        System.out.println("error " + e);
        return null;
    }

}

Then in POSTMAN I pass this:

{
    "descripcion": "Primera prueba",
    "nombre": "Prueba 1",
    "atributos": [
        "hello",
        "kek",
        "lul"
    ]
}

And it works fine, the problem is when I try to do the same by Java, for example:

List atributos = new ArrayList<>();
atributos.add("hello");
atributos.add("kek");
atributos.add("lul");

System.out.println(bus.prueba("Prueba 1", "Primera Prueba", atributos));

bus.prueba just executes the service but then in console I get this error:

14:16:56,567 INFO  [stdout] (default task-2) error com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 66 path $.atributos

I did the search of the error and found this: Gson: Expected begin_array but was STRING

I understand the error but whats the solution? I can't really control how the JSON builds the arraylist can I? This is the method prueba in my client:

public String prueba(String nombre, String descripcion, List atributos) {
        HashMap map = new HashMap<>();

        map.put("nombre", nombre);
        map.put("descripcion", descripcion);
        map.put("atributos", atributos);
        String respuesta = utilidadesRestSeguridad.consumir("prueba", map);
        return respuesta;

    }

In my client component this is the method that builds the json:

public static JsonObject generateJSON(HashMap map) throws MalformedURLException {
    JsonObject json = new JsonObject();
    for (Object key : map.keySet()) {
        json.addProperty(key.toString(), map.get(key).toString());
    }

    return json;

}

And thats it guys if you wanna see more code or me to explain something tell me I appreciate any help.

I think maybe the error is in the method generateJSON because of the .toString(), but then how I should handle that case?

BugsForBreakfast
  • 712
  • 10
  • 30

3 Answers3

1

Assuming that the line utilidadesRestSeguridad.consumir("prueba", map) ends up calling your generateJSON method downstream, then your issue is likely in the generateJSON() method as you suspect. Basically, you are just adding all elements as strings. If one of the elements in your map is an instance of a List, then you need to call JsonObject#add("atributos", value). For example, you will need something like the following code:

if (map.get(key) instanceof List) {
    json.add(key.toString(), map.get(key);
} else {
    json.addProperty(key.toString(), map.get(key).toString());
}
entpnerd
  • 10,049
  • 8
  • 47
  • 68
  • Hey man that sounds like a great solution, but if I try it then the editor tells me that the method add expects (String, JsonElement), what can I do there? The cast doesn't work it says ArrayList cannot be cast to gson.JsonElement :/ – BugsForBreakfast Jun 12 '19 at 19:55
  • So the class `JsonArray` is a subclass of `JsonElement`. So you need to convert your existing `java.util.List` into an instance of `com.google.gson.JsonArray`. Worst case scenario, you can just `add` each element of your `List` to the new `JsonArray`. https://static.javadoc.io/com.google.code.gson/gson/2.6.2/com/google/gson/JsonArray.html#add-java.lang.String- – entpnerd Jun 12 '19 at 20:10
  • Check out the answer I just posted bro – BugsForBreakfast Jun 12 '19 at 20:27
1

As I suspected, the error was in the generateJSON method, needed to add this validation that entpnerd suggested:

public static JsonObject generateJSON(HashMap map) throws MalformedURLException {
    JsonObject json = new JsonObject();

    for (Object key : map.keySet()) {
        if (map.get(key) instanceof List) {
            JsonParser parser = new JsonParser();
            parser.parse((map.get(key).toString()));
            json.add(key.toString(), parser.parse((map.get(key).toString())));
        } else {
            json.addProperty(key.toString(), map.get(key).toString());
        }
    }

    return json;
}

Notice that I had to use JsonParser, not sure how is it working but at the end that made it work.

Source: How to parse this JSON String with GSON?

Anyways Im gonna try the solution entpnerd is suggesting and post it too.

Here is the implementation of entpnerd suggestion:

public static JsonObject generateJSON(HashMap map) throws MalformedURLException {
    JsonObject json = new JsonObject();

    for (Object key : map.keySet()) {
        if (map.get(key) instanceof List) {
            JsonArray jsonArray = new JsonArray();
            for (Object object : (ArrayList<Object>) map.get(key)) {
                jsonArray.add(object.toString());
            }
            json.add(key.toString(), jsonArray);
        } else {
            json.addProperty(key.toString(), map.get(key).toString());
        }
    }

    return json;
}

it works too, you guys decide which one to use, thanks very much.

My only question is, what if the element that is an array, has more arrays inside it, what would you do?

BugsForBreakfast
  • 712
  • 10
  • 30
0

You don't need to get that json value manually, add requestbody annotation to your method parameter

public PruebaJSON prueba(@RequestBody PruebaJSON json){
    System.out.println(json);
};