Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore property during deserialization but retain in serialization not working #95

Closed
nezda opened this issue Oct 23, 2012 · 26 comments
Closed
Milestone

Comments

@nezda
Copy link

nezda commented Oct 23, 2012

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);
    }
@cowtowncoder
Copy link
Member

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

@nezda
Copy link
Author

nezda commented Oct 23, 2012

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?

@cowtowncoder
Copy link
Member

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.

@nezda
Copy link
Author

nezda commented Oct 25, 2012

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?

@cowtowncoder
Copy link
Member

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)

@nezda
Copy link
Author

nezda commented Oct 29, 2012

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?

@cowtowncoder
Copy link
Member

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.

@jmcazaux
Copy link

I stumbled on the same issue.

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

@cowtowncoder
Copy link
Member

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

@mmontag
Copy link

mmontag commented Mar 29, 2014

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

@jmcazaux
Copy link

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

@cowtowncoder
Copy link
Member

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.

@kschulst
Copy link

kschulst commented Sep 8, 2014

+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?

@ppawel
Copy link

ppawel commented Nov 4, 2014

+1

2 similar comments
@gregorriegler
Copy link

+1

@igorng
Copy link

igorng commented Dec 18, 2014

+1

@kamkie
Copy link

kamkie commented Jan 3, 2015

+1

@herau
Copy link
Contributor

herau commented Jan 14, 2015

👍 +1

@lorrin
Copy link

lorrin commented Jan 23, 2015

+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.

@apajaros
Copy link

apajaros commented Feb 2, 2015

+1

2 similar comments
@tostrowski
Copy link

+1

@tonypiazza
Copy link

+1

@cowtowncoder
Copy link
Member

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.

@Reeska
Copy link

Reeska commented Dec 1, 2016

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

@vkrishna17
Copy link

vkrishna17 commented Apr 14, 2017

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.

@cowtowncoder
Copy link
Member

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests