2016-10-19 3 views
1

getter/setterParcelableのようにAutoValueを使用しています。AutoValueを使用しているときにJSONをArrayListに変換できません

オブジェクトのJSON値をSharedPreferencesに保存しておき、必要に応じて取得しています。しかし、これはConstructorを直接使用することを許可しないAutoValueを使用しているので、SharedPreferencesの文字列として格納されたJSON配列をArrayList<T>に変換しようとすると例外がスローされます。ここで

は、私が取得しています例外である - ここで

java.lang.RuntimeException: Failed to invoke public org.yadavvi.tutorials.governor.data.Governor() with no args 
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:111) 
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:206) 
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) 
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 
at com.google.gson.Gson.fromJson(Gson.java:879) 
at com.google.gson.Gson.fromJson(Gson.java:844) 
at com.google.gson.Gson.fromJson(Gson.java:793) 
at org.yadavvi.tutorials.governor.data.source.local.GovernorLocalDataSource.getGovernors(GovernorLocalDataSource.java:60) 
at org.yadavvi.tutorials.governor.data.source.local.GovernorLocalDataSourceTest.getGovernors_callsOnSuccessOfGetGovernorsCallback(GovernorLocalDataSourceTest.java:69) 

.... 

Caused by: java.lang.InstantiationException: Can't instantiate abstract class org.yadavvi.tutorials.governor.data.Governor 
at java.lang.reflect.Constructor.newInstance(Native Method) 
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:108) 
... 41 more 

Model/AutoValueクラスがどのように見えるかである -

package org.yadavvi.tutorials.governor.data; 


import com.google.auto.value.AutoValue; 
import com.google.gson.Gson; 
import com.google.gson.TypeAdapter; 
import com.google.gson.annotations.SerializedName; 

/** 
* Immutable Governor created using AutoValue. 
*/ 
@AutoValue 
public abstract class Governor { 

    public static Governor create(String name) { 
     return new AutoValue_Governor(name); 
    } 

    @SerializedName("name") 
    abstract String name(); 
} 

、ここでどのように私はJSON配列を変換しようとするクラスです文字列をArrayList<T>のように見える -

package org.yadavvi.tutorials.governor.data.source.local; 


import android.content.Context; 
import android.content.SharedPreferences; 
import android.support.annotation.NonNull; 
import android.util.Log; 

import org.yadavvi.tutorials.governor.data.Governor; 
import org.yadavvi.tutorials.governor.data.source.GovernorDataSource; 
import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 
import com.google.gson.reflect.TypeToken; 

import java.io.BufferedReader; 
import java.io.FileReader; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 


public class GovernorLocalDataSource implements GovernorDataSource { 

    .... 

    @Override 
    public void getGovernors(@NonNull GetGovernorsCallback callback) { 
     Gson gson = new GsonBuilder().create(); 
     List<Governor> governors; 

     String governorsString = mSharedPreference.getString(GOVERNORS, ""); 
     Log.i(TAG, "governorsString: " + governorsString); 
     if (governorsString.equalsIgnoreCase("")) { 
      governors = populateGovernors(); 
      governorsString = gson.toJson(governors); 
      mSharedPreference.edit().putString(GOVERNORS, governorsString).commit(); 
     } else { 
      governors = gson.fromJson(governorsString, new TypeToken<ArrayList<Governor>>(){}.getType()); 
     } 

     if (governors != null && governors.size() > 0) { 
      callback.onSuccess(governors); 
     } else { 
      callback.onFailure(); 
     } 
    } 

    .... 

} 

例外iこのラインで投げsの -

governors = gson.fromJson(governorsString, new TypeToken<ArrayList<Governor>>(){}.getType()); 

EDIT:私は私のAndroidプロジェクトにいくつかのAutoValue-Extensionsを持っています。build.gradleはこのようになります

アプリ - このリンクの下に

apply plugin: 'com.android.application' 

android { 
    compileSdkVersion 24 
    buildToolsVersion "24.0.2" 
    defaultConfig { 
     applicationId "org.yadavvi.tutorials.governor" 
     minSdkVersion 21 
     targetSdkVersion 24 
     versionCode 1 
     versionName "1.0" 
     testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 
    } 
    buildTypes { 
     release { 
      minifyEnabled false 
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
     } 
    } 
} 

dependencies { 
    compile fileTree(include: ['*.jar'], dir: 'libs') 
    testCompile 'junit:junit:4.12' 
    testCompile 'org.mockito:mockito-core:2.2.5' 
    testCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 
     exclude group: 'com.android.support', module: 'support-annotations' 
    }) 

    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 
     exclude group: 'com.android.support', module: 'support-annotations' 
    }) 
    androidTestCompile 'org.mockito:mockito-core:2.2.5' 

    compile 'com.android.support:appcompat-v7:24.2.1' 
    compile 'com.google.auto.value:auto-value:1.2' 
    compile 'com.ryanharter.auto.value:auto-value-gson:0.4.3' 
} 

答えて

1

私はGsonBuilderにカスタムTypeAdapterFactoryを追加して、正常に動作するようです。

package org.yadavvi.tutorials.governor.data; 

import com.google.gson.typeadapterfactory; 
import com.ryanharter.auto.value.gson.gsontypeadapterfactory; 

@GsonTypeAdapterFactory 
public abstract class GovernorAdapterFactory implements TypeAdapterFactory { 

    public static GovernorAdapterFactory create() { 
     return new AutoValueGson_GovernorAdapterFactory(); 
    } 

} 

GovernorLocalDataSourceはそうのように変更された - -

TypeAdapterFactoryは、次のようになります

public class GovernorLocalDataSource implements GovernorDataSource { 

    @Override 
    public void getGovernors(@NonNull GetGovernorsCallback callback) { 
     Gson gson = new GsonBuilder() 
       .registerTypeAdapterFactory(GovernorAdapterFactory.create()) 
       .create(); 
     List<Governor> governors; 

     String governorsString = mSharedPreference.getString(GOVERNORS, EMPTY_STRING); 
     if (governorsString.isEmpty()) { 
      governors = populateGovernors(); 
      governorsString = gson.toJson(governors); 
      mSharedPreference.edit().putString(GOVERNORS, governorsString).commit(); 
     } else { 
      Type type = new TypeToken<ArrayList<Governor>>() {}.getType(); 
      governors = gson.fromJson(governorsString, type); 
     } 

     if (governors != null && governors.size() > 0) { 
      callback.onSuccess(governors); 
     } else { 
      callback.onFailure(); 
     } 

    } 

} 

PS:誰かがWHYを説明することができればそれは素晴らしいことですこれは機能します。

+1

これは、Gson Auto Value拡張のドキュメントに従う方法です:GsonにAdapterFactoryを指定する必要があります。さもなければ、それはそれが抽象であるのでできないリフレクションによってガバナーオブジェクトを作成しようとします。拡張機能によって作成されたアダプタファクトリは、基本クラスの代わりにGovernorのAutoValue実装を使用するように指示します。 –

+0

@JulienArzulありがとう! 'TypeAdapter'と' TypeAdapterFactory'を説明しようとしている[記事](http://federico.defaveri.org/2013/07/07/gson-custom-serialization-falling-in-default-serialization/)を読みました。私は今それを得ると思います。私は 'AutoValue'から生成されたコードも見ました。' jsonReader.nextName() 'が' name'でなければ 'next value'をスキップするようなものがたくさんあります。 –

関連する問題