Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/180.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
GSON java如何在映射和打印之间使用不同的名称?_Java_Android_Json_Gson - Fatal编程技术网

GSON java如何在映射和打印之间使用不同的名称?

GSON java如何在映射和打印之间使用不同的名称?,java,android,json,gson,Java,Android,Json,Gson,我有这样一个JSON: { "aggregation": { "CityAgg" : { "key" : "Paris" } } } Gson gson = new Gson(); Query2 query2 = gson.fromJson(response, Query2.class); 我创建映射,并为每个字段添加一个@SerializedName,因为我想为变量创建自定义名称 例如,在JSON中,有一个键名key,但我希望Java中的变量是cityN

我有这样一个JSON:

{
  "aggregation": {
    "CityAgg" : {
      "key" : "Paris"
    }
  }
}
Gson gson = new Gson();
Query2 query2 = gson.fromJson(response, Query2.class);
我创建映射,并为每个字段添加一个
@SerializedName
,因为我想为变量创建自定义名称

例如,在JSON中,有一个键名
key
,但我希望Java中的变量是
cityName

因此,我这样做:

@SerializedName("key")
public String cityName
String query2String = gson.toJson(query2);
Gson gsonPretty = new GsonBuilder().setPrettyPrinting().create();
String prettyJson = gsonPretty.toJson(query2String);
我可以将响应JSON动态映射到我的对象,如下所示:

{
  "aggregation": {
    "CityAgg" : {
      "key" : "Paris"
    }
  }
}
Gson gson = new Gson();
Query2 query2 = gson.fromJson(response, Query2.class);
它工作得很好

但是,当我要打印映射对象时,我会执行以下操作:

@SerializedName("key")
public String cityName
String query2String = gson.toJson(query2);
Gson gsonPretty = new GsonBuilder().setPrettyPrinting().create();
String prettyJson = gsonPretty.toJson(query2String);
问题是,在
prettyJson
中,我可以看到
,而不是
cityName

我想知道是否有一种定制的方法。我不想看到

或者应该使用a或者应该使用反射来更改注释的值

更新:最坏的解决方案

使用反射看起来像这样

    ClassLoader classLoader = URLClassLoader.newInstance(new URL[]{YourClass.class.getResource("YourClass.class")});
    Class locAnnotation = classLoader.loadClass("yourPackage.Query2");

    Field field = locAnnotation.getDeclaredField("cityName");
    final Annotation fieldAnnotation = field.getAnnotation(SerializedName.class);
    changeAnnotationValue(fieldAnnotation, "oldValue", "newValue");


public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue) {
    Object handler = Proxy.getInvocationHandler(annotation);
    Field f;
    try {
        f = handler.getClass().getDeclaredField("memberValues");
    } catch (NoSuchFieldException | SecurityException e) {
        throw new IllegalStateException(e);
    }
    f.setAccessible(true);
    Map<String, Object> memberValues;
    try {
        memberValues = (Map<String, Object>) f.get(handler);
    } catch (IllegalArgumentException | IllegalAccessException e) {
        throw new IllegalStateException(e);
    }
    Object oldValue = memberValues.get(key);
    if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
        throw new IllegalArgumentException();
    }
    memberValues.put(key, newValue);
    return oldValue;
}
ClassLoader ClassLoader=URLClassLoader.newInstance(新URL[]{YourClass.class.getResource(“YourClass.class”)});
Class locAnnotation=classLoader.loadClass(“yourPackage.Query2”);
Field=locAnnotation.getDeclaredField(“cityName”);
final Annotation fieldAnnotation=field.getAnnotation(SerializedName.class);
changeAnnotationValue(字段注释,“旧值”、“新值”);
公共静态对象changeAnnotationValue(注释注释、字符串键、对象newValue){
对象处理程序=Proxy.getInvocationHandler(注释);
字段f;
试一试{
f=handler.getClass().getDeclaredField(“memberValues”);
}catch(NoSuchFieldException | SecurityException e){
抛出新的非法状态异常(e);
}
f、 setAccessible(true);
映射成员值;
试一试{
memberValues=(Map)f.get(handler);
}捕获(IllegalArgumentException | IllegalAccessException e){
抛出新的非法状态异常(e);
}
对象oldValue=memberValues.get(键);
如果(oldValue==null | | oldValue.getClass()!=newValue.getClass()){
抛出新的IllegalArgumentException();
}
memberValues.put(key,newValue);
返回旧值;
}

如果您不想像前面提到的那样编写自定义序列化器/反序列化器类,您可以始终创建某种类型的DTO对象

您的域类:

class CityAgg {
    @SerializedName("key")
    protected String cityName;

    public String getCityName() {
        return cityName;
    }
}

class Aggregation {
    @SerializedName("CityAgg")
    protected CityAgg cityAgg;

    public CityAgg getCityAgg() {
        return cityAgg;
    }
}

class Query2 {
    @SerializedName("aggregation")
    protected Aggregation aggregation;

    public Aggregation getAggregation() {
        return aggregation;
    }
}
DTO类示例:

class CityAggDto {
    protected String cityName;

    public CityAggDto(CityAgg query2) {
        this.cityName = query2.getCityName();
    }
}
样本使用:

String response = "{ \"aggregation\": { \"CityAgg\": { \"key\": \"value\" } } }";

Gson gson = new Gson();
Gson gsonPretty = new GsonBuilder().setPrettyPrinting().create();

Query2 query2 = gson.fromJson(response, Query2.class);
CityAggDto cityAggDto = new CityAggDto(query2.getAggregation().getCityAgg());

String cityAggDtoJson = gson.toJson(cityAggDto);
String cityAggDtoPrettyJson = gsonPretty.toJson(cityAggDto);

Log.d(TAG, "onCreate: " + cityAggDtoJson);
Log.d(TAG, "onCreate: " + cityAggDtoPrettyJson);
结果:

@SerializationName
注释用于两种操作—序列化和反序列化—这就是JSON字符串包含
key
key的原因

令人遗憾的是,尽管
@SerializationName
注释可以与方法一起使用,但对getter和setter使用不同的值将不起作用,因为GSON仅基于字段:

使用字段vs getter指示Json元素

一些Json库使用类型的getter来推断Json元素。我们选择使用所有非瞬时、静态或合成的字段(继承层次结构上)。我们这样做是因为并非所有类都使用适当命名的getter编写。此外,getXXX或isXXX可能是语义的,而不是指示属性

然而,也有很好的参数支持属性。我们打算在后一个版本中增强Gson,以支持属性作为指示Json字段的替代映射。目前,Gson是基于字段的

资料来源:


这就是我改用杰克逊的原因。:)

使用也可以work@RC. 没有调用任何注释alternate@RC. 我这样做了:@SerializedName(value=“CityAgg”,alternate=“city”),但我仍然可以看到
CityAgg
正在被加密,而不是
city
@AniaDavid简单的hack是在
PrettyPrint()
过程中更改注释值,然后在使用…:)使用Reflection@RC. 听起来alternate不适合打印,谢谢你也能提供解决方案吗?你提供的答案我找不到soltin。