Jackson-databind: Ignore property during deserialization but retain in serialization not working

Created on 23 Oct 2012  路  26Comments  路  Source: FasterXML/jackson-databind

Using com.fasterxml.jackson.core:jackson-{core,annotations,databind} 2.1.0, I think the code below to ignore a computed property (i.e., no field) during deserialization (property zip), but include it in serialization used to work, but now it doesn't. I also tried removing class level @JsonIgnoreProperties({"zip"}) and adding @JsonIgnore along with @JsonProperty("zip") but that didn't work either.

The variant with a field still works: https://gist.github.com/2510887 .

    @JsonIgnoreProperties({"zip"})
    public static class Foo {
        private final int bar;


        public Foo(@JsonProperty("bar") final int bar) {
            this.bar = bar;
        }


        public int getBar() {
            return bar;
        }


        @JsonProperty("zip")
        public int getZip() {
            return bar * 2;
        }


        static <T> T fromJson(final String json, final Class<T> clazz) {
            try {
                return new ObjectMapper().readValue(json, clazz);
            } catch (final IOException ioe) {
                throw Throwables.propagate(ioe);
            }
        }


        static String asJson(final Object obj) {
            try {
                return new ObjectMapper().writeValueAsString(obj);
            } catch (final IOException ioe) {
                throw Throwables.propagate(ioe);
            }
        }
    }


    @Test
    public void testIgnoreDuringDeserializationButNotSerialization() {
        final Foo foo = new Foo(1);
        final String json = Foo.asJson(foo);
        // json does not include zip computed property
        LG.info("foo: {}", json);
        final Foo reconstituted = Foo.fromJson(json, Foo.class);
    }

Most helpful comment

I have tried @JsonIgnoreProperties(value = "fieldName", allowGetters=true). This worked for me.
But if I try @JsonProperty(access = JsonProperty.Access.READ_ONLY) on getter method, didn't work.

All 26 comments

Which version did this work in? And what kind of failure do you get? (exception?)

Actually, its possible it never worked as I wanted :$ . I just reverted to 2.0.6 with same result. I thought that @JsonIgnoreProperties({"zip"}) would cause property zip to not be required during deserialization and @JsonProperty("zip") would cause property zip to be included in serialized output. What I'm seeing is @JsonIgnoreProperties({"zip"}) seems to cause property zip to not be required during deserialization (desired), but also trumps @JsonProperty("zip"), as property zip is not included in serialized output.

Is there an annotation-based way to get this behavior?

Hmmh. I see, yes, that is bit problematic. I can think of alternatives, but none entirely good:

  1. Use mix-ins for one of the cases, separate ObjectMapper
  2. Define bogus " setZip(Object x)" method that does nothing (or even just any single-argument method, annotated with '@JsonProperty("zip")')

The underlying problem is due to per-class @JsonIgnoreProperties essentially having precedence over per-property instructions; but unfortunately this can not be easily changed for multiple reasons.

I'd like to be able to achieve this with annotations and no extra fields or bogus API additions -- seems like a common desire for computed properties. I understand adjusting existing annotation behaviors/implications is hard to do while maintaining backward compatibility.

Should I leave this issue open to be interpreted as a feature request or close it as an invalid bug?

I think title is clear enough to work as an RFE.

And I do see the utility. But I am not 100% sure of how to do it, since semantics of @JsonIgnoreProperties can not be changed lightly, wrt backwards compatibility. Plus I think it often makes sense; although when going to exact details of how to merge conflicting signals, perhaps there is room for improvement.

Can you think of additional ways to go about this? As usual, adding a new DeserializationFeature is rather easy (to expose a switch); so there could be something that suggests that ignoring a property for which a getter exists, but not setter, is fine.

FWIW ,another work-around (for time being) for your case is of course using "ignoreUnknown=true".

... and thinking of this, yet another way to expose this would be to add

'@JsonIgnoreProperties(ignorePartial=true)` (or "ignoreSplit" or whatever)

which would basically recognize "gettable" things as ignorable, implicitly.

But I may be thinking along convoluted paths here, so better suggestions are completely welcome!
(I mean, aside from 'try to make existing code merge these things in better way', which I will consider too -- but I have a feeling that the pipeline used for merging things may make this a very difficult change to make)

I don't really like implementing this with a new DeserializationFeature - makes the programmer's job of understanding the "conflicting signals" they're sending that much more indirect. The best (half-baked) idea that's come to me is adding some properties to the @JsonIgnore annotation like duringSerialization / forSerialization and duringDeserialization / forDeserialization with defaults that maintain current behavior - I like attaching this information directly to the "special" field/accessor (vs. the class-wide @JsonIgnoreProperties annotation properties you proposed). Unfortunately, I think this would break current field-@JsonIgnore'd + accessor @JsonProperty serialization-only property inclusion (https://gist.github.com/2510887). Maybe similar properties on the @JsonProperty annotation? Thoughts?

Interesting idea, wrt forSerialization. Could also be used for @JsonIgnoreProperties, come to think of that (either as boolean or as alternate list to add to base set).

Another possibility could be to try to add some kind of "read-only" semantics: this could even go in @JsonProperty. This would basically imply full semantics of "serialize, but do not try to deserialize".
Actually I guess term "read-only" is confusing, or at least context-sensitive -- it makes sense from Java perspective (can only get, not set), but not necessarily from JSON perspective.

As to kind of work-around approaches: we still have @JsonSetter and @JsonGetter annotations, which we to be deprecated, but then I thought that there are cases where those might come in handy. So while kludge-y, one could consider adding, say, @JsonSetter on getter, to indicate same thing ("don't worry about setter, let's call this a setter"). Pretty ugly actually... maybe not worth considering.

I stumbled on the same issue.

Any progress with implementing read-only properties in an elegant way ?

I am open to suggestions of best way (from user perspective) to do it. No concrete plans at this point.

+1 for @nezda's suggestion. @JsonNoDeserialize, or something like that.

Either @JsonNoDeserialize or @JsonReadOnly which might be easier to understand.

It would be great as well if that worked when the property is not an instance variable (in my case there just a getter).

My main concern with @JsonNoDeserialize is just that it gets quite specific. In a way that is of course also good (less ambiguous), but I have noticed that some users find API "too complex" when number of things listed on javadocs grows. In a way @JsonReadOnly would be nicer semantically (more generic but clear for intended initial use case), but it's still one more annotation to add.

One more possibility would be to add a property to existing @JsonDeserialize. Perhaps like:

@JsonDeserialize(skip=true)

since it could also be added for @JsonSerialize.

+1 for adding a property to the existing @JsonDeserialize and @JsonSerialize annotations. Seems like an intuitive and clear approach.

What would be the best "non-hacky" approach to prevent deserialization of spesific fields until this feature is implemented?

+1

+1

+1

+1

:+1: +1

+1 Would be nice to handle the @JsonCreator use case too. E.g. have getter that returns computed property, don't want to include property in the constructor argument list.

+1

+1

+1

Ok: I ended up adding new properties allowGetters and allowSetters (defaulting to false).
So, to support "read-only" properties with @JsonIgnoreProperties, you can use:

@JsonIgnoreProperties(value={ "computed" }, allowGetters=true)
public class Stuff {
   // other accessors first...

   // and then pseudo-property with just getter, no matching setters
   public int getComputed() { return 42; }
}

If alternative constructs are desired (like, say, adding ability to say @JsonProperty(readonly=true) or something), please file a separate feature request.

Thank you very much guys this is the thing that really helped me 馃憤

I have tried @JsonIgnoreProperties(value = "fieldName", allowGetters=true). This worked for me.
But if I try @JsonProperty(access = JsonProperty.Access.READ_ONLY) on getter method, didn't work.

@vkrishna17 This is a closed issue to if have remaining issues it makes sense to file a new issue with specific remaining problem(s).

Was this page helpful?
0 / 5 - 0 ratings