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

Android M: Cannot make field constructor accessible #648

Closed
JakeWharton opened this issue May 30, 2015 · 39 comments
Closed

Android M: Cannot make field constructor accessible #648

JakeWharton opened this issue May 30, 2015 · 39 comments

Comments

@JakeWharton
Copy link
Contributor

D/Retrofit﹕java.lang.SecurityException: Can't make field constructor accessible
            at java.lang.reflect.Constructor.setAccessible(Constructor.java:334)
            at com.google.gson.internal.ConstructorConstructor.newDefaultConstructor(ConstructorConstructor.java:97)
            at com.google.gson.internal.ConstructorConstructor.get(ConstructorConstructor.java:79)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:82)
            at com.google.gson.Gson.getAdapter(Gson.java:359)
            at com.google.gson.internal.bind.CollectionTypeAdapterFactory.create(CollectionTypeAdapterFactory.java:52)
            at com.google.gson.Gson.getAdapter(Gson.java:359)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:122)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.access$100(ReflectiveTypeAdapterFactory.java:46)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:92)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:91)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:142)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:83)
            at com.google.gson.Gson.getAdapter(Gson.java:359)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:122)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.access$100(ReflectiveTypeAdapterFactory.java:46)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:92)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:91)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:142)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:83)
            at com.google.gson.Gson.getAdapter(Gson.java:359)
            at com.google.gson.internal.bind.CollectionTypeAdapterFactory.create(CollectionTypeAdapterFactory.java:52)
            at com.google.gson.Gson.getAdapter(Gson.java:359)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:122)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.access$100(ReflectiveTypeAdapterFactory.java:46)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:92)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:91)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:142)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:83)
            at com.google.gson.Gson.getAdapter(Gson.java:359)
            at com.google.gson.Gson.fromJson(Gson.java:809)
            at com.google.gson.Gson.fromJson(Gson.java:775)
            at retrofit.converter.GsonConverter.fromBody(GsonConverter.java:63)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:367)
            at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
            at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
            at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
            at retrofit.Platform$Android$2$1.run(Platform.java:142)
            at java.lang.Thread.run(Thread.java:818)

Originally filed at square/retrofit#870.

Note: this might be a bug in the preview OS runtime and not Gson, but it's definitely not a Retrofit problem.

@JakeWharton
Copy link
Contributor Author

Maybe relevant: http://developer.android.com/preview/behavior-changes.html#behavior-art-runtime

Not exactly the cause here, but not surprising that since it's in the same vein it might have been effected.

@RicardoRFaria
Copy link

@JakeWharton I tried simulate this error without success.
I used the android emulator with api version 22. Can you provide more information like device and the class that generated the problem?

@swankjesse
Copy link
Collaborator

Are we trying to deserialize an instance of java.lang.reflect.Field ? It's pretty reasonable that that doesn't work. Here's a snippet of Constructor.java:

    public void setAccessible(boolean flag) {
        Class<?> declaringClass = getDeclaringClass();
        if (declaringClass == Class.class) {
            throw new SecurityException("Can't make class constructor accessible");
        } else if (declaringClass == Field.class) {
            throw new SecurityException("Can't make field constructor accessible");
        } else if (declaringClass == Method.class) {
            throw new SecurityException("Can't make method constructor accessible");
        }
        super.setAccessible(flag);

@JakeWharton
Copy link
Contributor Author

Seems a reasonable guess. This isn't my original bug, I was just moving it from a project I work on.

@ulyssesdotcodes
Copy link

I get this with an app on a Nexus 6 running Android M.

@cdreier
Copy link

cdreier commented Aug 21, 2015

just updated the Nexus 5 to the latest Android M preview and getting the same error. As it was working before, it seems to be only a problem with the most recent version of Android M (Build MPA44I)?

@inder123
Copy link
Collaborator

Hopefully Google will fix it before releasing Android M. Gson is used in a fairly large number of Android projects, and breaking them will be a big no no.

@swankjesse
Copy link
Collaborator

@cdreier are you using Gson on an instance of java.lang.reflect.Field? That's superweird.

The right fix for this is to write a type adapter for that class.

@cdreier
Copy link

cdreier commented Aug 23, 2015

@swankjesse no, i'm using Retrofit for a few rest-calls. I think i figured out a bit more, perhaps something changed in the List interface?

Simple Retrofit service:

    public interface SynchronisationService {
        @GET("/rooms/all")
        public void getAll(Callback<List<Room>> rooms);
    }

Room is a stupi POJO, but with a List of light-switches...

    public class Room {

        private String name;
        private int id;

        private List<LightSwitch> switches;

        /** ... **/
    }

Response is something like this:

    [
        {
            "name": "livingroom",
            "id": "1",
            "switches": [
                {
                    "name": "big lamp",
                    "id": "1"
                },
                {
                    "name": "smaller lamp",
                    "id": "2"
                }
            ]
        }
    ]

Without this switch-list in my room, everything is working fine!
If i want Retrofit / gson to parse my switch-list directly in the room, im getting the stacktrace Jake Wharton posted.

@saleehk
Copy link

saleehk commented Aug 24, 2015

You can try adding GsonConverter

new GsonConverter(new GsonBuilder()
                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
                .serializeNulls()
                .create())

In your RestAdapter.Builder()

RestAdapter.Builder()
                .setConverter(new GsonConverter(new GsonBuilder()
                        .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
                        .serializeNulls()
                        .create()))
                .setEndpoint(endPoint)
                .build()

@nBollard
Copy link

I am using Retrofit and GSON in a project and only encountered this issue on Android M after replacing SugarORM with ActiveAndroid.

@dkadrikj
Copy link

dkadrikj commented Oct 8, 2015

Is there any progress with this one? It is present with the official Android 6 release.

@haleykoike
Copy link

We experienced this same issue on our app on official Android 6 release. Adding this to our GsonBuilder as seen above seemed to resolve the issue.

new GsonBuilder()
            .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)

@cdreier
Copy link

cdreier commented Oct 9, 2015

perhaps something changed with the reflection api in android 6?
my workaround was to declare these fields causing the error as transient.

public class Switch {
    public String name;
    public Room room;
    public int id;

    private transient SwitchService switchService;

}

@endiirawan
Copy link

yeah @crowdcast-hk already resolve this issue. its work.

@inisic
Copy link

inisic commented Oct 22, 2015

It seams bug has been fixed in new version (2.4) .
"com.google.code.gson:gson:2.4"

@krusevdespark
Copy link

upgraded to 2.4 but app still crashes with the same exception on Marshmallow

@inisic
Copy link

inisic commented Oct 26, 2015

Did you try to exclude fields with modifiers?
new GsonBuilder().excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)

@aat-antoine
Copy link

@inisic if you need to add these lines, problem is not fixed :)

In my case, I don't use gson with retrofit (only gson) but i have the same problem.
If i only add

.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)

problem is still here. To solve my problem, i have to set

excludeFieldsWithoutExposeAnnotation()

But i have to expose all fields i need ><. Is there a way to know where is the problem ? In the stacktrace, there is no reference to my code

@David-Kr
Copy link

This exclude(excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC) didn't help me. Class which extends Object is deserialized correctly, but classes which extends Model from ActiveAndroid throws exception. I found only one solution => write custom deserializer. I hope this is only temporary solution and this will be fix at GSON library.

@JakeWharton
Copy link
Contributor Author

The cause continues to seem like the use of Class or Field in the
serialized object's fields without marking it transient. There is no reason
to be serializing either of these types.

On Tue, Oct 27, 2015, 9:02 PM DavidKrybus notifications@github.com wrote:

This exclude(excludeFieldsWithModifiers(Modifier.FINAL,
Modifier.TRANSIENT, Modifier.STATIC) didn't help me. Class which extends
Object is deserialized correctly, but classes which extends Model from
ActiveAndroid throws exception. I found only one solution => write custom
deserializer. I hope this is only temporary solution and this will be fix
at GSON library.


Reply to this email directly or view it on GitHub
#648 (comment).

@FreakTheMighty
Copy link

I'm in the same boat. My tests pass running in API 22, but fail for API 23.

@jirivrany
Copy link

I had the same issue. I'm using Gson with Retrofit and ActiveAndroid.

The solution with

excludeFieldsWithoutExposeAnnotation()

suggested by @aat-antoine works for me.

@arlindiDev
Copy link

Im using Retrofit + Gson so I used the excludeFIeldsWithouAnnotation() option and it worked.

Retrofit retrofit =
        new Retrofit.Builder()
                .baseUrl(Api.ENDPOINT)
                .addConverterFactory(
                        GsonConverterFactory.create(new GsonBuilder()
                                .excludeFieldsWithoutExposeAnnotation()
                                .create()))
                .client(new OkHttpClient())
                .build();

@jdsingh
Copy link

jdsingh commented Jan 27, 2016

@jirivrany Thanks excludeFieldsWithoutExposeAnnotation() worked for me.

@aeroechelon
Copy link

I'm having this issue on Android M as well. Any idea what Can't make field constructor accessible refers to? I think setting that to transient would be a better solution than using the @Expose property on every single member.

@swankjesse
Copy link
Collaborator

You’re using Gson to encode an instance of java.lang.reflect.Field. Don’t do that.

@aeroechelon
Copy link

@swankjesse That's an log error I'm getting (along with everyone else using Gson in this thread) while using the default Gson instance on Android 6.0.

Anyone using ActiveAndroid having problems using the .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC) workaround? Any data that is persisted using the default GsonBuilder() and then models deserialized with the new exclude rule causes some errors querying / storing models deserialized against this new rule.

@arlindiDev
Copy link

@aeroechelon I was trying to use ActiveAndroid and Gson and my workaround is fine for parsing the data with gson, but when I try to save fields that have relationships it doesnt work.

@zhenglingxiao
Copy link

I use Gson's ExclusionStrategy to skip java.lang.reflect.Field and java.lang.reflect.Method, my simple demo.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    String json = "{\"name\": \"Ricky\", \"age\": 25}";

    ExclusionStrategy exclusionStrategy = new ExclusionStrategy() {

        @Override
        public boolean shouldSkipField(FieldAttributes fieldAttributes) {
            return false;
        }

        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            return clazz == Field.class || clazz == Method.class;
        }
    };

    Gson gson = new GsonBuilder()
            .addSerializationExclusionStrategy(exclusionStrategy)
            .addDeserializationExclusionStrategy(exclusionStrategy)
            .create();

    // Student is a simple class extends com.activeandroid.Model
    Student student = gson.fromJson(json, Student.class);
    student.save();

    List<Student> students = new Select().from(Student.class).execute();
    if (students != null && students.size() > 0) {
        Student stu = students.get(0);
        Log.d("zlx", stu.name + "'s age: " + stu.age);
    }
}

@luiszacheu
Copy link

I had the same problem when using Retrofit + Gson + ActiveAndroid, but when i insert this line excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)" in my GsonBuilder() it worked, but I do not understand what happened :(

@rafaelcgo
Copy link

👍 to excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)

@malinkang
Copy link

@jirivrany excludeFieldsWithoutExposeAnnotation()work for me

@ghost
Copy link

ghost commented Jun 18, 2016

i tried this like

Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
.excludeFieldsWithoutExposeAnnotation()
.create();

retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(httpClient)
.build();

but still getting same error. i am using retrofit + GSON+ Active Android.
what should i do for this...

@quydm
Copy link

quydm commented Jul 27, 2016

I'm using OkHttp + Gson + ActiveAndroid

GsonBuilder builder = new GsonBuilder();
builder.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC);
Gson gson = builder.create();

work for me

@JakeWharton
Copy link
Contributor Author

This continues to look like the serialization of java.lang.reflect.Field or java.lang.reflect.Method. No action to take.

@AnthonyKoueik
Copy link

I'm using Retrofit+ Gson + ActiveAndroid

GsonBuilder builder = new GsonBuilder();
builder.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC);
Gson gson = builder.create();

worked for me

RowlandOti added a commit to RowlandOti/MovieSquire that referenced this issue Mar 31, 2017
…nd above. Th issue was related to the GSON library as discussed under - google/gson#648
@dphans
Copy link

dphans commented Nov 8, 2017

Mmm. Did you using extension of Kotlin language?
I have same problem when using kotlin extension, details below:

I've writen function exension for base model:

ModelExtension.kt

fun Model.toJson(): String {
   return try {
      Gson().toJson(this@toJson, Model::class.java)
   } catch(exception: Exception) {
      "{}"
   }
}

I move it into Model class and it solve my problem...

@ashwindmk
Copy link

I use Gson's ExclusionStrategy to skip java.lang.reflect.Field and java.lang.reflect.Method, my simple demo.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    String json = "{\"name\": \"Ricky\", \"age\": 25}";

    ExclusionStrategy exclusionStrategy = new ExclusionStrategy() {

        @Override
        public boolean shouldSkipField(FieldAttributes fieldAttributes) {
            return false;
        }

        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            return clazz == Field.class || clazz == Method.class;
        }
    };

    Gson gson = new GsonBuilder()
            .addSerializationExclusionStrategy(exclusionStrategy)
            .addDeserializationExclusionStrategy(exclusionStrategy)
            .create();

    // Student is a simple class extends com.activeandroid.Model
    Student student = gson.fromJson(json, Student.class);
    student.save();

    List<Student> students = new Select().from(Student.class).execute();
    if (students != null && students.size() > 0) {
        Student stu = students.get(0);
        Log.d("zlx", stu.name + "'s age: " + stu.age);
    }
}

This worked for me, thanks @zhenglingxiao

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

No branches or pull requests