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

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

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

Спасибо!

Ответ 1

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

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

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

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

Ответ 2

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

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Ответ 3

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

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

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

@JsonIgnoreProperties(ignoreUnknown=true)

Ответ 4

public @interface JsonIgnoreProperties

Аннотации, которые могут использоваться для подавления сериализации свойств (во время сериализации) или игнорирования обработки свойств JSON, прочитанных (во время десериализации).

чтобы исключить сериализацию или десериализацию заданных полей, вы можете использовать:

@JsonIgnoreProperties(ignoreUnknown=true)

Ответ 5

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

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

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

Ответ 6

Подход, основанный на аннотациях, лучше. Но иногда требуется ручное управление. Для этого вы можете использовать без метода 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);

Ответ 7

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

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

Ответ 9

Если вы хотите ВСЕГДА исключать определенные свойства для любого класса, вы можете использовать метод 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;
        }
    });