Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any jackson json strategy (using annotations or another way), that will execute some logic prior and post deserialization of field?

I need to execute some code after each deserialization is done on a POJO's fields. Is there any way I can do this through some jackson annotation (or other) strategy?

  1. One way to go with this is create a custom deserializer for each field type that will implement PostLogicDeserializerInterface or extend some PostLogicDeserializerAbstract. But this will make loads of cluttering code that will be hard to maintain (instead of just using @JsonProperty). So I think this is not a good idea.

  2. I saw that you can use @JsonDeserialize on class level but only for value classes. From the documentation:

When annotating value classes, configuration is used for instances of the value class but can be overridden by more specific annotations (ones that attach to methods or fields).

So I think this won't work, either.

  1. Using some custom logic in the POJOs setter methods is a bad practice! And on the other side, I think jackson uses reflection to set the fields anyway... Not a good strategy, neither.

My goal is to determine the percentage of fields that were set by the deserializer. I would need to have a counter that will increase on each invoked deserialization (populated field). And once the whole class(POJO) deserialization is over, I would need to execute some logic using reflection.

The way I have that implemented now, is

  • once I have the POJO deserialized by the jackson mapper, I go through each field using reflection
  • check if it has been set, f.i. if it is null or -1 for primitive numbers (previously initial values). (one conn of this approach is that you can't check a boolean if it was set)
  • use reflection for some other kind of checking (lets call it logic X)
  • execute logic that depends on percentage of set fields and logic X.

I would prefer some jackson strategy, since I wouldn't need to check the POJO with reflection. It would rather be done in place (at the time the POJO gets deserialized).

Cheers,
Despot

like image 388
despot Avatar asked Apr 02 '11 10:04

despot


People also ask

What is Jackson annotations used for?

The Jackson annotation @JsonCreator is used to tell Jackson that the Java object has a constructor (a "creator") which can match the fields of a JSON object to the fields of the Java object.

Which methods does Jackson rely upon to deserialize a JSON formatted string?

The @JsonSetter annotation tells Jackson to deserialize the JSON into Java object using the name given in the setter method. Use this annotation when your JSON property names are different to the fields of the Java object class, and you want to map them.

How does Jackson JSON work?

The Jackson ObjectMapper can parse JSON from a string, stream or file, and create a Java object or object graph representing the parsed JSON. Parsing JSON into Java objects is also referred to as to deserialize Java objects from JSON. The Jackson ObjectMapper can also create JSON from Java objects.

What is the use of JSON property annotation?

@JsonProperty is used to mark non-standard getter/setter method to be used with respect to json property.


1 Answers

There isn't any specific feature to do post- or pre-processing at this point; and this sort of gets close to boundaries of what data binding should do. If I had to do this for specific fields, I would probably just add it in setter, since that is simple thing to do and works; but requires same logic in all relevant setters.

@JsonDeserialize can also be used for individual properties (field, setter), so you could create a custom deserializer: and since you want post-processing, you could just locate "real" deserializer (ideally by making JsonDeserializer implement either ContextualDeserializer or ResolvableDeserializer -- this may not matter here, but for general case it's done here to avoid problems with cyclic dependencies), delegate to it, and modify value. This assumes it is value you care about more than field.

Finally, there are also ways to modify BeanDeserializer instances (by registering BeanDeserializerModifier) -- you could sub-class relevant components (SettableBeanProperty I think...) to hook in additional handling, or even replace deserializer to use, keeping a reference to the original "default" deserializer.

But in the end, your case sounds like something that may be best handled by something else: for example Bean Validation API (jsr-303) seems like a potentially good match for post-processing logic. Since it is somewhat orthogonal to data binding, it could be a superior alternative since it would be independent of data binding (jackson), reusable, all the good stuff.

like image 72
StaxMan Avatar answered Oct 06 '22 00:10

StaxMan