Ronald Saunfe
Ronald Saunfe

Reputation: 651

How to convert String containing JSON object to actual JSON using Java

I have stayed with the problem for more than 3 days of research but cant find any solvable solution. My android project makes a request to my gcloud functions and the function returns a string response with a String format:

[{"response": [{"Commission": 50, "Price": 0.5, "Quantity": "20"}, {"Commission": 50, "Quantity": 20, "Price": 1}, {"Quantity": 20, "Price": 10, "Commission": 50}], "code": 200}]

I was able to convert the string to JSON and retrieve the value of the "response" key.

try {
                //convertion of response to json to fetch value
                JSONObject jsonObj = new JSONObject("[{"response": [{"Commission": 50, "Price": 0.5, "Quantity": "20"}, {"Commission": 50, "Quantity": 20, "Price": 1}, {"Quantity": 20, "Price": 10, "Commission": 50}], "code": 200}]");
                String code = jsonObj.getString("code");

                final String Cod = code;
                if (Cod.equals("200")){
                    String availableInv = jsonObj.getString("response");
                    availableInv = availableInv.replace("[", "");
                    availableInv = availableInv.replace("]", "");
                    String strng[] = availableInv.split("},");

                    for (String val:strng) {
                        int valLength = val.length();
                        if(!val.substring(valLength-1, valLength).contentEquals("}")) {
                            val +="}";
                        }
                        System.out.println(">>>>>>=====================response==========="+val);
                        JSONObject jsonObjInv = new JSONObject(val);
                        float price = Float.valueOf(jsonObjInv.getString("Price"));
                        float comission = Float.valueOf(jsonObjInv.getString("Commission"));
                        float quantity = Float.valueOf(jsonObjInv.getString("Quantity"));
                        myDataset.add(new InvestmentsModel(price,comission, quantity));
                    }
                }
            }

Now i want to be able to iterate through the list of the JSON object and fetch the keys and values. When i run my solution i get the following error:

2020-03-24 16:17:55.235 4959-5006/com.example.SMS E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
Process: com.example.SMS, PID: 4959
java.util.regex.PatternSyntaxException: Syntax error in regexp pattern near index 1
},
 ^
    at java.util.regex.Pattern.compileImpl(Native Method)
    at java.util.regex.Pattern.compile(Pattern.java:1340)
    at java.util.regex.Pattern.<init>(Pattern.java:1324)
    at java.util.regex.Pattern.compile(Pattern.java:946)
    at java.lang.String.split(String.java:2384)
    at java.lang.String.split(String.java:2426)
    at com.example.SMS.Fragment.investEarnFrag_1$5.onResponse(investEarnFrag_1.java:251)
    at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:504)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
    at java.lang.Thread.run(Thread.java:764)

Upvotes: 0

Views: 412

Answers (1)

Anıl
Anıl

Reputation: 136

Seems that you find your answer in the comments. However, I think there is some point which is worth to emphasize here.

First of all, since you already decided to serialize your raw json response to a java object, which is JSONObject in this case, there is no point to parse the rest of the string anymore. You should stick with one of the methodologies to keep it consistent. So, in this case the methodology should be either parsing the whole json string or using org.json features. In my personal opinion, you should keep using the org.json.

Using org.json

The response you shared is in form of array/list of object.

[{"response": [{"Commission": 50, "Price": 0.5, "Quantity": "20"}, {"Commission": 50, "Quantity": 20, "Price": 1}, {"Quantity": 20, "Price": 10, "Commission": 50}], "code": 200}]

Since we have array of objects, we should use JSONArray to keep our json in.

JSONArray jsonArray = new JSONArray("[{\"response\": [{\"Commission\": 50, \"Price\": 0.5, \"Quantity\": \"20\"}, {\"Commission\": 50, \"Quantity\": 20, \"Price\": 1}, {\"Quantity\": 20, \"Price\": 10, \"Commission\": 50}], \"code\": 200}]");
// just to exemplify we get the first element, this should be depending on the business logic
JSONObject jsonObj = (JSONObject) jsonArray.get(0);

Now, we have the inner object in our jsonObj variable, which is:

{
  "response": [
    {
      "Commission": 50, 
      "Price": 0.5, 
      "Quantity": "20"
    }, 
    {
      "Commission": 50, 
      "Quantity": 20, 
      "Price": 1
    }, 
    {
      "Quantity": 20, 
      "Price": 10, 
      "Commission": 50
    }
  ], 
  "code": 200
}

So, we can easily get on key response which will be againg an array of object. We can easily iterate on it.

Note that in json all keys are string while values can be string, numeric, booelan and object. For instance, status can be parsed as integer.

try {
    //convertion of response to json to fetch value
    JSONArray jsonArray = new JSONArray("[{\"response\": [{\"Commission\": 50, \"Price\": 0.5, \"Quantity\": \"20\"}, {\"Commission\": 50, \"Quantity\": 20, \"Price\": 1}, {\"Quantity\": 20, \"Price\": 10, \"Commission\": 50}], \"code\": 200}]");
    JSONObject jsonObj = (JSONObject) jsonArray.get(0);
    int code = jsonObj.getInt("code");
    List<InvestmentsModel> myDataset = new ArrayList<>();

    if (code == 200){
        JSONArray availableInv = jsonObj.getJSONArray("response");

        for (Object val: availableInv) {
            JSONObject value = (JSONObject) val;

            float price = value.getFloat("Price");
            float comission = value.getFloat("Commission");
            float quantity = value.getFloat("Quantity");
            myDataset.add(new InvestmentsModel(price,comission, quantity));
        }
    }
} catch (Exception e ) {
    // todo handle exception
}  

This can be a more naive answer to your question than parsing the raw response.

Taking one step further

It seems that we already have model class for InvestmentsModel. The more elegant approach is to keep things in their own contexts and to create for pojos for responses.

Assumed we have such InvestmentsModel:

import com.fasterxml.jackson.annotation.JsonProperty;

public class InvestmentsModel {

    @JsonProperty("Price")
    private float price;

    @JsonProperty("Commission")
    private float comission;

    @JsonProperty("Quantity")
    private float quantity;

    public InvestmentsModel() {
    }

    public InvestmentsModel(float price, float comission, float quantity) {
        this.price = price;
        this.comission = comission;
        this.quantity = quantity;
    }

    public InvestmentsModel price(float price) {
        this.price = price;
        return this;
    }

    public InvestmentsModel comission(float comission) {
        this.comission = comission;
        return this;
    }

    public InvestmentsModel quantity(float quantity) {
        this.quantity = quantity;
        return this;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    public float getComission() {
        return comission;
    }

    public void setComission(float comission) {
        this.comission = comission;
    }

    public float getQuantity() {
        return quantity;
    }

    public void setQuantity(float quantity) {
        this.quantity = quantity;
    }

    @Override
    public String toString() {
        return "[price -> " + this.price + ", comission -> " + this.comission + ", quantity -> " + this.quantity + "]";
    }
}

For the response structure, we have:

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;

public class GetInvestmentsResponseModel {

    @JsonProperty("response")
    private List<InvestmentsModel> response;

    @JsonProperty("code")
    private int code;

    public GetInvestmentsResponseModel() {
    }

    public GetInvestmentsResponseModel(List<InvestmentsModel> response, int code) {
        this.response = response;
        this.code = code;
    }

    public GetInvestmentsResponseModel response(List<InvestmentsModel> response) {
        this.response = response;
        return this;
    }

    public GetInvestmentsResponseModel code(int code) {
        this.code = code;
        return this;
    }

    public List<InvestmentsModel> getResponse() {
        return response;
    }

    public void setResponse(List<InvestmentsModel> response) {
        this.response = response;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }
}

And then code becomes:

        final String rawResponse = "[{\"response\": [{\"Commission\": 50, \"Price\": 0.5, \"Quantity\": \"20\"}, {\"Commission\": 50, \"Quantity\": 20, \"Price\": 1}, {\"Quantity\": 20, \"Price\": 10, \"Commission\": 50}], \"code\": 200}]";

        ObjectMapper mapper = new ObjectMapper();

        try {

            GetInvestmentsResponseModel[] responseObjects = mapper.readValue(rawResponse, GetInvestmentsResponseModel[].class);

            GetInvestmentsResponseModel responseObject = responseObjects[0];

            if(responseObject.getCode() == 200) {
                List<InvestmentsModel> investmentsModels = responseObject.getResponse();
                System.out.println(investmentsModels);
            }

        } catch (JsonProcessingException e) {
            // handle JsonProcessingException
        }

Outputs as just as in the InvestmentsModel's toString():

[[price -> 0.5, comission -> 50.0, quantity -> 20.0], [price -> 1.0, comission -> 50.0, quantity -> 20.0], [price -> 10.0, comission -> 50.0, quantity -> 20.0]]

Take one more step further

The final suggestion is to use swagger to both keep track of the api and get rid of the most of the boilerplate code. It can be used both clients and servers, and keeps APIs documented and clean. Please check this out for swagger.

Upvotes: 1

Related Questions