我有一个A类,它有一些私有字段,同一个类扩展了另一个B类,它也有一些A类私有字段。
public class A extends B {
private BigDecimal netAmountTcy;
private BigDecimal netAmountPcy;
private BigDecimal priceTo;
private String segment;
private BigDecimal taxAmountTcy;
private BigDecimal taxAmountPcy;
private BigDecimal tradeFeesTcy;
private BigDecimal tradeFeesPcy;
// getter and setter for the above fields
}
并且B级有一些属于A级的私人战场
现在当我尝试从A类上面创建JSON字符串时,我得到以下异常:
class com.hexgen.ro.request.A declares multiple JSON fields named netAmountPcy
如何解决这个问题?
由于它们是私有字段,因此在创建json字符串时应该没有任何问题,但我不确定。
我创建json字符串,如下所示:
Gson gson = new Gson();
tempJSON = gson.toJson(obj);
这里obj是A类的对象
答案 0 :(得分:60)
由于它们是私有字段,因此在创建json字符串时应该没有任何问题
我不认为这个陈述是正确的,GSON在序列化时会查看对象的私有字段,这意味着包含了超类的所有私有字段,当你有相同名称的字段时会抛出错误。
如果您不希望包含任何特定字段,则必须使用transient
关键字对其进行标记,例如:
private transient BigDecimal tradeFeesPcy;
答案 1 :(得分:57)
这有点晚了,但我遇到了同样的问题。唯一的事情是我无法修改超类,因为该代码不是我的。我解决这个问题的方法是创建一个排除策略,跳过任何具有超类中存在的同名字段的字段。这是我的课程代码:
public class SuperclassExclusionStrategy implements ExclusionStrategy
{
public boolean shouldSkipClass(Class<?> arg0)
{
return false;
}
public boolean shouldSkipField(FieldAttributes fieldAttributes)
{
String fieldName = fieldAttributes.getName();
Class<?> theClass = fieldAttributes.getDeclaringClass();
return isFieldInSuperclass(theClass, fieldName);
}
private boolean isFieldInSuperclass(Class<?> subclass, String fieldName)
{
Class<?> superclass = subclass.getSuperclass();
Field field;
while(superclass != null)
{
field = getField(superclass, fieldName);
if(field != null)
return true;
superclass = superclass.getSuperclass();
}
return false;
}
private Field getField(Class<?> theClass, String fieldName)
{
try
{
return theClass.getDeclaredField(fieldName);
}
catch(Exception e)
{
return null;
}
}
}
然后,我在构建器中设置序列化和反序列化排除策略,如下所示:
builder.addDeserializationExclusionStrategy(new SuperclassExclusionStrategy());
builder.addSerializationExclusionStrategy(new SuperclassExclusionStrategy());
希望这有助于某人!
答案 2 :(得分:9)
如果您有不同的字段,也会出现相同的错误消息,但它们具有相同的@SerializedName
。
@SerializedName("date_created")
private Date DateCreated;
@SerializedName("date_created")
private Integer matchTime;
复制/粘贴你可以犯这样的错误。因此,查看类及其祖先并检查它。
答案 3 :(得分:7)
在proguard.config的底部添加以下行 (如果你在项目中使用proguard)
-keepclassmembers class * {
private <fields>;
}
答案 4 :(得分:2)
我使用GsonBuilder
和ExclusionStrategy
来避免出现如下所示的多余字段,这很简单明了。
Gson json = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
if(f.getName().equals("netAmountPcy")){
return true;
}
return false;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}).create();
答案 5 :(得分:1)
对于Kotlin的解决方案,正如@ Adrian-Lee建议的那样,你必须调整一些空检查
class SuperclassExclusionStrategy : ExclusionStrategy {
override fun shouldSkipClass(clazz: Class<*>?): Boolean {
return false
}
override fun shouldSkipField(f: FieldAttributes?): Boolean {
val fieldName = f?.name
val theClass = f?.declaringClass
return isFieldInSuperclass(theClass, fieldName)
}
private fun isFieldInSuperclass(subclass: Class<*>?, fieldName: String?): Boolean {
var superclass: Class<*>? = subclass?.superclass
var field: Field?
while (superclass != null) {
field = getField(superclass, fieldName)
if (field != null)
return true
superclass = superclass.superclass
}
return false
}
private fun getField(theClass: Class<*>, fieldName: String?): Field? {
return try {
theClass.getDeclaredField(fieldName)
} catch (e: Exception) {
null
}
}
}
答案 6 :(得分:0)
在我的情况下,我愚蠢到用X类注册一个适配器,并尝试使用Y类从json序列化:
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Game.class, new TournamentSerializer());
final Gson gson = gsonBuilder.create();
createdTournament = gson.fromJson(jsonResponse.toString(), Tournament.class);
答案 7 :(得分:0)
我认为您不应该使成员成为临时成员,这可能会导致错误,因为您将来可能需要的成员可能被隐藏了。
我解决此问题的方法是使用自定义命名策略,并将完整的类名附加到Json,这样做的缺点是它将导致更大的Json,如果您需要它来使用Rest Api之类的东西,则会客户端以这种方式命名字段很奇怪,但我只需要序列化即可写入android上的磁盘。
这是Kotlin中自定义命名策略的实现
import com.google.gson.FieldNamingStrategy
import java.lang.reflect.Field
class GsonFieldNamingStrategy : FieldNamingStrategy {
override fun translateName(field: Field?): String? {
return "${field?.declaringClass?.canonicalName}.${field?.name}"
}
}
因此,对于所有字段,将附加完整的规范名称,这将使子类的名称与父类的名称不同,但是在反序列化时,将使用子类的值。
答案 8 :(得分:0)
对于 Kotlin-er:
val fieldsToExclude = listOf("fieldToExclude", "otherFieldToExclude")
GsonBuilder()
.setExclusionStrategies(object : ExclusionStrategy {
override fun shouldSkipField(f: FieldAttributes?) = f?.let { fieldsToExclude.contains(it.name) } ?: false
override fun shouldSkipClass(clazz: Class<*>?) = false
})
.create()