0

I am trying to send a JSON Object of array of JSON objects from my android app to server, but it doesen't work. I have tried it using POSTMAN and it works. The following are the codes i have tried and the json format.

Here is the JSON Format

{
    "products": [
        {
            "product_id": 1,
            "product_name": "Smart Watch",
            "product_price": 99.99
        },

        {
            "product_id": 2,
            "product_name": "Smart TV",
            "product_price": 999.99
        }
    ]
}

Here is POJO Class

import com.google.gson.annotations.SerializedName;

public class Product {

    @SerializedName("product_id")
        public int productId;
        @SerializedName("product_name")
        public String productName;
        @SerializedName("product_price")
        public double productPrice;



    public Product(Integer productId, String productName, Float productPrice) {
        this.productId = productId;
        this.productName = productName;
        this.productPrice = productPrice;

    }

    public Integer getProductId() {
        return productId;
    }

    public void setProductId(Integer productId){
        this.productId = productId;
    }

    public String getproductName() {
        return productName;
    }

    public void setproductName(String productName) {
        this.productName = productName;
    }

    public String getproductPrice() {
        return productPrice;
    }

    public void setproductPrice(String productPrice) {
        this.productPrice = productPrice;
    }


}

Here is my ServiceGenerator Class

public class ServiceGenerator {

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    public static <S> S createService(Class<S> serviceClass, String baseUrl)
    {
        Retrofit builder = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .client(httpClient.build())
                .build();

        return builder.create(serviceClass);
    }
}

Added another class Customers

public class Customers {
    @SerializedName("customers")
    public List<Customer> customers;

    public List<Customer> getCustomers() {
        return customers;
    }

    public void setCustomers(List<Customer> customers) {
        this.customers = customers;
    }
}

Here is my Interface Class

public interface IRetrofit {
    @Headers({

            "Accept: application/json",
            "Content-Type: application/json"
    })
    @POST("addproduct")
    Call<Products> postRawJSON(@Body Products products);


}

and My MainActivity Class

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void onPostClicked(View view){

        // Using the Retrofit
        IRetrofit jsonPostService = ServiceGenerator.createService(IRetrofit.class, "http://192.168.122.1/productmanager/products/");


        Product product = new Products(null, "Samsung Galaxy A5", 234.54);
        Call<Product> call = jsonPostService.postRawJSON(product);
        call.enqueue(new Callback<Product>() {

            @Override
            public void onResponse(Call<Product> call, Response<Product> response) {
                try{
                    Log.e("response-success", response.body().toString());
                }catch (Exception e){
                    e.printStackTrace();
                }

            }

            @Override
            public void onFailure(Call<Product> call, Throwable t) {
                Log.e("response-failure", call.toString());
            }
        });
    }
}

I have called the onPostClicked() method from the layout android:OnClicked property.

I have also edited the AnroidManifest File and added

<uses-permission android:name="android.permission.INTERNET" />

and am connected to the same network.

Using POSTMAN i tried sending this and it works(adds it to the db)

{
    "products": [
        {
            "product_name": "Galaxy A2",
            "product_price": 599.99
        }


    ]
}

and when i send a GET Request it also shows me it has added the new record

{
    "products": [
        {
            "product_id": 1,
            "product_name": "Smart Watch",
            "product_price": 99.99
        },

        {
            "product_id": 2,
            "product_name": "Smart TV",
            "product_price": 999.99
        },
 {
                "product_id": 3,
                "product_name": "Galaxy A2",
                "product_price": 599.99
            }

    ]
}

Here is my Log

I/TAG: --> POST http://192.168.122.1/productmanager/products/ http/1.1
       Content-Type: application/json
       Content-Length: 249
       Accept: application/json
I/TAG: {"product_id":"","product_name":"Samsung Galaxy A5","product_price":234.5}
       --> END POST (249-byte body)
I/TAG: <-- 200 OK http://192.168.122.1/productmanager/products/addcproduct (266ms)
       Date: Fri, 28 Sep 2018 12:29:59 GMT
       Server: Apache/2.4.34 (Win32) OpenSSL/1.0.2o PHP/5.6.37
       X-Powered-By: PHP/5.6.37
       Keep-Alive: timeout=5, max=100
       Connection: Keep-Alive
       Transfer-Encoding: chunked
       Content-Type: text/html; charset=UTF-8
