229

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?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Michael Wiles
  • 20,902
  • 18
  • 71
  • 101
  • 1
    Tim gave a good answer. Another possibility is that if you have a common base class, you can put class annotations to that one; annotations are inherited by Jackson. – StaxMan Aug 18 '11 at 18:44
  • 1
    I think I tried that, but it seems you have to tell the sub classes to use what the base case defines... – Michael Wiles Aug 19 '11 at 08:40
  • 2
    No, unless sub-class overrides class annotation, parent's annotations are visible as if they were part of sub-class definition (if not, this would be a bug). This is not necessarily how JDK deals with annotations, but Jackson implements full inheritance for annotations (even for method annotations). – StaxMan Aug 19 '11 at 18:10
  • Beware of the `INFER_PROPERTY_MUTATORS` flag. It forces the visibility of setters if there is a visible getter or field. – Ondra Žižka Jun 17 '18 at 23:43
  • [And others](https://github.com/FasterXML/jackson-databind/blob/master/src/main/java/com/fasterxml/jackson/databind/MapperFeature.java). – Ondra Žižka Jun 18 '18 at 02:50

9 Answers9

191

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.

pmartin8
  • 1,545
  • 1
  • 20
  • 36
Tim Helmstedt
  • 2,744
  • 1
  • 20
  • 10
  • 4
    Good, although I think you may need to also set the checker (withXxx() methods usually create a new object). So something like 'mapper.setVisibilityChecker(mapper.getVisibilityChecker().with...);' – StaxMan Aug 18 '11 at 18:43
  • @StaxMan good call on setVisibilityChecker, I edited the answer to reflect. – Kevin Bowersox Sep 29 '11 at 18:27
  • 56
    `withGetterVisibility` doesn't cover `is*` methods, but there's `withIsGetterVisibility` for them. – qerub May 12 '12 at 19:23
  • 15
    ```setVisibilityChecker```is deprecated. Use ```setVisibility``` instead. – Henrik Sachse Apr 06 '16 at 12:09
  • 1
    This is just what I needed! This configuration allowed me to use a Mixin to easily convert Hibernate entities to DTOs. By default the ObjectMapper serializes everything and a Mixin would have to specify which properties to ignore (i.e. a subtraction instead of an intersection). – TastyWheat Jun 03 '19 at 18:00
  • 1
    @StaxMan thanks, this comment just saved me. – PowR Nov 02 '21 at 16:57
181

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.

lukk
  • 3,164
  • 1
  • 30
  • 36
  • 1
    Hi guys, I am using Jackson 1.9.0 jar. I am getting additional json property, while serializing object to json string. I need to get the json string, which contains only mentioned variables with @JsonProperty. Can you please help me on this ? – jrh Nov 23 '13 at 22:01
  • 8
    You can start with class annotation mentioned in OP question: `@JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)` Next, you have to annotate each property you want to include with `@JsonProperty` – lukk Nov 25 '13 at 16:07
  • Thanks! Before, I've found many code examples where JsonMethod was referenced instead of PropertyAccessor. If you search for JsonMethod, you rarely get links to PropertyAccessor then... What is the best way to find replacement class names in successor artifacts? Can be tough and nasty, no? – philburns Mar 26 '19 at 15:44
47

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

Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197
18

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.

mfe
  • 1,158
  • 10
  • 15
10

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

Christian Bongiorno
  • 5,150
  • 3
  • 38
  • 76
6

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

retodaredevil
  • 1,261
  • 1
  • 13
  • 20
5

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

}

times29
  • 2,782
  • 2
  • 21
  • 40
3

@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();
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
1

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.

paulonio
  • 311
  • 1
  • 5