잭슨과의 JSON 역직렬화 커스텀
Flickr API를 사용하고 있습니다.메서드를 호출할 때 기본 JSON 결과는 다음과 같습니다.
{
"user": {
"id": "21207597@N07",
"username": {
"_content": "jamalfanaian"
}
},
"stat": "ok"
}
이 응답을 Java 개체로 구문 분석합니다.
public class FlickrAccount {
private String id;
private String username;
// ... getter & setter ...
}
JSON 속성은 다음과 같이 매핑해야 합니다.
"user" -> "id" ==> FlickrAccount.id
"user" -> "username" -> "_content" ==> FlickrAccount.username
유감스럽게도 주석을 사용하여 이 작업을 수행할 수 있는 멋지고 우아한 방법을 찾을 수 없습니다.지금까지의 접근법은 JSON String을 읽어들이는 것입니다.Map<String, Object>
거기서 가치를 얻을 수 있습니다.
Map<String, Object> value = new ObjectMapper().readValue(response.getStream(),
new TypeReference<HashMap<String, Object>>() {
});
@SuppressWarnings( "unchecked" )
Map<String, Object> user = (Map<String, Object>) value.get("user");
String id = (String) user.get("id");
@SuppressWarnings( "unchecked" )
String username = (String) ((Map<String, Object>) user.get("username")).get("_content");
FlickrAccount account = new FlickrAccount();
account.setId(id);
account.setUsername(username);
하지만 이건 가장 비도덕적인 방법이라고 생각해요주석 또는 사용자 지정 역직렬화기를 사용하는 간단한 방법이 있습니까?
이것은 저에게 매우 당연한 일이지만, 물론 효과가 없습니다.
public class FlickrAccount {
@JsonProperty( "user.id" ) private String id;
@JsonProperty( "user.username._content" ) private String username;
// ... getter and setter ...
}
이 클래스에 커스텀디시리얼라이저를 쓸 수 있습니다.다음과 같은 경우가 있습니다.
class FlickrAccountJsonDeserializer extends JsonDeserializer<FlickrAccount> {
@Override
public FlickrAccount deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Root root = jp.readValueAs(Root.class);
FlickrAccount account = new FlickrAccount();
if (root != null && root.user != null) {
account.setId(root.user.id);
if (root.user.username != null) {
account.setUsername(root.user.username.content);
}
}
return account;
}
private static class Root {
public User user;
public String stat;
}
private static class User {
public String id;
public UserName username;
}
private static class UserName {
@JsonProperty("_content")
public String content;
}
}
그런 다음 클래스용 디시리얼라이저를 정의해야 합니다.다음과 같이 할 수 있습니다.
@JsonDeserialize(using = FlickrAccountJsonDeserializer.class)
class FlickrAccount {
...
}
커스텀 클래스를 실장하고 싶지 않기 때문에(Username
사용자 이름을 매핑하기 위해 조금 더 우아하지만 여전히 매우 추악한 접근 방식을 사용하였습니다.
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(in);
JsonNode user = node.get("user");
FlickrAccount account = new FlickrAccount();
account.setId(user.get("id").asText());
account.setUsername(user.get("username").get("_content").asText());
기대했던 것만큼 우아하진 않지만 적어도 추한 캐스팅은 다 없앴어요.이 솔루션의 또 다른 장점은 도메인 클래스(FlickrAccount
)는 잭슨 주석으로 오염되지 않았습니다.
@Michaw Ziober의 대답에 근거해, 나는 가장 직접적인 해결책을 사용하기로 결정했다.사용방법@JsonDeserialize
사용자 지정 역직렬화기를 사용한 주석:
@JsonDeserialize( using = FlickrAccountDeserializer.class )
public class FlickrAccount {
...
}
단, 디시리얼라이저에서는 내부 클래스는 사용하지 않습니다.JsonNode
상기와 같이:
class FlickrAccountDeserializer extends JsonDeserializer<FlickrAccount> {
@Override
public FlickrAccount deserialize(JsonParser jp, DeserializationContext ctxt) throws
IOException, JsonProcessingException {
FlickrAccount account = new FlickrAccount();
JsonNode node = jp.readValueAsTree();
JsonNode user = node.get("user");
account.setId(user.get("id").asText());
account.setUsername(user.get("username").get("_content").asText());
return account;
}
}
Simple Module을 사용할 수도 있습니다.
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override public JsonDeserializer<?> modifyDeserializer(
DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (beanDesc.getBeanClass() == YourClass.class) {
return new YourClassDeserializer(deserializer);
}
return deserializer;
}});
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
objectMapper.readValue(json, classType);
난 이렇게 만들었어:
public class FlickrAccount {
private String id;
@JsonDeserialize(converter = ContentConverter.class)
private String username;
private static class ContentConverter extends StdConverter<Map<String, String>, String> {
@Override
public String convert(Map<String, String> content) {
return content.get("_content"));
}
}
}
사용자 이름을 Flickr Account 내의 클래스로 만들고 _content 필드를 지정해야 합니다.
언급URL : https://stackoverflow.com/questions/19158345/custom-json-deserialization-with-jackson
'programing' 카테고리의 다른 글
MongoDb 합계 쿼리 (0) | 2023.03.29 |
---|---|
TypeScript에서 Enum like type을 생성하는 방법 (0) | 2023.03.29 |
Woocommerce 숍 페이지 커스텀템플릿 (0) | 2023.03.29 |
데이터베이스가 다운된 경우에도 Spring 서버를 부팅하려면 어떻게 해야 합니까? (0) | 2023.03.29 |
스프링 부트엔티티 클래스에 옵션 전달 방법 <> (0) | 2023.03.29 |