I/TAG: <pre class="cake-error"><a href="javascript:void(0);" onclick="document.getElementById('cakeErr5bae1ec79e019-trace').style.display = (document.getElementById('cakeErr5bae1ec79e019-trace').style.display == 'none' ? '' : 'none');"><b>Notice</b> (8)</a>: Undefined index: products [<b>APP/Controller\productsController.php</b>, line <b>77</b>]<div id="cakeErr5bae1ec79e019-trace" class="cake-stack-trace" style="display: none;"><a href="javascript:void(0);" onclick="document.getElementById('cakeErr5bae1ec79e019-code').style.display = (document.getElementById('cakeErr5bae1ec79e019-code').style.display == 'none' ? '' : 'none')">Code</a> <a href="javascript:void(0);" onclick="document.getElementById('cakeErr5bae1ec79e019-context').style.display = (document.getElementById('cakeErr5bae1ec79e019-context').style.display == 'none' ? '' : 'none')">Context</a><pre id="cakeErr5bae1ec79e019-code" class="cake-code-dump" style="display: none;"><code><span style="color: #000000"><span style="color: #0000BB">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$product&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$productTable</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newEntity</span><span style="color: #007700">();</span></span></code>
       <span class="code-highlight"><code><span style="color: #000000"><span style="color: #0000BB">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$products&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">request</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">data</span><span style="color: #007700">[</span><span style="color: #DD0000">'products'</span><span style="color: #007700">];</span></span></code></span>
       <code><span style="color: #000000"><span style="color: #0000BB">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">if&nbsp;(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">request</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">is</span><span style="color: #007700">(</span><span style="color: #DD0000">'post'</span><span style="color: #007700">))&nbsp;{</span></span></code></pre><pre id="cakeErr5bae1ec79e019-context" class="cake-context" style="display: none;">$res = []
       $productTable = object(App\Model\Table\ProductsTable) {

        &#039;registryAlias&#039; =&gt; &#039;products&#039;,
        &#039;table&#039; =&gt; &#039;products&#039;,
        &#039;alias&#039; =&gt; &#039;products&#039;,
        &#039;entityClass&#039; =&gt; &#039;App\Model\Entity\product&#039;,
        &#039;associations&#039; =&gt; [],
        &#039;behaviors&#039; =&gt; [],
        &#039;defaultConnection&#039; =&gt; &#039;default&#039;,
        &#039;connectionName&#039; =&gt; &#039;default&#039;

       }
       $product = object(App\Model\Entity\product) {

        &#039;[new]&#039; =&gt; true,
        &#039;[accessible]&#039; =&gt; [
            &#039;product_id&#039; =&gt; true,
            &#039;product_name&#039; =&gt; true,
            &#039;product_price&#039; =&gt; true,

        ],
        &#039;[dirty]&#039; =&gt; [],
        &#039;[original]&#039; =&gt; [],
        &#039;[virtual]&#039; =&gt; [],
        &#039;[errors]&#039; =&gt; [],
        &#039;[invalid]&#039; =&gt; [],
        &#039;[repository]&#039; =&gt; &#039;products&#039;

       }</pre><pre class="stack-trace">App\Controller\productsController::addproduct() - APP/Controller\ProductsController.php, line 77
       Cake\Controller\Controller::invokeAction() - CORE\src\Controller\Controller.php, line 440
       Cake\Http\ActionDispatcher::_invoke() - CORE\src\Http\ActionDispatcher.php, line 119
       Cake\Http\ActionDispatcher::dispatch() - CORE\src\Http\ActionDispatcher.php, line 93
       Cak
       <-- END HTTP (22852-byte body)
E/response-failure: retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall@4958691

Please help. Thank You in advance

4
  • 192.168.122.1 is local network IP address. It will work if it is connected to same notwork. Commented Sep 28, 2018 at 7:23
  • Yes, i am connected to the same network, but it still doesn't work Commented Sep 28, 2018 at 7:25
  • open 192.168.122.1/productmanager/products/addproduct in your test device browser and tell me the result Commented Sep 28, 2018 at 7:30
  • @VinayakB it shows a bunch of errors, but i tried it using postman on my host device, and it works(adds the product) Commented Sep 28, 2018 at 7:36

3 Answers 3

2

You need to pass a List of Product as @Body. Which means your Request model is an Object which contains a List of Product objects

Try creating the POJO classes like this

        public class Product {
            @SerializedName("product_id")
            public int productId;
            @SerializedName("product_name")
            public String productName;
            @SerializedName("product_price")
            public double productPrice;
        }

        public class ProductRequest {
            @SerializedName("products")
            public List<Product> products;
        }

Note: Add setters and getters if you are making fields private

Then in your retrofit interface

     Call<JsonObject> postRawJSON(@Body ProductRequest products);

Also, Instead of JsonObject use the POJO class for your response JSON structure

Update: Do the following steps

1) Create the ProductRequest model like this

    ProductRequest productRequest = new ProductRequest();
    ArrayList<Product> productList = new ArrayList<>();
    Product product = new Product(1, "Samsung Galaxy A5", 234.54);
    productList.add(product);
    productRequest.products = productList;

2) Create a POJO class for the response JSON of this API. For example create a ProductResponse class. Since I don't know your response structure, I assume it would be something like

{
  "code" : 200 , 
  "status" : "Success"
}

So for the above Response , the POJO class you have to create as follows

 public class ProductResponse {
    @SerializedName("code")
    public int code;
    @SerializedName("status")
    public String status;
}

3) Create your IRetrofit interface like this

    public interface IRetrofit {
    @Headers({
            "Accept: application/json",
            "Content-Type: application/json"
    })
    @POST("addproduct")
    Call<ProductResponse> addProducts(@Body ProductRequest productRequest);

4) Now in your Activity following is the full code to create the Request (as shown Step 1) and call the API

    ProductRequest productRequest = new ProductRequest();
    ArrayList<Product> productList = new ArrayList<>();
    Product product = new Product(1, "Samsung Galaxy A5", 234.54);
    productList.add(product);
    productRequest.products = productList;

    Call<ProductResponse> productResponseCall = jsonPostService.addProducts(productRequest);
    productResponseCall.enqueue(new Callback<ProductResponse>() {
        @Override
        public void onResponse(Call<ProductResponse> call, Response<ProductResponse> response) {
            ProductResponse productResponse = response.body(); // this  your result

        }

        @Override
        public void onFailure(Call<ProductResponse> call, Throwable t) {
            Log.e("response-failure", call.toString());
        }
    });
Sign up to request clarification or add additional context in comments.

18 Comments

i am trying to send one product at a time actually.
But the JSON what you have posted in the question is the structure expected by your server right?
Not necessarily as i have said i tried it using postman, i just sent a product and it worked
You said you are sending one object via postman and in your updated question still you are sending a list only??
I have updated the answer with all the steps. Please try it once
|
0

Your server requires you to send a list of Products, in your Android app you are sending 1 product (1 Java model). What you should do is send a list of models.

You could have avoided this problem if you gave your classes better names

Products products = new Products(null, "Samsung Galaxy A5", 234.54);

is bad because you are not creating products but a product.

5 Comments

I am actually trying to send one product at a time
Does your API accept an endpoint where only one product can be send?
If it does not, then you can create an ArrayList of 1 Product and send that object instead.
I have edited my post. I tried using postman and just sent one and it worked
You are still sending a list of 1 product. Change your Java code to what is suggested here: stackoverflow.com/a/52550479/3999808 IF THIS DOES NOT WORK, POST YOUR LOG
0

As I can see from your JSON sample, server accepts JSONObject which contains JSONArray of products

You tested it using Postman with same parameters as your server accepts. But, in your application you're preparing an object of Product class and passing it to API request. So, the final payload will be like below,

{
    "product_id": 1,
    "product_name": "Smart Watch",
    "product_price": 99.99
}

Just a JSONObject of products instead of products JSONArray.

Follow what @Srt suggested in his answer. That's correct way of sending data to your API (as per the requirement)

And also I came across your comments posted under other answers here. In one of them you said

There is no error, it just doesn't work. It doesn't add the new record – S.Jay

To check what's happening while Retrofit executing network requests, you need to add OkHttpLoggingInterceptor which logs every single request (including errors) being executed through Retrofit library.

Add this dependency to your build.gradle (app level) and sync the project

implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'

After syncing the project add below code into ServiceGenerator class

import okhttp3.logging.HttpLoggingInterceptor;
import android.util.Log;

public class ServiceGenerator {

private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

public static <S> S createService(Class<S> serviceClass, String baseUrl) {

    // add logging interceptor to OkHttpClient
     httpClient.addInterceptor(getInterceptor());

    Retrofit builder = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .client(httpClient.build())
            .build();

      return builder.create(serviceClass);
    }

    public static HttpLoggingInterceptor getInterceptor() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
           @Override
           public void log(String message) {
               Log.i("TAG", message);
           }
        });
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        return interceptor;
    }
}

Just add HttpLoggingInterceptor to OkHttpClient like I mentioned in above code. (or copy and paste the code)

Now, that should log every single request.

2 Comments

I have accepted and edited my code according to @Srt, and i have posted my log error
Still you're sending the same JSON body {"product_id":"","product_name":"Samsung Galaxy A5","product_price":234.5} (look into Retrofit logging interceptor's log message) which causing the following error at server side Undefined index: products [APP/Controller\productsController.php, line 77] Not sure why you're not understanding [or following] the @Srt s answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.