Gson에서 추상 클래스 직렬화 취소
JSON 형식의 트리 오브젝트가 있어 Gson과 역직렬화하려고 합니다.각 노드에는 개체 유형 Node의 필드로 하위 노드가 포함됩니다.노드는 인터페이스이며, 몇 가지 구체적인 클래스 구현이 있습니다.디시리얼라이제이션 프로세스 중에 노드가 어떤 타입에 속하는지 모르는 경우 노드를 디시리얼라이제이션할 때 어떤 콘크리트 클래스를 구현해야 하는지 Gson과 어떻게 통신할 수 있습니까?각 노드에는 유형을 지정하는 구성원 필드가 있습니다.오브젝트가 시리얼화 되어 있을 때 필드에 접속하여 Gson에게 어떻게든 타입을 전달할 수 있는 방법이 있습니까?
감사합니다!
커스텀 JsonDeserializer 추가를 권장합니다.Node
s:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Node.class, new NodeDeserializer())
.create();
에 액세스 할 수 있습니다.JsonElement
역직렬화기 메서드에서 노드를 나타내며, 그것을 a로 변환한다.JsonObject
및 유형을 지정하는 필드를 가져옵니다.그런 다음 올바른 유형의 인스턴스를 만들 수 있습니다.Node
그걸 근거로 해서.
JSON Serializer와 JSONDeserializer를 모두 등록해야 합니다.또, 다음의 방법으로, 모든 인터페이스에 범용 어댑터를 실장할 수도 있습니다.
- [During Serialization] : 실제 inpact 클래스 유형의 META-info를 추가합니다.
- 디시리얼라이제이션 중 : 메타정보를 취득하여 해당 클래스의 JSONDeserailize를 호출합니다.
이것은 제가 지금까지 사용해 온 실장이고, 잘 동작하고 있습니다.
public class PropertyBasedInterfaceMarshal implements
JsonSerializer<Object>, JsonDeserializer<Object> {
private static final String CLASS_META_KEY = "CLASS_META_KEY";
@Override
public Object deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext)
throws JsonParseException {
JsonObject jsonObj = jsonElement.getAsJsonObject();
String className = jsonObj.get(CLASS_META_KEY).getAsString();
try {
Class<?> clz = Class.forName(className);
return jsonDeserializationContext.deserialize(jsonElement, clz);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
@Override
public JsonElement serialize(Object object, Type type,
JsonSerializationContext jsonSerializationContext) {
JsonElement jsonEle = jsonSerializationContext.serialize(object, object.getClass());
jsonEle.getAsJsonObject().addProperty(CLASS_META_KEY,
object.getClass().getCanonicalName());
return jsonEle;
}
}
그러면 다음과 같이 모든 인터페이스에 대해 이 어댑터를 등록할 수 있습니다.
Gson gson = new GsonBuilder()
.registerTypeAdapter(IInterfaceOne.class,
new PropertyBasedInterfaceMarshal())
.registerTypeAdapter(IInterfaceTwo.class,
new PropertyBasedInterfaceMarshal()).create();
비수집 타입, 특히 콘크리트 타입을 시리얼화에 사용하고 인터페이스 타입을 역직렬화에 사용하는 상황에서는 이 기능이 작동하지 않습니다.즉, 인터페이스를 실장하고 있는 단순한 클래스가 있어, 구체적인 클래스를 시리얼화한 후, 시리얼화할 인터페이스를 지정하면, 회복 불가능한 상황이 됩니다.
위의 예에서는 타입 어댑터는 인터페이스에 대해 등록되지만 concrete 클래스를 사용하여 시리얼화하면 사용되지 않습니다.즉, CLASS_META_KEY 데이터는 설정되지 않습니다.
어댑터를 계층형 어댑터로 지정하면(따라서 gson에게 계층 내 모든 유형에 어댑터를 사용하도록 지시함으로써), 시리얼라이저는 계속 자신을 호출하기 때문에 무한 루프가 됩니다.
인터페이스의 구체적인 실장으로부터 시리얼화해, 인터페이스와 Instance Creator만을 사용해 역시리얼화하는 방법을 아는 사람이 있습니까?
기본적으로는 gson은 구체적인 인스턴스를 만들지만 해당 필드는 설정하지 않습니다.
문제는 여기에 기록됩니다.
http://code.google.com/p/google-gson/issues/detail?id=411&q=interface
위의 내용을 조금 수정하고 싶습니다.
public class PropertyMarshallerAbstractTask implements JsonSerializer<Object>, JsonDeserializer<Object> {
private static final String CLASS_TYPE = "CLASS_TYPE";
@Override
public Object deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
JsonObject jsonObj = jsonElement.getAsJsonObject();
String className = jsonObj.get(CLASS_TYPE).getAsString();
try {
Class<?> clz = Class.forName(className);
return jsonDeserializationContext.deserialize(jsonElement, clz);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
@Override
public JsonElement serialize(Object object, Type type, JsonSerializationContext jsonSerializationContext) {
Gson gson = new Gson(); //without this line it will not work
gson.toJson(object, object.getClass()); //and this one
JsonElement jsonElement = gson.toJsonTree(object); //it needs to replace to another method...toJsonTree
jsonElement.getAsJsonObject().addProperty(CLASS_TYPE, object.getClass().getCanonicalName());
return jsonElement;
}
}
그런 다음 사용합니다.
Gson gson = new GsonBuilder()
.registerTypeAdapter(AbstractTask.class, new PropertyMarshallerOfAbstractTask())
.create();
그런 다음 List(추상 태스크에서 상속받은 비추상 클래스)를 Json으로 해석할 수 있습니다.
그리고 그것은 반대 방향으로 작용한다.
List<AbstractTask> abstractTasks = gson.fromJson(json, new TypeToken<List<AbstractTask>>(){}.getType());
쓰셔야 돼요.TypeToken
구글 지슨합니다.
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, foo Type);
gson.fromJson(json, fooType);
언급URL : https://stackoverflow.com/questions/3629596/deserializing-an-abstract-class-in-gson
'source' 카테고리의 다른 글
파일에 쓰지 않고 Jackson을 사용하여 Map을 JSON 표현으로 변환할 수 있는 방법이 있습니까? (0) | 2023.03.27 |
---|---|
JSON 개체를 TypeScript 개체로 해석하는 방법 (0) | 2023.03.27 |
{% 확장 '... %} 조건부로 만들 수 있는 방법이 있습니까? - 장고 (0) | 2023.03.27 |
React.js는 체크박스 상태를 변경할 수 없습니다. (0) | 2023.03.22 |
Typescript는 무엇을 의미합니까? (0) | 2023.03.22 |