agrosner/DBFlow

Retrofit + gson + stackoverflow

rhespanhol opened this issue ยท 18 comments

Im using retrofit + gson to pull and parse some json from a webservice to this object. Now i want to use that same object as Model but i keep getting stackoverflow.
Is there anyway to fix this?


 java.lang.StackOverflowError
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:380)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:375)
            at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:355)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:117)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:72)
            at com.google.gson.Gson.getAdapter(Gson.java:356)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.(ReflectiveTypeAdapterFactory.java:82)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:81)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:118)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:72)

Here is my model:


@Table
public class Category extends BaseModel implements  Parcelable {

    public Category() {
        super();
    }

    @Column(columnType = Column.PRIMARY_KEY)
    @SerializedName("id")
    public int mId;

    @Column
    @SerializedName("pantone")
    public String mColor;

    @SerializedName("langs")
    public ArrayList mCategoryLanguageArrayList;

...

This appears to be a GSON issue, not a DBFlow issue.

Thanks for your quick answer.

But you know any workaround to fix this?

looks good to me. I would debug GSON, and there is not much more I can do to help. Not that I don't want to, just I am not familiar with the library and not sure this error is a DBFlow issue.

@rhespanhol

I solved this by using Gson's @expose annotation.

Pass a custom Gson to Retrofit:

 Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();
 RestAdapter restAdapter = new RestAdapter.Builder()
                .setConverter(new GsonConverter(gson))
                .build();

Then add the @expose annotation to all your fields (that you want to deserialize) in your Model class.

Not sure why it works but it did.

Thanks @intrications, it worked!!

@intrications Can you give an example please? It doesn't work for me :(

Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();
return new RestAdapter.Builder()
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .setEndpoint(ApiEndpoint.QUICK_CLOUD_ROOT_API)
                .setRequestInterceptor(headers)
                .setClient(new ApacheClient(getNewHttpClient()))
                .setConverter(new GsonConverter(gson))
                .build();
In Model:

@Table(value = "user")
@ContainerAdapter
public class User extends BaseModel {

    @Expose
    @Column(columnType = Column.PRIMARY_KEY, name = "object_id")
    String objectId;

    @Expose
    @Column
    String name;

    @Expose
    @Column
    String email;

    @Expose
    @Column(name = "email_verified")
    boolean emailVerified;

    @Expose
    @Column(name = "created_at")
    String createdAt;

    @Expose
    @Column(name = "updated_at")
    String updatedAt;
}

Is something wrong? :(

What is ContainerAdapter? I didn't use that.
On 6 Mar 2015 18:11, "nambv" notifications@github.com wrote:

@intrications https://github.com/intrications Can you give an example
please? It doesn't work for me :(

Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
return new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(ApiEndpoint.QUICK_CLOUD_ROOT_API)
.setRequestInterceptor(headers)
.setClient(new ApacheClient(getNewHttpClient()))
.setConverter(new GsonConverter(gson))
.build();
In Model:

@table(value = "user")
@ContainerAdapter
public class User extends BaseModel {

@Expose
@Column(columnType = Column.PRIMARY_KEY, name = "object_id")
String objectId;

@Expose
@Column
String name;

@Expose
@Column
String email;

@Expose
@Column(name = "email_verified")
boolean emailVerified;

@Expose
@Column(name = "created_at")
String createdAt;

@Expose
@Column(name = "updated_at")
String updatedAt;

}

Is something wrong? :(

โ€”
Reply to this email directly or view it on GitHub
#121 (comment).

@intrications It's used to save model to database by calling method

model.save(false)

And thanks for your solution! Finally, It's work for me ^^

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
User user = gson.fromJson(result.getAsJsonObject(), User.class);
user.save(false);

@nambv @intrications @ContainerAdapter is used to generate an adapter to work with ModelContainers. Rather than always generating it, I made it separated to cut down on generated code.

@agrosner Thank you very much for your explaination ^^!

rjam commented

Instead of force exposing all fields, you should get the same result just by letting Gson know that it should not try to serialize/deserialize the contents of the BaseModel class your models are extending (namely the ModelAdapter field it holds). Try creating your gson instance like this and you should no longer need to add the @Expose annotation to all fields:

Gson gson = new GsonBuilder()
                .setExclusionStrategies(new ExclusionStrategy() {
                    @Override
                    public boolean shouldSkipField(FieldAttributes f) {
                        return f.getDeclaredClass().equals(ModelAdapter.class);
                    }

                    @Override
                    public boolean shouldSkipClass(Class<?> clazz) {
                        return false;
                    }
                })
                .create();

@rjam Many MANY THANKS!

@rjam Thanks for that. I wasn't sure exactly what it was in BaseModel that was causing the problem.

thanks guy`s....it was helpful.

This is also going to be an issue for anyone using Jackson + Retrofit + DBFlow.

The solution is for any class that extends BaseModel

make sure you do something along the lines of:

@JsonIgnore
@Override
public ModelAdapter getModelAdapter(){
    return super.getModelAdapter();
}

I'm using retrofit + jackson. And I also want to use the same model for the DB and Jackson. But, I'm getting this error. Can someone help me? I don't know where is the error exactly

03-01 20:38:11.462 27759-27759/com E/art: Throwing OutOfMemoryError "Failed to allocate a 28 byte allocation with 0 free bytes and 0B until OOM" (recursive case)
03-01 20:38:11.467 27759-27759/com E/art: "main" prio=5 tid=1 Runnable
03-01 20:38:11.467 27759-27759/com E/art: | group="main" sCount=0 dsCount=0 obj=0x73c14540 self=0xb4606800
03-01 20:38:11.467 27759-27759/com E/art: | sysTid=27759 nice=0 cgrp=apps sched=0/0 handle=0xb77b9160
03-01 20:38:11.467 27759-27759/com E/art: | state=R schedstat=( 924735144 476697697 652 ) utm=81 stm=10 core=0 HZ=100
03-01 20:38:11.467 27759-27759/com E/art: | stack=0xbf5a9000-0xbf5ab000 stackSize=8MB
03-01 20:38:11.467 27759-27759/com E/art: | held mutexes= "mutator lock"(shared held)

@Table(database = Database.class)
@JsonRootName(value = "login")
@JsonIgnoreProperties({"profileId", "id"})
public class Profile extends BaseModel implements Parcelable {

    @PrimaryKey(autoincrement = true)
    private int profileId;

    @Column
    @JsonProperty("email")
    private String username;

    @Column
    @JsonProperty("password")
    private String password;

    public Profile(){

    }
....
}

Forget it!

@AdamMTGreenberg is right!.

I just have to add the following in my model.

@JsonIgnore
@Override
public ModelAdapter getModelAdapter(){
    return super.getModelAdapter();
}

@anelrh26 like this, is right too!
@table(database = ExamDatabase.class)
@JsonIgnoreProperties({"modelAdapter"})
public class AnswerInfo extends BaseModel implements Serializable {
}