Using Jackson ObjectMapper with Java 8 Optional values

前端 未结 7 1877
长发绾君心
长发绾君心 2020-12-01 05:03

I was trying to use Jackson to write a class value to JSON that has Optional as fields:

public class Test {
    Optional field = Optional.of(\"         


        
相关标签:
7条回答
  • 2020-12-01 05:25

    If you are using latest version of Spring-boot then you could achieve this by adding the following dependency in the pom file

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jdk8</artifactId>
    </dependency>
    

    And auto wire the JacksonObjectMapper.

    @Autowired
    private ObjectMapper jacksonObjectMapper;
    

    Then use the above Spring container's mapper instance to convert Object to String

    jacksonObjectMapper.writeValueAsString(user);
    

    Spring blog says :

    Some well known Jackson modules are automatically registered if they are detected on the classpath:

    • jackson-datatype-jdk7: Java 7 types like java.nio.file.Path (as of 4.2.1 release)
    • jackson-datatype-joda: Joda-Time types
    • jackson-datatype-jsr310: Java 8 Date & Time API data types
    • jackson-datatype-jdk8: other Java 8 types like Optional (as of 4.2.0 release)
    0 讨论(0)
  • 2020-12-01 05:27

    Define new getter which will return String instead of Optional.

    public class Test {
        Optional<String> field = Optional.of("hello, world!");
    
        @JsonIgnore
        public Optional<String> getField() {
            return field;
        }
    
        @JsonProperty("field")
        public String getFieldName() {
            return field.orElse(null);
        }
    
    }
    
    0 讨论(0)
  • 2020-12-01 05:33

    You could use jackson-datatype-jdk8 which is described as:

    Support for new JDK8-specific types, such as Optional

    In order to do this:

    • add com.fasterxml.jackson.datatype:jackson-datatype-jdk8 as a dependency
    • register the module with your object mapper: objectMapper.registerModule(new Jdk8Module());
    0 讨论(0)
  • 2020-12-01 05:40

    Try passing in options into @JsonInclude annotation.
    For example, if you don't want to show field when the value is null. You might need to use Jackson-Modules >2.8.5.

    import com.fasterxml.jackson.annotation.JsonInclude;
    
    public class Test {
        @JsonInclude(JsonInclude.Include.NON_NULL)
        Optional<String> field;
    }
    
    0 讨论(0)
  • 2020-12-01 05:41

    You only need to register module Jdk8Module. Then it will serialize any Optional<T> as T if it is present or null otherwise.

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new Jdk8Module());
    

    Let's modify Test class a bit so we can test for an Optional.empty() value. This is similar to the original Test class when serialized because the object mapper is looking for the getter (since the field is private). Using the original Test class will work too, though.

    class Test {
        private final String field;
    
        public Test(String field) {
            this.field = field;
        }
    
        public Optional<String> getField() {
            return Optional.ofNullable(field);
        }
    }
    

    Then in our main class:

    Test testFieldNull = new Test(null);
    Test testFieldNotNull = new Test("foo");
    
    // output: {"field":null}
    System.out.println(objectMapper.writeValueAsString(testFieldNull)); 
    
    // output: {"field":"foo"}
    System.out.println(objectMapper.writeValueAsString(testFieldNotNull)); 
    
    0 讨论(0)
  • 2020-12-01 05:43

    The Optional class has a value field, but no standard getter/setter for it. By default, Jackson looks for getters/setters to find class properties.

    You can add a custom Mixin to identify the field as a property

    final class OptionalMixin {
        private Mixin(){}
        @JsonProperty
        private Object value;
    }
    

    and register it with your ObjectMapper.

    ObjectMapper mapper = new ObjectMapper();
    mapper.addMixInAnnotations(Optional.class, OptionalMixin.class);
    

    You can now serialize your object.

    System.out.println(mapper.writeValueAsString(new Test()));
    

    will print

    {"field":{"value":"hello, world!","present":true}}
    

    Consider also looking at jackson-datatype-guava. There's a Jackson Module implementation for Guava types including their Optional. It's possibly more complete than what I've shown above.

    0 讨论(0)
提交回复
热议问题