HHH-7325 - Allow disabling XML validations via setting

This commit is contained in:
Steve Ebersole 2012-05-18 12:18:42 -05:00
parent 3791267442
commit a046cc7a95
3 changed files with 119 additions and 9 deletions

View File

@ -0,0 +1,93 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal.xml;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.util.EventReaderDelegate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Used to wrap a StAX {@link XMLEventReader} in order to introduce namespaces into the underlying document. This
* is intended for temporary migration feature to allow legacy HBM mapping documents (DTD-based) to continue to
* parse correctly. This feature will go away eventually.
*
* @author Steve Ebersole
*/
public class NamespaceAddingEventReader extends EventReaderDelegate {
private final XMLEventFactory xmlEventFactory;
private final String namespaceUri;
public NamespaceAddingEventReader(XMLEventReader reader, String namespaceUri) {
this( reader, XMLEventFactory.newInstance(), namespaceUri );
}
public NamespaceAddingEventReader(XMLEventReader reader, XMLEventFactory xmlEventFactory, String namespaceUri) {
super( reader );
this.xmlEventFactory = xmlEventFactory;
this.namespaceUri = namespaceUri;
}
private StartElement withNamespace(StartElement startElement) {
// otherwise, wrap the start element event to provide a default namespace mapping
final List<Namespace> namespaces = new ArrayList<Namespace>();
namespaces.add( xmlEventFactory.createNamespace( "", namespaceUri ) );
Iterator<?> originalNamespaces = startElement.getNamespaces();
while ( originalNamespaces.hasNext() ) {
namespaces.add( (Namespace) originalNamespaces.next() );
}
return xmlEventFactory.createStartElement(
new QName( namespaceUri, startElement.getName().getLocalPart() ),
startElement.getAttributes(),
namespaces.iterator()
);
}
@Override
public XMLEvent nextEvent() throws XMLStreamException {
XMLEvent event = super.nextEvent();
if ( event.isStartElement() ) {
return withNamespace( event.asStartElement() );
}
return event;
}
@Override
public XMLEvent peek() throws XMLStreamException {
XMLEvent event = super.peek();
if ( event.isStartElement() ) {
return withNamespace( event.asStartElement() );
}
else {
return event;
}
}
}

View File

