다음과 같은 클래스 계층 구조가 있습니다.
interface MyEntity {
...
}
class MyEntityRef {
String id;
...
}
class MyEntityImpl {
String id;
String name;
...
}
의 인스턴스를 MyEntityRef
일반 문자열로 직렬화하고 싶습니다 .
"someEntityId"
및 MyEntityImpl
일반 개체의 인스턴스 :
{
id: "someEntityId",
name: "someName"
}
그리고 그 반대의 경우 : a를 역 직렬화 할 때 json이 일반 문자열 인 경우 a로, 일반 json 객체 인 경우 MyEntity
a로 역 직렬화되기를 원합니다 .MyEntityRef
MyEntityImpl
내 실제 코드에는 여러 유형의 엔티티 (예 : 다중 X
/ XRef
/ XImpl
트리플)가 있습니다. 이러한 모든 항목을 나열하지 않으려 고 인터페이스에 다음과 같이 주석을 달았습니다.
@MyEntityAnnotation(ref=MyEntityRef.class, impl=MyEntityImpl.class)
interface MyEntity {
...
}
이 주석 정보를 기반으로하는 모든 엔티티에 대해 위에서 설명한 직렬화 / 역 직렬화를 해결하는 방법을 알아내는 사람에게 추가 포인트가 주어집니다.
내가 시도한 것 : 내가 생각할 수있는 모든 것 ( SimpleDeserializers
/ SimpleSerializers
, BeanDeserializerModifier
/ BeanSerializerModifier
, TypeSerializer
/ TypeDeserializer
)
이것은 기술적으로 커스텀 디시리얼라이저 (아래 참조)를 사용하여 가능하지만 리플렉션 및 유형이 안전하지 않은 변환을 사용하면 매우 복잡하고 약간 어색해 보입니다. 양방향 참조를 사용하면 더 나은 운을 얻을 수 있지만 모델을 변경해야 할 수도 있습니다.
다음은 사용자 지정 deserializer를 기반으로 한 예입니다.
public class JacksonEntity {
@Retention(RetentionPolicy.RUNTIME)
static public @interface MyAnnotation {
Class<?> ref();
Class<?> impl();
}
@MyAnnotation(ref = MyEntityRef.class, impl = MyEntityImpl.class)
static public interface MyEntity {
}
static public class MyEntityRef implements MyEntity {
private final String id;
public MyEntityRef(String id) {
this.id = id;
}
@JsonValue
public String getId() {
return id;
}
@Override
public String toString() {
return "MyEntityRef{" +
"id='" + id + '\'' +
'}';
}
}
static public class MyEntityImpl implements MyEntity {
public final String id;
public final String name;
@JsonCreator
public MyEntityImpl(@JsonProperty("id") String id, @JsonProperty("name") String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "MyEntityImpl{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
static public class MyDeserializer extends JsonDeserializer<Object> {
private final Class<?> refType;
private final Class<?> implType;
public MyDeserializer(MyAnnotation annotation) {
this.refType = annotation.ref();
this.implType = annotation.impl();
}
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
JsonToken jsonToken = jp.getCurrentToken();
if (jsonToken == JsonToken.START_OBJECT) {
return jp.readValueAs(implType);
} else if (jsonToken == JsonToken.VALUE_STRING) {
try {
return refType.getConstructor(String.class).newInstance(jp.getValueAsString());
} catch (Exception e) {
throw new UnsupportedOperationException();
}
}
return null;
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc,
JsonDeserializer<?> deserializer) {
MyAnnotation myAnnotation = beanDesc.getClassAnnotations().get(MyAnnotation.class);
// it must be interface, otherwise getting meeting recursion
if (myAnnotation != null && beanDesc.getBeanClass().isInterface()) {
return new MyDeserializer(myAnnotation);
}
return super.modifyDeserializer(config, beanDesc, deserializer);
}
});
mapper.registerModule(module);
MyEntityRef ref = new MyEntityRef("id1");
MyEntityImpl impl = new MyEntityImpl("id2", "value");
String jsonRef = mapper.writeValueAsString(ref);
System.out.println(jsonRef);
String jsonImpl = mapper.writeValueAsString(impl);
System.out.println(jsonImpl);
System.out.println(mapper.readValue(jsonRef, MyEntity.class));
System.out.println(mapper.readValue(jsonImpl, MyEntity.class));
}
}
산출:
"id1"
{"id":"id2","name":"value"}
MyEntityRef{id='id1'}
MyEntityImpl{id='id2', name='value'}
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다