Jackson JSON Processor
  1. Jackson JSON Processor
  2. JACKSON-538

Add post-processing (deserialization) hook, like @JsonPostDeserialize

    Details

    • Type: New Feature New Feature
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: UNRESOLVED
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: Deserializer
    • Labels:
      None
    • Number of attachments :
      0

      Description

      Tatu, hello;

      I am using mapper policy like one shown below;

      what I am missing is @JsonMandatory annotation which would distinguish few fields in the bean which MUST be present for the deserializer to succed;(most other fields are already annotated with @JsonProperty and are optional)

      or am I missing some hidden feature?

      thank you.

      Andrei.

      #####################################################

      @SuppressWarnings("deprecation")
      public static void applyMapperPolicy(final ObjectMapper mapper)

      { /* READ: */ // must annotate fields with @JsonProperty explicitly mapper.getDeserializationConfig().disable( DeserializationConfig.Feature.AUTO_DETECT_FIELDS); // must annotate fields with @JsonProperty explicitly mapper.getDeserializationConfig().disable( DeserializationConfig.Feature.AUTO_DETECT_SETTERS); // must annotate fields with @JsonCerator explicitly mapper.getDeserializationConfig().disable( DeserializationConfig.Feature.AUTO_DETECT_CREATORS); // make all unknown into optional mapper.getDeserializationConfig().disable( DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES); /* WRITE: */ // will introduce tabs mapper.getSerializationConfig().enable( SerializationConfig.Feature.INDENT_OUTPUT); // must annotate with @JsonProperty explicitly mapper.getSerializationConfig().disable( SerializationConfig.Feature.AUTO_DETECT_FIELDS); // must annotate with @JsonProperty explicitly mapper.getSerializationConfig().disable( SerializationConfig.Feature.AUTO_DETECT_GETTERS); // must annotate with @JsonProperty explicitly mapper.getSerializationConfig().disable( SerializationConfig.Feature.AUTO_DETECT_IS_GETTERS); // no more empty fields mapper.getSerializationConfig().disable( SerializationConfig.Feature.WRITE_NULL_PROPERTIES); }

        Activity

        Hide
        Tatu Saloranta added a comment -

        I am not sure this is something Jackson should handle: that's what JSR-303 (Bean Validation API) is about. So this omission is deliberate.

        But I am not against someone writing a module (and adding hooks it needs, if any, from core) that would offer such validation functionality.
        In fact, using a JSR-303 implementation as the validator would make lots of sense. I just don't see this as something core or mapper should specifically implement.

        Show
        Tatu Saloranta added a comment - I am not sure this is something Jackson should handle: that's what JSR-303 (Bean Validation API) is about. So this omission is deliberate. But I am not against someone writing a module (and adding hooks it needs, if any, from core) that would offer such validation functionality. In fact, using a JSR-303 implementation as the validator would make lots of sense. I just don't see this as something core or mapper should specifically implement.
        Hide
        Andrei Pozolotin added a comment -

        can you please link me to the source of such module already done right? (outside of your source, independent effort?); and link for adding hooks?

        Show
        Andrei Pozolotin added a comment - can you please link me to the source of such module already done right? (outside of your source, independent effort?); and link for adding hooks?
        Hide
        Andrei Pozolotin added a comment -

        may be you should expose generic interface for JSR-303 in your core?

        Show
        Andrei Pozolotin added a comment - may be you should expose generic interface for JSR-303 in your core?
        Hide
        Tatu Saloranta added a comment -

        I am open to adding necessary hooks, but would need to get better idea as to what this should look like. I guess it would be sort of post-binding callback.
        I am not quite sure how useful this would be, mostly since what I do myself (just call validator after data binding) seems straight-forward and explicit; and keeps separate concerns (data binding, data validation) separate.

        But if a generic post-binding callback made sense for multiple use cases, this could be added.

        Show
        Tatu Saloranta added a comment - I am open to adding necessary hooks, but would need to get better idea as to what this should look like. I guess it would be sort of post-binding callback. I am not quite sure how useful this would be, mostly since what I do myself (just call validator after data binding) seems straight-forward and explicit; and keeps separate concerns (data binding, data validation) separate. But if a generic post-binding callback made sense for multiple use cases, this could be added.
        Hide
        Andrei Pozolotin added a comment -

        here is my use case du jour:

        I deserialize object form json; object has field: [String iconURL];
        this happens in osgi plugin which must convert url from [String] to [URL] in current bundle classloader before this object will be used in another bundle (which has different classloader, and can not see resource url from current bundle)

        so "post-binding callback" in this case would load:
        URL url = getClass().getClassLoader().getResource(iconURL)

        as a last step of deserialization

        Show
        Andrei Pozolotin added a comment - here is my use case du jour: I deserialize object form json; object has field: [String iconURL] ; this happens in osgi plugin which must convert url from [String] to [URL] in current bundle classloader before this object will be used in another bundle (which has different classloader, and can not see resource url from current bundle) so "post-binding callback" in this case would load: URL url = getClass().getClassLoader().getResource(iconURL) as a last step of deserialization
        Hide
        Andrei Pozolotin added a comment -

        so you are right: this is not @JsonMandatory it is @JsonPostDeserialize
        and it allows essentially to avoid making a custom deserializer
        for cases when you just need to tweek a couple of fields
        along with validation / default value enforcement

        Show
        Andrei Pozolotin added a comment - so you are right: this is not @JsonMandatory it is @JsonPostDeserialize and it allows essentially to avoid making a custom deserializer for cases when you just need to tweek a couple of fields along with validation / default value enforcement
        Hide
        Tatu Saloranta added a comment -

        Actually I think it would be reasonable to have both: will leave this one for @JsonMandatory (which might make sense to add actually), also create @JsonPostDeserialize for separate RFE.

        Show
        Tatu Saloranta added a comment - Actually I think it would be reasonable to have both: will leave this one for @JsonMandatory (which might make sense to add actually), also create @JsonPostDeserialize for separate RFE.
        Hide
        Alex Porras added a comment -

        Hello,

        I'm just catching up with this thread, as I was looking to see if Jackson had such hooks. My only suggestion against @JsonMandatory is that it is only convering one facet of JSR-303 validation (for example, in addition to @NotNull, which I suppose would be the implied equivalent of @JsonMandatory, JSR-303 has things like @Min(2). I presume that is why Andrei suggested "@JsonPostDeserialize", as I think what we are seeking is an annotation that says "call JSR-303 validation, whatever that is", and leave the "what" to the JSR-303 annotations themselves. May I suggest @JsonValidate?

        Also, I would be glad to help with this if I can get familiar with the sources, or write unit tests.

        Show
        Alex Porras added a comment - Hello, I'm just catching up with this thread, as I was looking to see if Jackson had such hooks. My only suggestion against @JsonMandatory is that it is only convering one facet of JSR-303 validation (for example, in addition to @NotNull, which I suppose would be the implied equivalent of @JsonMandatory, JSR-303 has things like @Min(2). I presume that is why Andrei suggested "@JsonPostDeserialize", as I think what we are seeking is an annotation that says "call JSR-303 validation, whatever that is", and leave the "what" to the JSR-303 annotations themselves. May I suggest @JsonValidate? Also, I would be glad to help with this if I can get familiar with the sources, or write unit tests.
        Hide
        Tatu Saloranta added a comment -

        True, there is danger of doing one small part in area that I have said I don't want to venture in (I prefer tools that to limited number of things well, and leave other aspects to other libs that focus in these).

        I do think however that there is more need for a hook to be called immediately after deserialization, not just for validation but for possible resolving of references or other initialization tasks that can not be done in constructor (or more generally in ValueInstantiator), since data for pojo is not yet available.

        I am not sure what the name for this ought to be: while @JsonValidate is nice in itself, it would wrongly imply that validation is the focus, and probably lead to requests for bigger and bigger subset of JSR-303 style functionality.

        Finally: if a post-deserialization hook is added, it should be possible to create something like "jackson4jsr313", which would use the hook to invoke JSR-303 validation on POJOs automatically.
        This because Jackson core should not have dependency on JSR-303, and modules are the way to properly add extensions like this.

        Does above make sense?

        Show
        Tatu Saloranta added a comment - True, there is danger of doing one small part in area that I have said I don't want to venture in (I prefer tools that to limited number of things well, and leave other aspects to other libs that focus in these). I do think however that there is more need for a hook to be called immediately after deserialization, not just for validation but for possible resolving of references or other initialization tasks that can not be done in constructor (or more generally in ValueInstantiator), since data for pojo is not yet available. I am not sure what the name for this ought to be: while @JsonValidate is nice in itself, it would wrongly imply that validation is the focus, and probably lead to requests for bigger and bigger subset of JSR-303 style functionality. Finally: if a post-deserialization hook is added, it should be possible to create something like "jackson4jsr313", which would use the hook to invoke JSR-303 validation on POJOs automatically. This because Jackson core should not have dependency on JSR-303, and modules are the way to properly add extensions like this. Does above make sense?
        Hide
        Alex Porras added a comment -

        Hi Tatu,

        Yes, it makes perfect sense, having jsr303 specific hooks build on top of the generic post-deserialization hook. The only thing I may add is: should this exist in serialization too?

        Regards,

        Alex

        Show
        Alex Porras added a comment - Hi Tatu, Yes, it makes perfect sense, having jsr303 specific hooks build on top of the generic post-deserialization hook. The only thing I may add is: should this exist in serialization too? Regards, Alex
        Hide
        Tatu Saloranta added a comment -

        Good question. If history is any guidance, there's high chance of wanting something similar eventually, even if it wasn't immediately obvious.
        But I think we can split this in two parts: hook to call should probably differ anyway, and it might be that one rather wants "pre-serialization" hooks... so we can add another Jira entry for serialization side.

        Show
        Tatu Saloranta added a comment - Good question. If history is any guidance, there's high chance of wanting something similar eventually, even if it wasn't immediately obvious. But I think we can split this in two parts: hook to call should probably differ anyway, and it might be that one rather wants "pre-serialization" hooks... so we can add another Jira entry for serialization side.
        Hide
        Alex Porras added a comment -

        Sounds great. If you'd like, once you have the post-deserialization hook in place, I could take a stab at doing the jackson4jsr303 one. Or let me know if I can help in any way.

        Cheers,

        Alex

        Show
        Alex Porras added a comment - Sounds great. If you'd like, once you have the post-deserialization hook in place, I could take a stab at doing the jackson4jsr303 one. Or let me know if I can help in any way. Cheers, Alex
        Hide
        Tatu Saloranta added a comment -

        Definitely, I could use help with jsr303 module, once hook is added. It may take a while, given large number of items to work on 1.9, but it sounds like one of more important features to add.

        Show
        Tatu Saloranta added a comment - Definitely, I could use help with jsr303 module, once hook is added. It may take a while, given large number of items to work on 1.9, but it sounds like one of more important features to add.
        Hide
        Alex Porras added a comment -

        Glad to hear it. I'm getting familiar with it myself, so hopefully I'll be able to contribute by the time you get this in 1.9. I am watching this jira, so I'll keep an eye out for an email sometime.

        Show
        Alex Porras added a comment - Glad to hear it. I'm getting familiar with it myself, so hopefully I'll be able to contribute by the time you get this in 1.9. I am watching this jira, so I'll keep an eye out for an email sometime.
        Hide
        Tatu Saloranta added a comment -

        Just realized one practical concern: for validation, annotation should only apply to root value, since it is recursive. But for other kinds of post-processing, makes more sense to apply to all pojos.
        So it is quite possible that hook for specific validation use should be different after all; something to call after root-level readValue() call.

        Show
        Tatu Saloranta added a comment - Just realized one practical concern: for validation, annotation should only apply to root value, since it is recursive. But for other kinds of post-processing, makes more sense to apply to all pojos. So it is quite possible that hook for specific validation use should be different after all; something to call after root-level readValue() call.
        Hide
        Alex Porras added a comment -

        Good morning Tatu,

        Let's see if I am understanding you correctly: if you have class A instance that has class B instance as a child, would you expect the implementor to call the hook by annotating class A only, and jackson recurse through to B, or would the post processing callback provide the root level object to the method, and the implementor decides on the scope of their callback?

        Alex

        Show
        Alex Porras added a comment - Good morning Tatu, Let's see if I am understanding you correctly: if you have class A instance that has class B instance as a child, would you expect the implementor to call the hook by annotating class A only, and jackson recurse through to B, or would the post processing callback provide the root level object to the method, and the implementor decides on the scope of their callback? Alex
        Hide
        Tatu Saloranta added a comment -

        I remember Bean validators to do recursive validation (depending on annotations), which makes sense, otherwise calling app would indeed have to manually implement recursive solution. And without validation framework doing this there are many things that can not really be verified.
        So for that use case calling validation-hook for all POJOs would cause lots of unnecessary calls.

        I am basically suggesting possible need for two kinds of callbacks; one only for the mapper.readValue() context, and another for each time object was complete. Latter actually requires lots of work just because each and every deserializer would need to be aware of having to check for registered listeners.

        Show
        Tatu Saloranta added a comment - I remember Bean validators to do recursive validation (depending on annotations), which makes sense, otherwise calling app would indeed have to manually implement recursive solution. And without validation framework doing this there are many things that can not really be verified. So for that use case calling validation-hook for all POJOs would cause lots of unnecessary calls. I am basically suggesting possible need for two kinds of callbacks; one only for the mapper.readValue() context, and another for each time object was complete. Latter actually requires lots of work just because each and every deserializer would need to be aware of having to check for registered listeners.
        Hide
        Alex Porras added a comment -

        That makes sense. Maybe you can wait on the latter, more complicated use case, until you see a need?

        Show
        Alex Porras added a comment - That makes sense. Maybe you can wait on the latter, more complicated use case, until you see a need?
        Hide
        Tatu Saloranta added a comment -

        Note: JACKSON-767 now exists for adding something simple like:

        @JsonProperty(required=true)

        which would handle '@JsonMandatory' use case; but no additional post-processing.

        Show
        Tatu Saloranta added a comment - Note: JACKSON-767 now exists for adding something simple like: @JsonProperty(required=true) which would handle '@JsonMandatory' use case; but no additional post-processing.
        Hide
        Tatu Saloranta added a comment -

        Closing as part of move to github issues. Does not mean this isn't on our radar; need to have an entry at jackson-databind project, either specific for use case (check-is-required), or generic.

        Main challenge is still the fact that BeanDeserializer has too many codepaths, and passing of state is difficult currently.

        Show
        Tatu Saloranta added a comment - Closing as part of move to github issues. Does not mean this isn't on our radar; need to have an entry at jackson-databind project, either specific for use case (check-is-required), or generic. Main challenge is still the fact that BeanDeserializer has too many codepaths, and passing of state is difficult currently.
        Show
        Tatu Saloranta added a comment - Moved to: https://github.com/FasterXML/jackson-databind/issues/279

          People

          • Assignee:
            Tatu Saloranta
            Reporter:
            Andrei Pozolotin
          • Votes:
            3 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: