Як я можу сказати Джексону ігнорувати властивість, для якої я не маю контролю над вихідним кодом?


112

Коротше кажучи, одна з моїх сутностей має GeometryCollection, яка кидає виняток, коли ви називаєте "getBoundary" (чому це інша книга, бо зараз скажемо, що це так).

Чи є спосіб я можу сказати Джексону не включати цього конкретного геттера? Я знаю, що можу використовувати @JacksonIgnore, коли володію / контролюю код. Але це не так, Джексон закінчує досягнення цієї точки шляхом постійної серіалізації батьківських об'єктів. Я бачив варіант фільтрації в документації на Джексона. Це правдоподібне рішення?

Дякую!

Відповіді:


168

Можна використовувати Джексона Мікінса . Наприклад:

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

З цим Mixin

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

З цим:

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

Редагувати:

Завдяки коментарям, API Jackson 2.5+ змінився і його потрібно викликати objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)


1
І якщо властивість генерується машиною і має непідтримувані символи у своєму імені? Подібно до '@'? JVM дозволяє, але компілятор Java цього не робить. У Джексона є рішення для цього?
позначка

3
А в Джексона 2.2 цеobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan

Як ігнорувати, вказавши ім'я властивості замість getter?
Ерран Морад

68

Ще одна можливість полягає в тому, що якщо ви хочете ігнорувати всі невідомі властивості, ви можете налаштувати картограф таким чином:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

5
Було б чудово, якби ми могли налаштувати objectMapper лише ігнорувати властивості specifc. тобто повідомляємо про виняток для всіх нових / невідомих полів, за винятком того, що скажемо "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);

9
Такий підхід для мене не працює, але міксин це робить. Я все ще отримую ігноровані властивості після серіалізації. Чому у нас є комбінації, коли ми маємо безAtribute ()?
Ерран Морад

9

Тут помітно добре працюють примітки про змішані описи, як уже згадувалося. Ще одна можливість, окрім власності @JsonIgnore, - використовувати @JsonIgnoreType, якщо у вас є тип, який ніколи не слід включати (тобто якщо всі екземпляри властивостей GeometryCollection слід ігнорувати). Потім ви можете або додати його безпосередньо (якщо ви керуєте типом), або використовуючи суміш, наприклад:

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

Це може бути зручніше, якщо у вас є безліч класів, у яких є один одинарний аксесуар 'IgnoredType getContext ()' або близько того (що стосується багатьох фреймворків)


5

У мене була подібна проблема, але вона стосувалася двонаправлених стосунків у сплячці. Я хотів показати одну сторону стосунків і програмно ігнорувати іншу, залежно від того, з якою думкою я маю справу. Якщо ви не можете цього зробити, ви закінчитеся з неприємними 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. Я сподіваюся, що це допомагає комусь іншому, це особливо негарна проблема з Джексоном, яка не мала хорошого рішення для моєї справи.


Для чого імпорт Match.match()?
Пасупаті Раджаманікам

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.