Как я могу сказать Джексону игнорировать свойство, исходный код которого у меня не контролируется?

112

Короче говоря, у одной из моих сущностей есть GeometryCollection, которая генерирует исключение, когда вы вызываете getBoundary (почему это другая книга, а пока давайте предположим, что это работает именно так).

Есть ли способ сказать Джексону не включать этот конкретный получатель? Я знаю, что могу использовать @JacksonIgnore, когда владею / контролирую код. Но это не тот случай, Джексон достигает этой точки путем непрерывной сериализации родительских объектов. Я видел опцию фильтрации в документации Джексона. Это правдоподобное решение?

Спасибо!

индивидуалист
источник

Ответы:

168

Вы можете использовать миксины Джексона . Например:

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

С этим миксином

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

С этим:

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

Редактировать:

Благодаря комментариям с Jackson 2.5+ API изменился и должен вызываться с objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)

Амир Раминфар
источник
1
А если свойство сгенерировано компьютером и в его названии есть неподдерживаемые символы? Подобно '@'? JVM позволяет это, а компилятор Java - нет. Есть ли у Джексона решение для этого?
отметка
3
А в jackson 2.2 этоobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan
Как игнорировать, указав имя свойства вместо геттера?
Эрран Морад
68

Еще одна возможность: если вы хотите игнорировать все неизвестные свойства, вы можете настроить преобразователь следующим образом:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Laloumen
источник
5
Было бы здорово, если бы мы могли настроить objectMapper так, чтобы он игнорировал только определенные свойства. т.е. сообщать об исключении для всех новых / неизвестных полей, за исключением, например, «myfield». Что-то вродеmapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27
Обратите внимание, что это также можно настроить на считывающем устройстве, используя without():mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
Дрю Стивенс
Я бы настоятельно не советовал использовать этот механизм. «Строгий» образ мышления Джексона, вызывающий появление ошибок в неизвестных / необработанных полях, является одной из его сильных сторон и хорошо соответствует статически типизированной / анализируемой во время компиляции природе Java. Гораздо лучше вместо этого отказаться от обработки заданного набора игнорируемых полей.
Пер Лундберг,
26

Использование класса Java

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

Использование аннотации

@JsonIgnoreProperties(ignoreUnknown=true)
Сириш Ярлагадда
источник
11

Аннотационный подход лучше. Но иногда требуется ручное управление. Для этого вы можете использовать без метода 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);
Fırat KÜÇÜK
источник
9
Этот подход у меня не работает, а вот миксин работает. Я все еще получаю игнорируемые свойства после сериализации. Почему у нас есть миксины, когда у нас есть withoutAttribute ()?
Эрран Морад
9

Как уже упоминалось, здесь очень хорошо работают смешанные аннотации. Другая возможность, выходящая за рамки свойства @JsonIgnore, - использовать @JsonIgnoreType, если у вас есть тип, который никогда не должен включаться (т.е. если все экземпляры свойств GeometryCollection должны игнорироваться). Затем вы можете либо добавить его напрямую (если вы контролируете тип), либо с помощью смешивания, например:

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

Это может быть более удобно, если у вас есть много классов, у которых есть один метод доступа IgnoredType getContext () или около того (что характерно для многих фреймворков).

StaxMan
источник
5

У меня была аналогичная проблема, но она была связана с двунаправленными отношениями Hibernate. Я хотел показать одну сторону отношений и программно игнорировать другую, в зависимости от того, с какой точкой зрения я имел дело. Если вы не можете этого сделать, вы получите неприятные StackOverflowExceptions. Например, если бы у меня были эти предметы

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

public class B{
  Long id;
  A parent;
}

Я бы хотел программно игнорировать parentполе в B, если бы я смотрел на A, и игнорировать childrenполе в A, если бы я смотрел на B.

Я начал использовать миксины для этого, но это очень быстро становится ужасным; у вас есть так много бесполезных классов, которые существуют исключительно для форматирования данных. В итоге я написал свой собственный сериализатор, чтобы упростить эту задачу: https://github.com/monitorjbl/json-view .

Он позволяет программно указать, какие поля игнорировать:

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")));

Он также позволяет легко указывать очень упрощенные представления с помощью сопоставителей подстановочных знаков:

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

В моем первоначальном случае потребность в простых представлениях, подобных этому, заключалась в том, чтобы показать самый минимум о родителе / ​​потомке, но это также стало полезным для нашей ролевой безопасности. Менее привилегированные представления объектов должны возвращать меньше информации об объекте.

Все это исходит от сериализатора, но я использовал Spring MVC в своем приложении. Чтобы заставить его правильно обрабатывать эти случаи, я написал интеграцию, которую вы можете добавить к существующим классам контроллеров Spring:

@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();
  }
}

Оба доступны на Maven Central. Я надеюсь, что это поможет кому-то еще, это особенно неприятная проблема с Джексоном, у которой не было хорошего решения для моего случая.

monitorjbl
источник
Для чего нужен импорт Match.match()?
Pasupathi Rajamanickam,
2

Если вы хотите ВСЕГДА исключать определенные свойства для любого класса, вы можете использовать setMixInResolverметод:

    @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;
        }
    });
Fifman
источник