Serializer/Deserializer for Vavr objects

3.7k Views Asked by At

Hello Im trying to add vavr to my projet, right now Im struggling with proper serializaition of Vavr.List objects. Below is my controller:

import io.vavr.collection.List;

 @GetMapping(value = "/xxx")
    public List<EntityDeleted> getFile() {
        return List.of(new EntityDeleted(true),new EntityDeleted(true),new EntityDeleted(true),new EntityDeleted(true));
}

EntityDeleted is my custom object, List is Vavr collection as shown in import statement. The response Im getting in Postman is:

{
    "empty": false,
    "lazy": false,
    "async": false,
    "traversableAgain": true,
    "sequential": true,
    "singleValued": false,
    "distinct": false,
    "ordered": false,
    "orNull": {
        "deleted": true
    },
    "memoized": false
}

where I expect JSON list of my objects. Below is my config:

@SpringBootApplication
public class PlomberApplication {

    public static void main(String[] args) {
        SpringApplication.run(PlomberApplication.class, args);
    }

    @Bean
    public ObjectMapper jacksonBuilder() {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.registerModule(new VavrModule());
    }
}

and bit of pom.xml

 <dependency>
            <groupId>io.vavr</groupId>
            <artifactId>vavr</artifactId>
            <version>0.9.0</version>
        </dependency>
        <dependency>
            <groupId>io.vavr</groupId>
            <artifactId>vavr-jackson</artifactId>
            <version>0.9.0</version>
        </dependency>
3

There are 3 best solutions below

4
On BEST ANSWER

Spring Boot retrieves all instances of com.fasterxml.jackson.databind.Module class and initializes ObjectMapper with them. There's no need for additional magic.

My dependencies are as follows (Spring Boot 1.5.7.RELEASE):

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    compile group: 'io.vavr', name: 'vavr', version: '0.9.1'
    compile group: 'io.vavr', name: 'vavr-jackson', version: '0.9.1'
}

With application configurured like this:

@SpringBootApplication
public class BootvavrApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootvavrApplication.class, args);
    }

    @Bean
    Module vavrModule() {
        return new VavrModule();
    }
}

and controller mapped like this:

import io.vavr.collection.List;
@RestController
class TestController {

    @GetMapping("/test")
    List<String> testing() {
        return List.of("test", "test2");
    }
}

output is:

["test","test2"]

You can check the code out here: https://github.com/mihn/bootvavr

1
On

I'm not familiar with SpringBoot, but it seems you should return the VavrModule object instead of the ObjectMapper in your jacksonBuilder() method.

I base myself on these links:

2
On

The ObjectMapper you register as a bean is just not the one being use to serialize into JSON, Spring MVC won't use it to as it's not what he is looking for.

To handle content for HTTP Spring MVC uses HttpMessageConverter and if he detects Jackson in the classpath a MappingJackson2HttpMessageConverter will be autoconfigured if not specified.

In Spring Boot adding should be enough to register the custom MessageConverter:

@Bean  
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();   
    ObjectMapper mapper = new ObjectMapper();

    mapper.registerModule(new VavrModule());

    // Spring MVC default Objectmapper configuration
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);

    jacksonConverter.setObjectMapper(mapper);   
    return jacksonConverter;  
}

In a pure Spring MVC application you would have to had the following code in the WebMvcConfigurerAdapter class:

@Bean  
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();   
    ObjectMapper mapper = new ObjectMapper();

    mapper.registerModule(new VavrModule());

    // Spring MVC default Objectmapper configuration
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);

    jacksonConverter.setObjectMapper(mapper);   
    return jacksonConverter;  
}

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(customJackson2HttpMessageConverter());
    super.addDefaultHttpMessageConverters();
}

Some Documentation about ObjectMapper in Spring MVC

Hope it helped!