retrofit and orm library throw StackOverflow - android

I try to use 2 libraries:
square/Retrofit - Rest client
satyan/sugar - db orm
retrofit use gson, so do class
public class Book{
String name;
public Book(String name) {
this.name = name;
}
}
ok, retrofit succesfully get data from server and put in our Book class.
now i want save this data. for use orm need extend parent class
public class Book extends SugarRecord<Book>{
String name;
public Book(String name) {
this.name = name;
}
}
but after extend the parent class, retrofit cannot parse json.
so we get an error:
java.lang.RuntimeException: An error occured while executing doInBackground()
...
Caused by: retrofit.RetrofitError: java.lang.StackOverflowError at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:390)
...
Caused by: java.lang.StackOverflowError at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
...
how to make friends 2 libraries that they use one object class?
or how to specify the retrofit, so that it did not touch Book's class parent?

Error happens when Gson tries to resolve type information about an object it have to deserialize. It gets into an infinite recursion due to the cyclic reference to your Book class in extends declaration.
However even if Gson could cope with your class, I would not recommend using these libs combination.
You see, what Gson does is much alike to what standard Java serialization does but in JSON format. I mean that Gson takes the internal state of your object and performs its serialization. And when it parses JSON it creates an object with the state specified in this JSON.
If you take a look at SugarRecord class, you'll see that it has a field named "tableName". Thus if you passed your Book object to Gson instance, you'd get
{name: "book name", tableName: "table_book"}.
Moreover, if you got a response from server which is like
{name: "another book name", tableName: "something absolutely unrelated"},
you would get an instance of Book with a state exactly matching what is described in this response. Meaning, with tableName being not equal to what you would like...
You could workaround this issue using exclusion strategies in Gson, but overall you'll get yet another problem.
P.S. After a quick look at SugarRecord class on github I do not understand why it has a type parameter at all. It's even not used really. Thus technically I think you'll be able to combine these 2 libraries, if you skip type parameter in extends declaration making your class look like class Book extends SugarRecod { }, and use an exclusion strategy. Yet, I wouldn't do it myself in practice :).

Your POJO class need a empty constructor :
you shoud add this constructor to your Book class:
public Book(){
}

Related

How does differentiate between Serialized data class and normal Serialized class?

