Ormlite RawRowMapper truncated double - android

I am using RawRowMapper to load relevant columns from ormlite. RawRowMapper returns all data as String.
The observation is that it truncates the double value.
Example:
Data inserted -> 57.1117146374
Data type used to store the data -> Double
Data from Ormlite when directly queried: -> 57.1117146374 (This is correct and essentially means that ormlite is actually storing the data correctly)
Data from Ormlite when using mapper -> 57.1117 (Truncated data coming as part of String[] resultColumns
Any idea how do I avoid it getting truncated?
EDIT:
#DatabaseField(columnName = "LAT")
private Double lat;
Object Field:
private double lat;
The key here is that the string in resultcolumns[], I get is already truncated.

Data from Ormlite when using mapper -> 57.1117 (Truncated data coming as part of String[] resultColumns
The problem seems to be that getting a double value out as a String is truncated by Android's cursor.getString(...) method. Not sure why but if the result is extracted by using cursor.getDouble(columnIndex); on the same column-index, the full precision is preserved.
The solution here I believe is to map the rows differently. If you use dao.queryRaw(String, DataType[], ...) method, the double field seems to be extracted appropriately. Here's a sample from my test class.
GenericRawResults<Object[]> results =
dao.queryRaw(dao.queryBuilder().selectColumns("lat")
.prepareStatementString(), new DataType[] { DataType.DOUBLE });
CloseableIterator<Object[]> iterator = results.closeableIterator();
try {
assertTrue(iterator.hasNext());
Object[] objs = iterator.next();
assertEquals(foo.doubleField, objs[0]);
} finally {
iterator.close();
}
You could also use a custom row mapper and the dao.queryRaw(String, RawRowMapper, ...) method to convert and return a custom object with a double field.

Related

Value of type java.lang.String cannot be converted to JSONObject - Android

Seen this thread for possible solutions but it beats me.
I store a customer data object as a JSON String in shared preferences (Android) and try to retrieve the string convert back to customer object and use for validations. The conversion from object to JSON String occurs perfectly well and stores in preferences (as a key value(string) pair).
When I try to create a JSONObject or an array (Its not an array but tried anyway) using the SharedPreferences.getString(key,"") - I always get the same error "Value ... of type java.lang.String cannot be converted to JSONObject".
I am hoping a different pair of eyes catch something I could not.
Error message with data (masked):
Value
{"address":{"city":"city","country":"country","customer_address_id":0,"customer_id":0,"house_number":"#123, Lane 1, Street 1","latitude":0.0,"longitude":0.0,"postcode":"12001","street":"Lane 2, Street 2"},"ageGroup":"25-45","dateOfBirth":"1537308474000","email":"abc#abc.com","firstName":"abcdefg","gender":"","id":"108","lastName":"xyz","locale":"en_us","middleName":"none","phone":"1234567890","uuid":"8c3ce2c5-600f-3c4e-bc07-727d61fae7ff"}
of type java.lang.String cannot be converted to JSONObject.
All am trying to do is (gist of code):
Saving to shared prefs using below:
jsonAdapter = moshi.adapter(RegisterUser.class);
mRegisterUser = (RegisterUser) jsonAdapter.fromJson(regisCustUser.toString());
prefs = UserPrefs.getUserPrefs(getApplicationContext());
prefs.setPrefsItem(UserPrefs.getregUserKey(), jsonAdapter.toJson(mRegisterUser));`
where setPrefsItem does below:
JsonAdapter jsonAdapter = moshi.adapter(javaObject.getClass());
String cartJson = jsonAdapter.toJson(javaObject);
// Log.e("CartJsonreflection", cartJson);
editor.putString(prefKey, cartJson);
editor.commit();
Here is where retrieve occurs:
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
...
private static SharedPreferences settings;
...
public static Object someMethod(String prefKey, Object javaObject) {
String prefJson = settings.getString(prefKey, "");
JSONObject regisCustomer = new JSONObject(prefJson);
javaObject = (someObject) jsonAdapter.fromJson(regisCustomer.toString());
// casting is redundant but added for clarity
return javaObject;
}
Where prefJson has the above string.
I have tried to validate the JSON string on two websites - https://jsoneditoronline.org/ and https://jsonlint.com/
I have even pasted the string in Notepad++ for any special characters but found none.
Might be the case that you are trying to convert the empty string which the default string to JSONObject .
Make sure you are getting a value in prefJson by , making sure that you have initialized the SharedPreferenceswith the correct key and the key for the getString() is also right.
var s ="{\"address\":{\"city\":\"city\",\"country\":\"country\",\"customer_address_id\":0,\"customer_id\":0,\"house_number\":\"#123, Lane 1, Street 1\",\"latitude\":0.0,\"longitude\":0.0,\"postcode\":\"12001\",\"street\":\"Lane 2, Street 2\"},\"ageGroup\":\"25-45\",\"dateOfBirth\":\"1537308474000\",\"email\":\"abc#abc.com\",\"firstName\":\"abcdefg\",\"gender\":\"\",\"id\":\"108\",\"lastName\":\"xyz\",\"locale\":\"en_us\",\"middleName\":\"none\",\"phone\":\"1234567890\",\"uuid\":\"8c3ce2c5-600f-3c4e-bc07-727d61fae7ff\"}";
val regisCustomer = JSONObject(s)
println(regisCustomer.toString())
Since hardcoding the string with your value worked .
Try below
Gson gson = new GsonBuilder().create();
public static <T> T someMethod(String prefKey, Class<T> type) {
String prefJson = settings.getString(prefKey, "");
return gson.fromJson(prefJson , type);
}
Solution includes pieces of answers from other post.
I had to do:
prefJson= prefJson.replace("\\\"", "\"");
prefJson = prefJson.substring(prefJson.indexOf("{"), prefJson.lastIndexOf("}") + 1);
The quirky thing was the sharedpreferences had the exact string as below (including start and end quotes('"') in the value. Not sure why that was an issue, only when passed as a parameter. The quotes and the escape characters were ignored when hard coded into the string variable:
"{\"address\":{\"city\":\"City\",\"country\":\"Country\",\"customer_address_id\":0,\"customer_id\":0,\"house_number\":\"#123, Lane 1, Street 1\",\"latitude\":0.0,\"longitude\":0.0,\"postcode\":\"PA 12345\",\"street\":\"Lane 2, Street 2\"},\"ageGroup\":\"25-45\",\"dateOfBirth\":\"1537368909000\",\"email\":\"abc#abc.com\",\"firstName\":\"First Name\",\"gender\":\"\",\"id\":\"119\",\"lastName\":\"Last Name\",\"locale\":\"en_us\",\"middleName\":\"none\",\"phone\":\"0987654321\",\"uuid\":\"8c3ce2c5-600f-3c4e-bc07-727d61fae7ff\"}"
which had to be converted to:
{"address":{"city":"City","country":"Country","customer_address_id":0,"customer_id":0,"house_number":"#123, Lane 1, Street 1","latitude":0.0,"longitude":0.0,"postcode":"PA 12345","street":"Lane 2, Street 2"},"ageGroup":"25-45","dateOfBirth":"1537368909000","email":"abc#abc.com","firstName":"First Name","gender":"","id":"119","lastName":"Last Name","locale":"en_us","middleName":"none","phone":"0987654321","uuid":"8c3ce2c5-600f-3c4e-bc07-727d61fae7ff"}
Note: Moderators, please feel free to remove or merge this questiont if this sounds repetitive.Thank you everyone.

Firebase Database change node ID

How can I change the naming of the nodes of my children in the image below?
questions_stats is a List<Integer>, I'm aware that I get integers as nodes Id because this is a List. I create each of the children randomly with a number between 0 and 1000. I set this ID as part of the object and to find it I loop trough the list. What I want is to set the "0671" as the Key of the Object at the moment I create it.
How should I define my object in order to access each child with an Id that I define as a String.
Each of the questions_stats is an object.
This is my UserProfile Class definition.
public class UserProfile implements Parcelable {
private List<Integer> questions_list;
private List<QuestionsStats> questions_stats;
private String country_name, share_code, user_name;
private int token_count;
private Boolean is_guest;
public UserProfile() {
}
public UserProfile(List<Integer> questions_list, List<QuestionsStats> questions_stats, String country_name, String share_code, String user_name, int token_count, Boolean is_guest) {
this.questions_list = questions_list;
this.questions_stats = questions_stats;
this.country_name = country_name;
this.share_code = share_code;
this.user_name = user_name;
this.token_count = token_count;
this.is_guest = is_guest;
}
}
I know I can set them using the child("0159").setValue(QuestionStats) individually.
But for my purpose I need to retrieve the data of the "user" as a whole and then iterate whithin questions_stats like it is a List.
How should I define my UserProfile class in order to achieve what I want?
Anybody could give me a hint?
How can I change the node names of my children in the image below?
Answer: There is no way in which you can change the names of the nodes from your Firebase database. There is no API for doing that. What can you do instead is to attach a listener on that node and get the dataSnapshot object. Having that data, you can write it in another place using other names. You cannot simply rename them from 0 to 0000, 1 to 0001 and so on.
Perhaps I should have asked for How to "Set" the node Id instead of "Change"
What I have is an List<QuestionsStats>, but when using an List<QuestionsStats> you get indexes as Keys, What I want is to have the same List<QuestionsStats> but instead of indexes, String Keys for each of my items.
So I changed my List for a Map<String, QuestionsStats>. Now the tricky part is when parceling the Object. You can use readMap() or writeMap() to parcel as shown here in this answer by #David Wasser, but it gives a warning:
Please use writeBundle(Bundle) instead. Flattens a Map into the parcel
at the current dataPosition(), growing dataCapacity() if needed. The
Map keys must be String objects. The Map values are written using
writeValue(Object) and must follow the specification there. It is
strongly recommended to use writeBundle(Bundle) instead of this
method, since the Bundle class provides a type-safe API that allows
you to avoid mysterious type errors at the point of marshalling.
So with the help of the comments in This Question I parceled using this code, note that I'm leaving the "easy" way commented in case somebody find it useful or have any comment on that :
protected UserProfile(Parcel in) {
// in.readMap(myMap, Object.class.getClassLoader());
myMap = new HashMap<>();
String[] array = in.createStringArray();
Bundle bundle = in.readBundle(Object.class.getClassLoader());
for (String s : array) {
myMap.put(s, (Object) bundle.getParcelable(s));
}
}
#Override
public void writeToParcel(Parcel dest, int flags) {
// dest.writeMap(myMap);
Bundle bundle = new Bundle();
for (Map.Entry<String, Object> entry : myMap.entrySet()) {
bundle.putParcelable(entry.getKey(), entry.getValue());
}
Set<String> keySet = myMap.keySet();
String[] array = keySet.toArray(new String[keySet.size()]);
dest.writeStringArray(array);
dest.writeBundle(bundle);
}
Why I want this, well at the moment my list contains less than 100 items but it could grow up to a 1000, I'm no Pro, but I believe that if I already know the key of the item I'm interested in will be always better than having to iterate over the list to find it. In the end my main problem was the usage of a Map, I did not know howto.

Convert Array list to Sparse Array

I have copied some code from a project and want to reuse a small part of it in my private app.
The class contains a Sparse Array
public class GolfResult {
String hcpAfter;
String hcpBefore;
SparseArray roundResults;
public GolfResult() {
hcpAfter = "";
hcpBefore = "";
roundResults = new SparseArray();
}
}
I have created an ArrayList for roundResults that is filled with the necessary data.
Then I am trying to fill the instance with content.
GolfResult golferRes = new GolfResult();
SparseArray<RoundResults> hu= new SparseArray<>();
hu = roundresults; // *
golferRes.setHcpAfter("33");
golferRes.setHcpBefore("kk");
golferRes.setRoundResults(hu);
But the problem is that hu = roudresults is not possible, because of the error message:
required: Android.util.SparseArray found: java.util.Array List
Any help will be welcome.
After receiving two helpful answers I got a step further, but now I am facing the problem that my SparseArray hu is empty {}.
The content of hu should be the class roundresults that has the following structure:
public class RoundResults {
boolean actualRound;
private List<HoleResult> holeResults;
Integer roundId;
Integer roundNumber;
String unfinishedReason;
The arrayList roundresults has the size of 1 and has data in the objects.
unfinishedReason =""
holeResults = ArrayLIST size= 18
roundID = "1"
roundNumber = "1"
actualRound = true
hu ={}
mValues = All elements are null
mSize = 0
Does anybody have an idea why?
SparseArray is different than ArrayList, from the documentation:
SparseArrays map integers to Objects. Unlike a normal array of
Objects, there can be gaps in the indices. It is intended to be more
memory efficient than using a HashMap to map Integers to Objects, both
because it avoids auto-boxing keys and its data structure doesn't rely
on an extra entry object for each mapping.
It's using a key value pair principle where the key is an integer and the value which the key mapping is the object. You need to use put [(int key, E value)](https://developer.android.com/reference/android/util/SparseArray.html#put(int, E)) where the E is your object. Remember that:
Adds a mapping from the specified key to the specified value,
replacing the previous mapping from the specified key if there was
one.
So you need to use a loop to add each object in your ArrayList as #valentino-s says:
SparseArray<RoundResults> hu= new SparseArray<>();
for( int i = 0; i < roundresults.size(); i++) {
// i as the key for the object.
hu.put(i, roundresults.get(i));
}
If I understand well your problem, maybe you can try with this:
for ( int i=0; i<roundresults.size(); i++ ) {
hu.put(i,roundresults.get(i));
}
After some trial and error I found a solution for the empty hu:
Instead of put I used append and it is working now.
hu.append(i, roundresults.get(i));
Time for a beer.

Gson converting int into double when parsing json string

I have this JSON file into my assets. I am parsing it using Gson into the following model class:
public class SearchRequest {
private ArrayList<String> _source;
private int from;
private int size;
private Object sort;
private Object query;
public void setFrom(int from) {
this.from = from;
}
public void setSize(int size) {
this.size = size;
}
public void setArtist(String artistName) {
Gson gson = new Gson();
JsonObject object = gson.toJsonTree(query).getAsJsonObject();
JsonArray should = object.getAsJsonObject("function_score").getAsJsonObject("query")
.getAsJsonObject("bool").getAsJsonArray("should");
should.get(0).getAsJsonObject().getAsJsonObject("match").addProperty("album_artist", artistName);
should.get(1).getAsJsonObject().getAsJsonObject("nested").getAsJsonObject("query")
.getAsJsonObject("bool").getAsJsonArray("must").get(0).getAsJsonObject()
.getAsJsonObject("match").addProperty("tracks.artist", artistName);
query = gson.fromJson(object.toString(), query.getClass());
}
}
When I convert this JSON into an object of this class, the query object becomes a LinkedTreeMap. But in this conversion, the key offset which is an integer, becomes double. In my JSON (line number 50), offset is 0, but after conversion, its 0.0. Screenshot:
Why is this happening? How to fix this?
How to fix this?
It's not a subject to be fixed and nothing to be worried about.
Why is this happening?
Your JSON<->Java mapping does not provide any mappings except the top-most one. That makes Gson work like that due to lack of the target type information, and LinkedTreeMap is used internally. Literals like 0 that may look like integers are also legal floating point values from the JSON format point of view: the JSON specification declares numbers only, and does not make any corrections on "integerness". Having no enough information on deserializing the data types, Gson applies the default parsing policies, and chooses java.lang.Double as a type that can hold any other standard numeric values that can hold less significance bits (longs can fit the room of doubles easily; but not sure what Gson does for BigDecimals -- JSON specifications does not seem to make any limits). So this is just internal Gson representation and you have a few options on that:
You can declare a mapping (write or generate by a specialized tool) that would even avoid internal LinkedTreeMaps. Tedious? Maybe. But much more power in type safety, javac control, or your favorite IDE navigation and suggestions.
Gson provides a bunch of methods to convert a JSON tree value to a target type: getAsJsonObject(), getAsJsonArray(), getAsInt(), and more allowing to get the target object in the representation you want. For example,
final Object value = searchRequest.query
.get("function_score").getAsJsonObject()
.get("functions").getAsJsonArray()
.get(0).getAsJsonObject()
.get("linear").getAsJsonObject()
.get("date").getAsJsonObject()
.get("offset").getAsInt();
System.out.println(value + " " + value.getClass());
gives:
0 class java.lang.Integer
because of get("offset").getAsInt() that's internally implemented as return isNumber() ? getAsNumber().intValue() : ...; for JSON primitives.
You can apply partial mappings. For example, you can extract the date JSON tree and convert it to a special mapping having the private int offset; field declared: gson.fromJson(dateJsonObject, DateMapping.class).
Again, Gson just does not have enough type information and works really fine.

Not able to get name/value pairs from JSON object, when using variable

Not able to get name/value pairs from JSON object, when using the variable but able to read it when hard coding the name.
To better explain :
1) My JSON object is like this -
{.....
{ "rates":{ "name1": value1, "name2": value2 ...etc }
...}
2) I am able to read this object in my android app.
3) Now this rate object name value pairs, i am trying to read based on user input -
String s1 = '"'+name1+'"'; // here name1 i got from user input, & converted into string
4) Now when i am trying to get the value from rates object, i am getting null exception -
JSONObject rateObject = jObject.getJSONObject("rates"); //able to get
complete object
String rate1 = (String) rateObject.get(s1); // giving NULL exception
5) But if i use hard code string, it works -
String rate1 = (String) rateObject.get("name1"); // working
Any pointers why its not working while using variable.
thanks
Thanks for suggestions, i sorted out the problem. There are 2 mistakes i was doing - 1) Using the quotes as correctly pointed out by others and 2) casting the double value to string. Correcting both has resolved my problem :)
In terms of your final code snippet, you are actually doing
String rate1 = (String) rateObject.get("\"name1\""); //note the extra quotes
because you have bookended the user input string with double-quote characters. You just want the input string itself with no bookending. The quotes in the JSON notation serve to delineate each key name; the quotes are not part of the key name itself.
You need to omit the quotes when you create s1:
String s1 = name1;
Or, if name1 is not a String already:
String s1 = name1.toString();
Replace:
String s1 = '"'+name1+'"';
with:
String s1 = name1;

Categories

Resources