Getting NPE while using <cache usage="read-only"/> in HBMXML in Hibernate 5.2.11

Hello Team,
I have upgraded the Hibernate version from Hibernate ORM 4.3 to 5.2.11 version, we are using the hibernate framework using .hbmxml files. We came across a use-case which is throwing NPE now, its a simple use-case of using cache usage attribute in Entity Definition.

The simplified version of our hbmxml file looks as shown below

<hibernate-mapping>
    <class entity-name="CountryCrash" lazy="true"
        name="xyz.test.CountryCrash" table="COUNTRY">
		<cache usage="read-only"/>
        <id name="id" type="long" unsaved-value="0">
            <column name="ID"/>
            <generator class="sequence">
                <param name="sequence">GENERAL_SEQUENCE</param>
            </generator>
        </id>
        <property name="name" type="string">
            <column name="NAME"/>
        </property>
    </class>
</hibernate-mapping>

While this was working perfectly fine with the older versions of Hibernate, with the upgrade to Hibernate Version 5.2.11, it has started throwing the following exception

java.lang.NullPointerException
	at com.sun.xml.bind.v2.runtime.unmarshaller.StAXConnector$1.getPublicId(StAXConnector.java:101)
	at org.apache.xerces.util.SAXLocatorWrapper.getPublicId(Unknown Source)
	at org.apache.xerces.xni.parser.XMLParseException.<init>(Unknown Source)
	at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
	at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
	at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
	at org.apache.xerces.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source)
	at org.apache.xerces.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source)
	at org.apache.xerces.impl.xs.XMLSchemaValidator.handleStartElement(Unknown Source)
	at org.apache.xerces.impl.xs.XMLSchemaValidator.startElement(Unknown Source)
	at org.apache.xerces.jaxp.validation.ValidatorHandlerImpl.startElement(Unknown Source)
	at com.sun.xml.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.startElement(ValidatingUnmarshaller.java:101)
	at com.sun.xml.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:75)
	at com.sun.xml.bind.v2.runtime.unmarshaller.StAXEventConnector.handleStartElement(StAXEventConnector.java:261)
	at com.sun.xml.bind.v2.runtime.unmarshaller.StAXEventConnector.bridge(StAXEventConnector.java:130)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:460)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:435)
	at org.hibernate.boot.jaxb.internal.AbstractBinder.jaxb(AbstractBinder.java:171)
	at org.hibernate.boot.jaxb.internal.MappingBinder.doBind(MappingBinder.java:61)
	at org.hibernate.boot.jaxb.internal.AbstractBinder.doBind(AbstractBinder.java:102)
	at org.hibernate.boot.jaxb.internal.AbstractBinder.bind(AbstractBinder.java:84)
	at org.hibernate.boot.jaxb.internal.JaxpSourceXmlSource.doBind(JaxpSourceXmlSource.java:29)
	at org.hibernate.boot.MetadataSources.addDocument(MetadataSources.java:409)
	at org.hibernate.cfg.Configuration.addDocument(Configuration.java:462)

I tried to debug using Hibernate ORM sources but didn’t get much help as to why we are getting an NPE for this scenario.

Please let me know if i am missing something or if we missed something while upgrading. This issue happens only if we add

<cache usage="read-only"/>

attribute in hbmxml, if we remove it, it works fine.

Appreciate your help in Advance.

Thanks,

Have you tried adding the schema? Either use the DTD:

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

or the XSD:

<hibernate-mapping xmlns="http://www.hibernate.org/xsd/hibernate-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.hibernate.org/xsd/hibernate-mapping http://www.hibernate.org/xsd/hibernate-mapping/hibernate-mapping-4.0.xsd">

Tried it , my actual xml was having

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                                   "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

before

<hibernate-mapping>
    <class entity-name="CountryCrash" lazy="true"
        name="xyz.test.CountryCrash" table="COUNTRY">
		<cache usage="read-only"/>
        <id name="id" type="long" unsaved-value="0">
            <column name="ID"/>
            <generator class="sequence">
                <param name="sequence">GENERAL_SEQUENCE</param>
            </generator>
        </id>
        <property name="name" type="string">
            <column name="NAME"/>
        </property>
    </class>
</hibernate-mapping>

but it doesn’t work.

Strange. Could you please create a reproducer with this test case template so that I can take a deeper look?

Yes Sure, I am working on this only.

Thanks

While i am in the process of creating the unit test for this, i found that the problem is a bit different while initializing the configuration Object.

