Serialization Money object in spring boot to REST api to have only price and currency

197 Views Asked by At

I have a project in Springboot and MongoDB, i want to serialize for the api get result the Money result with currency and amount and same when creating object but when i use the classic converter this is my json of my catalog and product list

[
  {
    "_id": "652274dc3f9cb11dc1118d3d",
    "products": [
      {
        "_id": null,
        "name": "ECW",
        "description": "new carbon wheel",
        "category": null,
        "variations": null,
        "price": {
          "currency": {
            "context": {
              "providerName": "java.util.Currency",
              "empty": false
            },
            "currencyCode": "AED",
            "defaultFractionDigits": 2,
            "numericCode": 784
          },
          "number": 4000,
          "factory": {
            "defaultMonetaryContext": {
              "precision": 0,
              "fixedScale": false,
              "maxScale": 63,
              "amountType": "org.javamoney.moneta.Money",
              "providerName": null,
              "empty": false
            },
            "minNumber": null,
            "maxNumber": null,
            "amountType": "org.javamoney.moneta.Money",
            "maximalMonetaryContext": {
              "precision": 0,
              "fixedScale": false,
              "maxScale": -1,
              "amountType": "org.javamoney.moneta.Money",
              "providerName": null,
              "empty": false
            }
          },
          "context": {
            "precision": 256,
            "fixedScale": false,
            "maxScale": -1,
            "amountType": "org.javamoney.moneta.Money",
            "providerName": null,
            "empty": false
          },
          "zero": false,
          "negative": false,
          "positive": true,
          "negativeOrZero": false,
          "positiveOrZero": true,
          "numberStripped": 4000
        },
        "vat": 5,
        "active": true
      }
    ],
    "date": "2023-10-08T09:22:36.473+00:00",
    "publicationDate": null,
    "active": true,
    "current": true
  }
]

As you can see the price serialization is awful so i a, trying to serialize to display only currency and amount

this my dto

@Data
@Builder
public class ProductDto {
    @Id
    private String id;
    private String name;
    private String description;
    private Category category;
    private List<Variation> variations;
    private MonetaryAmount price;
    private Double vat;
    private boolean active;
}

converters for mongo

@Configuration
public class MongoConfiguration {
    @Bean
    public MongoCustomConversions mongoCustomConversions() {
        return new MongoCustomConversions( List.of( new MoneyReadConverter(), new MoneyWriteConverter() ) );
    }
}

reader

package com.www.converter;

import javax.money.MonetaryAmount;
import org.javamoney.moneta.Money;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;

@ReadingConverter
public class MoneyReadConverter implements Converter<String, MonetaryAmount> {
    @Override
    public MonetaryAmount convert(String moneyString) {
        return Money.parse(moneyString);
    }
}

and writer

package com.www.converter;

import javax.money.MonetaryAmount;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.WritingConverter;

@WritingConverter
public class MoneyWriteConverter implements Converter<MonetaryAmount, String> {
    @Override
    public String convert(MonetaryAmount money) {
        return money.toString();
    }
}

then in controller

@GetMapping
    Flux<CatalogDto> getCatalogs() {
        return catalogService.getAll();
    }

and in my service

@Override
    public Flux<CatalogDto> getAll() {

        Flux<Catalog> catalogFlux  = catalogRepository.findAll();
        return catalogFlux
                .map( CatalogMapper::mapToCatalogDto )
                .switchIfEmpty( Flux.empty());
    }

pom.xml

<dependency>
            <groupId>org.javamoney</groupId>
            <artifactId>moneta</artifactId>
            <version>1.1</version>
        </dependency>

i tried to use some lib as jackson but it crashes application like use of ambigus configuration any idea ? like using a json deserializer just for this field in annotation?

1

There are 1 best solutions below

0
cyril On

So finally i listened chatGpt and added a jackson serializer with a module class

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

public class MoneyModule extends SimpleModule {
    public MoneyModule() {
        addSerializer( Money.class, new MoneySerializer());
        //add unserializer if needed
    }
}

then module registrer

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;

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

then serializer

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import org.javamoney.moneta.Money;

public class MoneySerializer extends JsonSerializer<Money> {
    @Override
    public void serialize(Money value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        gen.writeNumberField("amount", value.getNumber().doubleValue());
        gen.writeStringField("currency", value.getCurrency().getCurrencyCode());
        gen.writeEndObject();
    }
}

then in DTO

@JsonSerialize(using = MoneySerializer.class)
private MonetaryAmount price;

and finally the output looks alike

 "variations": null,
        "price": {
          "amount": 4000,
          "currency": "AED"
        },