Reputation: 21194
Default jackon behaviour seems to use both properties (getters and setters) and fields to serialize and deserialize to json.
I would like to use the fields as the canonical source of serialization config and thus don't want jackson to look at properties at all.
I can do this on an individual class basis with the annotation:
@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
But I don't want to have to put this on every single class...
Is it possible to configure this globally? Like add some to the Object Mapper?
Upvotes: 238
Views: 200540
Reputation: 38710
@since 2.10
version we can use JsonMapper.Builder and accepted answer could look like:
JsonMapper mapper = JsonMapper.builder()
.visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
.visibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
.visibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE)
.visibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE)
.visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE)
.build();
Upvotes: 6
Reputation: 341
It's very tricky in Kotlin with data classes and is* methods. For example for class:
data class SomeClass(val foo: String, val bar: String, val isSomething: Boolean):Serializable { fun isEmpty() = foo.isEmpty() }
I'm getting json like: {"bar"="bar", "empty"=false, "foo"="foo", "isSomething"=true}
And after setting: setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE)
the json is: {"bar"="bar", "foo"="foo"}
The only way I found to have isSomething
and do not have empty
is adding the @JsonIgnore
or @JvmSynthetic
annotation on isEmpty()
Moreover the fun fact is that adding method like isFoo(): Boolean
serializes foo only once, as a String.
Upvotes: 1
Reputation: 3373
If you use Spring Boot, you can configure Jackson globally as follows:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@Configuration
public class JacksonObjectMapperConfiguration implements Jackson2ObjectMapperBuilderCustomizer {
@Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.visibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
jacksonObjectMapperBuilder.visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
jacksonObjectMapperBuilder.visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY);
}
}
Upvotes: 7
Reputation: 1382
If you want a way to do this globally without worrying about the configuration of your ObjectMapper
, you can create your own annotation:
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonAutoDetect(
getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE,
creatorVisibility = JsonAutoDetect.Visibility.NONE
)
public @interface JsonExplicit {
}
Now you just have to annotate your classes with @JsonExplicit
and you're good to go!
Also make sure to edit the above call to @JsonAutoDetect
to make sure you have the values set to what works with your program.
Credit to https://stackoverflow.com/a/13408807 for helping me find out about @JacksonAnnotationsInside
Upvotes: 8
Reputation: 2844
You can configure individual ObjectMappers like this:
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
If you want it set globally, I usually access a configured mapper through a wrapper class.
Upvotes: 200
Reputation: 18030
Specifically for boolean is*()
getters:
I've spend a lot of time on why neither below
@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
nor this
setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE);
setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
worked for my Boolean Getter/Setter.
Solution is simple:
@JsonAutoDetect(isGetterVisibility = Visibility.NONE, ...
setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);
UPDATE: spring-boot allowed configure it:
jackson:
visibility.field: any
visibility.getter: none
visibility.setter: none
visibility.is-getter: none
See Common application properties # JACKSON
Upvotes: 49
Reputation: 5648
How about this: I used it with a mixin
non-compliant object
@Entity
@Getter
@NoArgsConstructor
public class Telemetry {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long pk;
private String id;
private String organizationId;
private String baseType;
private String name;
private Double lat;
private Double lon;
private Instant updateTimestamp;
}
Mixin:
@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
public static class TelemetryMixin {}
Usage:
ObjectMapper om = objectMapper.addMixIn(Telemetry.class, TelemetryMixin.class);
Telemetry[] telemetries = om.readValue(someJson, Telemetry[].class);
There is nothing that says you couldn't foreach any number of classes and apply the same mixin.
If you're not familiar with mixins, they are conceptually simply: The structure of the mixin is super imposed on the target class (according to jackson, not as far as the JVM is concerned).
Upvotes: 10
Reputation: 1218
for jackson 1.9.10 I use
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(JsonMethod.ALL, Visibility.NONE);
mapper.setVisibility(JsonMethod.FIELD, Visibility.ANY);
to turn of auto dedection.
Upvotes: 18
Reputation: 3244
In Jackson 2.0 and later you can simply use:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
...
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
to turn off autodetection.
Upvotes: 188