How to specify jackson to only use fields - preferably globally

JavaJsonJackson

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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.

Solution 3 - Java

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 https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html">Common application properties # JACKSON

Solution 4 - Java

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.

Solution 5 - Java

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

Solution 6 - Java

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

Solution 7 - Java

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);
    }

}

Solution 8 - Java

@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.SETTER, JsonAutoDetect.Visibility.NONE)
	.visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE)
	.build();

Solution 9 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMichael WilesView Question on Stackoverflow
Solution 1 - JavaTim HelmstedtView Answer on Stackoverflow
Solution 2 - JavalukkView Answer on Stackoverflow
Solution 3 - JavaGrigory KislinView Answer on Stackoverflow
Solution 4 - JavamfeView Answer on Stackoverflow
Solution 5 - JavaChristian BongiornoView Answer on Stackoverflow
Solution 6 - JavaretodaredevilView Answer on Stackoverflow
Solution 7 - JavaTimesView Answer on Stackoverflow
Solution 8 - JavaMichał ZioberView Answer on Stackoverflow
Solution 9 - JavapaulonioView Answer on Stackoverflow