convertValue ignore anySetter/anyGettter

47 views
Skip to first unread message

Ken Hancock

unread,
Aug 11, 2023, 12:31:13 PM8/11/23
to jackson-user

I have a pojo that serializes any additional properties into 

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
    return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
    this.additionalProperties.put(name, value);
}


However, I have an odd use case where I want to be able to strip any additional properties before writing an object. I'm fairly sure with all of Jackson's configuration settings that I should be able to configure a mapper such that mapper.convertValue(myPojo, MyPojo.class) should be able to serialize and deserialize back again, dropping the additionalProperties when it serializes?   The pojo is deeply nested and auto-generated, so I'd prefer not to hard-code having to just clear additionalProperties at each sub-object.

Thanks,

Ken

Joo Hyuk Kim (김주혁)

unread,
Aug 12, 2023, 8:31:54 AM8/12/23
to jackson-user

Hello Ken,

To make things clear, a few questions.

  • Meaning of "to strip any additional properties before writing an object". Are you looking to exclude `additionalProperties` only during serialization, but include in deserialization?
  • Is the primary intent to generate a JSON output that does not include `additionalProperties`, or is there another objective?
  • Could you also provide a simple, reproducible example using just Jackson and Java?

Thanks,

Joo Hyuk, Kim (Vince)

Ken Hancock

unread,
Aug 14, 2023, 10:59:36 AM8/14/23
to jackson-user

Hi Vince,

If I'm understanding the implementation of mapper.convertVaue(), I think it doesn't matter whether it's on serialization or deserialization since convertValue() does both.

To illustrate, let's say I have a pojo with one field and the anySetter/anyGetter:

@JsonProperty("onlyField")
private String onlyField;

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
    return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
    this.additionalProperties.put(name, value);
}

If I deserialize {"onlyField": "someValue", "additional": "anotherValue"}, I end up with a pojo with object.getOnlyField() == "someValue") and object.getAdditionalProperties().get("additional") == "anotherValue")

Now when I call mapper.convertValue(object, MyPojo.class):
if I drop on serialization, I end up with a serialized object of {"onlyField": "someValue"}
if I drop on deserialize, I start with a serialized object of  {"onlyField": "someValue", "additional": "anotherValue"} but end up with a pojo with an empty map in object.getAditionalProperties().

If I can do it at either step, I'd love to know how, but either one will solve my current problem.

Here's a gist with a sample, which currently fails: https://gist.github.com/hancockks/02509e5d06b0f1d95b1e3e6c4a23a9f1

Joo Hyuk Kim (Vince)

unread,
Aug 15, 2023, 5:30:35 AM8/15/23
to jackson-user

> if I drop on...

Though I am not sure what you mean by "dropping on", but as far as I understood....

```java

SimpleObject simpleObject = new SimpleObject();

simpleObject.setSingleField("onlyField");

simpleObject.setAdditionalProperty("additional", "additional");

simpleObject.setAdditionalProperty("remains", "remains");

```

...should serialize into `{"singleField":"onlyIfeld"}`.


And JSON string `{"onlyField": "someValue", "additional": "anotherValue"}` should deserialize into an instance of `SimpleObject` class with "onlyField" as its singleField and empty map?

Try simply removing `@JsonAnySetter` and `@JsonAnyGetter`. 


Hope it helps,

thanks

Ken Hancock

unread,
Aug 15, 2023, 2:59:26 PM8/15/23
to jackson-user
I can't remove the @JsonAnySetter and @JsonAnyGetter as 

(1) those are generated automatically from the schema
(2) in the nominal use case I want to preserve the additional properties

It's only in one special case where I'm sending data to an external system that I need to strip them off, hence I'd like to be able to configure that at runtime via a differently configured mapper.

Joo Hyuk Kim (Vince)

unread,
Aug 15, 2023, 9:15:49 PM8/15/23
to jackson-user
There was similar issue in jackson-databind Github , but the issue is per-class declaration usecase.

If we can have a differently configured mapper,  how about....

1. Copy the global mapper via `mapper.copy()`
2. Add custom de/serializer to the new mapper from (1)
3. The custom de/serializer from (2) will handle de/serialization for specific cases?

... this, might work? 

Ken Hancock

unread,
Aug 16, 2023, 8:19:16 AM8/16/23
to jackson-user
I think so, but that was my original question -- I couldn't figure out how to customize the master to drop that field.

Ken Hancock

unread,
Aug 16, 2023, 10:35:51 AM8/16/23
to jackso...@googlegroups.com
Success. I used the setAnnotationIntrospector to essentially remove the @JsonAnyGetter():
ObjectMapper mapper = new ObjectMapper();

mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
@Override
public Boolean hasAnyGetter(final Annotated m) {
return false;
}
});


--
You received this message because you are subscribed to the Google Groups "jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jackson-user/de0ff137-4ffe-445c-b6f5-f345ecc5caecn%40googlegroups.com.

Joo Hyuk Kim (Vince)

unread,
Aug 16, 2023, 10:51:54 AM8/16/23
to jackson-user
I see, having a seperate mapper instance and disabling (sort of).

Hope it solves your case ✌🏼✌🏼

Tatu Saloranta

unread,
Aug 18, 2023, 10:18:39 PM8/18/23
to jackso...@googlegroups.com
On Wed, Aug 16, 2023 at 7:35 AM Ken Hancock <hanc...@gmail.com> wrote:
>
> Success. I used the setAnnotationIntrospector to essentially remove the @JsonAnyGetter():
>
> ObjectMapper mapper = new ObjectMapper();
>
> mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
> @Override
> public Boolean hasAnyGetter(final Annotated m) {
> return false;
> }
> });

That definitely works: an alternative could be to use mix-in
annotations to associate `@JsonAnyGetter(false)` "over" existing one.

What might also work -- although I haven't verified this -- is use of
`@JsonIgnoredProperties` along with any-getter/-setter annotation
(it works on regular `Map` valued properties but may or may not work
with any getter)

-+ Tatu +-
> To view this discussion on the web visit https://groups.google.com/d/msgid/jackson-user/CAGi%2BZD2_x%3D6sVuTcfp57CxHq2xj_3sfdym8qwbhCKcZmdQo6Mw%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages