問題描述:在基於Spring MVC的RESTful接口,當接口中請求參數Bean的字段被 @JsonProperty(access = Access.WRITE_ONLY) 約束時,通過postman調用rest接口,可以得到該字段可以值,也就是get/set是沒問題的。
當通過feign接口調用時,該字段會被序列化為字節碼傳到所在服務的機器上,當反序列化該字段時,得到的字段值為null
原因:被Access.WRITE_ONLY約束的字段值不會被序列化進去,所以對方獲得的值為null。而postman直調服務器時,是將值直接序列化為字節碼,所以可以獲取到值。
@JsonProperty( access = Access.WRITE_ONLY ) private String userPassword; @JsonIgnore private String uuid;
如下,為@JsonProperty內部結構。
package com.fasterxml.jackson.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonProperty { String USE_DEFAULT_NAME = ""; int INDEX_UNKNOWN = -1; String value() default ""; boolean required() default false; int index() default -1; String defaultValue() default ""; JsonProperty.Access access() default JsonProperty.Access.AUTO; public static enum Access { AUTO, READ_ONLY, WRITE_ONLY, READ_WRITE; private Access() { } } }
解決方法:摒棄該約束字段的Bean,新建一個Bean進行訪問,調feign接口。
擴展知識點:
1. jackson依賴jar導入
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.1</version> </dependency>
2. 關於jackson中@JsonIgnore
和 @JsonProperty
的說明
可參考:http://fasterxml.github.io/jackson-annotations/javadoc/2.9/com/fasterxml/jackson/annotation/JsonProperty.Access.html
3. 示例代碼驗證
首先,新建一個用於傳參的Bean,UserTest,其中字段被@JsonProperty(分為Access.WRITE_ONLY、Access.READ_ONLY)和@JsonIgnore修飾
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; @JsonInclude(JsonInclude.Include.NON_NULL) public class UserTest { private String userName; @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) private String userPassword; @JsonIgnore private String uuid; @JsonProperty(access = JsonProperty.Access.READ_ONLY) private String readOnly; @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) private String trans = "0"; }
其次,新建一個接口test
@PostMapping(value = "/test") public String test(@RequestBody UserTest test) { log.info("請求參數 -->{}", JSON.toJSONString(test)); return "success"; }
啟動服務,通過postman調用接口
打印結果如下:
2020-01-25 11:57:53.450 請求參數 -->{"trans":"0","userName":"name","userPassword":"123456"}
以上,通過對結果分析,發現用postman的body體內,所設置的字段readOnly未被打印,說明在該字段未被set(說明了被READ_ONLY修飾的字段僅支持get方法)進去,而字段trans能被打印,是因為該字段有被初始化值(有初始化值的字段無論設置為READ_ONLY或WRITE_ONLY修飾,都在不設置的情況下展示默認值)。
因此,總結如下:
WRITE_ONLY:僅做反序列化操作。
READ_ONLY:僅做序列化操作。