消除重复的Json元素并检索以大写字母开头的元素名称spring boot/java
Posted
技术标签:
【中文标题】消除重复的Json元素并检索以大写字母开头的元素名称spring boot/java【英文标题】:Eliminate duplicate Json elements and retrieve element names starting with capital letters spring boot/java 【发布时间】:2019-12-01 10:42:58 【问题描述】:我正在使用 Spring Boot 和 Spring Framework (spring-boot-starter-parent 2.1.6.RELEASE) 开发一个 Rest Client 我有一个代表响应对象的类,如下所示:
public class ValidateResponse
private String ResponseCode;
private String ResponseDesc;
//getters and setters
//constructors using fields
//empty constructor
我正在为外部 api 创建一个 web-hook,我需要为特定端点返回一个 JSON 对象(JSON 对象属性必须以大写字母开头)。我正在调用从嵌套在 RequestMapping
根路径中的 PostMapping
方法返回对象:
@PostMapping("hooks/validate")
public ValidateResponse responseObj(@RequestHeader Map<String, String> headersObj)
ValidateResponse response = new ValidateResponse("000000", "Success");
logger.info("Endpoint = hooks/validate | Request Headers = ", headersObj);
return response;
但是,当我从邮递员那里到达终点时,我得到了重复的变量
"ResponseCode": "000000",
"ResponseDesc": "Success",
"responseCode": "000000",
"responseDesc": "Success"
我知道 pojo-json 转换是由 spring 处理的,但我不明白为什么转换会产生重复的变量。
注意:我知道 ResponseDesc
和 ResponseCode
没有使用命名变量的最佳标准(camelCasing)声明。
我根据 Java Language Specification做了一些挖掘工作
标识符是 Java 字母和 Java 数字的无限长度序列,其中第一个必须是 Java 字母。
和
“Java 字母”包括大写和小写 ASCII 拉丁字母 AZ (\u0041-\u005a) 和 az (\u0061-\u007a),以及由于历史原因,ASCII 下划线(_ 或 \u005f)和美元符号($,或 \u0024)。 $ 字符应仅用于机械生成的源代码中,或者很少用于访问遗留系统上预先存在的名称。
所以,我假设使用Camelcase
格式定义变量在语法上是正确的[需要对此进行澄清]。
我正在考虑必须手动创建 JSON 对象,但我想先了解这种行为的原因。任何指针表示赞赏。
【问题讨论】:
【参考方案1】:Jackson
反序列化它遇到的所有公共字段。但是,如果您希望 Jackson
以您预期的元素名称返回响应(在您的 case 元素以大写字母开头),请创建字段 private
并使用 @JsonProperty(expected_name_here)
注释它们。您的类文件通常如下所示
public class ValidateResponse
@JsonProperty("ResponseDesc")
private String responseCode;
@JsonProperty("ResponseDesc")
private String responseDesc;
//getters and setters
//constructors using fields
//empty constructor
注意:这些字段的 getter 和 setter 应该是
public
,否则Jackson
将在类中看不到任何要反序列化的内容。
【讨论】:
我在没有 (expected_name) 值的字段上方使用 @JsonProperty 注释。将值添加到注释可以解决问题 但是,如果您确实公开了这些字段,那么 getter 和 setter 的意义何在? 我已将字段设置为私有【参考方案2】:public class ValidateResponse
@JsonProperty("ResponseDesc")
public String responseCode;
@JsonProperty("ResponseDesc")
public String responseDesc;
//getters and setters
//constructors using fields
//empty constructor
这必须解决您的问题,但我不知道原因,因为它需要深入杰克逊调查。
编辑
我找到了原因。 该字段被重复,因为在您的情况下,您有:
2 个以大写字母命名的公共字段 -> 它们将由 jackson 处理 2 个吸气剂getResponseCode
和 getResponseDesc
-> 他们将被解决
相应地作为属性 responseCode
和 responseDesc
的访问器。
总结一下 - 您有 4 个由 Jackson 解决的属性。只需将您的字段设为私有即可解决您的问题,但我仍然建议使用 JsonProperty
方法。
【讨论】:
我为ResponseCode
和ResponseDesc
创建了访问器,专门返回ResponseCode
和ResponseDesc
,但Jackson 解析了额外的responseDesc
和responseCode
字段。
在字段上方添加@JsonProperty注解并将("property_name")值添加到注解中解决了!
@JuneM3ta 在任何情况下我都会将字段本身设为私有,因为否则不需要创建访问器
我已将字段设置为私有【参考方案3】:
我在项目pom.xml
文件中添加了一个com.google.code.gson
依赖项来配置Spring Boot 以使用Gson(而不是默认的jackson)。
从hooks/validate
端点返回的 Json 对象的属性名称必须以大写字母开头。使用 java 类生成响应对象会导致 camelCased
属性名称,因此我决定手动创建 JSON 响应对象。下面是创建自定义 JSON 对象的代码:
public ResponseEntity<String> responseObj(@RequestHeader Map<String, String> headersObj)
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
JsonObject response = new JsonObject();
response.addProperty("ResponseCode", "00000000");
response.addProperty("ResponseDesc" , "Success");
logger.info("Endpoint = hooks/validate | Request Headers = ", headersObj);
return ResponseEntity.ok().headers(responseHeaders).body(response.toString());
注意 JSON 对象以 String
的形式返回,因此来自端点的响应必须有一个额外的标头来定义 MediaType
以通知调用系统响应是 JSON 格式:
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
然后将标头添加到响应中:
return ResponseEntity.ok().headers(responseHeaders).body(response.toString());
【讨论】:
以上是关于消除重复的Json元素并检索以大写字母开头的元素名称spring boot/java的主要内容,如果未能解决你的问题,请参考以下文章
如何在颤动中检索json数据元素以列出view.builder?