Skip to content

Commit b600965

Browse files
committed
HHH-18455 - Implement option to run strict JPA compliance validation
Signed-off-by: Jan Schatteman <[email protected]>
1 parent 15b9357 commit b600965

File tree

22 files changed

+478
-69
lines changed

22 files changed

+478
-69
lines changed

hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
2222
import org.hibernate.resource.jdbc.spi.StatementInspector;
2323
import org.hibernate.type.format.FormatMapper;
24+
import org.hibernate.boot.xsd.XmlValidationMode;
2425

2526
import jakarta.persistence.criteria.Nulls;
2627

@@ -746,6 +747,18 @@ public interface SessionFactoryBuilder {
746747
@Incubating
747748
SessionFactoryBuilder applyXmlFormatMapper(FormatMapper xmlFormatMapper);
748749

750+
/**
751+
* Specifies a {@link XmlValidationMode validation mode} to use for validation of XML files.
752+
*
753+
* @param xmlValidationMode The {@link XmlValidationMode} to use.
754+
*
755+
* @return {@code this}, for method chaining
756+
*
757+
* @see org.hibernate.cfg.AvailableSettings#XML_VALIDATION_MODE
758+
*/
759+
@Incubating
760+
SessionFactoryBuilder applyXmlValidationMode(XmlValidationMode xmlValidationMode);
761+
749762
/**
750763
* After all options have been set, build the SessionFactory.
751764
*

hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.hibernate.boot.spi.MetadataImplementor;
2020
import org.hibernate.boot.spi.SessionFactoryBuilderImplementor;
2121
import org.hibernate.boot.spi.SessionFactoryOptions;
22+
import org.hibernate.boot.xsd.XmlValidationMode;
2223
import org.hibernate.bytecode.internal.SessionFactoryObserverForBytecodeEnhancer;
2324
import org.hibernate.bytecode.spi.BytecodeProvider;
2425
import org.hibernate.cache.spi.TimestampsCacheFactory;
@@ -431,6 +432,12 @@ public void disableJtaTransactionAccess() {
431432
this.optionsBuilder.disableJtaTransactionAccess();
432433
}
433434

435+
@Override
436+
public SessionFactoryBuilder applyXmlValidationMode(XmlValidationMode xmlValidationMode) {
437+
this.optionsBuilder.applyXmlValidationMode( xmlValidationMode );
438+
return this;
439+
}
440+
434441
@Override
435442
public SessionFactory build() {
436443
return new SessionFactoryImpl( metadata, buildSessionFactoryOptions(), bootstrapContext );

hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.hibernate.boot.spi.BootstrapContext;
3434
import org.hibernate.boot.spi.MetadataBuildingContext;
3535
import org.hibernate.boot.spi.SessionFactoryOptions;
36+
import org.hibernate.boot.xsd.XmlValidationMode;
3637
import org.hibernate.cache.internal.NoCachingRegionFactory;
3738
import org.hibernate.cache.internal.StandardTimestampsCacheFactory;
3839
import org.hibernate.cache.spi.RegionFactory;
@@ -283,6 +284,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
283284

284285
private final int queryStatisticsMaxSize;
285286

287+
private XmlValidationMode xmlValidationMode;
286288

287289
@SuppressWarnings( "unchecked" )
288290
public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, BootstrapContext context) {
@@ -656,6 +658,8 @@ else if ( jdbcTimeZoneValue != null ) {
656658
configurationSettings,
657659
false
658660
);
661+
662+
this.xmlValidationMode = ConfigurationHelper.resolveXmlValidationMode( configurationSettings );
659663
}
660664

661665
private boolean disallowBatchUpdates(Dialect dialect, ExtractedDatabaseMetaData meta) {
@@ -1347,6 +1351,9 @@ public boolean isPreferJdbcDatetimeTypesInNativeQueriesEnabled() {
13471351
return preferJdbcDatetimeTypes;
13481352
}
13491353

1354+
@Override
1355+
public XmlValidationMode getXmlValidationMode() { return xmlValidationMode; }
1356+
13501357
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13511358
// In-flight mutation access
13521359

@@ -1621,7 +1628,6 @@ public void enableGeneratorNameScopeCompliance(boolean enabled) {
16211628
mutableJpaCompliance().setGeneratorNameScopeCompliance( enabled );
16221629
}
16231630

1624-
16251631
public void enableCollectionInDefaultFetchGroup(boolean enabled) {
16261632
this.collectionsInDefaultFetchGroupEnabled = enabled;
16271633
}
@@ -1630,6 +1636,10 @@ public void disableJtaTransactionAccess() {
16301636
this.jtaTransactionAccessEnabled = false;
16311637
}
16321638

1639+
public void applyXmlValidationMode(XmlValidationMode xmlValidationMode) {
1640+
this.xmlValidationMode = xmlValidationMode;
1641+
}
1642+
16331643
public SessionFactoryOptions buildOptions() {
16341644
if ( jpaCompliance instanceof MutableJpaCompliance ) {
16351645
jpaCompliance = mutableJpaCompliance().immutableCopy();

hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
package org.hibernate.boot.jaxb.internal;
66

77
import java.io.InputStream;
8+
import java.util.function.Consumer;
89
import javax.xml.stream.XMLEventReader;
910
import javax.xml.stream.XMLInputFactory;
1011
import javax.xml.stream.XMLStreamException;
1112
import javax.xml.stream.events.StartElement;
1213
import javax.xml.stream.events.XMLEvent;
1314
import javax.xml.transform.Source;
14-
import javax.xml.validation.Schema;
1515

1616
import org.hibernate.boot.MappingException;
1717
import org.hibernate.boot.ResourceStreamLocator;
@@ -21,6 +21,7 @@
2121
import org.hibernate.boot.jaxb.internal.stax.LocalXmlResourceResolver;
2222
import org.hibernate.boot.jaxb.spi.Binder;
2323
import org.hibernate.boot.jaxb.spi.Binding;
24+
import org.hibernate.boot.xsd.XmlValidationMode;
2425
import org.hibernate.internal.util.StringHelper;
2526

2627
import org.jboss.logging.Logger;
@@ -37,15 +38,18 @@ public abstract class AbstractBinder<T> implements Binder<T> {
3738

3839
private final LocalXmlResourceResolver xmlResourceResolver;
3940

41+
protected InputStreamAccess streamAccess;
42+
4043
protected AbstractBinder(ResourceStreamLocator resourceStreamLocator) {
4144
this.xmlResourceResolver = new LocalXmlResourceResolver( resourceStreamLocator );
4245
}
4346

44-
public abstract boolean isValidationEnabled();
47+
public abstract XmlValidationMode getXmlValidationMode();
4548

4649
@Override
47-
public <X extends T> Binding<X> bind(InputStreamAccess stream, Origin origin) {
48-
final XMLEventReader eventReader = createReader( stream.accessInputStream(), origin );
50+
public <X extends T> Binding<X> bind(InputStreamAccess streamAccess, Origin origin) {
51+
this.streamAccess = streamAccess;
52+
final XMLEventReader eventReader = createReader( streamAccess.accessInputStream(), origin );
4953
try {
5054
return doBind( eventReader, origin );
5155
}
@@ -147,17 +151,19 @@ protected static boolean hasNamespace(StartElement startElement) {
147151
return StringHelper.isNotEmpty( startElement.getName().getNamespaceURI() );
148152
}
149153

150-
protected <X extends T> X jaxb(XMLEventReader reader, Schema xsd, JAXBContext jaxbContext, Origin origin) {
154+
protected void validateXml(Unmarshaller unmarshaller, Consumer<Unmarshaller> validationAction) {
155+
// handled by subclasses if needed/applicable
156+
validationAction.accept(unmarshaller);
157+
}
158+
159+
protected <X extends T> X jaxb(XMLEventReader reader, JAXBContext jaxbContext, Origin origin, Consumer<Unmarshaller> validationAction) {
151160
final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler();
152161

153162
try {
154163
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
155-
if ( isValidationEnabled() ) {
156-
unmarshaller.setSchema( xsd );
157-
}
158-
else {
159-
unmarshaller.setSchema( null );
160-
}
164+
165+
validateXml( unmarshaller, validationAction );
166+
161167
unmarshaller.setEventHandler( handler );
162168

163169
//noinspection unchecked

hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/ConfigurationBinder.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,22 @@
88
import javax.xml.stream.XMLEventReader;
99
import javax.xml.stream.events.StartElement;
1010

11+
import jakarta.xml.bind.Unmarshaller;
1112
import org.hibernate.Internal;
1213
import org.hibernate.boot.ResourceStreamLocator;
1314
import org.hibernate.boot.jaxb.Origin;
1415
import org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl;
1516
import org.hibernate.boot.jaxb.internal.stax.ConfigurationEventReader;
1617
import org.hibernate.boot.jaxb.spi.Binding;
1718
import org.hibernate.boot.xsd.ConfigXsdSupport;
19+
import org.hibernate.boot.xsd.XmlValidationMode;
1820
import org.hibernate.internal.util.config.ConfigurationException;
1921

2022
import jakarta.xml.bind.JAXBContext;
2123
import jakarta.xml.bind.JAXBException;
2224

25+
import java.util.function.Consumer;
26+
2327
/**
2428
* @author Steve Ebersole
2529
*/
@@ -32,8 +36,8 @@ public ConfigurationBinder(ResourceStreamLocator resourceStreamLocator) {
3236
}
3337

3438
@Override
35-
public boolean isValidationEnabled() {
36-
return false;
39+
public XmlValidationMode getXmlValidationMode() {
40+
return XmlValidationMode.DISABLED;
3741
}
3842

3943
@Override
@@ -42,11 +46,22 @@ protected <X extends JaxbPersistenceImpl> Binding<X> doBind(
4246
StartElement rootElementStartEvent,
4347
Origin origin) {
4448
final XMLEventReader reader = new ConfigurationEventReader( staxEventReader, xmlEventFactory );
49+
50+
final Consumer<Unmarshaller> validationAction;
51+
// evaluate extended (the former validate_xml 'true') in case anyone should override getXmlValidationMode() to switch it on
52+
if ( getXmlValidationMode() == XmlValidationMode.EXTENDED ) {
53+
validationAction = unmarshaller -> unmarshaller.setSchema(
54+
ConfigXsdSupport.configurationXsd().getSchema() );
55+
}
56+
else {
57+
validationAction = unmarshaller -> unmarshaller.setSchema( null );
58+
}
59+
4560
final JaxbPersistenceImpl bindingRoot = jaxb(
4661
reader,
47-
ConfigXsdSupport.configurationXsd().getSchema(),
4862
jaxbContext(),
49-
origin
63+
origin,
64+
validationAction
5065
);
5166
//noinspection unchecked
5267
return new Binding<>( (X) bindingRoot, origin );

0 commit comments

Comments
 (0)