24

I am using a library com.fasterxml.jackson library for JsonSchema, I am creating an IntegerSchema object, when I set range for integer schema using below code:

main(){
     IntegerSchema intSchema = new IntegerSchema();
     // setMaximum accepts Double object 
     intSchema.setMaximum(new Double(102000000));
     // setMaximum accepts Double object
     intSchema.setMinimum(new Double(100));
    
     printJsonSchema(intSchema);
}


public void printJsonSchema(JsonSchema schema){
        ObjectMapper mapper = new ObjectMapper();
        try {
            logger.info(mapper.writeValueAsString(schema));
        } catch (JsonProcessingException e) {
            throw new IllegalStateException(e);
        }
}

When I convert IntegerSchema to string using ObjectMapper getting below response:

{"type":"integer","maximum":1.02E8,"minimum":100.0}

maximum and minimum values are getting converted to scientific notation.

But I need output in non scientific notation as below:

{"type":"integer","maximum":102000000,"minimum":100}

I cannot change IntegerSchema class.

Please suggest how to get the required output without extending IntegerSchema class?

Thanks in advance

Ahmad MOUSSA
  • 2,729
  • 19
  • 31
Abhij
  • 1,222
  • 4
  • 19
  • 37

6 Answers6

21

this is a java issue somewhat I believe. If you debug your program, your Double will always be displayed scientifically, so what we'll want is to force it into a String. This can be achieved in Java in multiple ways, and you can look it up here:

How to print double value without scientific notation using Java?

In terms of your specific question about Jackson, I've written up some code for you:

public class ObjectMapperTest {

    public static void main(String[] args) throws JsonProcessingException {

        IntegerSchema schema = new IntegerSchema();
        schema.type = "Int";
        schema.max = 10200000000d;
        schema.min = 100d;

        ObjectMapper m = new ObjectMapper();

        System.out.println(m.writeValueAsString(schema));

    }

    public static class IntegerSchema {

        @JsonProperty
        String type;
        @JsonProperty
        double min;
        @JsonProperty
        @JsonSerialize(using=MyDoubleDesirializer.class)
        double max;
    }

    public static class MyDoubleDesirializer extends JsonSerializer<Double> {


        @Override
        public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException, JsonProcessingException {
            // TODO Auto-generated method stub

            BigDecimal d = new BigDecimal(value);
            gen.writeNumber(d.toPlainString());
        }

    }

}

The trick is to register a custom Serializer for your Double value. This way, you can control what you want.

I am using the BigDecimal value to create a String representation of your Double. The output then becomes (for the specific example):

{"type":"Int","min":100.0,"max":10200000000}

I hope that solves your problem.

Artur

Community
  • 1
  • 1
pandaadb
  • 6,306
  • 2
  • 22
  • 41
  • 4
    You can also register a module to apply the serializer to all doubles across the entire system. See http://stackoverflow.com/a/25945058/14731 for an explanation of how this is done. – Gili Aug 26 '16 at 19:04
  • 1
    BigDecimal returns very long decimal size like : 10200000000.00001237234, you can use this to user 4 decimal: gen.writeNumber(bigDecimal.setScale(4, RoundingMode.CEILING).toPlainString()); – Arif Acar Feb 26 '20 at 09:16
  • This tutorial (https://www.baeldung.com/spring-boot-jsoncomponent) showed how to quickly add a Jackson serializer/deserializer in a Spring Boot application by leveraging component scanning with the @JsonComponent annotation. – taha Oct 14 '22 at 19:47
15

Feature.WRITE_BIGDECIMAL_AS_PLAIN set this for your Object Mapper

binh phung
  • 175
  • 1
  • 2
  • 3
    Like this: mapper.configure(Feature.WRITE_BIGDECIMAL_AS_PLAIN, true); – p01nt3r Jul 17 '18 at 14:43
  • 4
    As the name suggests clearly, this works for BigDecimal only. It does not apply to Double – Xinchao Oct 31 '18 at 11:52
  • 1
    [Feature.WRITE_NUMBERS_AS_STRINGS](https://fasterxml.github.io/jackson-core/javadoc/2.5/com/fasterxml/jackson/core/JsonGenerator.Feature.html#WRITE_NUMBERS_AS_STRINGS) instead. Although it will do it for all numbers not only doubles ! – Monssef Apr 14 '20 at 14:38
10

I know I am answering late, but something I faced may help other

While converting a BigDecimal I have faced below is working

mapper = mapper.setNodeFactory(JsonNodeFactory.withExactBigDecimals(true));

while this is not working for me

mapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
A Paul
  • 8,113
  • 3
  • 31
  • 61
  • 2
    I don't understand the reason, but this is the solution that worked in my case too. Neither `WRITE_BIGDECIMAL_AS_PLAIN` nor `WRITE_NUMBERS_AS_STRINGS` worked in my case, but setting node factory withExactBigDecimals did. I'm performing the serialization by: `myJsonMapper.valueToTree(myPojo)` with Jackson 2.11. – Gerard Bosch Dec 31 '20 at 10:23
  • Can confirm that this solution worked for me when changing the configuration on Spring's `controllerObjectMapper`, to stop reformatting of BigDecimals in a controller that takes a raw `@RequestBody JsonNode` as input. – Matsu Q. Aug 17 '23 at 17:37
  • withExactBigDecimals is deprecated now – FreeGor Aug 30 '23 at 14:41
5

Update for Jakson 2.9.10:

Property WRITE_BIGDECIMAL_AS_PLAIN replaced to com.fasterxml.jackson.core.JsonGenerator. You could use:

mapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
Volodya Lombrozo
  • 2,325
  • 2
  • 16
  • 34
1

If you are using ValueToTree then no need of any factory settings. only problem with ValueToTree is it is converting as TextNode (String Fromat), So if you have any logic based on ObjectNodes it will not work

-1

You should use

mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);

To avoid scientific notation on floating numbers.

You can find an example below.

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);

String test ="{\"doubleValue\" : 0.00001}";

try {
    System.out.println(mapper.readTree(test).toPrettyString());
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

Output

{
    "doubleValue" : 0.00001
}
Mustafa Poya
  • 2,615
  • 5
  • 22
  • 36
Sakrof
  • 1
  • 2