Reputation: 7
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"> $product </span><span style="color: #007700">= </span><span style="color: #0000BB">$productTable</span><span style="color: #007700">-></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"> $products </span><span style="color: #007700">= </span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">request</span><span style="color: #007700">-></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"> </span><span style="color: #007700">if (</span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">request</span><span style="color: #007700">-></span><span style="color: #0000BB">is</span><span style="color: #007700">(</span><span style="color: #DD0000">'post'</span><span style="color: #007700">)) {</span></span></code></pre><pre id="cakeErr5bae1ec79e019-context" class="cake-context" style="display: none;">$res = []
$productTable = object(App\Model\Table\ProductsTable) {
'registryAlias' => 'products',
'table' => 'products',
'alias' => 'products',
'entityClass' => 'App\Model\Entity\product',
'associations' => [],
'behaviors' => [],
'defaultConnection' => 'default',
'connectionName' => 'default'
}
$product = object(App\Model\Entity\product) {
'[new]' => true,
'[accessible]' => [
'product_id' => true,
'product_name' => true,
'product_price' => true,
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'products'
}</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
Upvotes: 0
Views: 567
Reputation: 2735
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());
}
});
Upvotes: 2
Reputation: 5190
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.
Upvotes: 0
Reputation: 1690
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.
Upvotes: 0