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)
jshree
fonte
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)
Ariel Kogan
fonte
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.

Suresh
fonte
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á.

StaxMan
fonte
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)
Scott
fonte
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) 
Amit Kaneria
fonte
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.

Felix Kimutua
fonte
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);
user2542697
fonte
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);
Aalkhodiry
fonte
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)
tomrozb
fonte
15

Funcionou para mim com o seguinte código:

ObjectMapper mapper =new ObjectMapper();    
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j_bond007
fonte
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.

ddc
fonte
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".

Jim Ferrans
fonte
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

mytwocentsads
fonte
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.

George Papatheodorou
fonte
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
}
ajith r
fonte
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)
TedTrippin
fonte
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
}
nunca inverno
fonte
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.

Rohitesh
fonte
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"}]}
sagar
fonte
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;
}
Ran0990BK
fonte
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.

ThierryC
fonte
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

jodu
fonte
4

Isso funcionou perfeitamente para mim

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Niamath
fonte
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.

superuserdo
fonte
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);
Dino Tw
fonte
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
}
Sayantan
fonte
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.

krmanish007
fonte
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
cwa
fonte
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;
}
NoobEditor
fonte
2

importar com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties

Gank
fonte
Talvez algumas outras evidências ou doc seria bom
Benj
@JsonIgnoreProperties (ignoreUnknown = true) funciona bem, obrigado
Guilherme