I have a Java program that reads data from a database, and shows it on a user interface. One of these data types is a money amount - and so it automatically triggers me to use BigDecimal as explained here . However in my case I don't do anything with this field except
render it on the UI.
give it another application (over http) who may write it into another database.
Considering the data in the database is of a type similar to double, I don't see any advantage into casting that double precision database field into a BigDecimal because it just gets converted to a string anyway (either for the UI, or for the webservice).
Am I missing something?
There is no requirement to use BigDecimal for monetary values however you must ensure that the amount is stored precisely without any rounding or precision problems normally encountered in float or double data types.
There are few ways to achieve this:
Java 9 comes with JSR 354: Money and Currency API classes e.g. MonetaryAmount.
Store the amount as long using the smallest meaningful currency unit e.g. for USD it's the cent. Look out because some currencies don't use fractional units e.g. YEN.
Mentioned BigDecimal.
Store the amount as String if it doesn't require any processing on your side. It's an ugly approach but if you are only passing the amounts around it might do e.g. read from XML and expose using REST API.
Related
I'm trying to get my head around Spring Boot and so I'm working on a small probability calculator app. My application needs to use doubles or floats for its calculations and it seems like Spring does not have an easy way of validating these data types. Now, it seems that I could change the double variables into BigDecimal, I tried that, but then I ran into another issue because I am working with logarithms and it quickly became apparent that doing any kind of calculation with BigDecimal is going to lead to big chunks of unnecessary code.
Is there really no easy way to validate Doubles and Floats?
If you want to validate the decimal numbers then you can use the following code
#DecimalMin(value = "0.1", inclusive = true)
#DecimalMax(value = "9.9", inclusive = true)
private BigDecimal measurement;
Is there any standard as for sending amounts in rest ?
What is the proper way to send POST request with body with amount field and where can I find explanation ?
"amount": "2.222222222"
or
"amount": 2.222222222
Note that REST isn't always JSON. You appear to be actually asking about JSON-encoding money values.
If you're consuming an existing JSON API, you don't have a choice to make: the API spec will tell you whether the field is expected to be a string or a number.
If you're designing a new API, you need to make this choice.
The JSON standard specifies how to encode a number containing a decimal point, but it doesn't specify anything about how the decoded number should be represented. It's very likely that a decoding library would decode it as a floating-point number.
With very few exceptions, it's a bad idea to use floating-point for money: Why not use Double or Float to represent currency?. For this reason my advice would be use strings to transfer money values, and explicitly convert in both the client and the server. This means leaves less scope for intermediate JSON handling code to change the value.
Also note that a JSON Number has no unit. If you encode a monetary value as a string, you have the option to include a currency in the format: "£123.45". Of course both the encoder and the decoder would need to know about this format.
My goal is to synchronize abitrary rows of data by using the JSON-Format.
As I do not know the exact scheme for the rows (it is a general sync method), my datamodel apparently has to rely on "Object". So in Java I will have an array of Map<String,Object> to be synchronized with the server.
Translating such a row into JSON would give something like
{{"string":"stringvalue"},{"double1":1234.567},{"double2":1234.0},{"long":1234}}
so far, so good - no problem with moshi - everything works as expected.
Now the Problem: When I try to deserialize that JSON with moshi, I get back a double-value for the "long" member. Moshi converts all numbers to Doubles. But unfortunately not all numbers can be safely converted to doubles. Very big integers (aka longs) have a problem with the limited precision of doubles. And rounding-effects also might exist.
I opened an issue with moshi, but unfortunately that was closed. Maybe I wasn't clear enough. (Issue 192)
JSON has no concept of integer - only numbers and Strings. But the subtle detail from "double2" from the example above might lead to a solution for my problem:
If a number does not contain a decimal-point, it is an integer and should be converted to a long.
As longs can not be losslessly converted to doubles, I need a method to intercept the parser before the value is converted to double. But how to do that?
Moshi has this handy concept of JsonAdapters - but unfortunately I currently do not see how I can use them in this case:
The input-type of such an JsonAdapter would have to be Object because I can not cast a generated double to long. So I have to intercept the parser before he converts any value.
But how to return more than one type from there? (I would have to return String, Double or Long from there - or if I can limit the inputs to only numbers I would at least have to return Longs or Doubles.)
(My backend is written in PHP and automatically produces the desired output: Integers are written without a decimal-point.)
I am afraid it's not possible without changing Moshi source code. The JSON string source passes through JsonReader which converts all numbers to double. I could not find a way how to alter this behavior since all subclasses are package-protected.
I have a big number in a database; in this case, 10,000,000,000. Whenever I use that information for something, like sending a message with it, instead of 10,000,000,000, it says 1E10, and I really do not want that.
Can I avoid that in any way?
If I go to the database, the value is 10,000,000,000.
It's the same number, just represented in scientific notation.
Since you don't describe how you are storing the value, you can use DecimalFormat#getNumberInstance to help format it to one that doesn't contain the scientific notation.
double foo = 10000000000L;
System.out.println(foo);
System.out.println(DecimalFormat.getIntegerInstance().format(foo));
This outputs:
1.0E10
10,000,000,000
I'm using java and Apache derby to create a project that deals with big numbers. Everything is going fine except when i store big numbers.
For eg. when i save 1000000000 through my java class to a derby table, it automatically becomes 1.0E9. When this value is retrieved in another form it is displayed like 1.0E9. How can I stop this? I'm using float data type to do this.
In other words, how can I save 1000000000 as 1000000000 and not 1.0E9
Like above said you could use a BigInteger or you could just covert 1.0E9 to what the number actually is. 1.0 x 10^9.
1.0e9 is the same as 1000000000; it's just a representation issue. You just have to apply the proper formatters when transforming it to a string.
Two things that would make this easier are to use the NUMERIC column type in Derby, and also use either BigDecimal or BigInteger data types in your Java code, or possibly a long if you're confident that the long can hold the values in your problem domain.
import java.math.BigInteger;
//...
//...
//...
BigInteger store = new BigInteger("1000000000");