잭슨이 역직렬화를 위해 노-아르그 컨스트럭터를 필요로 하는 시기는?
봄 부츠 프로젝트에서 잭슨의 이상한 행동을 발견했습니다.인터넷으로 검색해보고 어떻게 해야할지 찾아봤지만, 왜 그런지는 아직도 모르겠어요.
사용자 대상:
@Setter
@Getter
@AllArgsConstructor
public class UserDto {
private String username;
private String email;
private String password;
private String name;
private String surname;
private UserStatus status;
private byte[] avatar;
private ZonedDateTime created_at;
}
새 사용자를 추가하는 것도 좋습니다.
TagDto:
@Setter
@Getter
@AllArgsConstructor
public class TagDto {
private String tag;
}
새 태그를 추가하려고 하면 다음 오류가 발생합니다.
com.fasterxml.jackson.databind.exc.MismatchInputException: TagDto 인스턴스를 구성할 수 없음(Creator가 하나 이상 존재함): Object 값에서 deserialize할 수 없음(Delegate- 또는 Property-based Creator 없음)
이 문제에 대한 해결책은 TagDto 클래스에 zero-arg constructor를 추가하는 것이었습니다.
왜 잭슨은 UserDto로 잘 작동하면서 TagDto에서 deserialization을 위해 no-arg constructor를 요구합니까?
두 가지를 모두 추가할 때 동일한 방법을 사용합니다.내 태그 및 사용자 엔티티는 모두 다음과 같이 주석이 달렸습니다.
@Entity
@Setter
@Getter
@NoArgsConstructor
그리고 모든 arg compactor를 갖습니다.
@Entity
@Setter
@Getter
@NoArgsConstructor
public class User extends AbstractModel {
private String username;
private String password;
private String email;
private String name;
private String surname;
private UserStatus status;
@Lob
private byte[] avatar;
@Setter(AccessLevel.NONE)
private ZonedDateTime created_at;
public User(final String username, final String password, final String email, final String name, final String surname) {
this.username = username;
this.password = password;
this.email = email;
this.name = name;
this.surname = surname;
this.created_at = ZonedDateTime.now();
}
}
@Entity
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Tag extends AbstractModel {
private String tag;
}
@MappedSuperclass
@Getter
public abstract class AbstractModel {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
}
엔터티 생성:
@PostMapping(path = "/add")
public ResponseEntity<String> add(@Valid @RequestBody final D dto) {
this.abstractModelService.add(dto);
return new ResponseEntity<>("Success", HttpStatus.CREATED);
}
public void add(final D dto) {
//CRUD repository save method
this.modelRepositoryInterface.save(this.getModelFromDto(dto));
}
@Override
protected Tag getModelFromDto(final TagDto tagDto) {
return new Tag(tagDto.getTag());
}
@Override
protected User getModelFromDto(final UserDto userDto) {
return new User(userDto.getUsername(), userDto.getPassword(), userDto.getEmail(), userDto.getName(), userDto.getSurname());
}
JSON 구문 분석 시 오류 발생
{"tag":"example"}
우체부 localhost를 통해 발송됨:8081/태그/추가, 반품
{
"timestamp": "2020-09-26T18:50:39.974+00:00",
"status": 400,
"error": "Bad Request",
"message": "",
"path": "/tag/add"
}
저는 롬복 v1.18.12와 스프링부트 2.3.3을 사용하고 있습니다.잭슨 v2.11.2와 함께 릴리즈.
TL;DR: 해결책은 끝에 있습니다.
Jackson은 POJO를 만드는 여러 가지 방법을 지원합니다.다음은 가장 일반적인 방법을 나열하지만 전체 목록은 아닐 가능성이 높습니다.
no-arg constructor를 사용하여 인스턴스를 만든 다음 setter 메서드를 호출하여 속성 값을 할당합니다.
public class Foo { private int id; public int getId() { return this.id; } @JsonProperty public void setId(int id) { this.id = id; } }
지정은 선택 사항이지만 , , , ...와 같은 주석과 함께 매핑을 미세 조정하는 데 사용할 수 있습니다.
인수가 있는 생성자를 사용하여 인스턴스를 만듭니다.
public class Foo { private int id; @JsonCreator public Foo(@JsonProperty("id") int id) { this.id = id; } public int getId() { return this.id; } }
시공자 지정은 선택 사항이지만 시공자가 둘 이상일 경우 필수라고 생각합니다.지정하기
@JsonProperty
매개 변수의 경우 선택 사항이지만 매개 변수 이름이 클래스 파일에 포함되지 않은 경우 속성 이름을 지정하는 데 필요합니다(-parameters
컴파일러 옵션).매개 변수는 속성이 필요함을 나타냅니다.setter 메서드를 사용하여 옵션 속성을 설정할 수 있습니다.
공장 메서드를 사용하여 인스턴스를 만듭니다.
public class Foo { private int id; @JsonCreator public static Foo create(@JsonProperty("id") int id) { return new Foo(id); } private Foo(int id) { this.id = id; } public int getId() { return this.id; } }
다음을 사용하여 텍스트 값에서 인스턴스(instance(인스턴스)
String
시공자public class Foo { private int id; @JsonCreator public Foo(String str) { this.id = Integer.parseInt(id); } public int getId() { return this.id; } @JsonValue public String asJsonValue() { return Integer.toString(this.id); } }
이것은 POJO가 단순한 텍스트 표현을 가질 때 유용합니다. 예를 들어,
LocalDate
는 3가지 속성을 가진 POJO입니다(year
,month
,dayOfMonth
), 그러나 일반적으로 단일 문자열로 직렬화되는 것이 가장 좋습니다 (yyyy-MM-dd
형식).@JsonValue
직렬화 시 사용할 방법을 식별하고,@JsonCreator
역직렬화 시 사용할 시공자/공장-method을 식별합니다.참고: 다음 이외의 JSON 값을 사용한 단일 값 구성에도 사용할 수 있습니다.
String
, 하지만 그것은 매우 드뭅니다.
네, 그게 배경 정보였어요.질문의 예시들에 대해 무슨 일이 일어나고 있는지, 그것은UserDto
생성자가 하나밖에 없기 때문에 작동합니다(따라서).@JsonCreator
필요 없음), 그리고 많은 논쟁들 (그래서.@JsonProperty
필요 없음).
하지만, 에 대해서는TagDto
주석이 없는 단일 논항 생성자만 존재하므로 잭슨은 해당 생성자를 유형 #2가 아닌 유형 #4(위의 제 목록에서)로 분류합니다.
즉, POJO가 값 클래스가 될 것으로 예상되며, 여기서 엔클로저 객체의 JSON이 될 것입니다.{ ..., "tag": "value", ... }
,것은 아니다.{ ..., "tag": {"tag": "example"}, ... }
.
이 문제를 해결하려면 Jackson에게 다음을 지정하여 생성자가 값 유형 생성자(#4)가 아닌 속성 초기화 생성자(#2)임을 알려주어야 합니다.@JsonProperty
건설업자의 주장에 관하여.
즉, Lombok에서 생성자를 생성하도록 할 수 없습니다.
@Setter
@Getter
public class TagDto {
private String tag;
public TagDto(@JsonProperty("tag") String tag) {
this.tag = tag;
}
}
언급URL : https://stackoverflow.com/questions/64080983/when-does-jackson-require-no-arg-constructor-for-deserialization
'programing' 카테고리의 다른 글
워드 프레스에서 CORS 사용 (0) | 2023.10.29 |
---|---|
Oracle에서 "Create Directory" 권한 부여 (0) | 2023.10.29 |
버튼으로 div 표시/숨기기? (0) | 2023.10.29 |
업데이트 실행 중 SQL 업데이트가 하위 쿼리에 영향을 줍니까? (0) | 2023.10.29 |
파이썬 형식(f-string) 문자열에서 !r은 무엇을 의미합니까? (0) | 2023.10.29 |