So i am having this sample XML written to an xml file sample.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping auto-import="true" default-access="property" default-cascade="none" default-lazy="true">
    <class dynamic-insert="false" dynamic-update="false" entity-name="CountryCrash" lazy="true" mutable="true" optimistic-lock="version" polymorphism="implicit" select-before-update="false" table="COUNTRY">
        <cache include="all" usage="read-only" />
        <tuplizer class="org.hibernate.bugs.SampleTestTuplizer" entity-mode="dynamic-map" />
        <id name="id" type="long" unsaved-value="0">
            <column name="ID" />
            <generator class="sequence">
                <param name="sequence">GENERAL_SEQUENCE</param>
            </generator>
        </id>
    </class>
</hibernate-mapping>

While trying to initialize the Configuration Object with the following sample code

Configuration hibernateConfig = new Configuration();
hibernateConfig.addFile("sample.xml");

In Hibernate 4.3, this works and is able to add the mappings to the configuration but in Hibernate 5.2, i am getting the following exception

Caused by: org.hibernate.boot.InvalidMappingException: Could not parse mapping document: sample.xml (FILE)
at org.hibernate.boot.jaxb.internal.InputStreamXmlSource.doBind(InputStreamXmlSource.java:46)
at org.hibernate.boot.jaxb.internal.FileXmlSource.doBind(FileXmlSource.java:43)
at org.hibernate.boot.jaxb.internal.FileXmlSource.doBind(FileXmlSource.java:32)
at org.hibernate.boot.spi.XmlMappingBinderAccess.bind(XmlMappingBinderAccess.java:70)
at org.hibernate.boot.MetadataSources.addFile(MetadataSources.java:300)
at org.hibernate.boot.MetadataSources.addFile(MetadataSources.java:288)
at org.hibernate.cfg.Configuration.addFile(Configuration.java:352)
at org.hibernate.bugs.ORMUnitTestCase.configure(ORMUnitTestCase.java:64)

I am just in the process to do some cleanup and send the test-case, but thought if this could give us some details on why the same mapping works with hibernate 4.3 API but not with hibernate 5.2 API.

Thanks,

@beikov: I have created the test-case for this issue, Unfortunately have some problems with Two Factor Authentication in my GIT account due to which i am unable to push the changes, however i have uploaded the test-case template at this link

Can you please take a look?

Just try to run the ORMUnitTestCase.java file in hibernate-orm-4 and hibernate-orm-5.
Also cross check that in hibernate-orm-5, the following line

configuration.addFile("src/test/resources/configSettingsWithoutCache.xml");

works perfectly fine for xml which doesn’t have the cache attribute viz
<cache include="all" usage="read-only" />

but configuration.addFile("src/test/resources/configSettings.xml"); throws the following exception

Could not parse mapping document: src/test/resources/configSettings.xml (FILE)
at org.hibernate.boot.jaxb.internal.InputStreamXmlSource.doBind(InputStreamXmlSource.java:46)
at org.hibernate.boot.jaxb.internal.FileXmlSource.doBind(FileXmlSource.java:43)
at org.hibernate.boot.jaxb.internal.FileXmlSource.doBind(FileXmlSource.java:32)
at org.hibernate.boot.spi.XmlMappingBinderAccess.bind(XmlMappingBinderAccess.java:70)
at org.hibernate.boot.MetadataSources.addFile(MetadataSources.java:300)
at org.hibernate.boot.MetadataSources.addFile(MetadataSources.java:288)
at org.hibernate.cfg.Configuration.addFile(Configuration.java:352)

The actual issue is mentioned explicitly in the comments in ORMUnitTestCase.java.

Do let me know if you need anything else to reproduce this issue, meanwhile i am trying with the GitHub team to resolve the Two Factor Authentication issue.

Thanks,
Ashudeep

Thanks, I’ll take a look as soon as I find some time for this.

Hey, so if you put the cache after the tuplizer it works. Apparently the JAXB model is out of sync with the XSD that is published. I created https://hibernate.atlassian.net/browse/HHH-14320 which will fix this. Thanks for the report.

As far as I understand, the XSD from the following URL has to be used which has the expected order: http://hibernate.org/xsd/orm/hbm/legacy-mapping-4.0.xsd

Yes using cache after tuplizer works, so with http://hibernate.org/xsd/orm/hbm/legacy-mapping-4.0.xsd do you mean to say that we should use cache attribute only after tuplizer,It wasn’t the same earlier right? Or is this the change in behavior that needs to be incorporated in the code?

Thanks,
Ashudeep

I’m saying that you should follow the legacy-mapping xsd which requires cache to come after tuplizer. That’s intended.

Oh Okay, sounds reasonable, Thanks for the explanation and debugging this issue.

Thanks,
Ashudeep

1 Like