Estou tentando incluir JSON bruto dentro de um objeto Java quando o objeto é (des) serializado usando Jackson. Para testar essa funcionalidade, escrevi o seguinte teste:
public static class Pojo {
public String foo;
@JsonRawValue
public String bar;
}
@Test
public void test() throws JsonGenerationException, JsonMappingException, IOException {
String foo = "one";
String bar = "{\"A\":false}";
Pojo pojo = new Pojo();
pojo.foo = foo;
pojo.bar = bar;
String json = "{\"foo\":\"" + foo + "\",\"bar\":" + bar + "}";
ObjectMapper objectMapper = new ObjectMapper();
String output = objectMapper.writeValueAsString(pojo);
System.out.println(output);
assertEquals(json, output);
Pojo deserialized = objectMapper.readValue(output, Pojo.class);
assertEquals(foo, deserialized.foo);
assertEquals(bar, deserialized.bar);
}
O código produz a seguinte linha:
{"foo":"one","bar":{"A":false}}
O JSON é exatamente como eu quero que as coisas pareçam. Infelizmente, o código falha com uma exceção ao tentar ler o JSON de volta para o objeto. Aqui está a exceção:
org.codehaus.jackson.map.JsonMappingException: Não é possível desserializar a instância de java.lang.String do token START_OBJECT em [Fonte: java.io.StringReader@d70d7a; linha: 1, coluna: 13] (por meio da cadeia de referência: com.tnal.prism.cobalt.gather.testing.Pojo ["bar"])
Por que Jackson funciona bem em uma direção, mas falha na direção oposta? Parece que ele deve ser capaz de obter sua própria saída como entrada novamente. Eu sei que o que estou tentando fazer é pouco ortodoxo (o conselho geral é criar um objeto interno para bar
que tenha uma propriedade chamada A
), mas não quero interagir com esse JSON de forma alguma. Meu código está atuando como uma passagem para este código - quero pegar este JSON e enviá-lo de volta sem tocar em nada, porque quando o JSON muda, não quero que meu código precise de modificações.
Obrigado pelo conselho.
EDIT: Tornou Pojo uma classe estática, o que estava causando um erro diferente.
fonte
Seguindo a resposta de @StaxMan , fiz os seguintes trabalhos como um encanto:
E, para ser fiel à pergunta inicial, fica aqui o teste de trabalho:
fonte
getJson()
que retorna umString
afinal. Se ele apenas retornasse oJsonNode
que foi configurado através do setter, seria serializado conforme desejado, não?node.asText()
retorna um valor vazio ao ladotoString()
.Consegui fazer isso com um desserializador personalizado (cortar e colar a partir daqui )
fonte
@JsonRawValue
@JsonSetter pode ajudar. Veja meu exemplo ('dados' devem conter JSON não analisado):
fonte
Além da ótima resposta de Roy Truelove , esta é como injetar o desserializador personalizado em resposta à aparência de :
@JsonRawValue
fonte
Este é um problema com suas classes internas. A
Pojo
classe é uma classe interna não estática de sua classe de teste e Jackson não pode instanciar essa classe. Portanto, ele pode serializar, mas não desserializar.Redefina sua classe assim:
Observe a adição de
static
fonte
Esta solução fácil funcionou para mim:
Então, consegui armazenar o valor bruto do JSON na variável rawJsonValue e não foi problema desserializá-lo (como objeto) com outros campos de volta para JSON e enviar por meio do meu REST. Usar @JsonRawValue não me ajudou porque o JSON armazenado foi desserializado como String, não como objeto, e não era isso que eu queria.
fonte
Isso funciona até mesmo em uma entidade JPA:
Idealmente, o ObjectMapper e mesmo JsonFactory são do contexto e são configurados de forma a manipular seu JSON corretamente (padrão ou com valores não padrão como floats 'Infinity' por exemplo).
fonte
JsonNode.toString()
documentaçãoMethod that will produce developer-readable representation of the node; which may <b>or may not</b> be as valid JSON.
Portanto, esta implementação é realmente muito arriscada.JsonNode.asText()
interno e produzirá o Infinity e outros valores JSON não padrão.Aqui está um exemplo completo de como usar os módulos Jackson para fazer o
@JsonRawValue
trabalho de ambas as maneiras (serialização e desserialização):Então você pode registrar o módulo depois de criar
ObjectMapper
:fonte
org.codehaus.jackson
pacote sem perceber. Certifique-se de que todas as suas importações vêmcom.fasterxml.jackson
.Eu tinha exatamente o mesmo problema. Encontrei a solução neste post: Analisar árvore JSON para classe simples usando Jackson ou suas alternativas
Confira a última resposta. Ao definir um configurador personalizado para a propriedade que recebe um JsonNode como parâmetro e chama o método toString no jsonNode para definir a propriedade String, tudo funciona.
fonte
Usar um objeto funciona bem em ambos os sentidos ... Este método tem um pouco de sobrecarga desserializando o valor bruto em duas vezes.
RawHello.java
RawJsonValue.java
fonte
Tive um problema parecido, mas usando uma lista com muitos itens JSON (
List<String>
).Eu gerenciei a serialização usando a
@JsonRawValue
anotação. Mas, para a desserialização, tive que criar um desserializador personalizado com base na sugestão de Roy.Abaixo você pode ver o meu desserializador "Lista".
fonte