Fields in a "Serializable" class should either be transient or serializable
2023, Mar 23
problem
- java:S1948
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class UserRequest implements ValueObject {
private Map params;
@Override
public String toString() {
return toJson();
}
}
- Map으로 생성한 params 변수가 key. value 모두 형이 특정되어있으면
Map<String, String>
이거나 serializable했으면 가능하지만, value로 맵핑되는 값이 string일 수도 있고 list일 수도 있어서 형을 선언할 수 없었습니다.
cause
- sonarqube 설명을 보면
Fields in a Serializable class must themselves be either Serializable or transient even
if the class is never explicitly serialized or deserialized.
For instance, under load, most J2EE application frameworks flush objects to disk,
and an allegedly Serializable object with non-transient,
non-serializable data members could cause program crashes,
and open the door to attackers.
In general a Serializable class is expected to fulfil its contract and
not have an unexpected behaviour when an instance is serialized.
This rule raises an issue on non-Serializable fields, and on collection fields
when they are not private (because they could be assigned non-Serializable values externally),
and when they are assigned non-Serializable types within the class.
- 요점하면 직렬화 클래스의 필드는 Serializable하게 하거나 transient 선언해서 제외시키라는 뜻
- non-Serializable한 필드이거나 private이 아닌 collection 필드들, 또는 직렬화할 수 없는 유형(Map, List 등등)은 이 룰에 검출된다.
Resolve
- 가이드처럼 transient를 붙여서 제외시키는 방법이 있고
- Map 원시형 자체 말고 Map<String, String> 처럼 직렬/역직렬화가능하게 타입 선언하거나
param변수자체를 serializable한 객체로 생성한다.
// UserParam Serializable객체로 생성하고 @NoArgsConstructor public class UserParam extends HashMap<String, Object> implements JsonSerializable { @Override public String toString() { return toJson(); } } // private UserParam params; 로 변경한다. public class UserRequest implements ValueObject { private UserParam params; @Override public String toString() { return toJson(); } }