使用 AutoValue 时无法将 JSON 转换为 ArrayList
Unable to convert JSON to ArrayList when using AutoValue
我正在使用 AutoValue 来处理 getter/setter
和 Parcelable
。
我将对象的 JSON 值存储在 SharedPreferences
中,然后在需要时检索它们。但是,当我尝试将 SharedPreferences
中存储为字符串的 JSON 数组转换为 ArrayList<T>
时会引发异常,因为我使用的 AutoValue
不允许使用 Constructor
直接。
这是我遇到的异常 -
java.lang.RuntimeException: Failed to invoke public org.yadavvi.tutorials.governor.data.Governor() with no args
at com.google.gson.internal.ConstructorConstructor.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.construct(ConstructorConstructor.java:108)
... 41 more
这是 Model/AutoValue
class 的样子 -
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>
的 class 的样子 -
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();
}
}
....
}
这一行抛出异常 -
governors = gson.fromJson(governorsString, new TypeToken<ArrayList<Governor>>(){}.getType());
编辑: 我的 Android
项目中有一些 AutoValue-Extensions
。
app 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'
}
下面的 link 可能会有所帮助,基本上您需要使用具体的 class.
而不是抽象的 class
Gson deserialize json. java.lang.RuntimeException: Failed to invoke public com.derp.procedure.model.SkeletonElement() with no args] with root cause
我已将自定义 TypeAdapterFactory
添加到 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
改成了这样 -
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: 如果有人能解释一下 为什么 这有效。
我正在使用 AutoValue 来处理 getter/setter
和 Parcelable
。
我将对象的 JSON 值存储在 SharedPreferences
中,然后在需要时检索它们。但是,当我尝试将 SharedPreferences
中存储为字符串的 JSON 数组转换为 ArrayList<T>
时会引发异常,因为我使用的 AutoValue
不允许使用 Constructor
直接。
这是我遇到的异常 -
java.lang.RuntimeException: Failed to invoke public org.yadavvi.tutorials.governor.data.Governor() with no args
at com.google.gson.internal.ConstructorConstructor.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.construct(ConstructorConstructor.java:108)
... 41 more
这是 Model/AutoValue
class 的样子 -
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>
的 class 的样子 -
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();
}
}
....
}
这一行抛出异常 -
governors = gson.fromJson(governorsString, new TypeToken<ArrayList<Governor>>(){}.getType());
编辑: 我的 Android
项目中有一些 AutoValue-Extensions
。
app 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'
}
下面的 link 可能会有所帮助,基本上您需要使用具体的 class.
而不是抽象的 classGson deserialize json. java.lang.RuntimeException: Failed to invoke public com.derp.procedure.model.SkeletonElement() with no args] with root cause
我已将自定义 TypeAdapterFactory
添加到 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
改成了这样 -
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: 如果有人能解释一下 为什么 这有效。