when syncing webservices with SQLite, array and object error appear - android

i am trying to get my json data into my sqlite, from web services to android.
This is the error that i get when i start syncing.
error stating Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
The error appear on this chunk of codes.
public String processSync(String response) {
String status = FAILED;
try {
String formattedData = getFormattedData(response);
final GsonBuilder gsonBuilder = new GsonBuilder();
final Gson gson = gsonBuilder.create();
ProductDataBean[] productDataBeanArray = gson.fromJson(formattedData, ProductDataBean[].class);
AdministratorHelper administratorHelper = new AdministratorHelper();
status = administratorHelper.insertProductData(context, productDataBeanArray);
} catch (Exception e) {
e.printStackTrace();
}
return status;
}
AdministratorHelper.java
public class AdministratorHelper {
DBLiteUtils dbLiteUtils;
AdministratorDao dao = new AdministratorDao();
public String insertProductData(Context context, ProductDataBean[] productDataBeanArray){
String status = FAILED;
try{
dbLiteUtils = new DBLiteUtils(context);
dbLiteUtils.open();
status = dao.insertProductData(dbLiteUtils, productDataBeanArray);
} catch (Exception e){
e.printStackTrace();
} finally {
dbLiteUtils.close();
}
return status;
}
AdministratorDao.java
public class AdministratorDao {
private Cursor cursor;
//Insert Product Details into SQLite
public String insertProductData(DBLiteUtils dbLiteUtils, ProductDataBean[] productDataBeanArray){
String status = FAILED;
try {
if(productDataBeanArray.length > 0) {
//Delete Existing Data
dbLiteUtils.deleteAll("ProductMaster");
//Base Insert Query for inserting New Data into ProductMaster Table
String query = "INSERT INTO ProductMaster(ItemId, Description, Barcode, TransStatusCode) VALUES ";
//Iterate the productDataBeanArray in order to get productDataBean which contains a single product details
for (ProductDataBean productDataBean : productDataBeanArray) {
//Concatenate the Base Insert Query and the product details
query = query+"('"+productDataBean.getItemId().trim()+"', '"+productDataBean.getDescription().trim().replace("\'", "\'\'")+"', '"+productDataBean.getBarcode().trim()+"', '"+productDataBean.getTransStatusCode().trim()+"'),"; //.trim() removes unwanted empty spaces
}
//Remove the last comma from the iterated complete query
query = query.substring(0, query.length()-1);
//execute the query
dbLiteUtils.executeQuery(query);
//return success
status = SUCCESS;
}
} catch (Exception e){
e.printStackTrace();
}
return status;
}
This is my code in the visual studio to get the json data
public class ProductController : ApiController
{
public IEnumerable<Product> Get()
{
List<Product> pproducts;
using (estocktakeEntities entities = new estocktakeEntities())
{
pproducts = entities.Products.ToList();
//return entities.products.ToList();
}
return pproducts;
}
This is a sample of my json
[{"invtid":"02007997 ","ib_itemcode1":"0 ","transtatuscode":"IN","descr":"Pantene C/C Intensive Care Mask 6 x 150m"},
{"invtid":"1","ib_itemcode1":"1","transtatuscode":"IN","descr":"object1"},{"invtid":"13101336 ","ib_itemcode1":"47400179172 ","transtatuscode":"IN","descr":"Gillette Mach 3 Dispenser 8S (X12) "},
{"invtid":"13101473 ","ib_itemcode1":"47400179349 ","transtatuscode":"IN","descr":"Gillette Mach3 Cart 4S (X12)
Let me know if more information is needed, i will be more than willing to upload them.
thank you sir for your time.
EDIT 1
After trying to debug, i had this error, still not sure is it useful but here is the error and the codes related to it.
{"Message":"An error has occurred.","ExceptionMessage":"Value cannot be null.\r\nParameter name: entity","ExceptionType":"System.ArgumentNullException","StackTrace":" at System.Data.Entity.Utilities.Check.NotNull[T](T value, String parameterName)\r\n at System.Data.Entity.DbSet`1.Add(TEntity entity)\r\n at ProductServiceFinal.Controllers.ProductController.Post(Product productrecord)"}
ProductController.Post
public HttpResponseMessage Post([FromBody] Product productrecord)
{
try
{
using (estocktakeEntities entities = new estocktakeEntities())
{
entities.Products.Add(productrecord);
//entities.Entry(productrecord).State = System.Data.Entity.EntityState.Modified;
entities.SaveChanges();
var message = Request.CreateResponse(HttpStatusCode.Created, productrecord);
message.Headers.Location = new Uri(Request.RequestUri + productrecord.invtid.ToString());
return message;
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}

The error log is :com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column So I guess the problem is JSON body which was web service provided.
public String processSync(String response) {
String status = FAILED;
try {
String formattedData = getFormattedData(response);
final GsonBuilder gsonBuilder = new GsonBuilder();
final Gson gson = gsonBuilder.create();
ProductDataBean[] productDataBeanArray = gson.fromJson(formattedData, ProductDataBean[].class);
AdministratorHelper administratorHelper = new AdministratorHelper();
status = administratorHelper.insertProductData(context, productDataBeanArray);
} catch (Exception e) {
Log.e("tag",formattedData); // log out this JSON
e.printStackTrace();
}
return status;
}
And EDIT 1 told me that the problem may occur in web service. (I guess web service returns a wrong JSON).
My advice is that add some "fault-tolerance" code to Android project.
The root cause is probably in the web service.

Related

check playerSSign fail

When verifying the signature, the background server displays {"rtnCode":-1,"errMsg":"check playerSSign fail"}
The data provided by the client is
if(huaweiid != null){
PlayersClient player = Games.getPlayersClient(this, huaweiid);
player.getCurrentPlayer().addOnSuccessListener(new OnSuccessListener<Player>() {
#Override
public void onSuccess(Player player) {
String ts = player.getSignTs();
String playerId = player.getPlayerId();
int playerLevel = player.getLevel();
String playerSign = player.getPlayerSign();
//String displayName = player.getDisplayName();
//Uri hiResImageUri = player.getHiResImageUri();
//Uri iconImageUri = player.getIconImageUri();
JSONObject jo = new JSONObject();
try {
jo.put("signTs", ts);
jo.put("playerId", playerId);
jo.put("playerLevel", playerLevel);
jo.put("playerSign", playerSign);
EditText ed = findViewById(R.id.editText);
ed.setText(jo.toString());
Log.i("huawei user info", jo.toString());
} catch (JSONException e) {
e.printStackTrace();
Log.i("huawei user info", Objects.requireNonNull(e.getMessage()));
}
}
});
}
Use the preceding four data items and the following description document:
https://developer.huawei.com/consumer/cn/doc/HMSCore-References-V5/verify-login-signature-0000001050123503-V5
An error always occurs during the verification in the background.
{"rtnCode":-1,"errMsg":"check playerSSign fail"}
appId/cpid is obtained from agconnect-services.json and agconnect-services.json is downloaded from the background.
what’s the reason?
The following table describes the typical setting errors of the input parameters. Please verify the parameter settings.
https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/faq-check-login-0000001050746133-V5

Android Retrofit Request Using AWS Signature Authorization

I'm trying to get data from the API which needs to handle aws-authentication, my question is how can I generate Authorization and X-Amz-Date?
I have to pass 3 parameter as header: Content-Type, Authorization and X-Amz-Date.
As you can find in image:
here is the function that generate Authorization String:
public static String gerateOAuthAWS(Context co) throws Exception {
JodaTimeAndroid.init(co);
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").withLocale(Locale.US);
String ZONE = "GMT";
DateTime dt = new DateTime();
DateTime dtLondon = dt.withZone(DateTimeZone.forID(ZONE)).plusHours(1);
String formattedDate = dtLondon.toString(fmt);
String oauth = "AWS4-HMAC-SHA256 Credential="+ ACCESS_KEY+"/us-east-1/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature="+
getSignatureKey(SECRET_KEY,formattedDate,"us-east-1","execute-api");
return oauth;
}
static byte[] HmacSHA256(String data, byte[] key) throws Exception {
String algorithm="HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes("UTF8"));
}
static String getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Exception {
byte[] kSecret = ("AWS4" + key).getBytes("UTF8");
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return Base64.encodeToString(kSigning,Base64.DEFAULT).replaceAll("\n", "");
}
Content-Type is "application/x-www-form-urlencoded"
and generate X-Amz-Date something as: "201805138T120046Z"
then pass them through retrofit methods:
#GET("prod/video")
Call<ArrayList<Video>> getAllVideos(#Header("Content-Type")String content_type,
#Header("X-Amz-Date")String amz_date,
#Header("Authorization")String auth);
the result returns null and I'm sure the issue is related the authorization since it worked before well.
thanks for your helps :)
i always said to my friends why do you use retrofit or valley , if it's seems complicated to you !
instead you can use JSOUP or OKHTTP it's much easier and I realy love JSOUP
an example that you can connect and send you data:
private void fcmIdentity(final String fcmKey) {
new Thread(new Runnable() {
#Override
public void run() {
try {
SSLHelper.enableSSLSocket();
Connection.Response response = Jsoup
.connect(Urls.identity)
.header("Accept", "application/json")
.header("KEY_2", "VALUE_2")
.method(Connection.Method.POST)
.ignoreContentType(true)
.ignoreHttpErrors(true)
.validateTLSCertificates(true)
.followRedirects(true)
.data("fcm", "" + fcmKey)
.data("identity", preferences.getString("FCM_ID", ""))
.execute();
Log.i("fcmIdentity", response.statusCode() + "");
Log.i("fcmIdentity", response.toString());
Log.d("fcmIdentity", response.headers().toString());
Log.i("fcmIdentity", response.body());
} catch (Exception e) {
e.printStackTrace();
if (e instanceof IOException) {
G.toast(getString(R.string.connection_error), true);
}
}
}
}).start();
}
about SSLHelper it help to connect to HTTPS
for more info check my topic https://answers.uncox.com/android/question/13003

org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type[EDITED]

In Android web service using POST method of REST TEMPLATE, I am trying to send an object to server which contains few parameters and and 2 Objects. Those 2 Objects contains few parameters and 3 Lists of different Objects and each of those 3 Lists of Objects contains few parameters inside them and 1 List of Object that contains a byte array alone. Like in the below pics:
Pic 1[Main Object(The one I am trying to send)]:
Pic 2[Object inside the Main Object comprising 3 Lists of Objects]:
Pic 3[An Object as List comprising 1 List of Another Object inside it, likewise for the other 2(Accommodation & Others)]:
Pic 4[List of Object inside the sub-Object containing a byre array parameter alone]:
And my code for webservice POST method:
public static final String capUrl = "http://192.168.1.7:8084/CAPWS";
public Expenses setExpensesByBatch(Expenses expenses) {
try {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
List<HttpMessageConverter<?>> list = new ArrayList<HttpMessageConverter<?>>();
list.add(new MappingJacksonHttpMessageConverter());
restTemplate.setMessageConverters(list);
String b = restTemplate.postForObject(capUrl + "/UX/", expenses, String.class);
Log.e("String ===============b", b + " ++++");
} catch (Exception e) {
e.printStackTrace();
Log.e("expObjPost_WsCli_EX", e.toString());
}
return expenses;
}
Whatever I do it returns org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
My LOGCAT below:
My server side code:
#RequestMapping(value = CapRestURIConstants.UPDATEEXPENSES, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
String updateExpenses(#RequestBody Expenses expenses) {
String response = "true";
System.out.println("incoming--------" + "UPDATEEXPENSES");
try {
if (expenses != null) {
//System.out.println("expenses--------" + expenses);
int catType = expenses.getCategoryType();
String categoryType = String.valueOf(catType);
String categoryId = expenses.getCategoryId();
String batchId = expenses.getBatchId();
System.out.println("categoryType--------" + categoryType);
System.out.println("categoryId--------" + categoryId);
System.out.println("batchId--------" + batchId);
Batch batch = getBatchById(batchId);
if (batch != null) {
expenseDataNew(batch, expenses);
expenseImagesNew(batch, expenses);
}
}
} catch (Exception e) {
e.printStackTrace();
response = "faslse";
}
return response;
}
public void expenseDataNew(Batch batch, Expenses expenses) {
Session session = null;
Transaction transaction = null;
Gson gson = new Gson();
try {
LinkedTreeMap masterMap = (LinkedTreeMap) gson.fromJson(batch.getMasterJson(), Object.class);
LinkedTreeMap expenseObject = (LinkedTreeMap) masterMap.get("2007");
masterMap.replace(expenseObject, expenses);
String masterJson = gson.toJson(masterMap);
batch.setMasterJson(masterJson);
session = HibernateUtil.getSessionFactory().openSession();
transaction = session.beginTransaction();
session.saveOrUpdate(batch);
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
if (session != null) {
session.close();
}
}
}
public void expenseImagesNew(Batch batch, Expenses expenses) {
Session session = null;
Transaction transaction = null;
Gson gson = new Gson();
try {
// DIVERTING TO IMAGE DB
session = ImageHibernateUtil.getSessionFactory().openSession();
transaction = session.beginTransaction();
if (expenses != null) {
int catType = expenses.getCategoryType();
String categoryType = String.valueOf(catType);
System.out.println("categoryType--------" + categoryType);
String categoryId = expenses.getCategoryId();
System.out.println("categoryId--------" + categoryId);
String travelExpenseImgId = "f257f225-41da-11e7-be05-001d92ba9634";
String accommodationExpenseImgId = "204b4baf-41db-11e7-be05-001d92ba9634";
String otherExpenseImgId = "45d31872-41db-11e7-be05-001d92ba9634";
AssessorExpense assessorExpense = expenses.getAssessorExpense();
TCExpense tCExpense = expenses.getTcExpense();
Boolean isTravel, isAccomadation, isOthers;
List<Travel> travelList;
List<Accomadation> accommodationList;
List<Others> othersList;
ArrayList proof;
Expense expense;
ExpenseImage expenseImage;
// categoryType: 1 = Assessor
// categoryType: 4 = TC
if (categoryType.equals("1")) {
if (assessorExpense != null) {
isTravel = assessorExpense.isTravel();
if (isTravel) {
travelList = (ArrayList) assessorExpense.getTravel();
System.out.println("travelList.size()==" + travelList.size());
expense = getExpense(travelExpenseImgId);
System.out.println("expense==travel==1==:" + expense);
String expenseStr = String.valueOf(expense);
System.out.println("expenseStr==travel==1==:" + expenseStr);
for (Travel travel : travelList) {
List<ExpenseImageObject> expenseImageObjects = (ArrayList) travel.getExpenseImageObjects();
System.out.println("travel==expenseImageObjects.size()== :" + expenseImageObjects.size());
for (ExpenseImageObject image : expenseImageObjects) {
System.out.println("expense===travel==for==:" + expense);
expenseImage = new ExpenseImage();
expenseImage.setBatchId(batch.getBatchId());
expenseImage.setCategoryId(expenses.getCategoryId());
expenseImage.setExpimgId(expenseStr);
expenseImage.setImage(image.getImage());
expenseImage.setStatus(1); // dummy status 1 - Travel, 2 - Accommodation, 3 - Other
session.saveOrUpdate(expenseImage);
}
}
}
}
}
}
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
if (session != null) {
session.close();
}
}
}
I am actually trying to send an object with lists of data as well list of photos in each list to the server.
Browsed through several websites and almost all topics related to the error on Stack Overflow, Been sitting on this issue for more than a week. Hope I would find some help.
Try using "HttpHeaders" to set the content-type header explicitly to what is expected by the endpoint.
Then you use the "HttpEntity" with both your header and your body classes.
Example :
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> httpEntity = new HttpEntity<>("my body", requestHeaders);
byte[] response = restTemplate.postForObject(
"URL", httpEntity, byte[].class);
Change the call to something like this
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Accept","application/json;charset=utf-8");
RestTemplate restTemplate = new RestTemplate();
...
HttpEntity request = new HttpEntity(req, headers);
responseEntity = restTemplate.exchange(url, HttpMethod.POST, request,
String.class);
to specify content type
UPDATE
req is in fact body you send to the server. It could be e.g.
MultiValueMap<String, Object> req ...
There you in fact send request body and headers.
After a hell lot of research and experts suggestions, I finally managed to find the solution to my problem. The problem is not with the code. Its actually perfect. The problem is with the Objects I use to get & set. I am using NetBeans for server side coding. What I did was, I created my necessary Objects in Android studio, copied the parameters, getters & setters and pasted them on NetBeans, Object class. The problem was with the booleans I've been using. The booleans that are created on Android Studio didn't support on NetBeans in some cases, that prevented hitting the server. And after getting expert advice, I did the Object creation on NetBeans copied the parameters, getters & setters and pasted them on Android Studio Object class. And then it worked well. Took me more than 2 weeks to solve this issue. Hope this would be of some help.

Custom converter to subclass with Moshi

I have a User class. And two subclasses. Parent and Child.
I get json from my server with {"user":"..."} and need to convert it to parent or to child depending on user.type
As I understand I need to add custom converter this way:
Moshi moshi = new Moshi.Builder()
.add(new UserAdapter())
.build();
Here's my implementation of UserAdapter. I know it's dummy, but it's not working even this way:
public class UserAdapter {
#FromJson
User fromJson(String userJson) {
Moshi moshi = new Moshi.Builder().build();
try {
JSONObject jsonObject = new JSONObject(userJson);
String accountType = jsonObject.getString("type");
switch (accountType) {
case "Child":
JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class);
return childJsonAdapter.fromJson(userJson);
case "Parent":
JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class);
return parentJsonAdapter.fromJson(userJson);
}
} catch (JSONException | IOException e) {
e.printStackTrace();
}
return null;
}
#ToJson
String toJson(User user) {
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<User> jsonAdapter = moshi.adapter(User.class);
String toJson = jsonAdapter.toJson(user);
return toJson;
}
First of all I get following exception with this code.
com.squareup.moshi.JsonDataException: Expected a string but was BEGIN_OBJECT at path $.user
And second, I believe there's a better way to do it. Please advice.
Upd. here's stacktrace for the error:
com.squareup.moshi.JsonDataException: Expected a name but was BEGIN_OBJECT at path $.user
at com.squareup.moshi.JsonReader.nextName(JsonReader.java:782)
at com.squareup.moshi.ClassJsonAdapter.fromJson(ClassJsonAdapter.java:141)
at com.squareup.moshi.JsonAdapter$1.fromJson(JsonAdapter.java:68)
at com.squareup.moshi.JsonAdapter.fromJson(JsonAdapter.java:33)
at retrofit.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:33)
at retrofit.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:23)
at retrofit.OkHttpCall.parseResponse(OkHttpCall.java:148)
at retrofit.OkHttpCall.execute(OkHttpCall.java:116)
at retrofit.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:111)
at retrofit.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:88)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable.unsafeSubscribe(Observable.java:7710)
at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
This seems to me like the example you want to follow for your custom de/serialization of your JSON data: https://github.com/square/moshi#another-example
It uses an intermediate class that corresponds to the JSON structure, and Moshi will inflate it automatically for you. Then, you can use the inflated data to build your specialized user classes. For example:
// Intermediate class with JSON structure
class UserJson {
// Common JSON fields
public String type;
public String name;
// Parent JSON fields
public String occupation;
public Long salary;
// Child JSON fields
public String favorite_toy;
public Integer grade;
}
abstract class User {
public String type;
public String name;
}
final class Parent extends User {
public String occupation;
public Long salary;
}
final class Child extends User {
public String favoriteToy;
public Integer grade;
}
Now, the adapter:
class UserAdapter {
// Note that you pass in a `UserJson` object here
#FromJson User fromJson(UserJson userJson) {
switch (userJson.type) {
case "Parent":
final Parent parent = new Parent();
parent.type = userJson.type;
parent.name = userJson.name;
parent.occupation = userJson.occupation;
parent.salary = userJson.salary;
return parent;
case "Child":
final Child child = new Child();
child.type = userJson.type;
child.name = userJson.name;
child.favoriteToy = userJson.favorite_toy;
child.grade = userJson.grade;
return child;
default:
return null;
}
}
// Note that you return a `UserJson` object here.
#ToJson UserJson toJson(User user) {
final UserJson json = new UserJson();
if (user instanceof Parent) {
json.type = "Parent";
json.occupation = ((Parent) user).occupation;
json.salary = ((Parent) user).salary;
} else {
json.type = "Child";
json.favorite_toy = ((Child) user).favoriteToy;
json.grade = ((Child) user).grade;
}
json.name = user.name;
return json;
}
}
I think that this is much cleaner, and allows Moshi to do its thing, which is creating objects from JSON and creating JSON from objects. No mucking around with old-fashioned JSONObject!
To test:
Child child = new Child();
child.type = "Child";
child.name = "Foo";
child.favoriteToy = "java";
child.grade = 2;
Moshi moshi = new Moshi.Builder().add(new UserAdapter()).build();
try {
// Serialize
JsonAdapter<User> adapter = moshi.adapter(User.class);
String json = adapter.toJson(child);
System.out.println(json);
// Output is: {"favorite_toy":"java","grade":2,"name":"Foo","type":"Child"}
// Deserialize
// Note the cast to `Child`, since this adapter returns `User` otherwise.
Child child2 = (Child) adapter.fromJson(json);
System.out.println(child2.name);
// Output is: Foo
} catch (IOException e) {
e.printStackTrace();
}
There's now a much better way to do this, using PolymorphicJsonAdapterFactory. See https://proandroiddev.com/moshi-polymorphic-adapter-is-d25deebbd7c5
You probably tried to implement you parsing according to: https://github.com/square/moshi#custom-type-adapters
There String is used as an argument of #FromJson method, so it can be magically parsed to some mapping helper class or String and we have to parse it manually, right? Actually no, you can either use mapping helper class or Map.
Thus your exception Expected a string but was BEGIN_OBJECT at path $.user was caused by Moshi trying to get that user as a String (because that's what you implied in your adapter), whereas it is just another object.
I don't like parsing ALL possible fields to some helper class as in case of polymorphism that class might become very big and you need to rely or remembering/commenting code.
You can handle it as a map - that is default model for unknown types - and convert it to json, so in your case that would look something like:
#FromJson
User fromJson(Map<String, String> map) {
Moshi moshi = new Moshi.Builder().build();
String userJson = moshi.adapter(Map.class).toJson(map);
try {
JSONObject jsonObject = new JSONObject(userJson);
String accountType = jsonObject.getString("type");
switch (accountType) {
case "Child":
JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class);
return childJsonAdapter.fromJson(userJson);
case "Parent":
JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class);
return parentJsonAdapter.fromJson(userJson);
}
} catch (JSONException | IOException e) {
e.printStackTrace();
}
return null;
}
Of course you can just handle map directly: retrieve "type" string and then parse the rest of map to chosen class. Then there is no need to use JSONObject at all with nice benefit of not being dependent on Android and easier testing of parsing.
#FromJson
User fromJson(Map<String, String> map) {
Moshi moshi = new Moshi.Builder().build();
try {
String userJson = moshi.adapter(Map.class).toJson(map);
switch (map.get("type")) {
case "Child":
JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class);
return childJsonAdapter.fromJson(userJson);
case "Parent":
JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class);
return parentJsonAdapter.fromJson(userJson);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

JSON parsing not encoding string with underscore in Android using Volley

I am trying to encode a string which contains a URL, I have a strange issue where the complete string is not being returned, I have noticed that it may be related to the underscore, I have tried a few solution where I replace the underscore, but haven't had much luck with that solution. Below is the JSON.
[{"id":"1","source":"BBC WORLD NEWS",
"time_date":"Sat, 25 Oct 2014 10:49:13",
"title":"Iran hangs woman despite campaign","description":"Iran defies an international campaign and hangs a woman who killed a man she said was trying to sexually abuse her.",
"link":"http:\/\/www.bbc.co.uk\/news\/world-middle-east-29769468#sa-ns_mchannel=rss&ns_source=PublicRSS20-sa",
"image":"http:\/\/news.bbcimg.co.uk\/media\/images\/78529000\/jpg\/_78529517_78528720.jpg"},
I am trying to retrieve the image element from the json. The following is what I receive from my parsing.
http://news.bbcimg.co.uk/media/images/78526000/jpg
I am using this code at the moment:
String imageurl = feed.getImage();
try {
imageurl = URLDecoder.decode(imageurl, "UTF-8");
System.out.println("---------------------------"+imageurl);
imageurl.replace("_", "%5f");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
getimage method:
private String image;
public String getImage() {
return image;
}
private void requestNewsData(String uri) {
RestAdapter api = new RestAdapter.Builder().setEndpoint(ENDPOINT).build();
NewsAPI restapi = api.create(NewsAPI.class);
restapi.news(new Callback<List<RssObject>>() {
public void success(final List<RssObject> newsFeed, Response response) {
Log.v("nas", "the webservice success " + response.getReason());
for (int i = 0; i < newsFeed.size(); i++) {
System.out.println(newsFeed.get(i).description);
newsList.add(newsFeed.get(i).description);
FeederModel feed = new FeederModel();
feed.setSource(newsFeed.get(i).source);
feed.setImage(newsFeed.get(i).image); // adding setimage
}
}
The retrieved string is missing the final part of the url.
Any suggestion would be gratefully appreciated. Thanks.

Categories

Resources