Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN not taken into account when serializing BigDecimal as String #2323

Closed
membersound opened this issue May 8, 2019 · 10 comments

Comments

@membersound
Copy link

membersound commented May 8, 2019

The following test should convert a BigDecimal number to "3.033" string in json. But in fact it only converts it to double.

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.junit.Test;

import java.math.BigDecimal;

import static org.junit.Assert.assertEquals;

public class JacksonTest {
	public class MyDto {
		private BigDecimal number;

		public BigDecimal getNumber() {
			return number;
		}

		public void setNumber(BigDecimal number) {
			this.number = number;
		}
	}

	@Test
	public void testBigDecimalSerialization() throws Exception {
		ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN);
		MyDto dto = new MyDto();
		dto.number = new BigDecimal("3.033");
		String json = mapper.writeValueAsString(dto);

		assertEquals("{\"number\":\"3.033\"}", json);
	}
}

Result:

org.junit.ComparisonFailure: 
Expected :{"number":"3.033"}
Actual   :{"number":3.033}

jackson-databind-2.9.8

@cowtowncoder
Copy link
Member

You may be misunderstanding function of SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN: it does not convert BigDecimal into JSON String, but simple enforces representation as "plain", not using scientific notation.

To force serialization of (all) numbers as JSON Strings, you can use JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS

@membersound
Copy link
Author

Ok sorry, but that would force any numbers being returned as strings? Couldn't I enable this feature for BigDecimals only?

@cowtowncoder
Copy link
Member

@sddakoty That would force all numbers as Strings on output.

Another method that should work would be use of @JsonFormat:

public class POJO {
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    public BigDecimal value;
}

and you can actually define it for all values of a type, see "config overrides" on:

https://medium.com/@cowtowncoder/jackson-2-8-features-5fc692887944

for details. Hope this helps!

@membersound
Copy link
Author

membersound commented May 11, 2019

Could you give an example how I apply this JsonFormat for all BigDecimals in my applicaiton, without having to apply the annotation each time? Would it be as follows?

mapper.configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));

If yes, what would it use internally? BigDecimal.toPlainString()?

@cowtowncoder
Copy link
Member

@sddakoty Yes I think that should be it, wrt String output. However looking at code (NumberSerializer.java), format with Shape.STRING uses ToStringSerializer, which simply calls value.toString().

So it may actually be that this would not work if you want to avoid scientific notation.

I'll reopen this issue, reword it, to suggest that combination should be taken into account (so that you would combine the feature AND format to get what you want).
But in the meantime you will have to create a simple custom serializer I think, which looks like ToStringSerializer except using toPlainString().

@cowtowncoder cowtowncoder reopened this May 11, 2019
@cowtowncoder cowtowncoder changed the title SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN not taken into account? SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN not taken into account when serializing BigDecimal as String May 11, 2019
@membersound
Copy link
Author

Got ok. So atm the only solution would be as follows, eg:

public class BigDecimalSerializer extends JsonSerializer<BigDecimal> {
        @Override
    public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider provider) throws IOException, JsonProcessingException {
        if (value != null) {
            gen.writeString(value.toPlainString());
        }
    }    
}

Indeed it would be great I one could configure this effect directly through some serialization feature.

@cowtowncoder
Copy link
Member

@sddakoty Almost, but you can actually remove that if check there: serialize() method is never called with null value (null handling is separate and caller must handle it).

And yes I hope I find time to implement this in near future.

@cowtowncoder
Copy link
Member

Actually, I think it already works; fixed with #2230, to be included in 2.10 (and is included in 2.10.0.pr1 already).

@membersound
Copy link
Author

So what is the correct settings and configuration now with the fix, if I'd just want BigDecimal being written as plain string, and none of the other digits?

@cowtowncoder
Copy link
Member

@membersound Usage question belong to user mailing list. This issue is specifically ensuring that setting SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN works not only when written as JSON number, but also when written as JSON String (i.e. within double-quotes).
So for plain serialization, just enable SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants