Jackson com JSON: campo não reconhecido, não marcado como ignorável


674

Preciso converter uma certa string JSON em um objeto Java. Estou usando o Jackson para manipulação de JSON. Não tenho controle sobre o JSON de entrada (li de um serviço da web). Esta é a minha entrada JSON:

{"wrapper":[{"id":"13","name":"Fred"}]}

Aqui está um caso de uso simplificado:

private void tryReading() {
    String jsonStr = "{\"wrapper\"\:[{\"id\":\"13\",\"name\":\"Fred\"}]}";
    ObjectMapper mapper = new ObjectMapper();  
    Wrapper wrapper = null;
    try {
        wrapper = mapper.readValue(jsonStr , Wrapper.class);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("wrapper = " + wrapper);
}

Minha classe de entidade é:

public Class Student { 
    private String name;
    private String id;
    //getters & setters for name & id here
}

Minha classe Wrapper é basicamente um objeto de contêiner para obter minha lista de alunos:

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

Eu continuo recebendo esse erro e o "wrapper" retorna null. Não tenho certeza do que está faltando. Alguém pode ajudar por favor?

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: 
    Unrecognized field "wrapper" (Class Wrapper), not marked as ignorable
 at [Source: java.io.StringReader@1198891; line: 1, column: 13] 
    (through reference chain: Wrapper["wrapper"])
 at org.codehaus.jackson.map.exc.UnrecognizedPropertyException
    .from(UnrecognizedPropertyException.java:53)

2
Eu encontrei este útil para evitar a criação de uma classe de invólucro: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});e depoisStudent myStudent = dummy.get("wrapper");
pulkitsinghal

6
O JSON deve ter a seguinte aparência: String jsonStr = "{\" students \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}}"; se você está esperando Wrapper objeto em seu pedido repouso pós
Dmitri Algazin

2
Relacionado (mas diferente) pergunta: Ignorando novos campos na JSON objetos usando Jackson
sleske

5
E, aliás, a maioria das respostas a essa pergunta realmente responde a uma pergunta diferente, a saber, uma semelhante à que eu ligo acima.
sleske

4
A maioria das respostas ajuda a escovar o problema sob o tapete, em vez de resolvê-lo :(
NoobEditor 13/18

Respostas:


989

Você pode usar a anotação em nível de classe de Jackson:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Ele ignorará todas as propriedades que você não definiu no seu POJO. Muito útil quando você está procurando apenas algumas propriedades no JSON e não deseja escrever o mapeamento inteiro. Mais informações no site de Jackson . Se você deseja ignorar qualquer propriedade não declarada, escreva:

@JsonIgnoreProperties(ignoreUnknown = true)

9
Ariel, existe alguma maneira de declarar isso externo à classe?
quer

4
Estou serializando classes que não possuo (não posso modificar). Em uma exibição, eu gostaria de serializar com um determinado conjunto de campos. Em outra visão, quero um conjunto diferente de campos serializados (ou talvez renomeie as propriedades no JSON).
Jon Lorusso

11
Devo acrescentar que você precisa fazer o (ignoreUnknown = true)ao anotar sua classe de outra forma não vai funcionar
necromante

85
Julián, essa não é a resposta correta para a pergunta do OP. No entanto, suspeito que as pessoas venham aqui, porque pesquisam no Google como ignorar propriedades não definidas no POJO e este é o primeiro resultado. Por isso, acabam votando na resposta de Suresh (foi o que aconteceu comigo). Embora a pergunta original não tenha nada a ver com querer ignorar propriedades indefinidas.
Ric Jafe

5
este é um imho configuração padrão muito estúpido, se você adicionar uma propriedade para o seu api, toda a serialização falhar
headsvk

478

Você pode usar

ObjectMapper objectMapper = getObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Ele ignorará todas as propriedades que não são declaradas.


5
Isto não funcionou para mim, ele ainda falha em propriedades desconhecidas
Denis Kniazhev

1
Você pode colar pelo menos um pedaço do código exatamente o que você está fazendo? Você pode ter perdido alguma coisa lá ... Ou fazendo isso ou usando "@JsonIgnoreProperties (ignoreUnknown = true)" Seu problema deve ser resolvido. De qualquer forma boa sorte.
Suresh

27
FWIW - Eu tive que importar essa enumeração um pouco diferente: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES
raf

9
^ Acima é para versões de Jackson anteriores a 2
755

10
Você também pode encadear essas chamadas como:. GetObjectMapper () disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
icfantv

126

A primeira resposta está quase correta, mas o necessário é alterar o método getter, NÃO campo - campo é privado (e não é detectado automaticamente); além disso, os getters têm precedência sobre os campos se ambos estiverem visíveis (também existem maneiras de tornar os campos privados visíveis, mas se você deseja obter o getter, não há muito sentido)

Portanto, getter deve ser nomeado getWrapper()ou anotado com:

@JsonProperty("wrapper")

Se você preferir o nome do método getter como está.


Elabore - qual getter precisa ser alterado ou anotado?
Frans

você quer dizer anotado com @JsonGetter ("wrapper"), certo?
pedram Bashiri

@pedrambashiri Não, quero dizer @JsonProperty. Embora @JsonGetterseja um alias legal, raramente é usado como @JsonPropertytrabalho para getters, setters e campos; setters e getters podem ser distinguidos por assinatura (um não aceita argumentos, retorna não nulo; outro aceita um argumento).
precisa saber é o seguinte

Esta é a resposta que eu estava procurando! Parece que Jackson tem problemas para mapear o JSON de origem para o seu POJO, mas você pode garantir correspondências marcando os getters. Obrigado!
Andrew Kirna

90

usando o Jackson 2.6.0, isso funcionou para mim:

private static final ObjectMapper objectMapper = 
    new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

e com a configuração:

@JsonIgnoreProperties(ignoreUnknown = true)

12
Com essa configuração, a anotação é desnecessária #
neworld

Você precisa configurar o ObjectMapper e o Annotation na classe? Eu acho que o objectMapper irá corrigir para todos, sem a necessidade de anotar cada classe. Eu uso a anotação embora.
Prayagupd

Você não precisa das duas configurações na mesma classe. Você também pode usar o DI para obter uma instância global singleton do ObjectMapper, para definir a FAIL_ON_UNKNOWN_PROPERTIESpropriedade globalmente.
user991710

Você não precisa dos dois, pode escolher um ou outro.
heez

58

pode ser alcançado de 2 maneiras:

  1. Marque o POJO para ignorar propriedades desconhecidas

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. Configure o ObjectMapper que serializa / desserializa o POJO / json como abaixo:

    ObjectMapper mapper =new ObjectMapper();            
    // for Jackson version 1.X        
    mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    // for Jackson version 2.X
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 

2
Por que essa deveria ser a resposta aceita? Isso diz apenas para ignorar propriedades desconhecidas, enquanto a questão era encontrar uma maneira de envolver o json em um objeto que esta solução diz claramente que deve ignorar.
Sayantan

42

Isso funcionou perfeitamente para mim

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(
    DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

@JsonIgnoreProperties(ignoreUnknown = true) anotação não.


2
Voto negativo, pois não responde à pergunta do OP. Ignorar propriedades desconhecidas não resolve o problema dele, mas o deixa com uma Wrapperinstância em que a lista de alunos está nullvazia ou não.
Frans

37

Isso funciona melhor do que Tudo, consulte esta propriedade.

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    projectVO = objectMapper.readValue(yourjsonstring, Test.class);

Trabalhando como esperado!
MADHAIYAN M 15/09/15

Sim, esse foi o que resolveu meu problema - que correspondia ao título deste post.
21816 Scott Langeberg

As respostas funcionam bem para mim e é muito fácil.Obrigado
Touya Akira

29

Se você estiver usando o Jackson 2.0

ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

por que essa configuração não tem efeito para mim?
Zhaozhi

@zhaozhi Depende versão Jackson
Aalkhodiry

20

De acordo com o documento, você pode ignorar os campos selecionados ou todos os campos desconhecidos:

 // to prevent specified fields from being serialized or deserialized
 // (i.e. not include in JSON output; or being set even if they were included)
 @JsonIgnoreProperties({ "internalId", "secretKey" })

 // To ignore any unknown properties in JSON input without exception:
 @JsonIgnoreProperties(ignoreUnknown=true)

15

Funcionou para mim com o seguinte código:

ObjectMapper mapper =new ObjectMapper();    
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

15

Adicionar setters e getters resolveu o problema , o que eu senti é que o problema real era como resolvê-lo, mas não como suprimir / ignorar o erro. Eu recebi o erro " Campo não reconhecido. Não marcado como ignorável .. "

Embora eu use a anotação abaixo na parte superior da classe, ele não foi capaz de analisar o objeto json e me fornecer a entrada

@JsonIgnoreProperties (ignoreUnknown = true)

Então percebi que não adicionei setters e getters, depois de adicionar setters e getters ao "Wrapper" e ao "Student" funcionou como um encanto.


Essa parece ser a única resposta que realmente responde à pergunta. Todas as outras respostas estão apenas marcando propriedades desconhecidas como ignoradas, mas 'wrapper' não é uma propriedade desconhecida, é o que estamos tentando analisar.
lbenedetto

14

Jackson está reclamando porque não consegue encontrar um campo em sua classe Wrapper chamado "wrapper". Está fazendo isso porque seu objeto JSON possui uma propriedade chamada "wrapper".

Eu acho que a correção é renomear o campo da sua classe Wrapper para "wrapper" em vez de "alunos".


Obrigado Jim. Eu tentei isso e não resolveu o problema. Eu estou querendo saber se estou faltando alguma anotação ..
jshree

1
Hmm, o que acontece quando você cria os dados equivalentes em Java e depois usa Jackson para gravá- los em JSON. Qualquer diferença entre esse JSON e o JSON acima deve ser uma pista do que está acontecendo de errado.
Jim Ferrans

Esta resposta funcionou para mim, com o exemplo da pergunta.
sleske

14

Eu tentei o método abaixo e funciona para essa leitura de formato JSON com Jackson. Use a solução já sugerida de: anotando getter com@JsonProperty("wrapper")

Sua classe de wrapper

public Class Wrapper{ 
  private List<Student> students;
  //getters & setters here 
} 

Minha sugestão de classe wrapper

public Class Wrapper{ 

  private StudentHelper students; 

  //getters & setters here 
  // Annotate getter
  @JsonProperty("wrapper")
  StudentHelper getStudents() {
    return students;
  }  
} 


public class StudentHelper {

  @JsonProperty("Student")
  public List<Student> students; 

  //CTOR, getters and setters
  //NOTE: If students is private annotate getter with the annotation @JsonProperty("Student")
}

No entanto, isso forneceria a saída do formato:

{"wrapper":{"student":[{"id":13,"name":Fred}]}}

Também para obter mais informações, consulte https://github.com/FasterXML/jackson-annotations

Espero que isto ajude


Bem-vindo ao stackoverflow. Dica, você pode usar os {}símbolos na barra de ferramentas para formatar seus snippets de código.
Leigh

11

Essa solução é genérica ao ler fluxos json e precisa obter apenas alguns campos, enquanto os campos não mapeados corretamente em suas Classes de Domínio podem ser ignorados:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)

Uma solução detalhada seria usar uma ferramenta como jsonschema2pojo para gerar automaticamente as classes de domínio necessárias, como Student, do esquema do json Response. Você pode fazer o último com qualquer conversor json para esquema online.


10

Anote os alunos de campo como abaixo, pois há incompatibilidade nos nomes de propriedade json e propriedade java

public Class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;
    //getters & setters here
}

9

Como ninguém mais mencionou, pensei que eu iria ...

O problema é que sua propriedade em seu JSON é chamada "wrapper" e sua propriedade em Wrapper.class é chamada "estudantes".

Então também ...

  1. Corrija o nome da propriedade na classe ou no JSON.
  2. Anote sua variável de propriedade conforme o comentário de StaxMan.
  3. Anote o setter (se você tiver um)

6

defina public seus campos de classe não privados .

public Class Student { 
    public String name;
    public String id;
    //getters & setters for name & id here
}

2
má prática - isso quebra o encapsulamento.
Downhillski

1
Eu ouvi isso.
Downhillski

Sua classe está em risco quando o usuário a usa, porque o estado interno pode ser alterado por esses campos.
Downhillski

5

O que funcionou para mim foi tornar a propriedade pública. Isso resolveu o problema para mim.


1
Trabalhou para mim: D
TienLuong

5

Qualquer mudança

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

para

public Class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}

---- ou ----

Mude sua sequência JSON para

{"students":[{"id":"13","name":"Fred"}]}

5

Sua entrada

{"wrapper":[{"id":"13","name":"Fred"}]}

indica que é um objeto, com um campo chamado "wrapper", que é uma coleção de alunos. Então, minha recomendação seria:

Wrapper = mapper.readValue(jsonStr , Wrapper.class);

onde Wrapperé definido como

class Wrapper {
    List<Student> wrapper;
}

5

O novo Firebase Android introduziu algumas mudanças enormes; abaixo da cópia do documento:

[ https://firebase.google.com/support/guides/firebase-android] :

Atualize seus objetos de modelo Java

Como no SDK 2.x, o Firebase Database converterá automaticamente objetos Java para os quais você passa DatabaseReference.setValue()em JSON e pode ler JSON em objetos Java usando DataSnapshot.getValue().

No novo SDK, ao ler JSON em um objeto Java com DataSnapshot.getValue(), propriedades desconhecidas no JSON agora são ignoradas por padrão, para que você não precise mais@JsonIgnoreExtraProperties(ignoreUnknown=true) .

Para excluir campos / getters ao gravar um objeto Java em JSON, a anotação agora é chamada em @Excludevez de @JsonIgnore.

BEFORE

@JsonIgnoreExtraProperties(ignoreUnknown=true)
public class ChatMessage {
   public String name;
   public String message;
   @JsonIgnore
   public String ignoreThisField;
}

dataSnapshot.getValue(ChatMessage.class)

AFTER

public class ChatMessage {
   public String name;
   public String message;
   @Exclude
   public String ignoreThisField;
}

dataSnapshot.getValue(ChatMessage.class)

Se houver uma propriedade extra no seu JSON que não esteja na sua classe Java, você verá este aviso nos arquivos de log:

W/ClassMapper: No setter/field for ignoreThisProperty found on class com.firebase.migrationguide.ChatMessage

Você pode se livrar desse aviso colocando uma @IgnoreExtraPropertiesanotação em sua classe. Se você deseja que o Firebase Database se comporte como no SDK 2.x e gere uma exceção se houver propriedades desconhecidas, poderá colocar uma @ThrowOnExtraPropertiesanotação em sua classe.


4

Da minha parte, a única linha

@JsonIgnoreProperties(ignoreUnknown = true)

não funcionou também.

Basta adicionar

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0


4

Isso funcionou perfeitamente para mim

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

Corrigi esse problema simplesmente alterando as assinaturas dos métodos setter e getter da minha classe POJO. Tudo o que eu precisava fazer era alterar o método getObject para corresponder ao que o mapeador estava procurando. No meu caso, eu tinha um getImageUrl originalmente, mas os dados JSON tinham image_url, o que estava descartando o mapeador. Alterei meu setter e getters para getImage_url e setImage_url .

Espero que isto ajude.


você está certo, aparentemente: se o nome que você quer é xxx_yyy A maneira de chamá-lo seria getXxx_yyy e setXxx_yyy. Isso é muito estranho, mas funciona.
sivi

3

O POJO deve ser definido como

Classe de resposta

public class Response {
    private List<Wrapper> wrappers;
    // getter and setter
}

Classe Wrapper

public class Wrapper {
    private String id;
    private String name;
    // getters and setters
}

e mapeador para ler o valor

Response response = mapper.readValue(jsonStr , Response.class);

Quase. Não wrappers, mas wrapper.
Frans

@ Franco Haha, obrigado por pegar o erro. Eu naturalmente uso o plural para uma coleção. Mas, de acordo com a pergunta do OP, deve ser singular.
Dino Tw

3

Essa pode ser uma resposta muito tardia, mas apenas alterar o POJO para isso deve resolver a string json fornecida no problema (já que a string de entrada não está sob seu controle, como você disse):

public class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}

3

Uma outra possibilidade é essa propriedade no application.properties spring.jackson.deserialization.fail-on-unknown-properties=false, que não precisará de nenhuma outra alteração de código no aplicativo. E quando você acredita que o contrato é estável, você pode remover essa propriedade ou marcar como verdadeira.


3

Esse pode não ser o mesmo problema que o OP tinha, mas no caso de alguém chegar aqui com o mesmo erro que eu, então isso os ajudará a resolver o problema. Recebi o mesmo erro do OP quando usei um ObjectMapper de uma dependência diferente da anotação JsonProperty.

Isso funciona:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonProperty;

Não funciona:

import org.codehaus.jackson.map.ObjectMapper; //org.codehaus.jackson:jackson-mapper-asl:1.8.8
import com.fasterxml.jackson.annotation.JsonProperty; //com.fasterxml.jackson.core:jackson-databind:2.2.3

obrigado! importação com.fasterxml.jackson.annotation.JsonProperty trabalhou para mim em vez do outro :-)
phil

2

O Google me trouxe aqui e fiquei surpreso ao ver as respostas ... todas sugeridas para contornar o erro ( que sempre volta 4 vezes mais tarde no desenvolvimento ) ao invés de resolvê-lo até que este cavalheiro tenha restaurado pela fé no SO!

objectMapper.readValue(responseBody, TargetClass.class)

é usado para converter uma String json em um objeto de classe, o que está faltando é que ele TargetClassdeve ter acesso público get/set terers. O mesmo está faltando no trecho de pergunta do OP também! :)

via lombok sua classe como abaixo deve funcionar !!

@Data
@Builder
public class TargetClass {
    private String a;
}

2

importar com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties


Talvez algumas outras evidências ou doc seria bom
Benj

@JsonIgnoreProperties (ignoreUnknown = true) funciona bem, obrigado
Guilherme
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.