The Mysterious Case of the Missing BigDecimal Constructor
My current project has recently been experiencing runtime exceptions of the form:
NoSuchMethodError: java.math.BigDecimal.<init>(I)V
These exceptions only showed up when we started creating a codebase that mixes code written for Java 1.4 and code written for Java 1.5 (we wanted our design to use generics and annotations).
Looking at the stack trace it was clear that the source of the runtime exception was construction of a BigDecimal
using an int
argument, for example, new BigDecimal(5)
. Looking over the Java API reveals that in Java 1.5 BigDecimal
has a constructor that takes a double
or an int
argument while in Java 1.4 BigDecimal
has no constructor that takes an int
argument.
Working through all the permutations with a colleague we were able to create the runtime exception when we built our code using a Java 1.5 build path, compiling for Java 1.4, and running the code on a Java 1.4 JVM. It turned out that the key mistake was to use the Java 1.5 build path. This only happened on certain misconfigured developer machines. Once we reconfigured the developer machines the runtime exception was gone.
Still, I was curious and I wanted to really understand the runtime exception. I installed the Bytecode Outline plugin for Eclipse so that I could see the bytecodes generated for new BigDecimal(5)
. You could also use the javap command line tool. Below are the interesting fragments of bytecode.
Build Path: 1.4.2
NEW java/math/BigDecimal
DUP
LDC 5.0
INVOKESPECIAL java/math/BigDecimal.<init>(D)V
Build Path: 1.5.0
NEW java/math/BigDecimal
DUP
ICONST_5
INVOKESPECIAL java/math/BigDecimal.<init>(I)V
Now it is easy to see what is going on. When the build path is for Java 1.4 the compiler converts the int
literal 5
to a double
. When the build path is for Java 1.5 the compiler generates a call to a constructor that takes an int
argument—a method that does not exist in the 1.4 runtime libraries.
Case closed.
If you want to know the meaning of operands such as DUP
and LDC
, you can read Chapter 6 of The Java Virtual Machine Specification.
We were stumped by this idiosyncrasy.
Awesome analysis!!
Thank you.
I have exactly this problem when using the constructor BigDecimal big = new BigDecimal(0) and so resolved by BigDecimal big = new BigDecimal(“0”) or another solution is to cast the value
BigDecimal big = new BigDecimal((double)0)