In this tutorial, we will override Spring web converters, to support Vavr List and Option in Spring Boot DTOs. The end goal is to be able to write the request DTO code like this:

import com.demo.model.Customer;
import io.vavr.collection.List;
import io.vavr.control.Option;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class CustomerDtoReq {
    private Option<String> name;
    private Option<Integer> number;
    private Option<String> city;
    private List<OrderDto> orders;
    private Option<MembershipDto> membership;
    
        public Customer toEntity() {
            var c = new Customer();
            c.setName(name);
            c.setNumber(number);
            c.setCity(city);
            c.setOrders(orders.map(x -> x.toEntity(c)));
            c.setMembership(membership.map(MembershipDto::toEntity));
    
            return c;
        }
}

Vavr List can be easily mapped (without the whole .stream() and .collect() boilerplate code). Vavr Option is very useful to avoid using Java’s null and hence avoiding NullPointerException at runtime. Compared to Java’s Optional it has many advantages like the .fold() method which follows functional programming best practices:

U fold(Supplier<? extends U> ifNone, Function<? super T, ? extends U> f)

To do this, we just need to override the Spring converters in WebMvcConfig, using the LibCustom library. First, add this dependency to your pom.xml:

<dependency>
    <groupId>io.github.jleblanc64</groupId>
    <artifactId>lib-custom</artifactId>
    <version>1.0.7</version>
</dependency>

Also, if we want the null non-initialized Option fields to be converted to Option.None, we need to override some functions from Spring web external libraries, using the LibCustom library. In WebMvcConfig, just call the following code:

import io.github.jleblanc64.libcustom.LibCustom;
import io.github.jleblanc64.libcustom.custom.jackson.VavrJackson2;
import io.github.jleblanc64.libcustom.custom.spring.VavrSpring6;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        VavrJackson2.override(converters);
        VavrSpring6.override();
        LibCustom.load();
    }
}

Then, non initialized null fields like private List<OrderDto> orders; are automatically mapped to List.empty(). No need to manually specify default value such as: private List<OrderDto> orders = List.empty();. Instead, you can forget about it, and just focus on your code logic, and directly map your Entity fields to your DTO fields such as:

c.setOrders(orders.map(x -> x.toEntity(c)));
c.setMembership(membership.map(MembershipDto::toEntity));

Also, this whole logic also works for your response DTOs. You can see a full working Spring Boot app that uses these strategies in my Github repo. You may leave a question in the issues if you need.


<
Previous Post
Use Vavr List and Option with Hibernate 6
>
Next Post
Use Vavr List and Option in Spring 6 JPA repository