【问题标题】:GSON wont rename fields inside HashMapGSON 不会重命名 HashMap 中的字段
【发布时间】:2021-04-05 21:18:05
【问题描述】:

我试图使用 GSON 序列化/反序列化 JSON。有问题的有效载荷是ApiGatewayAuthorizerContext。在里面,有一个HashMap<String, String>。但是在做from/to json的时候,字段命名策略并没有应用到Keys上。

@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiGatewayAuthorizerContext {

    //-------------------------------------------------------------
    // Variables - Private
    //-------------------------------------------------------------

    private Map<String, String> contextProperties = new HashMap<>();
    private String principalId;
    private CognitoAuthorizerClaims claims;
}

AwsProxyRequest 类中的MultiValuedTreeMap&lt;String, String&gt; 也一样,这是一个MultivaluedMap&lt;Key, Value&gt;

我的字段命名策略很简单,将-替换为_,例如下面的payload对于我使用的很多下游组件都不是有效的JSON,想把所有的'-'替换成'_' .

"MultiValueHeaders": {
    "Accept": [
        "application/json, text/plain, */*"
    ],
    "Authorization": [
        "Bearer ey...b9w"
    ],
    "Content-Type": [
        "application/json;charset=utf-8"
    ],
    "Host": [
        "aws-us-east-1-dev-dws-api.xxxxxxxx.com"
    ],
    "User-Agent": [
        "axios/0.20.0"
    ],
    "X-Amzn-Trace-Id": [
        "Root=1-xxxxxxxx-xxxxxxxxxxxxxxxx"
    ],
    "X-Forwarded-For": [
        "127.0.232.171"
    ],
    "X-Forwarded-Port": [
        "443"
    ],
    "X-Forwarded-Proto": [
        "https"
    ]
},

有什么想法吗?

编辑:添加字段命名策略。

public class ApiEventNamingStrategy implements FieldNamingStrategy {

  /**
   * Translates the field name into its {@link FieldNamingPolicy.UPPER_CAMEL_CASE} representation.
   *
   * @param field the field object that we are translating
   * @return the translated field name.
   */
  public String translateName(Field field) {
    String fieldName = FieldNamingPolicy.UPPER_CAMEL_CASE.translateName(field);
    if (fieldName.contains("-")) {
      fieldName = fieldName.replace('-', '_');
    }
    return fieldName;
  }
}

用于setFieldNamingStrategy如下图,

  private static Gson gson =
      (new GsonBuilder()).setFieldNamingStrategy(new ApiEventNamingStrategy()).create();

结果是,除了Map 中的成员变量之外的所有成员变量都被检查并重命名。似乎setFieldNamingStrategy 不会在Map 内部查看并重命名Keys

现在我正在查看使用registerTypeAdapterFactory 注册TypeAdapter。似乎@linfaxin 在这里gson-wont-properly-serialise-a-class-that-extends-hashmap 的答案会来救援!但问题是,在哪里/如何和/或在RetainFieldMapFactory 类中引入字段命名策略的正确位置,因为我看到了很多破解它的途径。

欢迎提出任何想法!

顺便说一句,这些值由AWS APIGateway 和一个自定义授权 lambda 填充。我认为我无法改变APIGateway 的行为。

【问题讨论】:

  • 请添加问题中缺少的关于字段命名转换的部分。到目前为止,您尝试了什么。
  • 另外,您如何期望Map&lt;String, String&gt; contextProperties 被填满?你在做一些用元素填充地图的事情吗?
  • 正确,contextProperties 由自定义授权 lambda 填充。可以修改contextProperties,但MultiValueHeaders 中的X-Amzn-Trace-IdX-Forwarded-For 等仍然过不去!
  • 您对字段命名策略的假设是错误的,因为它旨在翻译 类字段 名称(请参阅接口方法声明),而不是任意对象(提示:内部映射类型适配器工厂根本没有任何名称翻译功能)。此外,扩展哈希映射的链接问题是无关紧要的:它解决了 OP 试图将扩展类属性与 Gson 默认知道的映射接口合并的问题。最后,Gson 不知道非标准的MultiValuedTreeMap,因此您必须实现自定义类型适配器。

标签: java json amazon-web-services hashmap gson


【解决方案1】:

GSON 不会进入地图并考虑您想要做什么。杰克逊也是。

考虑到您已经将内容保存在地图中,我认为使用 3 行代码转换地图要容易得多,而不是尝试破解库如何序列化和反序列化对象。

Map<String, String> contextPropertiesNormalized= contextProperties.keySet()
                       .stream()
                       .collect(Collectors.toMap(k-> k.contains("-") ? k.replace("-","_"): k, v -> contextProperties::get));

【讨论】:

  • 是的,这是最简单的方法,但是有时不需要中间映射,因此创建反序列化器是有意义的。此外,这种情况下的映射通常应该从entries() 中收集,而不是keySet():它保证即使对于未引用不一定是线程安全的源映射的并行流也能正确收集条目(通常,流函数应该放在一边- 效果免费且不受当前词汇范围的“外部世界”上下文的约束)。另外,我相信您还指的是 String.replaceAll()(然后是 Pattern.compile() 以使用匹配器加快速度)。
猜你喜欢
  • 2019-04-29
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-06
  • 2014-09-10
相关资源
最近更新 更多