1. 現(xiàn)象
在開(kāi)發(fā)中遇到了一個(gè)bug筒溃,我在一個(gè)對(duì)象的 list 屬性中add了一個(gè)新值马篮,但是接口返回時(shí) list 并沒(méi)有被改變。
下面我用demo模擬了一下:
定義返回的對(duì)象clazz班級(jí)怜奖,studentsJson 對(duì)應(yīng)數(shù)據(jù)庫(kù)中存儲(chǔ)的 Json Array 字符串浑测,students是將字符串處理后返回的列表:
public class Clazz {
private String name;
private String studentsJson;
private List<Student> students;
public List<Student> getStudents() {
if (!StringUtils.isEmpty(studentsJson)) {
students = JSON.parseArray(studentsJson, Student.class);
return students;
}
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStudentsJson() {
return studentsJson;
}
public void setStudentsJson(String studentsJson) {
this.studentsJson = studentsJson;
}
@Override
public String toString() {
return "Clazz{" +
"name='" + name + '\'' +
", studentsJson='" + studentsJson + '\'' +
", students=" + students +
'}';
}
}
Student對(duì)象:
public class Student {
private String name;
// 省略 get/set 方法 ...
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
接口模擬:
@RestController
public class TestController {
Logger logger = LoggerFactory.getLogger(TestController.class);
@GetMapping("/test")
public Clazz showClazz() {
// 模擬數(shù)據(jù)庫(kù)中查出的對(duì)象
Clazz clazz = new Clazz();
clazz.setName("一班");
clazz.setStudentsJson("[{\"name\":\"zhangsan\"},{\"name\":\"lisi\"}]");
logger.info("初始clazz對(duì)象: {}", clazz);
List<Student> students = clazz.getStudents();
logger.info("調(diào)用getStudents方法獲取的students: {}", students);
students.add(new Student("wangwu"));
logger.info("向students中添加一個(gè)新的學(xué)生后: {}", students);
return clazz;
}
}
請(qǐng)求接口后的輸出:
2021-05-20 11:32:28.865 [INFO ] [http-nio-8080-exec-1] [c.jiangxb.test.TestController ] 初始clazz對(duì)象: Clazz{name='一班', studentsJson='[{"name":"zhangsan"},{"name":"lisi"}]', students=null}
2021-05-20 11:32:28.916 [INFO ] [http-nio-8080-exec-1] [c.jiangxb.test.TestController ] 調(diào)用getStudents方法獲取的students: [Student{name='zhangsan'}, Student{name='lisi'}]
2021-05-20 11:32:28.917 [INFO ] [http-nio-8080-exec-1] [c.jiangxb.test.TestController ] 向students中添加一個(gè)新的學(xué)生后: [Student{name='zhangsan'}, Student{name='lisi'}, Student{name='wangwu'}]
這里students中添加一個(gè)應(yīng)該是三個(gè)的,但是用postman調(diào)用返回后:
{
"name": "一班",
"studentsJson": "[{\"name\":\"zhangsan\"},{\"name\":\"lisi\"}]",
"students": [
{"name": "zhangsan"},
{"name": "lisi"}
]
}
2. 原因
從controller返回后歪玲,spring mvc會(huì)對(duì)返回值進(jìn)行處理
ServletInvocableHandlerMethod#invokeAndHandle
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
在這一步會(huì)調(diào)用對(duì)象的get方法迁央,所以手動(dòng)加入進(jìn)students中的對(duì)象被覆蓋掉了。
3. 建議
建議不要在 get/set 方法中寫(xiě)任何的邏輯滥崩,這樣雖然可以簡(jiǎn)化一些代碼岖圈,但是出現(xiàn)問(wèn)題時(shí)不容易排查,會(huì)有很大的隱患钙皮,也不利于其他同事修改蜂科。
這點(diǎn)在阿里Java開(kāi)發(fā)手冊(cè)(泰山版)中也有提到: