159

Long story short, one of my entities has a GeometryCollection that throws an exception when you call "getBoundary" (the why of this is another book, for now let's say this is the way it works).

Is there a way I can tell Jackson not to include that specific getter? I know I can use @JacksonIgnore when I do own/control the code. But this is not case, jackson ends reaching this point through continuous serialization of the parent objects. I saw a filtering option in jackson documentation. Is that a plausible solution?

Thanks!

fabien7474
  • 16,300
  • 22
  • 96
  • 124
maverick
  • 2,185
  • 2
  • 16
  • 22

8 Answers8

208

You can use Jackson Mixins. For example:

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

With this Mixin

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

With this:

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

Edit:

Thanks to the comments, with Jackson 2.5+, the API has changed and should be called with objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)

Matthew Read
  • 1,365
  • 1
  • 30
  • 50
Amir Raminfar
  • 33,777
  • 7
  • 93
  • 123
  • 1
    And if the property is machine generated and has unsupported characters in its name? Like '@'? JVM allows it, but Java compiler does not. Does Jackson have solution for this? – mark Mar 20 '13 at 16:13
  • 5
    And in jackson 2.2 it's `objectMapper.addMixInAnnotations(Class> target, Class> mixinSource);` – CorayThan Feb 24 '16 at 09:31
  • How do I ignore by specifying the property name instead of getter ? – Erran Morad Nov 10 '19 at 02:23
  • Also works for property defined in mixin class: `@JsonIgnore private HttpClient httpClient;` – aksh1618 Sep 14 '20 at 12:45
  • Just make sure to remove `mapper.disable(MapperFeature.USE_ANNOTATIONS);` If it is configured earlier, otherwise this Mixin annotations won't have any effect. – gkns May 10 '22 at 05:54
81

One other possibility is, if you want to ignore all unknown properties, you can configure the mapper as follows:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
AlexVogel
  • 10,601
  • 10
  • 61
  • 71
laloumen
  • 1,229
  • 2
  • 14
  • 15
  • 7
    It would be great if we could configure the objectMapper to ignore specifc properties only. i.e. report the exception for all new/unknown fields except lets say 'myfield'. Something like `mapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));` – ms_27 Aug 23 '16 at 06:23
  • 1
    Note that this can also be configured on a reader using `without()` as in: `mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)` – Drew Stephens Oct 03 '17 at 18:50
  • I would strongly advise against using this mechanism. The "strict" mindset in Jackson, causing errors to be raised on unknown/unhandled fields is one of its strengths and matches the statically typed/compile-time-analyzed nature of Java well. It's much better to opt out from handling a given set of ignored fields instead. – Per Lundberg Jan 13 '20 at 12:31
45

Using Java Class

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

Using Annotation

@JsonIgnoreProperties(ignoreUnknown=true)
Sireesh Yarlagadda
  • 12,978
  • 3
  • 74
  • 76
26

Annotation based approach is better. But sometimes manual operation is needed. For this purpose you can use without method of 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
  • 5,613
  • 2
  • 50
  • 53
  • 16
    This approach does not work for me, but the mixin one does. I still get the ignored properties after serialization. Why do we have mixins when we have withoutAttribute() ? – Erran Morad Nov 10 '19 at 02:20
  • 1
    "Why do we have mixins when we have withoutAttribute() ?" - Mixins cannot be set dynamically. https://stackoverflow.com/a/11849523/3105386, while we can do that with "withoutAttributes". That might be one of the reason. – Vipul Jain Oct 17 '20 at 17:00
  • 1
    Secondly, "withoutAttribute" is used when you want to ignore a field with certain name and don't care about the class. Mixin helps you define that with much more granularity with specific classes in which those fields needs to be ignored. – Vipul Jain Oct 17 '20 at 17:06
  • 1
    @ErranMorad Did you ever figure out why withoutAttribute() wasn't working? – Saurabh Shrivastava Nov 06 '20 at 16:58
  • @SaurabhShrivastava - no. I used something else. I don't remember anymore. – Erran Morad Nov 21 '20 at 18:21
  • This was exactly what I needed - to exclude specific fields at runtime. – Srki Rakic Aug 07 '21 at 02:10
  • This was exactly what I needed - to exclude specific fields at runtime. – Srki Rakic Aug 07 '21 at 02:11
  • 3
    `ObjectWriter.withoutAttribute` does not work as suggested in the answer. The _attribute_ does not refer to property names of input data and are never referenced in such a context, as pointed in [this comment](https://github.com/FasterXML/jackson-core/issues/700#issuecomment-849182602), for example. This method seems to be geared towards internal use, as can be seen [here](https://github.com/FasterXML/jackson-databind/blob/2.13/src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java#L364). – omahdi Aug 28 '21 at 19:05
10

If you want to ALWAYS exclude certain properties for any class, you could use setMixInResolver method:

    @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
  • 369
  • 4
  • 4
9

Mix-in annotations work pretty well here as already mentioned. Another possibility beyond per-property @JsonIgnore is to use @JsonIgnoreType if you have a type that should never be included (i.e. if all instances of GeometryCollection properties should be ignored). You can then either add it directly (if you control the type), or using mix-in, like:

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

This can be more convenient if you have lots of classes that all have a single 'IgnoredType getContext()' accessor or so (which is the case for many frameworks)

StaxMan
  • 113,358
  • 34
  • 211
  • 239
8

I had a similar issue, but it was related to Hibernate's bi-directional relationships. I wanted to show one side of the relationship and programmatically ignore the other, depending on what view I was dealing with. If you can't do that, you end up with nasty StackOverflowExceptions. For instance, if I had these objects

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

public class B{
  Long id;
  A parent;
}

I would want to programmatically ignore the parent field in B if I were looking at A, and ignore the children field in A if I were looking at B.

I started off using mixins to do this, but that very quickly becomes horrible; you have so many useless classes laying around that exist solely to format data. I ended up writing my own serializer to handle this in a cleaner way: https://github.com/monitorjbl/json-view.

It allows you programmatically specify what fields to ignore:

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

It also lets you easily specify very simplified views through wildcard matchers:

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

In my original case, the need for simple views like this was to show the bare minimum about the parent/child, but it also became useful for our role-based security. Less privileged views of objects needed to return less information about the object.

All of this comes from the serializer, but I was using Spring MVC in my app. To get it to properly handle these cases, I wrote an integration that you can drop in to existing Spring controller classes:

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

Both are available on Maven Central. I hope it helps someone else out there, this is a particularly ugly problem with Jackson that didn't have a good solution for my case.

monitorjbl
  • 4,280
  • 3
  • 36
  • 45
1

One more good point here is to use @JsonFilter. Some details here Feature: JSON Filter

Laurel
  • 5,965
  • 14
  • 31
  • 57