Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retrofit + gson + stackoverflow #121

Closed
rhespanhol opened this issue Mar 4, 2015 · 18 comments
Closed

Retrofit + gson + stackoverflow #121

rhespanhol opened this issue Mar 4, 2015 · 18 comments

Comments

@rhespanhol
Copy link

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;

...

@agrosner
Copy link
Owner

agrosner commented Mar 4, 2015

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

@rhespanhol
Copy link
Author

Thanks for your quick answer.

But you know any workaround to fix this?

@agrosner
Copy link
Owner

agrosner commented Mar 4, 2015

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.

@agrosner agrosner closed this as completed Mar 4, 2015
@intrications
Copy link
Contributor

@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.

@rhespanhol
Copy link
Author

Thanks @intrications, it worked!!

@ghost
Copy link

ghost commented Mar 6, 2015

@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? :(

@intrications
Copy link
Contributor

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).

@ghost
Copy link

ghost commented Mar 6, 2015

@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);

@agrosner
Copy link
Owner

agrosner commented Mar 6, 2015

@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.

@ghost
Copy link

ghost commented Mar 7, 2015

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

@rjam
Copy link

rjam commented Mar 17, 2015

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();

@Rainer-Lang
Copy link

@rjam Many MANY THANKS!

@intrications
Copy link
Contributor

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

@shashi2459
Copy link

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

@AdamMTGreenberg
Copy link

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();
}

@anelrh26
Copy link

anelrh26 commented Mar 1, 2016

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(){

    }
....
}

@anelrh26
Copy link

anelrh26 commented Mar 1, 2016

Forget it!

@AdamMTGreenberg is right!.

I just have to add the following in my model.

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

@ghost
Copy link

ghost commented Apr 4, 2016

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants