Como analisar uma string JSON no JsonNode em Jackson?

231

Deve ser tão simples, mas não consigo encontrá-lo depois de tentar por uma hora #embarrasing.

Eu preciso obter uma string JSON, por exemplo {"k1":v1,"k2":v2}, analisada como a JsonNode.

JsonFactory factory = new JsonFactory();
JsonParser jp = factory.createJsonParser("{\"k1\":\"v1\"}");
JsonNode actualObj = jp.readValueAsTree();

java.lang.IllegalStateException: No ObjectCodec defined for the parser, can not deserialize JSON into JsonNode tree

fadmaa
fonte
54
#embarrasing-- Não. Se coisas simples não são simples, o designer da API falhou, não você.
Jameshfisher
@ Resposta do StaxMan no código: JsonFactory factory = new MappingJsonFactory ();
Juan Rojas

Respostas:

371

Uma leve variação na resposta de Richards, mas readTreepode levar uma string, para que você possa simplificá-la para:

ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readTree("{\"k1\":\"v1\"}");
slashnick
fonte
44
Para quem precisa de um ObjectNodeem vez de um JsonNodeusomapper.valueToTree("{\"k1\":\"v1\"}")
Matthew Herbst
5
@MatthewHerbst Na 2.5.1, isso cria um novo nó de texto com a string "{\" k1 \ ": \" v1 \ "}" em vez de analisá-lo como JSON.
Mxew 26/04
69

Você precisa usar um ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
JsonFactory factory = mapper.getJsonFactory(); // since 2.1 use mapper.getFactory() instead
JsonParser jp = factory.createJsonParser("{\"k1\":\"v1\"}");
JsonNode actualObj = mapper.readTree(jp);

Mais documentação sobre a criação de analisadores pode ser encontrada aqui .

Richard Fearn
fonte
É possível pegar o JsonNode, modificá-lo um pouco e chamar o mapper.readValue (nó, classe); e sair de uma aula?
Portforwardpodcast
1
Sim. Existe até um apelido para isso mapper.treeToValue(). Mas readValue()também funciona.
23413 StaxMan
O link parece estar quebrado
manuna
28

Uma terceira variante:

ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readValue("{\"k1\":\"v1\"}", JsonNode.class);
qerub
fonte
O que a passagem no JsonNode.class realmente trouxe você aqui?
David
3
@ David: Nada, então a variante de slashnick é obviamente melhor se você só quer um JsonNode. No entanto, você geralmente não quer um JsonNode, então eu queria mostrar como dizer a Jackson que tipo de valor você deseja.
Qerub
Para mim, a passagem JsonNodeera aparentemente necessária para impedir que Jackson a desserializasse como outra coisa - o que teria falhado.
Cory Klein
5

A resposta de Richard está correta. Como alternativa, você também pode criar um MappingJsonFactory(in org.codehaus.jackson.map) que sabe onde encontrar ObjectMapper. O erro que você recebeu foi porque o regular JsonFactory(do corepacote) não tem dependência de ObjectMapper(que está no mapperpacote).

Mas geralmente você apenas usa ObjectMappere não se preocupa JsonParserou com outros componentes de baixo nível - eles serão necessários apenas se você desejar vincular partes do fluxo ou fazer manuseio de baixo nível.

StaxMan
fonte
3
import com.github.fge.jackson.JsonLoader;
JsonLoader.fromString("{\"k1\":\"v1\"}")
== JsonNode = {"k1":"v1"}
pdxleif
fonte
0

Nova abordagem para a pergunta antiga. Uma solução que funciona a partir do java 9+

ObjectNode agencyNode = new ObjectMapper().valueToTree(Map.of("key", "value"));

é mais legível e fácil de manter para objetos complexos. Ej

Map<String, Object> agencyMap = Map.of(
        "name", "Agencia Prueba",
        "phone1", "1198788373",
        "address", "Larrea 45 e/ calligaris y paris",
        "number", 267,
        "enable", true,
        "location", Map.of("id", 54),
        "responsible", Set.of(Map.of("id", 405)),
        "sellers", List.of(Map.of("id", 605))
);
ObjectNode agencyNode = new ObjectMapper().valueToTree(agencyMap);
Manuel Ortiz
fonte