Джексон бросает JsonMappingException при десериализации; требует однострочный конструктор?

Другой вопрос, но он относится к этому: Дезабилизация JSON с помощью Jackson - Почему JsonMappingException "Нет подходящего конструктора" ?

На этот раз я получаю другую ошибку, а именно, что десериализатор Джексона жалуется, что у меня нет метода "single-String constructor/ factory" в моем классе ProtocolContainer.

Однако, если я добавлю однострочный конструктор, например:

public ProtocolContainer(String json) {}

исключение действительно исчезает, но ProtocolContainer, который я ожидал там, есть все "пустые", т.е. все его свойства находятся в их исходном состоянии и не заполняются в соответствии со строкой JSON.

Почему это?

Я уверен, что вам не нужен конструктор с одним строком, и если вы это сделаете, вам не нужно будет заполнять свойства в этом конструкторе, верно?

=)

Ответ 1

О, так что еще раз я узнал ответ ПОСЛЕ того, как я разместил этот вопрос (хотя я и пробовал много вещей перед публикацией).

Что я сделал для решения этой проблемы, так это использовать аннотацию @JsonCreator. Я просто аннотировал мой статический метод Create, например:

@JsonCreator
public static ProtocolContainer Create(String jsonString)
{

    ProtocolContainer pc = null;
    try {
        pc = mapper.readValue(jsonString, ProtocolContainer.class);
    } catch (JsonParseException|JsonMappingException|IOException e) {
        // handle
    }

    return pc;
}

И тогда проблема решена.

Ответ 2

Исключение указывает на то, что значение JSON у вас есть String, что-то вроде:

{ "protocol" : "http" }

или, возможно, "JSON с двойными кавычками":

"\"{\"property\":\"value\"}\"

при попытке привязки как:

ProtocolContainer p = mapper.readValue(json, ProtocolContainer.class);

и в этом случае у Jackson нет свойств для отображения, просто String. И в этом случае он действительно требует либо настраиваемого десериализатора, либо метода создателя. Творческие методы - это либо конструкторы с одним строковым аргументом, либо однострочные аргументы статические методы: разница состоит в том, что только конструкторы могут быть автоматически обнаружены (это просто практическое сокращение, поскольку может быть только один такой конструктор, но несколько статические методы).

Ваше решение действительно работает, просто подумал, что я расскажу немного о том, что происходит.

Прочитав это во второй раз, кажется, что у вас есть вещи с двойным цитированием (JSON в JSON): еще одна вещь, которую следует учитывать, - это получить простой JSON, если это возможно. Но, возможно, это трудно сделать.

Ответ 3

У меня была та же проблема. Для меня решение заключалось в том, чтобы перейти от передачи метода String к convertValue в метод InputStream к readValue:

// Instead of this:
String jsonString = "..."
ProtocolContainer pc = mapper.convertValue(jsonString, ProtocolContainer.class);

// ... do this:
String jsonString = "..."
InputStream is = new StringInputStream(jsonString);
ProtocolContainer pc = mapper.readValue(is, ProtocolContainer.class);

Ответ 4

Кажется, что вы отправляете на сервер строку вместо объекта.

Вместо отправки строки, подлежащей анализу на стороне сервера, вы можете сделать это проще, просто отправив JSON.parse(stringObject), и Джексон будет десериализовать ее как обычно.