Jackson JSON дает исключение на коллекцию вложенного класса
Jackson JSON не имеет проблем с сериализацией / десериализацией этого класса:
public class MyClass {
public class Nested {
public String string;
public Nested() {}
}
public Nested nestedVar;
}
Но на этот раз:
public class MyClass {
class Nested {
public String string;
public Nested() {}
}
public Nested nestedVar;
public List<Nested> nestedList;
}
Я получаю это исключение при десериализации:
Ком.fasterxml.Джексон.база данных.JsonMappingException: не найден подходящий конструктор для type [simple type, class test.MyClass$Nested]: не удается создать экземпляр из объекта JSON (отсутствует конструктор по умолчанию или создатель, или, возможно, нужно добавить / включить информацию о типе?) в [источник: java.io.StringReader@26653222; строка: 1, столбец: 48] (через цепочку ссылок: тест.MyClass ["nestedList"] - > java.утиль.ArrayList[0])
В первом случае Джексон не имеет проблем с экземпляром вложенного класса, но не во втором случае.
Должен ли я написать пользовательский десериализатор?
Тестовый код (Джексон 2.6.3):
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
public class ATest {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
StringWriter sw = new StringWriter();
MyClass myClass = new MyClass();
MyClass.Nested nestedVar = myClass.new Nested();
List<MyClass.Nested> nestedList = new ArrayList<>();
nestedList.add(nestedVar);
myClass.nestedList =nestedList;
myClass.nestedVar = nestedVar;
mapper.writeValue(sw, myClass);
System.out.println(sw.toString());
StringReader sr = new StringReader(sw.toString());
MyClass z = mapper.readValue(sr, MyClass.class);
}
}
1 ответ:
Похоже, что распознавание нестатических внутренних классов выполняется там, где они являются свойствами непосредственно на содержащем их Бобе (
Обратите внимание, что вы все еще можете использовать Джексона для чтения свойствBeanDeserializerBase.java
строка 476 в 2.6.3). Так что промежуточный десериализатор коллекции прошел бы мимо этого. Пользовательский десериализатор, вероятно, самый простой вариант здесь.Nested
и просто реализовать его построение самостоятельно, в пользовательском десериализаторе только , используемом при десериализации спискаNested
объекты.Чтобы сделать это, аннотируйте список следующим образом:
@JsonDeserialize(contentUsing = NestedDeserializer.class) public List<Nested> nestedList;
А затем используйте пользовательский десериализатор, который будет:
Посмотрите на контекст синтаксического анализа при вызове, чтобы найти содержащий экземпляр
MyClass
.Инкапсулируйте десериализатор по умолчанию / корневого уровня
Nested
, чтобы делегировать ему работу по десериализации содержимого.Например:
public static final class NestedDeserializer extends StdDeserializer<MyClass.Nested> implements ResolvableDeserializer { private JsonDeserializer<Object> underlyingDeserializer; public NestedDeserializer() { super(MyClass.Nested.class); } @Override public void resolve(DeserializationContext ctxt) throws JsonMappingException { underlyingDeserializer = ctxt .findRootValueDeserializer(ctxt.getTypeFactory().constructType(MyClass.Nested.class)); } @Override public Nested deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonStreamContext ourContext = p.getParsingContext(); JsonStreamContext listContext = ourContext.getParent(); JsonStreamContext containerContext = listContext.getParent(); MyClass container = (MyClass) containerContext.getCurrentValue(); MyClass.Nested value = container.new Nested(); // note use of three-argument deserialize method to specify instance to populate underlyingDeserializer.deserialize(p, ctxt, value); return value; } }