#java #json #jackson
#java #json #джексон
Вопрос:
В настоящее время у меня есть объект Join, для которого я пытаюсь написать пользовательский десериализатор. Мы сохраняем ключ базы данных и имя Java-класса объекта в JSON, и это выглядит примерно так:
{
"@class": "com.mysite.data.ExpertFor",
"id": "expert-for-1",
"leftId": "user-profile-1",
"leftType": "com.mysite.data.UserProfile",
"rightId": "hotel-1",
"rightType": "com.mysite.data.Hotel"
}
Мы делаем это, чтобы нам не нужно было сохранять фактический объект в базе данных; скорее, мы извлекаем его при десериализации. Проблема в том, что мой пользовательский сериализатор не может видеть @class
элемент в потоке JSON — следовательно, он не может правильно создать экземпляр необходимого объекта после считывания всех данных. Вот мой десериализатор:
public Join deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
Map<String, Object> values = new HashMap<String, Object>();
// Loop through the JSON document and pull out all
// the values and put them into the map
JsonToken token = jp.nextToken();
while (token != JsonToken.END_OBJECT) {
logger.info("Non-data field: [" token "], name is [" jp.getCurrentName() "], text is [" jp.getText() "]");
if (token == JsonToken.VALUE_STRING) {
values.put(jp.getCurrentName(), jp.getText());
}
token = jp.nextToken();
}
// remainder of code omitted for brevity
}
Теперь строки Log4J, которые записываются в журналы, показывают все соответствующие элементы JSON, которые я ожидал бы, КРОМЕ @class
элемента
Data field: [VALUE_STRING], name is [id], text is [expert-for-1]
Data field: [VALUE_STRING], name is [leftId], text is [user-profile-1]
Data field: [VALUE_STRING], name is [rightId], text is [hotel-1]
Data field: [VALUE_STRING], name is [leftType], text is [com.mysite.data.UserProfile]
Data field: [VALUE_STRING], name is [rightType], text is [com.mysite.data.Hotel]
Я попытался добавить @JsonTypeInfo
аннотацию к своему классу, например
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
но, похоже, элемент «проглатывается» кодом, и я не знаю, как к нему добраться. И мне это нужно, потому что любые потомки Join
должны быть десериализованы. Вот некоторая дополнительная информация об иерархии, в которой находится этот класс:
Добавление аннотации @TypeInfo было сделано только для того, чтобы попытаться посмотреть, что происходит. Я получаю такое же поведение, независимо от того, есть оно или нет. Что действительно странно, так это то, что мы используем ту же базовую функциональность в других классах, которым требуется пользовательская десериализация, и они отлично видят @class . Вот иерархия этого:
@JsonAutoDetect(value = JsonMethod.NONE)
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
public abstract class TaggedObject implements Serializable {
...
}
и тогда у нас есть DataObject
public abstract class DataObject extends TaggedObject {
...
}
и тогда у нас есть наш класс Join:
@JsonSerialize(using = Join.Serializer.class)
@JsonDeserialize(using = Join.Deserializer.class)
public abstract class Join<L, R> extends DataObject {
...
}
Я бы подумал, что @JsonTypeInfo будет унаследован от TaggedObject, но здесь он не виден, тогда как он виден другими классами в той же иерархии.
У кого-нибудь есть идеи о том, как я могу захватить класс этого объекта, чтобы я мог создать соответствующий объект? Чего мне здесь не хватает?
Ответ №1:
Вы не должны пытаться вручную обрабатывать @class И объявлять его обрабатываемым Jackson с помощью @JsonTypeInfo — либо позвольте Jackson полностью обработать его (что он может и будет делать), либо удалите anntoation и обработайте все вручную.
Ответ №2:
используя модель дерева Джексона, следующий код выводит недостающие @class
:
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(jsonString);
Iterator<String> iterator = root.fieldNames();
while (iterator.hasNext()) {
String fieldName = iterator.next();
String fieldValue = root.get(fieldName).asText();
System.out.println("name is [" fieldName "], text is [" fieldValue "]");
}
Вывод:
name is [@class], text is [com.mysite.data.ExpertFor]
name is [id], text is [expert-for-1]
name is [leftId], text is [user-profile-1]
name is [leftType], text is [com.mysite.data.UserProfile]
name is [rightId], text is [hotel-1]
name is [rightType], text is [com.mysite.data.Hotel]
Комментарии:
1. Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему он решает проблему, улучшит долгосрочную ценность ответа.