The Mysterious Case of the Missing BigDecimal Constructor
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.
