This bug prevents some valid Java identifiers from being used as persisted fields names, and only when Envers is used. I marked it as a CRITICAL bug, because it may prevent someone from upgrading, or force them to rename lots of fields, specially for non-English users of Hibernate. I am using Hibernate 5.2.0. This problem did NOT exist on 4.3.11.Final. When I turn Envers on:
.applySetting(EnversService.INTEGRATION_ENABLED, true)
.applySetting(EnversIntegrator.AUTO_REGISTER, true)
Then Hibernate bootstrap fails when the following line builds the metadata:
Metadata metadata = metadataBuilder.build();
An example problem is an audited class (source code in UTF-8) containing a boolean field called "seÉfinal", since the character "É", an accented version of character "E", results in a parsing error: "Invalid byte 2 of 2-byte UTF-8 sequence". Many character will fail, for example: áéíóúãõñàèçÁÉÃÇ etc. Most commonly this is due to feeding ISO-8859-x (like Latin-1) but the XML parser thinking it is getting UTF-8 (or vice-versa). For example, certain sequences of Latin-1 characters (two consecutive characters with accents or umlauts) form something that is invalid as UTF-8, and specifically such that based on first byte, second byte has unexpected high-order bits. Maybe this is as simple as changing the used default character by something like String.getBytes() to String.getBytes("utf-8"). Please note that forms like String.getBytes() should be avoided, since they use the platform's default charset, which may result in code that works on some platforms and fails on others (they would even pass tests in some platforms that are, by chance, configured as expected by the code). The following is an offending XML Document, containing name="seÉFinal", created internally, in memory, by Envers:
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping auto-import="false">
<class entity-name="ModuloADM.CalculoDeDataRelativa.CalculoDeDataRelativa_AUD" discriminator-value="CalculoDeDataRelativa" table="CalculoDeDataRelativa_AUD" abstract="false">
<composite-id name="originalId">
<key-property name="recnum">
<column name="recnum" length="22" scale="2" precision="19"/>
<type name="Persist.HibernatePersist.PersistRecnum"/>
</key-property>
<key-many-to-one type="integer" class="org.hibernate.envers.DefaultRevisionEntity" name="REV">
<column name="REV"/>
</key-many-to-one>
</composite-id>
<property insert="true" update="false" name="REVTYPE" type="org.hibernate.envers.internal.entities.RevisionTypeType"/>
<property insert="true" update="false" name="seÉFinal" type="boolean">
<column name="seÉfinal" length="255" scale="2" precision="19"/>
</property>
</class>
</hibernate-mapping>
And this is the complete stacktrace:
org.hibernate.boot.MappingException: Unable to perform unmarshalling at line number 0 and column 0. Message: null : origin(envers)
at org.hibernate.boot.jaxb.internal.AbstractBinder.jaxb(AbstractBinder.java:177)
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:57)
at org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl$1.addDocument(AdditionalJaxbMappingProducerImpl.java:92)
at org.hibernate.envers.configuration.internal.EntitiesConfigurator.configure(EntitiesConfigurator.java:111)
at org.hibernate.envers.boot.internal.EnversServiceImpl.doInitialize(EnversServiceImpl.java:152)
at org.hibernate.envers.boot.internal.EnversServiceImpl.initialize(EnversServiceImpl.java:117)
at org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl.produceAdditionalMappings(AdditionalJaxbMappingProducerImpl.java:99)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:288)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:83)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:418)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:87)
at Bd.RelacionadosAoHibernate.UtilHibernate.createSessionFactory(UtilHibernate.java:470)
at Bd.RelacionadosAoHibernate.UtilHibernate.<clinit>(UtilHibernate.java:79)
at Aplicativo.InitAplicativoBdHttp.executaInicializacao_Hibernate(InitAplicativoBdHttp.java:108)
at Aplicativo.InitAplicativoBdHttp.inicializaBancoDeDados(InitAplicativoBdHttp.java:29)
at Aplicativo.InitAplicativo.inicializa(InitAplicativo.java:16)
at Http.Sessao.ListenerDeAplicacao.<clinit>(ListenerDeAplicacao.java:24)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at java.lang.Class.newInstance(Class.java:433)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:121)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4651)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5167)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1648)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:463)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:413)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1466)
at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1307)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1399)
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:828)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:323)
at sun.rmi.transport.Transport$1.run(Transport.java:178)
at sun.rmi.transport.Transport$1.run(Transport.java:175)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:174)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:557)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:812)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:671)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.xml.bind.UnmarshalException
- with linked exception:
[javax.xml.stream.XMLStreamException: ParseError at [row,col]:[67,50]
Message: Invalid byte 2 of 2-byte UTF-8 sequence.]
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:470)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:448)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:420)
at org.hibernate.boot.jaxb.internal.AbstractBinder.jaxb(AbstractBinder.java:171)
... 67 more
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[67,50]
Message: Invalid byte 2 of 2-byte UTF-8 sequence.
at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(XMLStreamReaderImpl.java:596)
at com.sun.xml.internal.stream.XMLEventReaderImpl.peek(XMLEventReaderImpl.java:276)
at javax.xml.stream.util.EventReaderDelegate.peek(EventReaderDelegate.java:104)
at org.hibernate.boot.jaxb.internal.stax.BufferedXMLEventReader.peek(BufferedXMLEventReader.java:96)
at javax.xml.stream.util.EventReaderDelegate.peek(EventReaderDelegate.java:104)
at org.hibernate.boot.jaxb.internal.stax.HbmEventReader.peek(HbmEventReader.java:47)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXEventConnector.handleCharacters(StAXEventConnector.java:164)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXEventConnector.bridge(StAXEventConnector.java:126)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:445)
... 69 more
I would also suggest that the bootstraping of Envers should issue better error messages. In this case it could have warned something along the lines of "Envers bootstraping failed when processing Users.class#seÉfinal. Caused by: javax.xml.stream.XMLStreamException: ParseError at row,col:67,50 Message: Invalid byte 2 of 2-byte UTF-8 sequence...". |