Import custom jackson serializer (Module) in webflutest Springboot 3.2

104 views Asked by At

I have an application in webflux and SpringBoot 3.2

i have custom Jackson Module and serializer, ubfortunately when i try to execute test no serializer found

Custom module

package ae.company.banking.configuration.converters;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new MoneyModule());
        objectMapper.registerModule(new JavaTimeModule());
        return objectMapper;
    }
}

DeSerializer

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import javax.money.CurrencyUnit;
import javax.money.Monetary;
import org.javamoney.moneta.Money;
import org.springframework.stereotype.Component;

@Component
public class MoneyDeserializer extends JsonDeserializer<Money> {

    @Override
    public Money deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.getCodec().readTree(p);
        double amount = node.get("amount").asDouble();
        String currencyCode = node.get("currency").asText();

        CurrencyUnit currency = Monetary.getCurrency(currencyCode);
        return Money.of(amount, currency);
    }
}

The module

package ae.company.banking.configuration.converters;

import com.fasterxml.jackson.databind.module.SimpleModule;
import org.javamoney.moneta.Money;

public class MoneyModule extends SimpleModule {
    public MoneyModule() {
        addSerializer( Money.class, new MoneySerializer());
        addDeserializer( Money.class, new MoneyDeserializer());
    }
}

my test

@WebFluxTest( controllers = UserController.class )
@Import( { JacksonConfig.class, FindUserById.class, FindAllUsers.class, AddUserAccount.class, AddUserBeneficiary.class, WebFluxControllerSecurityTestConfig.class } )
class UserControllerTest {
    @Autowired
    UserController controller;

    @MockBean
    UserRepository repository;

    @MockBean
    JwtTokenFilter filter;

    @Test
    @WithMockUser
    void testGetgetUserById() {
        CurrencyUnit eur = Monetary.getCurrency( "EUR" );

        var user = User.builder()
                .id( "4787889456456456456frfrfrf582" )
                .identityId( "iyioyuy9y98y9y9" )
                .firstName( "firstname2" )
                .lastName( "lastname2" )
                .role( Role.USER )
      .balance( Money.of( 200, eur ) )
                .username( "[email protected]" ).build();
        when( repository.findById( "4787889456456456456frfrfrf87" ) )
                .thenReturn( Mono.just( user ) );

        var testClient = WebTestClient.bindToController( controller ).webFilter( new SecurityContextServerWebExchangeWebFilter() )
                .apply( springSecurity() )
                .build();
        testClient
                .get().uri( "/api/v1/users/4787889456456456456frfrfrf87" )
                .exchange()
                .expectStatus().isOk()
                .expectBodyList( UserDto.class )
                .hasSize( 1 );
        Mockito.verify( repository, times( 1 ) ).findById( "4787889456456456456frfrfrf87" );
    }

And the error

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of javax.money.MonetaryAmount (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

1

There are 1 answers

0
cyril On

To make it work ive done this

var testClient = WebTestClient

        .bindToController( controller ).webFilter( new SecurityContextServerWebExchangeWebFilter() )
        .apply( springSecurity() )
        .build();
testClient
        .mutate()
        .codecs( clientCodecConfigurer ->
                clientCodecConfigurer.defaultCodecs()
                        .jackson2JsonDecoder( new Jackson2JsonDecoder( mapper ) ) ).build()
        .post().uri( "/api/v1/users/4787889456456456456frfrfrf87/SAVING" )
        .exchange()
        .expectStatus().isCreated()
        .expectBodyList( UserDto.class )
        .hasSize( 1 );
Mockito.verify( repository, times( 1 ) ).save( user );

and injected mapper

@Autowired ObjectMapper mapper;

i will try the solution of @M. Deinum