티스토리 뷰
발단상황
java를 사용하고 데이터베이스에서 조회된 데이터 목록을
JSON 형태로 응답을 해주는 방법 중 하나로는
ObjectMapper Class ( import com.fasterxml.jackson.databind.ObjectMapper; )가 있다.
ObjectMapper Class 내에 여러 메소드 중 하나인
writeValueAsString 메소드는 java의 Object를 직렬화 과정을 통하여
json 형태의 String 형으로 변환해 주는 역할을 한다.
이러한 기능을 이용하여 기능을 개발을 진행하던 중 원하는 결과를 반환하지 않는 경우가 발생하였다.
데이터베이스에서 데이터 목록을 조회하여
ObjectMapper의 writeValueAsString 메소드를 이용하여
값을 반환하는 기능을 개발하던 중 이였다.
하지만 예상했던 결과와 다르게 데이터 목록을 확인할 수 없었다.
작업한 소스코드의 일부는 아래와 같다.
ObjectMapper om = new ObjectMapper();
String resData;
List<TestEntity> list = TestService.selectTestList();
resData = om.writeValueAsString(list);
어느 부분에서 문제가 발생하는지 찾기 위해 순차적으로 디버깅을 진행해 보았다.
3번 라인의 list 객체에는 값이 정상적으로 담기는 것을 확인하였다.
하지만 4번 라인 resData 변수에는 아래와 같이 데이터가 담겨있었다.
[{},{}]
테스트를 위해 데이터는 2개를 입력해 둔 상태였다.
json 형태의 데이터가 배열 형태로 2개가 존재함은 확인하였음
key와 value 값이 존재하지 않는 것을 확인하였다.
문제해결
먼저 문제를 해결한 방법은 아래와 같다.
@Entity
@Table
@Data //해당 어노테이션을 추가해주었음. @Getter도 가능
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TestEntity {
private Long aId;
private String bId;
}
Entity Class에 Data 어노테이션을 추가해 주었다. (Getter 어노테이션도 가능 이유는 아래에 계속)
Dto Class의 toEntity 기능을 활용하려다가 누락된 것으로 보인다;;;
어노테이션을 추가해 준 후 아래와 같이 데이터가 정상적으로 조회되는 것을 확인할 수 있었다.
[{"aId":11,"bId":"33"},{"aId":22,"bId":"44"}]
원인분석
문제는 해결하였는데 문제가 발생한 원인을 좀 더 찾아보았다.
ObjectMapper 생성자부터 소스코드를 따라가 보았다.
ObjectMapper.java
public ObjectMapper() {
this(null, null, null);
}
public ObjectMapper(JsonFactory jf,
DefaultSerializerProvider sp, DefaultDeserializationContext dc)
{
...
_configOverrides = new ConfigOverrides();
...
}
ObjectMapper Class 내 생성자를 따라가다 보면
ConfigOverrides Class의 생성자를 생성하는 부분이 존재합니다.
ConfigOverrides.java
public ConfigOverrides() {
this(null,
// !!! TODO: change to (ALWAYS, ALWAYS)?
JsonInclude.Value.empty(),
JsonSetter.Value.empty(),
VisibilityChecker.Std.defaultInstance(),
null, null
);
}
ConfigOverrides 생성자의 VisibilityChecker.Std.defaultInstance() 매개변수를 따라가 봅니다.
VisibilityCheckerjava
public static Std defaultInstance() { return DEFAULT; }
protected final static Std DEFAULT = new Std(
Visibility.PUBLIC_ONLY, // getter
Visibility.PUBLIC_ONLY, // is-getter
Visibility.ANY, // setter
Visibility.ANY, // creator -- legacy, to support single-arg ctors
Visibility.PUBLIC_ONLY // field
);
Instance는 DEFAULT 옵션으로 선언되어있으며 해당 옵션의 값은 그 아래 코드 내에 선언되어 있습니다.
해당 옵션의 의미는 직렬화 진행 시 객체 생성을 위해 방식에 따라서
gettet, isGetter, filed(변수)의 해당 접근제어자는 public이어야만 하며
setter, creator(생성자)는 조건을 특정 짓지 않는다는 것이다.
이러한 내용을 기반으로 문제가 발생한 상황에 적용해 보면
json으로 직렬화해야 하는 객체에 getter 메소드 선언을 누락하였던 것이고
filed는 private 접근제어자로 선언이 되어있기 때문에 값을 가져올 수 없었던 것이었다.
만약 변수가 public이었다면 값을 가져올 수 있었지만
사용자에 의하여 값이 변경될 수 있으니 해당 경우는 흔하지 않을 것으로 보인다.
'JAVA' 카테고리의 다른 글
[java] 인코딩이 다른 시스템간 byte 데이터 주고받기 (1) | 2024.09.26 |
---|---|
MyBatis ORACLE SEQUENCE 미증가 해결 (1) | 2024.04.19 |
java RSA decryption is failed (bouncycastleprovider 관련) (1) | 2023.10.06 |
세션 일부 값 누락 현상 조치하기(세션 클러스터링) (0) | 2023.08.07 |
java Optional orElse() 의도하지 않은 로직 수행 시 확인사항 (0) | 2023.04.07 |
- Total
- Today
- Yesterday
- vscode
- SpringBoot
- Java
- jaxen
- jQuery
- JPA
- SQL
- IMAGE
- mybatis
- 날짜
- spring
- JSON
- 이벤트발생
- docker
- Eclipse
- parse
- 컨테이너
- Windows
- Git
- SSL
- html
- Linux
- gradle
- Oracle
- React
- 깨짐
- WAS
- btye
- TLS
- web
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |