I am New to Room Persistence Library in Android. I have looked into a lot of tutorials related to Room. But something is unclear about it.
I can relate my questions to the below response. If we use #Embedded in "Info", Is it possible to declare info POJO class as separate entity? because inside info I have another object called "preferences". How can I embed that to my Room Database ?
Next is How can I use Awb ArrayList in below sample for Type converters? Note that inside Awb ArrayList has one more "terms" array inside.
I would appreciate if some can show and explain to me the best way to Create Room from the below sample data. I know so many tutorials are there for simple JSON structure, but I didn't find any examples with nested JsonObjects.
{
"hashCode": 10461,
"jobs": [
{
"info": {
"jobDesc": "aaaaa",
"signatureRequired": "true”
"preferences": {
"podRequired": 0,
"eligableForCcod": false,
"signatureRequired": 1
}
},
"awb": [
{
"terms": [
{
"termValue": "INR1500.000",
"termType": "CASH_AMOUNT"
},
{
"termValue": "CTLDk",
"termType": "CX_EN"
}
],
"packagesCount": 1,
"accountId": "AE _MP",
"awb": "1234567878440"
}
]
}
]
}
I don't know if this is the best possible approach, but normally when I have complex objects in Room I define a converter class containing two TypeConverters. The first one converts from the structured object (your POJO class) to a String with GSON library, something like:
#TypeConverter
public String fromPojoToString(MyPojoClass info) {
if (info == null) {
return (null);
}
Gson gson = new Gson();
Type type = new TypeToken<MyPojoClass>() {
}.getType();
return gson.toJson(info, type);
}
The second converter converts from the string (stored inside Room) to the structured object (the POJO class). Something like:
#TypeConverter
public MyPojoClass fromStringtoPojo(String object) {
if (object == null) {
return (null);
}
Gson gson = new Gson();
Type type = new TypeToken<MyPojoClass>() {
}.getType();
return gson.fromJson(info, type);
}
This way you'll be able to serialize/deserialize your POJO class without writing a lot of boilerplate. Obviously, you have to annotate your AppDatabase class (the one that extends RoomDatabase) with your Converter using #TypeConverters annotation.
There is a good article about this approach here https://medium.com/#toddcookevt/android-room-storing-lists-of-objects-766cca57e3f9.
Hope that this helps, best luck!
Explore these link to easy understand room persistance database
https://www.youtube.com/watch?v=KAHAQunQkDE
https://developer.android.com/topic/libraries/architecture/adding-components#room
https://developer.android.com/training/data-storage/room/
Related
For my application, I have a recycler view that I'm using LiveData to populate. Each item in the recycler view is an Event object that I created. I'm using Room and Dao to store these Events and to create that abstraction layer between SQL and the repository and UI controller, but the problem is that Dao can only serialize primitize types into JSONs. I created type converters to convert between ArrayList and json, but I need to be able to convert between LiveData[ArrayList[Event]] in order to get this to work.
So far, this is what I have:
#TypeConverter
public static String fromEvent(LiveData<ArrayList<Event>> events){
Gson gson = new Gson();
String json = gson.toJson(events);
return json;
}
#TypeConverter
public static LiveData<ArrayList<Event>> fromEventString (String value){
Type eventType = new TypeToken<LiveData<ArrayList<Event>>>() {}.getType();
return new Gson().fromJson(value, eventType);
}
How do I interconvert between these two data types using Google's Gson library? Lol I'm obviously not too experienced with this.
Thanks for any help!!
This isn't exactly an answer, but I switched from ArrayList to the generic List, and it worked seamlessly. I was reading something about how Gson looks to the superclass of whatever data structure you're using to learn how to serialize and deserialize, so I wondered if switching to: List[Event] list = new ArrayList() instead of ArrayList[Event] list = new ArrayList() would do the trick. Indeed, for some reason RoomDatabase knew perfectly how to serialize it this way.
I have JSON in this format.
I m trying to create serialization class to store the value.
How to read the "personaldata" field?
I am making a separate class PersonalData to read it.
And in my main serialization class I am reading it as
List<PersonalData>personalData
Is it the right way to do it?
If so, how will I fetch the personal data values?
{
"result": [
{
"name": 0,
"age": 1,
"class": 0,
// More data here
"personalData": {
"isMarried": true,
"isEligible": false,
"Indian": true
}
}
]
}
If you are using some parser like GSON or LoganSquare you can use their annotations and it will be really easy to parse JSON directly to your model. Otherwise if you are using native JSON API
You can use something like this
JSONArray arr=new JSONArray(response);
JSONObject personalData=arr.getJSONObject("personalData");
I am making a separate class PersonalData to read it..
Okay, then that is how you access it. By getting that object from some parent Results object.
For example, given some implementation of the below classes, once you deserialize the JSON, you use Results.getResults().get(0).getPersonalData();
public class Results {
ArrayList<ResultData> result;
// TODO: write getResults()
}
public class ResultData {
int name, age, class;
// Some more data
PersonalData personalData;
// TODO: write getPersonalData()
}
public class PersonalData {
boolean isMarried, isEligible, Indian;
}
Ok so I have this piece of JSON that I want to parse with Gson. I would like the Strings to be the values and the longs to be the keys.
{"completed_questions":[["String",12345],...]}
The issue is the data type, when I try a Map<String, Long> it parses everything but gives me an error because of the duplicate String keys.
I tried to reverse it thinking Gson would know to switch them around but when I tried Map<Long, String> I got an error about not being able to parse my Strings as Longs.
To get it to work I created a swap map class that takes the Key and Value types and swaps them like so public class SwapMap<K, V> implements Map<K, V> however translating the swapped map actions like put/get/remove seem to be pretty difficult to make work.
What's the best way to parse this with Gson even though the strings aren't unique? (But the numbers are)
JSON doesn't allow identical keys on the same level in a json object. It seems like you are trying to map a json array to a java map.
Based on the following data structure, you would need a list if you want to use the default conversion provided by Gson.
{
"completed_questions": [
[
"String",
12345
],
[
"String",
12345
]
]
}
Here is a quick implementation:
private static void mapToObject() {
String json = "{\"completed_questions\":[[\"String\",12345],[\"String\",123456]]}";
Gson gson = new Gson();
CompletedQuestions questions = gson.fromJson(json, CompletedQuestions.class);
for (List<String> arr : questions.getCompleted_questions()) {
for (String val : arr) {
System.out.print(val + " ");
}
System.out.println();
}
}
public static class CompletedQuestions {
List<List<String>> completed_questions;
public List<List<String>> getCompleted_questions() {
return completed_questions;
}
}
This outputs:
String 12345
String 123456
The thing to note is that I am using a list for mapping purposes which closely resembles the data model provided.
This will require you to do the conversion to long yourself. But the way that json string looks. It seems like you would need to operate on the indices. If you have control over the json structure, I would recommending creating a better model. Other wise you can do something like list.get(0) -> your key list.get(1) -> your value which is the long on the inner list.
So what I did is just made a custom Gson Deserializer that mapped these values to a LongSparseArray<String>, which is the best way to go about it.
This is the relevant parts of the Deserializer:
for (JsonElement array : jsonObject.get("my_key").getAsJsonArray()) {
if (array.getAsJsonArray().size() == 2) {
String value = array.getAsJsonArray().get(VALUE).getAsString();
long key = array.getAsJsonArray().get(KEY).getAsLong();
progress.completedActivities.put(key, value);
}
}
Then I just added it to my Gson creator like so:
#Provides #Singleton Gson provideGson() {
return new GsonBuilder()
.registerTypeAdapter(MyClass.class, new MyClass())
.create();
}
I want to combine Retrofit and GreenDao but I have a problem with nested Json-Objects. My nested fields remain empty.
This is the Json DataStructure
[
{
"id": 1,
"street": "Streetname",
"zipcode": 12345,
"city": "MyCity",
"phone_number": "+123456789",
"position": "12.0000, 9.0000",
"company": {
"title": "CompanyName",
"group": {
"title": "GroupName"
}
}
}
]
My DaoGenerator looks like this
Entity customItem = schema.addEntity("CustomItems");
customItem.addIdProperty();
customItem.addStringProperty("street");
customItem.addIntProperty("zipcode");
customItem.addStringProperty("city");
customItem.addStringProperty("phone_number");
customItem.addStringProperty("position");
Entity company = schema.addEntity("Company");
company.addIdProperty();
company.addStringProperty("title");
Entity group = schema.addEntity("Group");
group.addIdProperty();
group.addStringProperty("title");
Property companyPropId = customItem.addLongProperty("companyId").notNull().getProperty();
customItem.addToOne(company, companyPropId);
Property groupPropId = company.addLongProperty("groupId").notNull().getProperty();
company.addToOne(group, groupPropId);
My problem is that customItem.getCompany() returns null but the values "id" to "position" are fine. I'm not sure what the problem is as my CustomItem class contains the member
private Company company;
and the setter for the company and I can't see any typo.
public void setCompany(Company company) {
if (company == null) {
throw new DaoException("To-one property 'companyId' has not-null constraint; cannot set to-one to null");
}
synchronized (this) {
this.company = company;
companyId = company.getId();
company__resolvedKey = companyId;
}
}
I got it running but I had multiple problems.
1) When I wanted to persist the CustomItem, Company, and Group I had the problem that the getters getCompany() and getGroup() returned null because they don't return the member directly but fetch it from the DB. Therefore I added a getter to the generated CustomItem entity class that simply returns the company member. Now I was able to insert company to the db. The getter looks like this:
// KEEP METHODS - put your custom methods here
public Company getCompanyLocal() {
return company;
}
// KEEP METHODS END
The same works for Company and Group, too. But there was another issue...
2) The second problem was the entity 'Group' as 'group' is a reserved SQL keyword. I see one solution and a bad workaround to this problem:
The good one is to change you json data from 'group' to i.e. 'business_group' and according to that change your DAOs. Done.
The bad workaround if you are in the same situation like me where you can't change the json you could do the following. I don't persist the group at all but can access it via the company. It somehow appears there. Therefore I added a getter to my Company class like the getter of CustomItem above. It works but you should avoid this. As you can't query your DB for group or load group from db.
To solve your second problem, add this code to your DAO generator:
beacon.addStringProperty("business_group"); //Daogenerator
And add this code into your network manager:
//add this into your network manager
FieldNamingStrategy strategy = new FieldNamingStrategy() {
#Override
public String translateName(Field field) {
if(field.getName().equalsIgnoreCase("business_group")) {
return "group";
} else {
return field.getName();
}
}
};
And set this property to your Gson:
//add this in your Gson
.setFieldNamingStrategy(strategy)
hopefully it helps!!
I have a problem that I have no idea about this, can anyone help me:
Ex we have a json:
{
"status":"0",
"result": {
"object1": {
"name":"name1",
"age":"21"
},
"object2": {
"event":"new year",
"date":"date"
},
"object1_1": {
"name":"name2",
"age":"22"
},
"object2_1": {
"event":"birthday",
"date":"date"
}
}
}
you can try convert to object by using jackson json.
http://jackson.codehaus.org/
If you want to deserialize this json to an object that contains a Map (and the map contains litteral values and other maps). Assuming you have a bean similar to :
class MyBean {
int status;
Map<String, Object> result;
}
MyBean myBean = new Gson().fromJson(jsonString, MyBean.class);
It should work with no modification. Note that if the type of status is not a number I'm not sure Gson does the conversion as in the json string the value is quoted, same thing applies to your "age" property.
You can also have a look at Genson library http://code.google.com/p/genson/ it has most Gson features, other ones that no other library provide and has better performances. Have a look at the wiki http://code.google.com/p/genson/wiki/GettingStarted.
EDIT
Are the names really things like object1_1, object2_1 etc? When looking at the structure I imagine that object1 goes with object2 and so long. If you use gson you can write a custom TypeAdapter http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/TypeAdapter.html.
So you can create a root object similar to
class Response {
int status;
List<MyObject> result;
}
class MyObject {
String name;
int age;
String event;
String date;
}
In the read method of your TypeAdapter you should compose instances of MyObject based on the keys (object1 with object2, object1_1 with object2_1...) or take a similar approach.
If you want more details on how to do that you can also ask on Gson google group.