web-dev-qa-db-fra.com

Java vers la sérialisation Jackson JSON: champs d'argent

Actuellement, j'utilise Jackson pour envoyer les résultats JSON à partir de mon application Web Spring.

Le problème que j'essaie est de faire sortir tous les champs d'argent avec 2 décimales. Je n'ai pas pu résoudre ce problème en utilisant setScale(2), car les nombres comme 25,50 sont tronqués à 25,5, etc.

Quelqu'un d'autre a-t-il réglé ce problème? Je pensais créer une classe Money avec un sérialiseur Jackson personnalisé ... pouvez-vous créer un sérialiseur personnalisé pour une variable de champ? Vous pouvez probablement ... Mais même quand même, comment pourrais-je demander à mon sérialiseur client d'ajouter le nombre comme un nombre avec 2 décimales?

40
ControlAltDel

Vous pouvez utiliser un sérialiseur personnalisé dans votre champ d'argent. Voici un exemple avec un MoneyBean. Le champ montant est annoté avec @ JsonSerialize (en utilisant = ...).

public class MoneyBean {
    //...

    @JsonProperty("amountOfMoney")
    @JsonSerialize(using = MoneySerializer.class)
    private BigDecimal amount;

    //getters/setters...
}

public class MoneySerializer extends JsonSerializer<BigDecimal> {
    @Override
    public void serialize(BigDecimal value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
            JsonProcessingException {
        // put your desired money style here
        jgen.writeString(value.setScale(2, BigDecimal.ROUND_HALF_UP).toString());
    }
}

C'est ça. Un BigDecimal est maintenant imprimé de la bonne façon. J'ai utilisé un testcase simple pour le montrer:

@Test
public void jsonSerializationTest() throws Exception {
     MoneyBean m = new MoneyBean();
     m.setAmount(new BigDecimal("20.3"));

     ObjectMapper mapper = new ObjectMapper();
     assertEquals("{\"amountOfMoney\":\"20.30\"}", mapper.writeValueAsString(m));
}
63
Steve

Au lieu de définir @JsonSerialize sur chaque membre ou getter, vous pouvez configurer un module qui utilise un sérialiseur personnalisé pour un certain type:

SimpleModule module = new SimpleModule();
module.addSerializer(BigInteger.class, new ToStringSerializer());
objectMapper.registerModule(module);

Dans l'exemple ci-dessus, j'ai utilisé le pour sérialiser le sérialiseur pour sérialiser les BigIntegers (car javascript ne peut pas gérer de telles valeurs numériques).

24
Modi

Vous pouvez utiliser @JsonFormat annotation avec shape comme STRING sur vos BigDecimal variables. Référez-vous ci-dessous:

 import com.fasterxml.jackson.annotation.JsonFormat;

  class YourObjectClass {

      @JsonFormat(shape=JsonFormat.Shape.STRING)
      private BigDecimal yourVariable;

 }
23
Sahil Chhabra

Je suis l'un des responsables de jackson-datatype-money , alors prenez cette réponse avec un grain de sel car je suis certainement biaisé. Le module devrait couvrir vos besoins et il est assez léger (pas de dépendances d'exécution supplémentaires). De plus, il est mentionné dans les Jackson docs , Spring docs et il y avait même quelques discussions déjà sur la façon de l'intégrer dans l'écosystème officiel de Jackson .

13
whiskeysierra

J'ai eu le même problème et je l'ai plutôt formaté en JSON en tant que chaîne. Cela peut être un peu un hack mais c'est facile à mettre en œuvre.

private BigDecimal myValue = new BigDecimal("25.50");
...
public String getMyValue() {
    return myValue.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
5
user1145065