We have come across a rather peculiar behaviour for an entity that does some work in its default constructor. The simplified essence is the following example:
@Entity
class Animal {
@Id
private Long id;
@Column
private int size;
public Animal() {
size = Integer.parseInt(initParam());
}
String initParam() {
return "42";
}
}
Note that initParam()
returns a constant; but when Hibernate creates a proxy for this class (either when directly calling entityManager.getReference(...)
or when loading a different entity with a lazy association to an Animal
), then we get a NumberFormatException
from the parseInt(...)
in the constructor (because its argument is null
).
Indeed, checking in the debugger confirms that the actual method initParam()
is not called, but intercepted in the org.hibernate.proxy.ProxyConfiguration.InterceptorDispatcher
.
The parts of the stacktrace:
org.hibernate.HibernateException: HHH000142: Bytecode enhancement failed: com...Animal
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyFactory.getProxy(ByteBuddyProxyFactory.java:102) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
at org.hibernate.tuple.entity.AbstractEntityTuplizer.createProxy(AbstractEntityTuplizer.java:746) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.createProxy(AbstractEntityPersister.java:5140) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
...
Caused by: java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:542) ~[?:1.8.0_322]
at java.lang.Integer.parseInt(Integer.java:615) ~[?:1.8.0_322]
at com...Animal.<init>(Animal.java:24) ~[classes/:?]
at com...Animal$HibernateProxy$UU9Nch9Z.<init>(Unknown Source) ~[classes/:?]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.8.0_322]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[?:1.8.0_322]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:1.8.0_322]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[?:1.8.0_322]
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyFactory.getProxy(ByteBuddyProxyFactory.java:89) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
I know it is somewhat frowned upon to do work in the constructor - this is a legacy code base. At the same time, AFAICS in the JPA spec and the Hibernate docs, there seem to be no restrictions on what can be done in the constructor.
As a side note, the constructor works fine when making initParam()
either final
or static
.
Am I missing something? Is this a known limitation or bug? Or could it be a problem of our dependencies? (The problem occurs with both hibernate-core-5.6.9.Final and hibernate-core-5.6.15.Final, using byte-buddy-1.12.18.)