@ -39,6 +39,7 @@ import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute; import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent; import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource; import javax.xml.transform.stream.StreamSource;
@ -54,10 +55,13 @@ import org.hibernate.internal.jaxb.JaxbRoot;
import org.hibernate.internal.jaxb.Origin; import org.hibernate.internal.jaxb.Origin;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbHibernateMapping; import org.hibernate.internal.jaxb.mapping.hbm.JaxbHibernateMapping;
import org.hibernate.internal.jaxb.mapping.orm.JaxbEntityMappings; import org.hibernate.internal.jaxb.mapping.orm.JaxbEntityMappings;
import org.hibernate.internal.xml.NamespaceAddingEventReader;
import org.hibernate.metamodel.MetadataSources; import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.spi.source.MappingException; import org.hibernate.metamodel.spi.source.MappingException;
import org.hibernate.metamodel.spi.source.XsdException; import org.hibernate.metamodel.spi.source.XsdException;
import org.hibernate.service.classloading.spi.ClassLoaderService; import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.config.spi.ConfigurationService;
import org.hibernate.service.config.spi.StandardConverters;
/** /**
* Helper class for unmarshalling xml configuration using StAX and JAXB. * Helper class for unmarshalling xml configuration using StAX and JAXB.
@ -69,11 +73,18 @@ public class JaxbHelper {
private static final Logger log = Logger.getLogger( JaxbHelper.class ); private static final Logger log = Logger.getLogger( JaxbHelper.class );
public static final String ASSUMED_ORM_XSD_VERSION = "2.0"; public static final String ASSUMED_ORM_XSD_VERSION = "2.0";
public static final String VALIDATE_XML_SETTING = "hibernate.xml.validate";
public static final String HIBERNATE_MAPPING_URI = "http://www.hibernate.org/xsd/hibernate-mapping";
private final MetadataSources metadataSources; private final MetadataSources metadataSources;
private final boolean validateXml;
public JaxbHelper(MetadataSources metadataSources) { public JaxbHelper(MetadataSources metadataSources) {
this.metadataSources = metadataSources; this.metadataSources = metadataSources;
this.validateXml = metadataSources.getServiceRegistry()
.getService( ConfigurationService.class )
.getSetting( VALIDATE_XML_SETTING, StandardConverters.BOOLEAN, true );
} }
public JaxbRoot unmarshal(InputStream stream, Origin origin) { public JaxbRoot unmarshal(InputStream stream, Origin origin) {
@ -138,11 +149,16 @@ public class JaxbHelper {
if ( "entity-mappings".equals( elementName ) ) { if ( "entity-mappings".equals( elementName ) ) {
final Attribute attribute = event.asStartElement().getAttributeByName( ORM_VERSION_ATTRIBUTE_QNAME ); final Attribute attribute = event.asStartElement().getAttributeByName( ORM_VERSION_ATTRIBUTE_QNAME );
final String explicitVersion = attribute == null ? null : attribute.getValue(); final String explicitVersion = attribute == null ? null : attribute.getValue();
validationSchema = resolveSupportedOrmXsd( explicitVersion ); validationSchema = validateXml ? resolveSupportedOrmXsd( explicitVersion ) : null;
jaxbTarget = JaxbEntityMappings.class; jaxbTarget = JaxbEntityMappings.class;
} }
else { else {
validationSchema = hbmSchema(); if ( !isNamespaced( event.asStartElement() ) ) {
// if the elements are not namespaced, wrap the reader in a reader which will namespace them as pulled.
log.debug( "HBM mapping document did not define namespaces; wrapping in custom event reader to introduce namespace information" );
staxEventReader = new NamespaceAddingEventReader( staxEventReader, HIBERNATE_MAPPING_URI );
}
validationSchema = validateXml ? hbmSchema() : null;
jaxbTarget = JaxbHibernateMapping.class; jaxbTarget = JaxbHibernateMapping.class;
} }
@ -155,7 +171,6 @@ public class JaxbHelper {
unmarshaller.setEventHandler( handler ); unmarshaller.setEventHandler( handler );
target = unmarshaller.unmarshal( staxEventReader ); target = unmarshaller.unmarshal( staxEventReader );
} }
catch ( JAXBException e ) { catch ( JAXBException e ) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append( "Unable to perform unmarshalling at line number " ); builder.append( "Unable to perform unmarshalling at line number " );
@ -170,6 +185,10 @@ public class JaxbHelper {
return new JaxbRoot( target, origin ); return new JaxbRoot( target, origin );
} }
private boolean isNamespaced(StartElement startElement) {
return ! "".equals( startElement.getName().getNamespaceURI() );
}
@SuppressWarnings( { "unchecked" }) @SuppressWarnings( { "unchecked" })
public JaxbRoot unmarshal(Document document, Origin origin) { public JaxbRoot unmarshal(Document document, Origin origin) {
Element rootElement = document.getDocumentElement(); Element rootElement = document.getDocumentElement();
@ -182,11 +201,11 @@ public class JaxbHelper {
if ( "entity-mappings".equals( rootElement.getNodeName() ) ) { if ( "entity-mappings".equals( rootElement.getNodeName() ) ) {
final String explicitVersion = rootElement.getAttribute( "version" ); final String explicitVersion = rootElement.getAttribute( "version" );
validationSchema = resolveSupportedOrmXsd( explicitVersion ); validationSchema = validateXml ? resolveSupportedOrmXsd( explicitVersion ) : null;
jaxbTarget = JaxbEntityMappings.class; jaxbTarget = JaxbEntityMappings.class;
} }
else { else {
validationSchema = hbmSchema(); validationSchema = validateXml ? hbmSchema() : null;
jaxbTarget = JaxbHibernateMapping.class; jaxbTarget = JaxbHibernateMapping.class;
} }

View File

@ -1,9 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.abstractembeddedcomponents.cid"> <hibernate-mapping xmlns="http://www.hibernate.org/xsd/hibernate-mapping"
package="org.hibernate.test.abstractembeddedcomponents.cid">
<class name="MyInterface" table="MY_INTF" proxy="MyInterface"> <class name="MyInterface" table="MY_INTF" proxy="MyInterface">
<composite-id> <composite-id>