While writing code for RecyclerView to get data I figured out there's a data class in Kotlin.
Following codes are taken from two different projects which are linked above.
#Serializable
data class MarsPhoto(
val id: String,
#SerialName(value = "img_src")
val imgSrc: String
)
class Contacts {
#SerializedName("country")
private val country:String? = null
fun getCountry():String?{
return country
}
}
I know that both classes are doing same job. So what does differentiate them? I also wonder in the MarsPhoto data class how they can get the id without declaring SerialName just the way they did for imgSrc. (I am just on the way to learning kotlin now, so I'm absolute beginner).
Basically for "data" class the compiler automatically derives the following members from all properties declared in the primary constructor:
equals()/hashCode() pair
toString() of the form "MarsPhoto(id=1, imgSrc=asdf)"
componentN() functions corresponding to the properties in their order of declaration.
copy()
You can read a lot more at enter link description here
On the SerializedName part of your question. if you are dealing with Gson lib by default it is using fields name as "SerializedName". And only if you want to use something different then field name, you can use SerializedName annotation and pass your custom value there. But usually, everybody just writes #SerializedName() with duplication of field names as value for every field.
It's a good idea if you are receiving and Serializing data from server from Json. Because Backend developers can use a bad keys in response, which you don't want to use in your code, so #SerializedName will be the only place where you will have to see this key, and you can name your fields however you like.
#Serializable used to mark class as serializable to disk or like into a file( alternative is Parcel able in android) special useful in case of process death or configuration changes and #SerializedName("country") used for json parsing when u receive the response from server
You get the id without #SerializedName because the JSON property field is the same as your variable name, but imgSrc and img_src is not. Still, even if they are the same, you should always use #SerializedName, because your variable names could be converted to random letters during code optimization, and obfuscation.

android Room with kotlin value class?

I'm trying to use a room entity with a value class:
#JvmInline
value class UserToken(val token: String)
and the entity:
#Entity(tableName = TABLE_AUTH_TOKEN)
data class TokenEntity(
#PrimaryKey val id: Int = 0,
val token: UserToken
)
I get the following error:
error: Entities and POJOs must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).
public final class TokenEntity {
^
is it even possible to use room with value class? I couldn't find anything about this. thanks
See the comment from #CommonsWare. Android does not yet support value classes for Room.
The same holds true for the value classes introduced in kotlin 1.5. The type is not supported.
— Support Inline class in Room entity
Here is a possible explanation according to Kotlin Inline Classes in an Android World.
Looking to solve this you could try and add a TypeConverter for your Inline class, but since your Inline class is just the value it wraps when it’s compiled, this doesn’t make much sense and it doesn’t work as you’d expect even if you tried...
I’m just guessing it’s because this is a TypeConverter converting UserId to Int which is basically the same as Int to Int 😭. Someone will probably solve this problem, but if you have to create a TypeConverter for your Inline class then you are still plus one class for the count (multidex). 👎
I think yes if you can provide a type converter for it to change it to some sort of primitive data type (int , string, long ...etc) when it needs to be stored, and to change it back to its class type when it's fetched from database.
You can read about Type Converters from here
Referencing complex data using Room
other than that, your other class should be an entity and bind both your entities together using a Relation.
at least that's what I know about how to use Room.
UserToken always will have only one attribute? In this case, you don't need two classes, just use token: String directly on your entity class;
If you really need keep this class, you have two options:
TypeConverter, where you basically will convert the object into a json, and save as string in the database;
Relation, where you will transform the UserToken in a entity, and on TokenEntity save the tokenId.

Mock model object without setters

I'm implementing tests on my Android app and I want to do unit tests on a model. The problem is that I do not have setters as the model is created with Realm or by parsing a CSV file (witch univocity csv parser).
So, how could I create a mocked object with valid values? I have something like that:
public class Content {
private String title;
private String description;
...
}
How could I generate a mocked Content object with a title and description data?
Thanks in advance
Use code below in your test class:
Field field = Content.class.getDeclaredField("str");
field.setAccessible(true);
field.set(yourObject, "some value");
yourObject is a instance of Content that you use in your test class.
But you shouldn't fill mock object - you should just define method result for mock object.
A word of warning: reflection has a lot of disadvantages; for example a simple name change for your fields will go unnoticed; and not lead to compiler errors but to failing unit tests later on.
This I suggest a different solution - providing a package-private or protected constructor that you can use to initialize your fields. Then you do not to use reflection; and at the same time, your "public" interface of that class doesn't change either, like:
public class Content {
// unit testing only
Content(String title, ... ) { ...
But of course, you have to do balancing - either you add that constructor that isn't required for production; or you go with not so robust reflection code!

Persisting entity relationships from REST service for Android

I am trying to maintain a local store of a database, accessible via a REST API. I am attempting to use the fantastic RoboSpice and Spring libraries for the REST client, Jackson to parse/cache the JSON response and ORMLite to persist the resulting objects.
The problem is that I don't know how to store foreign object relationships for the JSON responses I get. Sometimes the JSON objects are nested, other times they are referenced by Id.
A typical systems response
{
id:567,
name:"The only system",
competitions:[{
id:123,
system_id:567
...
}];
}
A competitions response
items: {
123:{
id:123,
system_id:567 // System only referenced by id
...
}}
Another competitions response
items: {
123:{
id:123,
system_id:567, // System referenced by id and nested
system:{
id:567,
name:"The only system",
...
}
}
}
Nested objects work fine, but it's the cases where there is a reference by id that is killing it. I have two classes for my data model as follows.
Systems class
#DatabaseTable("systems")
public class System {
#JsonProperty("id")
#DatabaseField(id=true, columnName="id")
private long id;
#JsonProperty("name")
#DatabaseField(columnName="name")
private String name;
#JsonProperty("competitions")
#ForeignCollectionField
private ForeignCollection<Competition> competitions;
// getters & setters omitted
}
Competition class
#DatabaseTable("competitions")
public class Competition {
#JsonProperty("id")
#DatabaseField(id=true,columnName="id")
private long id;
#JsonProperty("system_id")
#DatabaseField(columnName="id")
private long systemId; // This is definitely at least part of the problem
#JsonProperty("system")
#DatabaseField(foreign=true, columnName="system_id")
private System system;
// getters & setters omitted
}
Having two properties references the system_id seems like a definitively bad idea, but I can't find an alternative for the behaviour I want. Even if the system object is not nested in the Competition object, the Competition should be able to map a relationship to the System object in the local database, because the id of the system is always provided.
The other problem I suspect is that I'm using two object persisters, the JacksonObjectPersister and the InDatabaseObjectPersisterFactory (provided by RoboSpice for use with ORMLite). The reason for this is because I don't want to persist the lists that the objects are nested in to the database. By my understanding, Jackson should cache the JSON response from the server, ORMLite should cache the data model.
This is the error I'm getting
02-03 15:15:57.640: D//DefaultRequestRunner.java:166(20944): 15:15:57.636 Thread-28
An exception occurred during service execution :org.codehaus.jackson.map.JsonMappingException:(was java.lang.NullPointerException)
(through reference chain: com.company.app.api.objects.List["items"]->
java.util.HashMap["51"]->
com.company.app.api.objects.Competition["system_id"])
Apologies for what seems like a number of questions in one, I am bashing my head against a wall. I will attempt to wrap this essay up with a summary...
Is there any way to piece together object relationships using Jackson and ORMLite for the JSON responses I have provided?

FasterXML Jackson ObjectMapper for .Net MVC4 JSON POST Result Type Objects

I am sharing this for others working between Java clients and Web Services from .Net MVC4 and using RoboSpice and FasterXML Jackson frameworks. I could not find good information on stackoverflow on how to set up the JSON POJO class for proper object mapping for the POST result object. For POST operations the RESULT JSON comes back with the structure from the .Net web services:
{"ClassName":{"attribute_one":1,""attribute_two":1,"....}}
I could not figure out how to get the FastXml Jackson ObjectMapper readValue parsing to work. I got an empty result object after parsing with all the properties set to null or default values..., or invalid property name for the class name if I turned off the JsonIgnoreProperties.
The following POJO object definition finally worked for me. It has an outer class that matches the ClassName in the Result and then an inner static class for mapping the Single Result Object into a Java Class Object:
public class ClassNameOuter {
#JsonProperty("ClassName")
public ClassName _ClassName;
public ClassName get_ClassName() {
return _ClassName;
}
public void set_ClassName(ClassName _ClassName) {
this._ClassName = _ClassName;
}
#JsonIgnoreProperties(ignoreUnknown=true)
public static class ClassName {
#JsonProperty("attribute_one")
public long attribute_one;
#JsonProperty("attribute_two")
public long attribute_two;
For the experts out there on Jackson and Robospice....please share if there is a better way.
RoboSpice doesn't support yet parsing of XML using Jackson. It provides a module to parse XML using SimpleXMLSerializer but not jackson.
Can you indicate which classes of Jackson you used, I would add a module soon to RS.

Categories

Resources