How to format BigDecimal as "plain text" when serializing a JsonNode from a play controller ?

14,563 views
Skip to first unread message

Simon

unread,
Jul 17, 2014, 4:29:48 AM7/17/14
to play-fr...@googlegroups.com
Hi !

In Jackson, there is a settings to output a BigDecimal as a plain string instead of the scientific annotation : SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN. With this settings enabled, the serializer will call BigDecimal.toPlainString() instead of BigDecimal.toString().

To achieve this in my Play (Java) application :

1) I use a custom GlobalSettings class in which I configure the play Json API :

@Override
public void onStart(Application app) {

    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN);

    Json.setObjectMapper(mapper);
}

2) I created a simple route that map /test to my controller method which is :

public static Result test() {
    return ok(Json.toJson(BigDecimal.valueOf(100)));
}

However, when testing this route, the output is : 

1E+2

I expected the output :

100


So it looks like the object mapper settings are not taken into account when serializing a JsonNode from a play controller...

Looking at the play source code, I found that a JsonNode is serialised via JsonNode.toString() method in the method JavaResults.writeJson() :

def writeJson(implicit codec: Codec): Writeable[com.fasterxml.jackson.databind.JsonNode] = Writeable(json => codec.encode(json.toString), Some(ContentTypes.JSON))

JsonNode.toString() delegates this operation to DecimalNode.asText() which in turn calls BigDecimal.toString(), which uses the scientific notation... My custom object mapper settings can't be use in this case !


Would it be possible to use ObjectMapper.writeValueAsString(Object) on a JsonNode instead of the JsonNode.toString() method ? 

For example :

def writeJson(implicit codec: Codec): Writeable[com.fasterxml.jackson.databind.JsonNode] = Writeable(json => codec.encode(mapper.writeValueAsString(json)), Some(ContentTypes.JSON))

What do you think of this solution ? Is there a workaround in the mean time ?


amertum

unread,
Jul 17, 2014, 2:21:33 PM7/17/14
to play-fr...@googlegroups.com
Are you sure the onStart method is call in your Global extends GlobalSettings ? (This object must be defined in the root package.)

If not, it is an issue as Json.setObjectMapper said that it should work.

As for a work around, why not use an ObjectMapper factory directly in your Controller ?

public static Result test() {
    return ok(mapperFactory().valueToTree(BigDecimal.valueOf(100)));
}

private static ObjectMapper mapperFactory() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN);
    return mapper;

Simon

unread,
Jul 18, 2014, 3:36:34 AM7/18/14
to play-fr...@googlegroups.com
Hi,

Thank you to have taken the time to answer.

I am sure the onStart method is called. I added a log statement which is outputed in the console...

Your solution doesn't work, the response is still :

1E+2

This is because the problem arise when a JsonNode is converted into a JSON string, not when a Java object is converted into a JsonNode...

Your workaround should rather be something like this :

public Result test() {
    return ok(asJsonContent(BigDecimal.valueOf(100)));
}

private static Content asJsonContent(Object value) {
    String json;
    try {
        json = mapperFactory().writeValueAsString(value);
    } catch (JsonProcessingException e) {
        throw new RuntimeException(e);
    }
    return new Content() {
        @Override
        public String contentType() {
             return "application/json";
        }

        @Override
        public String body() {
            return json;
        }
    };
}

private static ObjectMapper mapperFactory() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN);
    return mapper;
}

Could the framework do this workaround for me ? Should I open an issue ?

ludo amertum

unread,
Jul 18, 2014, 4:44:21 AM7/18/14
to play-fr...@googlegroups.com
Which version of play are you using ? I've used this code with play 2.1.5 and never had any problem with scientific notation.


--
You received this message because you are subscribed to a topic in the Google Groups "play-framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/play-framework/hy5dOn-CfC0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to play-framewor...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Simon

unread,
Jul 21, 2014, 2:36:53 AM7/21/14
to play-fr...@googlegroups.com
I am using play for Java 2.3.1 and Jackson 2.3.2.

ludo amertum

unread,
Aug 9, 2014, 12:11:57 PM8/9/14
to play-fr...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages