Jackson deserialization : deserializable 개체의 필드에 주석과 함께 값을 삽입 할 수 있습니까?
역 직렬화하려면 다음과 같은 개체가 있습니다.
public class RelationsInput {
Relation relation1;
Relation relation2;
}
클래스 Relation
는 다음과 같습니다.
public class Relation {
RelationType relationtype;
... (more fields)
}
RelationType
enum이며 다른 모든 항목은 deserialize되는 값이 아닙니다.
relationType
클래스의 필드에 주석이있는 필드 의 열거 형 값을 "주입"할 수 RelationInput
있습니까? 다음과 같이
public class RelationsInput {
@RelationType(RelationType.OWNER)
Relation owner;
@RelationType(RelationType.TENANT)
Relation tenant;
}
Jackson이 이와 같은 것을 제공합니까?
답변
com.fasterxml.jackson.databind.deser.ContextualDeserializer
인터페이스로 사용자 정의 디시리얼라이저를 구현할 수 있습니다 . 컨텍스트로 deserialiser 인스턴스를 만들 수 있습니다.
아래 예를 참조하십시오.
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.Data;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class JsonContextualDeserializerApp {
public static void main(String[] args) throws IOException {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = JsonMapper.builder().build();
RelationsInput info = mapper.readValue(jsonFile, RelationsInput.class);
System.out.println(info.toString());
}
}
@Data
class RelationsInput {
@JsonDeserialize(using = RelationStdDeserializer.class)
@RelationTypeInfo(RelationType.OWNER)
private Relation owner;
@JsonDeserialize(using = RelationStdDeserializer.class)
@RelationTypeInfo(RelationType.TENANT)
private Relation tenant;
}
@Data
class Relation {
private int id;
private RelationType relationtype;
}
enum RelationType {OWNER, TENANT}
@Retention(RetentionPolicy.RUNTIME)
@interface RelationTypeInfo {
RelationType value();
}
class RelationStdDeserializer extends StdDeserializer<Relation> implements ContextualDeserializer {
private RelationType propertyRelationType;
public RelationStdDeserializer() {
this(null);
}
public RelationStdDeserializer(RelationType relationType) {
super(Relation.class);
this.propertyRelationType = relationType;
}
@Override
public Relation deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonDeserializer<Object> deser = ctxt.findRootValueDeserializer(ctxt.getTypeFactory().constructType(Relation.class));
Relation instance = (Relation) deser.deserialize(p, ctxt);
if (this.propertyRelationType != null) {
instance.setRelationtype(this.propertyRelationType);
}
return instance;
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
RelationTypeInfo typeInfo = property.getMember().getAllAnnotations().get(RelationTypeInfo.class);
return new RelationStdDeserializer(typeInfo.value());
}
}
페이로드에 대한 위 코드 :
{
"owner": {
"id": 1
},
"tenant": {
"id": 2
}
}
인쇄물:
RelationsInput(owner=Relation(id=1, relationtype=OWNER), tenant=Relation(id=2, relationtype=TENANT))
또한보십시오:
- Jackson을 사용하여 문자열 또는 개체로 역 직렬화
- Jackson Custom Deserializer에 종속성을 주입하는 방법
- Jackson-내부 개체 목록을 하나의 상위 수준 목록으로 역 직렬화
나는 그런 것이없는 것이 두렵다. 커스텀 디시리얼라이저를 사용할 수있는 것과 같은 주석을 사용하려는 경우. 먼저 다음과 같이 작성하십시오.
@RequiredArgsConstructor
public abstract class RelationTypeDeserializer extends JsonDeserializer<Relation> {
private final RelationType relationType;
@Override
public Relation deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
Relation r = p.readValueAs(Relation.class);
r.setRelationtype(relationType);
return r;
}
}
그런 다음 실제 구현하십시오.
public class OwnerDeserializer extends RelationTypeDeserializer {
public OwnerDeserializer() {
super(RelationType.OWNER);
}
}
과
public class TenantDeserializer extends RelationTypeDeserializer {
public TenantDeserializer() {
super(RelationType.TENANT);
}
}
그런 다음 다음과 같이 사용하십시오.
@Getter @Setter
public class RelationsInput {
@JsonDeserialize(using = OwnerDeserializer.class)
private Relation owner;
@JsonDeserialize(using = TenantDeserializer.class)
private Relation tenant;
}
요청한 작업을 수행하면 RelationType 필드에 대해 항상 동일한 값을 갖게됩니다. 어쨌든 한 가지 가능한 솔루션은 다음과 같이 개인화 된 serializer-deserializer를 사용하는 것입니다.
public class RelationTypeJsonSerializer extends JsonSerializer<RelationType> {
@Override
public void serialize(RelationType value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
String string = value.toString();//or something like that, convert the enum to string as you like
gen.writeString(string);
}
}
public class RelationTypeJsonDeserializer extends JsonDeserializer<RelationType> {
@Override
public RelationType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String toString = p.getCodec().readValue(p, String.class);//read the value as string
return RelationType.build(toString);//convert back the value to object, use switch if needed)
}
}
ObjectMapper om = new ObjectMapper();
SimpleModule localDateModule = new SimpleModule("RelationType Module");
localDateModule.addSerializer(RelationType.class, new RelationTypeJsonSerializer());
localDateModule.addDeserializer(RelationType.class, new RelationTypeJsonDeserializer());
om.registerModule(localDateModule);
열거 형을 앞뒤로 변환하려면 다음과 같이 map <String, RelationType>, 매우 간단하고 완벽하게 작동하는 것이 좋습니다.
Map<String, RelationType> map = new HashMap<String, RelationType>();
map.put("Some Type", RelationType.SOME_TYPE);
map.put("Some Other Type", RelationType.SOME_OTHER_TYPE);
그리고 직렬화하려면 get (string)을 사용하고 deserialize하려면 get (value)를 사용합니다 (일부 값의 키 찾기) 이것은 기본 serializer-deserializer가없는 것을 직렬화-역 직렬화하려는 경우의 일반적인 예입니다. 자세한 내용 은 Jackson을 사용하여 Color Java 클래스를 JSON으로 구문 분석하는 방법은 무엇입니까?