Como posso dizer a jackson para ignorar uma propriedade sobre a qual não tenho controle sobre o código-fonte?


112

Resumindo, uma das minhas entidades tem um GeometryCollection que lança uma exceção quando você chama "getBoundary" (o porquê disso é outro livro, por enquanto digamos que é assim que funciona).

Existe uma maneira de dizer a Jackson para não incluir aquele getter específico? Sei que posso usar @JacksonIgnore quando possuo / controlo o código. Mas este não é o caso, jackson termina atingindo este ponto através da serialização contínua dos objetos pais. Eu vi uma opção de filtragem na documentação de jackson. Essa é uma solução plausível?

Obrigado!

Respostas:


168

Você pode usar Jackson Mixins . Por exemplo:

class YourClass {
  public int ignoreThis() { return 0; }    
}

Com este Mixin

abstract class MixIn {
  @JsonIgnore abstract int ignoreThis(); // we don't need it!  
}

Com isso:

objectMapper.getSerializationConfig().addMixInAnnotations(YourClass.class, MixIn.class);

Editar:

Graças aos comentários, com Jackson 2.5+, a API mudou e deve ser chamada com objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)


1
E se a propriedade for gerada por máquina e tiver caracteres não suportados em seu nome? Gostar '@'? A JVM permite, mas o compilador Java não. Jackson tem solução para isso?
marcar

3
E em jackson 2.2 éobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan

Como faço para ignorar especificando o nome da propriedade em vez de getter?
Erran Morad de

68

Uma outra possibilidade é, se você deseja ignorar todas as propriedades desconhecidas, você pode configurar o mapeador da seguinte forma:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

5
Seria ótimo se pudéssemos configurar o objectMapper para ignorar apenas propriedades específicas. ou seja, relatar a exceção para todos os campos novos / desconhecidos, exceto, digamos, 'meu campo'. Algo comomapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27

Observe que isso também pode ser configurado em um leitor usando without()como em:mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
Drew Stephens,

Eu desaconselho fortemente o uso desse mecanismo. A mentalidade "estrita" em Jackson, fazendo com que erros sejam levantados em campos desconhecidos / não manipulados, é um de seus pontos fortes e combina bem com a natureza estaticamente digitada / analisada em tempo de compilação do Java. É muito melhor optar por não manipular um determinado conjunto de campos ignorados.
Per Lundberg

26

Usando a classe Java

new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

Usando Anotação

@JsonIgnoreProperties(ignoreUnknown=true)

11

A abordagem baseada em anotações é melhor. Mas às vezes a operação manual é necessária. Para este efeito, você pode usar sem método de ObjectWriter .

ObjectMapper mapper   = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
ObjectWriter writer   = mapper.writer().withoutAttribute("property1").withoutAttribute("property2");
String       jsonText = writer.writeValueAsString(sourceObject);

9
Essa abordagem não funciona para mim, mas a do mixin sim. Ainda recebo as propriedades ignoradas após a serialização. Por que temos mixins quando temos withoutAttribute ()?
Erran Morad de

9

As anotações mix-in funcionam muito bem aqui, como já foi mencionado. Outra possibilidade além de @JsonIgnore por propriedade é usar @JsonIgnoreType se você tiver um tipo que nunca deve ser incluído (ou seja, se todas as instâncias das propriedades GeometryCollection devem ser ignoradas). Você pode então adicioná-lo diretamente (se você controlar o tipo) ou usando o mix-in, como:

@JsonIgnoreType abstract class MixIn { }
// and then register mix-in, either via SerializationConfig, or by using SimpleModule

Isso pode ser mais conveniente se você tiver muitas classes em que todas tenham um único acessador 'IgnoredType getContext ()' ou algo assim (que é o caso de muitos frameworks)


5

Eu tive um problema semelhante, mas estava relacionado aos relacionamentos bidirecionais do Hibernate. Eu queria mostrar um lado do relacionamento e ignorar programaticamente o outro, dependendo de qual visão eu estava lidando. Se você não puder fazer isso, acabará com StackOverflowExceptions desagradáveis . Por exemplo, se eu tivesse esses objetos

public class A{
  Long id;
  String name;
  List<B> children;
}

public class B{
  Long id;
  A parent;
}

Gostaria de ignorar programaticamente o parentcampo em B se estivesse olhando para A e ignorar o childrencampo em A se estivesse olhando para B.

Comecei usando mixins para fazer isso, mas rapidamente se tornou horrível; você tem tantas classes inúteis espalhadas que existem apenas para formatar dados. Acabei escrevendo meu próprio serializador para lidar com isso de uma forma mais limpa: https://github.com/monitorjbl/json-view .

Ele permite que você especifique programaticamente quais campos ignorar:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JsonView.class, new JsonViewSerializer());
mapper.registerModule(module);

List<A> list = getListOfA();
String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(B.class, match()
        .exclude("parent")));

Ele também permite que você especifique facilmente visualizações muito simplificadas por meio de correspondências de curinga:

String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(A.class, match()
        .exclude("*")
         .include("id", "name")));

No meu caso original, a necessidade de visualizações simples como essa era mostrar o mínimo sobre o pai / filho, mas também se tornou útil para nossa segurança baseada em funções. Visualizações menos privilegiadas de objetos são necessárias para retornar menos informações sobre o objeto.

Tudo isso vem do serializador, mas eu estava usando Spring MVC em meu aplicativo. Para fazer com que ele lide adequadamente com esses casos, escrevi uma integração que você pode colocar nas classes de controlador Spring existentes:

@Controller
public class JsonController {
  private JsonResult json = JsonResult.instance();
  @Autowired
  private TestObjectService service;

  @RequestMapping(method = RequestMethod.GET, value = "/bean")
  @ResponseBody
  public List<TestObject> getTestObject() {
    List<TestObject> list = service.list();

    return json.use(JsonView.with(list)
        .onClass(TestObject.class, Match.match()
            .exclude("int1")
            .include("ignoredDirect")))
        .returnValue();
  }
}

Ambos estão disponíveis no Maven Central. Espero que ajude alguém por aí, este é um problema particularmente feio com Jackson que não tinha uma boa solução para o meu caso.


Para que serve a importação Match.match()?
Pasupathi Rajamanickam

2

Se você quiser SEMPRE excluir certas propriedades de qualquer classe, você pode usar o setMixInResolvermétodo:

    @JsonIgnoreProperties({"id", "index", "version"})
    abstract class MixIn {
    }

    mapper.setMixInResolver(new ClassIntrospector.MixInResolver(){
        @Override
        public Class<?> findMixInClassFor(Class<?> cls) {
            return MixIn.class;  
        }

        @Override
        public ClassIntrospector.MixInResolver copy() {
            return this;
        }
    });

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.