HHH-17377 - Migrate to JPA 3.2

https://hibernate.atlassian.net/browse/HHH-17377

JPA 3.2 B02
This commit is contained in:
Steve Ebersole 2023-11-07 16:52:47 -06:00
parent ad26e73c44
commit ffd5e26164
12 changed files with 340 additions and 318 deletions

View File

@ -0,0 +1,31 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.boot.jaxb.cfg.internal;
import org.hibernate.internal.util.StringHelper;
import jakarta.persistence.SharedCacheMode;
import jakarta.persistence.spi.PersistenceUnitTransactionType;
/**
* @author Steve Ebersole
*/
public class SharedCacheModeMarshalling {
public static SharedCacheMode fromXml(String name) {
if ( StringHelper.isEmpty( name ) ) {
return SharedCacheMode.UNSPECIFIED;
}
return SharedCacheMode.valueOf( name );
}
public static String toXml(SharedCacheMode sharedCacheMode) {
if ( sharedCacheMode == null ) {
return null;
}
return sharedCacheMode.name();
}
}

View File

@ -0,0 +1,31 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.boot.jaxb.cfg.internal;
import org.hibernate.internal.util.StringHelper;
import jakarta.persistence.AccessType;
import jakarta.persistence.spi.PersistenceUnitTransactionType;
/**
* @author Steve Ebersole
*/
public class TransactionTypeMarshalling {
public static PersistenceUnitTransactionType fromXml(String name) {
if ( StringHelper.isEmpty( name ) ) {
return PersistenceUnitTransactionType.RESOURCE_LOCAL;
}
return PersistenceUnitTransactionType.valueOf( name );
}
public static String toXml(PersistenceUnitTransactionType transactionType) {
if ( transactionType == null ) {
return null;
}
return transactionType.name();
}
}

View File

@ -0,0 +1,31 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.boot.jaxb.cfg.internal;
import org.hibernate.internal.util.StringHelper;
import jakarta.persistence.SharedCacheMode;
import jakarta.persistence.ValidationMode;
/**
* @author Steve Ebersole
*/
public class ValidationModeMarshalling {
public static ValidationMode fromXml(String name) {
if ( StringHelper.isEmpty( name ) ) {
return ValidationMode.AUTO;
}
return ValidationMode.valueOf( name );
}
public static String toXml(ValidationMode validationMode) {
if ( validationMode == null ) {
return null;
}
return validationMode.name();
}
}

View File

@ -146,7 +146,7 @@ public abstract class AbstractEventReader extends EventReaderDelegate {
} }
private Namespace mapNamespace(Namespace originalNamespace) { private Namespace mapNamespace(Namespace originalNamespace) {
if ( XsdHelper.shouldBeMappedToLatestJpaDescriptor( originalNamespace.getNamespaceURI() ) ) { if ( shouldBeMappedToLatestJpaDescriptor( originalNamespace.getNamespaceURI() ) ) {
// this is a namespace "to map" so map it // this is a namespace "to map" so map it
return xmlEventFactory.createNamespace( originalNamespace.getPrefix(), xsdDescriptor.getNamespaceUri() ); return xmlEventFactory.createNamespace( originalNamespace.getPrefix(), xsdDescriptor.getNamespaceUri() );
} }
@ -154,6 +154,8 @@ public abstract class AbstractEventReader extends EventReaderDelegate {
return originalNamespace; return originalNamespace;
} }
protected abstract boolean shouldBeMappedToLatestJpaDescriptor(String uri);
private XMLEvent wrap(EndElement endElement) { private XMLEvent wrap(EndElement endElement) {
final List<Namespace> targetNamespaces = mapNamespaces( existingXmlNamespacesIterator( endElement ) ); final List<Namespace> targetNamespaces = mapNamespaces( existingXmlNamespacesIterator( endElement ) );

View File

@ -20,9 +20,14 @@ public class ConfigurationEventReader extends AbstractEventReader {
public ConfigurationEventReader(XMLEventReader reader, XMLEventFactory xmlEventFactory) { public ConfigurationEventReader(XMLEventReader reader, XMLEventFactory xmlEventFactory) {
super( super(
ROOT_ELEMENT_NAME, ROOT_ELEMENT_NAME,
ConfigXsdSupport.getJPA32(), ConfigXsdSupport.configurationXsd(),
reader, reader,
xmlEventFactory xmlEventFactory
); );
} }
@Override
protected boolean shouldBeMappedToLatestJpaDescriptor(String uri) {
return !ConfigXsdSupport.configurationXsd().getNamespaceUri().equals( uri );
}
} }

View File

@ -24,4 +24,8 @@ public class MappingEventReader extends AbstractEventReader {
super( ROOT_ELEMENT_NAME, MappingXsdSupport.latestDescriptor(), reader, xmlEventFactory ); super( ROOT_ELEMENT_NAME, MappingXsdSupport.latestDescriptor(), reader, xmlEventFactory );
} }
@Override
protected boolean shouldBeMappedToLatestJpaDescriptor(String uri) {
return !MappingXsdSupport.latestDescriptor().getNamespaceUri().equals( uri );
}
} }

View File

@ -41,8 +41,12 @@ public class ConfigXsdSupport {
} }
public static boolean shouldBeMappedToLatestJpaDescriptor(String uri) { public static boolean shouldBeMappedToLatestJpaDescriptor(String uri) {
// JPA 1.0 and 2.0 share the same namespace URI // Any namespace prior to move to Jakarta (3.0) needs to be remapped
return getJPA10().getNamespaceUri().matches( uri ); // NOTE:
// - JPA 1.0 and 2.0 share the same namespace URI
// - JPA 2.1 and 2.2 share the same namespace URI
return !configurationXsd().getNamespaceUri().equals( uri );
} }
public XsdDescriptor jpaXsd(String version) { public XsdDescriptor jpaXsd(String version) {

View File

@ -19,6 +19,7 @@ public class XsdHelper {
public static boolean shouldBeMappedToLatestJpaDescriptor(String uri) { public static boolean shouldBeMappedToLatestJpaDescriptor(String uri) {
// JPA 1.0 and 2.0 share the same namespace URI // JPA 1.0 and 2.0 share the same namespace URI
// JPA 2.1 and 2.2 share the same namespace URI
return MappingXsdSupport.jpa10.getNamespaceUri().equals( uri ); return MappingXsdSupport.jpa10.getNamespaceUri().equals( uri );
} }
} }

View File

@ -9,17 +9,17 @@ package org.hibernate.jpa.boot.internal;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.hibernate.boot.archive.internal.ArchiveHelper;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.bytecode.spi.ClassTransformer;
import jakarta.persistence.SharedCacheMode; import jakarta.persistence.SharedCacheMode;
import jakarta.persistence.ValidationMode; import jakarta.persistence.ValidationMode;
import jakarta.persistence.spi.PersistenceUnitTransactionType; import jakarta.persistence.spi.PersistenceUnitTransactionType;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.bytecode.spi.ClassTransformer;
/** /**
* Describes the information gleaned from a {@code <persistence-unit/>} element in a {@code persistence.xml} file * Describes the information gleaned from a {@code <persistence-unit/>} element in a {@code persistence.xml} file
* whether parsed directly by Hibernate or passed to us by an EE container as a * whether parsed directly by Hibernate or passed to us by an EE container as a
@ -130,8 +130,12 @@ public class ParsedPersistenceXmlDescriptor implements org.hibernate.jpa.boot.sp
return validationMode; return validationMode;
} }
public void setValidationMode(ValidationMode validationMode) {
this.validationMode = validationMode;
}
public void setValidationMode(String validationMode) { public void setValidationMode(String validationMode) {
this.validationMode = ValidationMode.valueOf( validationMode ); setValidationMode( ValidationMode.valueOf( validationMode ) );
} }
@Override @Override
@ -139,8 +143,12 @@ public class ParsedPersistenceXmlDescriptor implements org.hibernate.jpa.boot.sp
return sharedCacheMode; return sharedCacheMode;
} }
public void setSharedCacheMode(SharedCacheMode sharedCacheMode) {
this.sharedCacheMode = sharedCacheMode;
}
public void setSharedCacheMode(String sharedCacheMode) { public void setSharedCacheMode(String sharedCacheMode) {
this.sharedCacheMode = SharedCacheMode.valueOf( sharedCacheMode ); setSharedCacheMode( SharedCacheMode.valueOf( sharedCacheMode ) );
} }
@Override @Override
@ -178,6 +186,12 @@ public class ParsedPersistenceXmlDescriptor implements org.hibernate.jpa.boot.sp
jarFileUrls.add( jarFileUrl ); jarFileUrls.add( jarFileUrl );
} }
public void addJarFileUrls(List<String> jarFiles) {
jarFiles.forEach( (jarFile) -> {
addJarFileUrl( ArchiveHelper.getURLFromPath( jarFile ) );
} );
}
@Override @Override
public ClassLoader getClassLoader() { public ClassLoader getClassLoader() {
return null; return null;

View File

@ -16,32 +16,26 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import jakarta.persistence.PersistenceException; import javax.xml.transform.stream.StreamSource;
import jakarta.persistence.spi.PersistenceUnitTransactionType;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Validator;
import org.hibernate.boot.archive.internal.ArchiveHelper; import org.hibernate.boot.archive.internal.ArchiveHelper;
import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.SourceType;
import org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl;
import org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl.JaxbPropertiesImpl;
import org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl.JaxbPropertiesImpl.JaxbPropertyImpl;
import org.hibernate.boot.jaxb.internal.ConfigurationBinder;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.xsd.ConfigXsdSupport;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.EntityManagerMessageLogger;
import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper; import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.w3c.dom.Document; import jakarta.persistence.PersistenceException;
import org.w3c.dom.Element; import jakarta.persistence.spi.PersistenceUnitTransactionType;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import static org.hibernate.internal.HEMLogging.messageLogger; import static org.hibernate.internal.HEMLogging.messageLogger;
@ -61,7 +55,8 @@ public class PersistenceXmlParser {
* *
* @return List of descriptors for all discovered persistence-units. * @return List of descriptors for all discovered persistence-units.
*/ */
public static List<ParsedPersistenceXmlDescriptor> locatePersistenceUnits(Map integration) { @SuppressWarnings({ "removal", "deprecation" })
public static List<ParsedPersistenceXmlDescriptor> locatePersistenceUnits(Map<?,?> integration) {
final PersistenceXmlParser parser = new PersistenceXmlParser( final PersistenceXmlParser parser = new PersistenceXmlParser(
ClassLoaderServiceImpl.fromConfigSettings( integration ), ClassLoaderServiceImpl.fromConfigSettings( integration ),
PersistenceUnitTransactionType.RESOURCE_LOCAL PersistenceUnitTransactionType.RESOURCE_LOCAL
@ -91,7 +86,8 @@ public class PersistenceXmlParser {
* *
* @return The single persistence-unit descriptor * @return The single persistence-unit descriptor
*/ */
public static ParsedPersistenceXmlDescriptor locateIndividualPersistenceUnit(URL persistenceXmlUrl, Map integration) { @SuppressWarnings("removal")
public static ParsedPersistenceXmlDescriptor locateIndividualPersistenceUnit(URL persistenceXmlUrl, Map<?,?> integration) {
return locateIndividualPersistenceUnit( persistenceXmlUrl, PersistenceUnitTransactionType.RESOURCE_LOCAL, integration ); return locateIndividualPersistenceUnit( persistenceXmlUrl, PersistenceUnitTransactionType.RESOURCE_LOCAL, integration );
} }
@ -105,10 +101,11 @@ public class PersistenceXmlParser {
* *
* @return The single persistence-unit descriptor * @return The single persistence-unit descriptor
*/ */
@SuppressWarnings({ "removal", "deprecation" })
public static ParsedPersistenceXmlDescriptor locateIndividualPersistenceUnit( public static ParsedPersistenceXmlDescriptor locateIndividualPersistenceUnit(
URL persistenceXmlUrl, URL persistenceXmlUrl,
PersistenceUnitTransactionType transactionType, PersistenceUnitTransactionType transactionType,
Map integration) { Map<?,?> integration) {
final PersistenceXmlParser parser = new PersistenceXmlParser( final PersistenceXmlParser parser = new PersistenceXmlParser(
ClassLoaderServiceImpl.fromConfigSettings( integration ), ClassLoaderServiceImpl.fromConfigSettings( integration ),
transactionType transactionType
@ -142,7 +139,8 @@ public class PersistenceXmlParser {
* *
* @return The matching persistence-unit descriptor * @return The matching persistence-unit descriptor
*/ */
public static ParsedPersistenceXmlDescriptor locateNamedPersistenceUnit(URL persistenceXmlUrl, String name, Map integration) { @SuppressWarnings("removal")
public static ParsedPersistenceXmlDescriptor locateNamedPersistenceUnit(URL persistenceXmlUrl, String name, Map<?,?> integration) {
return locateNamedPersistenceUnit( persistenceXmlUrl, name, PersistenceUnitTransactionType.RESOURCE_LOCAL, integration ); return locateNamedPersistenceUnit( persistenceXmlUrl, name, PersistenceUnitTransactionType.RESOURCE_LOCAL, integration );
} }
@ -156,11 +154,12 @@ public class PersistenceXmlParser {
* *
* @return The matching persistence-unit descriptor * @return The matching persistence-unit descriptor
*/ */
@SuppressWarnings({ "removal", "deprecation" })
public static ParsedPersistenceXmlDescriptor locateNamedPersistenceUnit( public static ParsedPersistenceXmlDescriptor locateNamedPersistenceUnit(
URL persistenceXmlUrl, URL persistenceXmlUrl,
String name, String name,
PersistenceUnitTransactionType transactionType, PersistenceUnitTransactionType transactionType,
Map integration) { Map<?,?> integration) {
assert StringHelper.isNotEmpty( name ); assert StringHelper.isNotEmpty( name );
final PersistenceXmlParser parser = new PersistenceXmlParser( final PersistenceXmlParser parser = new PersistenceXmlParser(
@ -179,6 +178,7 @@ public class PersistenceXmlParser {
* <p> * <p>
* Parses a specific persistence.xml file... * Parses a specific persistence.xml file...
*/ */
@SuppressWarnings("removal")
public static Map<String, ParsedPersistenceXmlDescriptor> parse( public static Map<String, ParsedPersistenceXmlDescriptor> parse(
URL persistenceXmlUrl, URL persistenceXmlUrl,
PersistenceUnitTransactionType transactionType) { PersistenceUnitTransactionType transactionType) {
@ -195,10 +195,11 @@ public class PersistenceXmlParser {
* *
* @return Map of persistence-unit descriptors keyed by the PU name * @return Map of persistence-unit descriptors keyed by the PU name
*/ */
@SuppressWarnings({ "removal", "deprecation" })
public static Map<String, ParsedPersistenceXmlDescriptor> parse( public static Map<String, ParsedPersistenceXmlDescriptor> parse(
URL persistenceXmlUrl, URL persistenceXmlUrl,
PersistenceUnitTransactionType transactionType, PersistenceUnitTransactionType transactionType,
Map integration) { Map<?,?> integration) {
PersistenceXmlParser parser = new PersistenceXmlParser( PersistenceXmlParser parser = new PersistenceXmlParser(
ClassLoaderServiceImpl.fromConfigSettings( integration ), ClassLoaderServiceImpl.fromConfigSettings( integration ),
transactionType transactionType
@ -212,6 +213,7 @@ public class PersistenceXmlParser {
private final PersistenceUnitTransactionType defaultTransactionType; private final PersistenceUnitTransactionType defaultTransactionType;
private final Map<String, ParsedPersistenceXmlDescriptor> persistenceUnits; private final Map<String, ParsedPersistenceXmlDescriptor> persistenceUnits;
@SuppressWarnings("removal")
protected PersistenceXmlParser(ClassLoaderService classLoaderService, PersistenceUnitTransactionType defaultTransactionType) { protected PersistenceXmlParser(ClassLoaderService classLoaderService, PersistenceUnitTransactionType defaultTransactionType) {
this.classLoaderService = classLoaderService; this.classLoaderService = classLoaderService;
this.defaultTransactionType = defaultTransactionType; this.defaultTransactionType = defaultTransactionType;
@ -222,7 +224,7 @@ public class PersistenceXmlParser {
return new ArrayList<>(persistenceUnits.values()); return new ArrayList<>(persistenceUnits.values());
} }
private void doResolve(Map integration) { private void doResolve(Map<?,?> integration) {
final List<URL> xmlUrls = classLoaderService.locateResources( "META-INF/persistence.xml" ); final List<URL> xmlUrls = classLoaderService.locateResources( "META-INF/persistence.xml" );
if ( xmlUrls.isEmpty() ) { if ( xmlUrls.isEmpty() ) {
LOG.unableToFindPersistenceXmlInClasspath(); LOG.unableToFindPersistenceXmlInClasspath();
@ -232,97 +234,146 @@ public class PersistenceXmlParser {
} }
} }
private void parsePersistenceXml(List<URL> xmlUrls, Map integration) { private void parsePersistenceXml(List<URL> xmlUrls, Map<?,?> integration) {
for ( URL xmlUrl : xmlUrls ) { for ( URL xmlUrl : xmlUrls ) {
parsePersistenceXml( xmlUrl, integration ); parsePersistenceXml( xmlUrl, integration );
} }
} }
protected void parsePersistenceXml(URL xmlUrl, Map integration) { protected void parsePersistenceXml(URL xmlUrl, Map<?,?> integration) {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracef( "Attempting to parse persistence.xml file : %s", xmlUrl.toExternalForm() ); LOG.tracef( "Attempting to parse persistence.xml file : %s", xmlUrl.toExternalForm() );
} }
final Document doc = loadUrl( xmlUrl ); final URL persistenceUnitRootUrl = ArchiveHelper.getJarURLFromURLEntry( xmlUrl, "/META-INF/persistence.xml" );
final Element top = doc.getDocumentElement();
final NodeList children = top.getChildNodes(); final JaxbPersistenceImpl jaxbPersistence = loadUrlWithJaxb( xmlUrl );
for ( int i = 0; i < children.getLength() ; i++ ) { final List<JaxbPersistenceImpl.JaxbPersistenceUnitImpl> jaxbPersistenceUnits = jaxbPersistence.getPersistenceUnit();
if ( children.item( i ).getNodeType() == Node.ELEMENT_NODE ) {
final Element element = (Element) children.item( i );
final String tag = element.getTagName();
if ( tag.equals( "persistence-unit" ) ) {
final URL puRootUrl = ArchiveHelper.getJarURLFromURLEntry( xmlUrl, "/META-INF/persistence.xml" );
ParsedPersistenceXmlDescriptor persistenceUnit = new ParsedPersistenceXmlDescriptor( puRootUrl );
bindPersistenceUnit( persistenceUnit, element );
if ( persistenceUnits.containsKey( persistenceUnit.getName() ) ) { for ( int i = 0; i < jaxbPersistenceUnits.size(); i++ ) {
LOG.duplicatedPersistenceUnitName( persistenceUnit.getName() ); final JaxbPersistenceImpl.JaxbPersistenceUnitImpl jaxbPersistenceUnit = jaxbPersistenceUnits.get( i );
continue;
}
// per JPA spec, any settings passed in to PersistenceProvider bootstrap methods should override if ( persistenceUnits.containsKey( jaxbPersistenceUnit.getName() ) ) {
// values found in persistence.xml LOG.duplicatedPersistenceUnitName( jaxbPersistenceUnit.getName() );
if ( integration.containsKey( AvailableSettings.JAKARTA_PERSISTENCE_PROVIDER ) ) { continue;
persistenceUnit.setProviderClassName( (String) integration.get( AvailableSettings.JAKARTA_PERSISTENCE_PROVIDER ) ); }
}
else if ( integration.containsKey( AvailableSettings.JPA_PERSISTENCE_PROVIDER ) ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.JPA_PERSISTENCE_PROVIDER,
AvailableSettings.JAKARTA_PERSISTENCE_PROVIDER
);
persistenceUnit.setProviderClassName( (String) integration.get( AvailableSettings.JPA_PERSISTENCE_PROVIDER ) );
}
if ( integration.containsKey( AvailableSettings.JPA_TRANSACTION_TYPE ) ) { final ParsedPersistenceXmlDescriptor persistenceUnitDescriptor = new ParsedPersistenceXmlDescriptor(
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( persistenceUnitRootUrl );
AvailableSettings.JPA_TRANSACTION_TYPE, bindPersistenceUnit( jaxbPersistenceUnit, persistenceUnitDescriptor );
AvailableSettings.JAKARTA_TRANSACTION_TYPE
);
String transactionType = (String) integration.get( AvailableSettings.JPA_TRANSACTION_TYPE );
persistenceUnit.setTransactionType( parseTransactionType( transactionType ) );
}
else if ( integration.containsKey( AvailableSettings.JAKARTA_TRANSACTION_TYPE ) ) {
String transactionType = (String) integration.get( AvailableSettings.JAKARTA_TRANSACTION_TYPE );
persistenceUnit.setTransactionType( parseTransactionType( transactionType ) );
}
if ( integration.containsKey( AvailableSettings.JPA_JTA_DATASOURCE ) ) { // per JPA spec, any settings passed in to PersistenceProvider bootstrap methods should override
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( // values found in persistence.xml
AvailableSettings.JPA_JTA_DATASOURCE, applyIntegrationOverrides( integration, persistenceUnitDescriptor );
AvailableSettings.JAKARTA_JTA_DATASOURCE
);
persistenceUnit.setJtaDataSource( integration.get( AvailableSettings.JPA_JTA_DATASOURCE ) );
}
else if ( integration.containsKey( AvailableSettings.JAKARTA_JTA_DATASOURCE ) ) {
persistenceUnit.setJtaDataSource( integration.get( AvailableSettings.JAKARTA_JTA_DATASOURCE ) );
}
if ( integration.containsKey( AvailableSettings.JPA_NON_JTA_DATASOURCE ) ) { persistenceUnits.put( persistenceUnitDescriptor.getName(), persistenceUnitDescriptor );
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( }
AvailableSettings.JPA_NON_JTA_DATASOURCE, }
AvailableSettings.JAKARTA_NON_JTA_DATASOURCE
);
persistenceUnit.setNonJtaDataSource( integration.get( AvailableSettings.JPA_NON_JTA_DATASOURCE ) );
}
else if ( integration.containsKey( AvailableSettings.JAKARTA_NON_JTA_DATASOURCE ) ) {
persistenceUnit.setNonJtaDataSource( integration.get( AvailableSettings.JAKARTA_NON_JTA_DATASOURCE ) );
}
decodeTransactionType( persistenceUnit ); private void bindPersistenceUnit(
JaxbPersistenceImpl.JaxbPersistenceUnitImpl jaxbPersistenceUnit,
ParsedPersistenceXmlDescriptor persistenceUnitDescriptor) {
final String name = jaxbPersistenceUnit.getName();
if ( StringHelper.isNotEmpty( name ) ) {
LOG.tracef( "Persistence unit name from persistence.xml : %s", name );
persistenceUnitDescriptor.setName( name );
}
Properties properties = persistenceUnit.getProperties(); //noinspection removal
ConfigurationHelper.overrideProperties( properties, integration ); final PersistenceUnitTransactionType transactionType = jaxbPersistenceUnit.getTransactionType();
if ( transactionType != null ) {
persistenceUnitDescriptor.setTransactionType( transactionType );
}
persistenceUnits.put( persistenceUnit.getName(), persistenceUnit ); persistenceUnitDescriptor.setProviderClassName( jaxbPersistenceUnit.getProvider() );
} persistenceUnitDescriptor.setNonJtaDataSource( jaxbPersistenceUnit.getNonJtaDataSource() );
persistenceUnitDescriptor.setJtaDataSource( jaxbPersistenceUnit.getJtaDataSource() );
persistenceUnitDescriptor.setSharedCacheMode( jaxbPersistenceUnit.getSharedCacheMode() );
persistenceUnitDescriptor.setValidationMode( jaxbPersistenceUnit.getValidationMode() );
persistenceUnitDescriptor.setExcludeUnlistedClasses( handleBoolean( jaxbPersistenceUnit.isExcludeUnlistedClasses(), false ) );
persistenceUnitDescriptor.addClasses( jaxbPersistenceUnit.getClasses() );
persistenceUnitDescriptor.addMappingFiles( jaxbPersistenceUnit.getMappingFiles() );
persistenceUnitDescriptor.addJarFileUrls( jaxbPersistenceUnit.getJarFiles() );
final JaxbPropertiesImpl propertyContainer = jaxbPersistenceUnit.getPropertyContainer();
if ( propertyContainer != null ) {
for ( JaxbPropertyImpl property : propertyContainer.getProperties() ) {
persistenceUnitDescriptor.getProperties().put(
property.getName(),
property.getValue()
);
} }
} }
} }
private void decodeTransactionType(ParsedPersistenceXmlDescriptor persistenceUnit) { private boolean handleBoolean(Boolean incoming, boolean fallback) {
// if transaction type is set already if ( incoming != null ) {
// use that value return incoming;
}
return fallback;
}
@SuppressWarnings("deprecation")
private void applyIntegrationOverrides(Map<?,?> integration, ParsedPersistenceXmlDescriptor persistenceUnitDescriptor) {
if ( integration.containsKey( AvailableSettings.JAKARTA_PERSISTENCE_PROVIDER ) ) {
persistenceUnitDescriptor.setProviderClassName( (String) integration.get( AvailableSettings.JAKARTA_PERSISTENCE_PROVIDER ) );
}
else if ( integration.containsKey( AvailableSettings.JPA_PERSISTENCE_PROVIDER ) ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.JPA_PERSISTENCE_PROVIDER,
AvailableSettings.JAKARTA_PERSISTENCE_PROVIDER
);
persistenceUnitDescriptor.setProviderClassName( (String) integration.get( AvailableSettings.JPA_PERSISTENCE_PROVIDER ) );
}
if ( integration.containsKey( AvailableSettings.JPA_TRANSACTION_TYPE ) ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.JPA_TRANSACTION_TYPE,
AvailableSettings.JAKARTA_TRANSACTION_TYPE
);
String transactionType = (String) integration.get( AvailableSettings.JPA_TRANSACTION_TYPE );
persistenceUnitDescriptor.setTransactionType( parseTransactionType( transactionType ) );
}
else if ( integration.containsKey( AvailableSettings.JAKARTA_TRANSACTION_TYPE ) ) {
String transactionType = (String) integration.get( AvailableSettings.JAKARTA_TRANSACTION_TYPE );
persistenceUnitDescriptor.setTransactionType( parseTransactionType( transactionType ) );
}
if ( integration.containsKey( AvailableSettings.JPA_JTA_DATASOURCE ) ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.JPA_JTA_DATASOURCE,
AvailableSettings.JAKARTA_JTA_DATASOURCE
);
persistenceUnitDescriptor.setJtaDataSource( integration.get( AvailableSettings.JPA_JTA_DATASOURCE ) );
}
else if ( integration.containsKey( AvailableSettings.JAKARTA_JTA_DATASOURCE ) ) {
persistenceUnitDescriptor.setJtaDataSource( integration.get( AvailableSettings.JAKARTA_JTA_DATASOURCE ) );
}
if ( integration.containsKey( AvailableSettings.JPA_NON_JTA_DATASOURCE ) ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting(
AvailableSettings.JPA_NON_JTA_DATASOURCE,
AvailableSettings.JAKARTA_NON_JTA_DATASOURCE
);
persistenceUnitDescriptor.setNonJtaDataSource( integration.get( AvailableSettings.JPA_NON_JTA_DATASOURCE ) );
}
else if ( integration.containsKey( AvailableSettings.JAKARTA_NON_JTA_DATASOURCE ) ) {
persistenceUnitDescriptor.setNonJtaDataSource( integration.get( AvailableSettings.JAKARTA_NON_JTA_DATASOURCE ) );
}
applyTransactionTypeOverride( persistenceUnitDescriptor );
final Properties properties = persistenceUnitDescriptor.getProperties();
ConfigurationHelper.overrideProperties( properties, integration );
}
@SuppressWarnings("removal")
private void applyTransactionTypeOverride(ParsedPersistenceXmlDescriptor persistenceUnitDescriptor) {
// if transaction type is set already, use that value
if ( persistenceUnitDescriptor.getTransactionType() != null ) {
return;
}
// else // else
// if JTA DS // if JTA DS
// use JTA // use JTA
@ -330,121 +381,18 @@ public class PersistenceXmlParser {
// use RESOURCE_LOCAL // use RESOURCE_LOCAL
// else // else
// use defaultTransactionType // use defaultTransactionType
if ( persistenceUnit.getTransactionType() != null ) { if ( persistenceUnitDescriptor.getJtaDataSource() != null ) {
return; persistenceUnitDescriptor.setTransactionType( PersistenceUnitTransactionType.JTA );
} }
else if ( persistenceUnitDescriptor.getNonJtaDataSource() != null ) {
if ( persistenceUnit.getJtaDataSource() != null ) { persistenceUnitDescriptor.setTransactionType( PersistenceUnitTransactionType.RESOURCE_LOCAL );
persistenceUnit.setTransactionType( PersistenceUnitTransactionType.JTA );
}
else if ( persistenceUnit.getNonJtaDataSource() != null ) {
persistenceUnit.setTransactionType( PersistenceUnitTransactionType.RESOURCE_LOCAL );
} }
else { else {
persistenceUnit.setTransactionType( defaultTransactionType ); persistenceUnitDescriptor.setTransactionType( defaultTransactionType );
} }
} }
private void bindPersistenceUnit(ParsedPersistenceXmlDescriptor persistenceUnit, Element persistenceUnitElement) { @SuppressWarnings("removal")
final String name = persistenceUnitElement.getAttribute( "name" );
if ( StringHelper.isNotEmpty( name ) ) {
LOG.tracef( "Persistence unit name from persistence.xml : %s", name );
persistenceUnit.setName( name );
}
final PersistenceUnitTransactionType transactionType = parseTransactionType(
persistenceUnitElement.getAttribute( "transaction-type" )
);
if ( transactionType != null ) {
persistenceUnit.setTransactionType( transactionType );
}
NodeList children = persistenceUnitElement.getChildNodes();
for ( int i = 0; i < children.getLength() ; i++ ) {
if ( children.item( i ).getNodeType() == Node.ELEMENT_NODE ) {
Element element = (Element) children.item( i );
String tag = element.getTagName();
if ( tag.equals( "non-jta-data-source" ) ) {
persistenceUnit.setNonJtaDataSource( extractContent( element ) );
}
else if ( tag.equals( "jta-data-source" ) ) {
persistenceUnit.setJtaDataSource( extractContent( element ) );
}
else if ( tag.equals( "provider" ) ) {
persistenceUnit.setProviderClassName( extractContent( element ) );
}
else if ( tag.equals( "class" ) ) {
persistenceUnit.addClasses( extractContent( element ) );
}
else if ( tag.equals( "mapping-file" ) ) {
persistenceUnit.addMappingFiles( extractContent( element ) );
}
else if ( tag.equals( "jar-file" ) ) {
persistenceUnit.addJarFileUrl( ArchiveHelper.getURLFromPath( extractContent( element ) ) );
}
else if ( tag.equals( "exclude-unlisted-classes" ) ) {
persistenceUnit.setExcludeUnlistedClasses( extractBooleanContent(element, true) );
}
else if ( tag.equals( "delimited-identifiers" ) ) {
persistenceUnit.setUseQuotedIdentifiers( true );
}
else if ( tag.equals( "validation-mode" ) ) {
persistenceUnit.setValidationMode( extractContent( element ) );
}
else if ( tag.equals( "shared-cache-mode" ) ) {
persistenceUnit.setSharedCacheMode( extractContent( element ) );
}
else if ( tag.equals( "properties" ) ) {
NodeList props = element.getChildNodes();
for ( int j = 0; j < props.getLength() ; j++ ) {
if ( props.item( j ).getNodeType() == Node.ELEMENT_NODE ) {
Element propElement = (Element) props.item( j );
if ( !"property".equals( propElement.getTagName() ) ) {
continue;
}
String propName = propElement.getAttribute( "name" ).trim();
String propValue = propElement.getAttribute( "value" ).trim();
if ( propValue.isEmpty() ) {
//fall back to the natural (Hibernate) way of description
propValue = extractContent( propElement, "" );
}
persistenceUnit.getProperties().put( propName, propValue );
}
}
}
}
}
}
private static String extractContent(Element element) {
return extractContent( element, null );
}
private static String extractContent(Element element, String defaultStr) {
if ( element == null ) {
return defaultStr;
}
NodeList children = element.getChildNodes();
StringBuilder result = new StringBuilder();
for ( int i = 0; i < children.getLength() ; i++ ) {
if ( children.item( i ).getNodeType() == Node.TEXT_NODE ||
children.item( i ).getNodeType() == Node.CDATA_SECTION_NODE ) {
result.append( children.item( i ).getNodeValue() );
}
}
return result.toString().trim();
}
private static boolean extractBooleanContent(Element element, boolean defaultBool) {
String content = extractContent( element );
if (content != null && content.length() > 0) {
return Boolean.valueOf(content);
}
return defaultBool;
}
private static PersistenceUnitTransactionType parseTransactionType(String value) { private static PersistenceUnitTransactionType parseTransactionType(String value) {
if ( StringHelper.isEmpty( value ) ) { if ( StringHelper.isEmpty( value ) ) {
return null; return null;
@ -460,32 +408,21 @@ public class PersistenceXmlParser {
} }
} }
private Document loadUrl(URL xmlUrl) { private JaxbPersistenceImpl loadUrlWithJaxb(URL xmlUrl) {
final String resourceName = xmlUrl.toExternalForm(); final String resourceName = xmlUrl.toExternalForm();
try { try {
URLConnection conn = xmlUrl.openConnection(); URLConnection conn = xmlUrl.openConnection();
conn.setUseCaches( false ); //avoid JAR locking on Windows and Tomcat // avoid JAR locking on Windows and Tomcat
try { conn.setUseCaches( false );
try (InputStream inputStream = conn.getInputStream()) {
final InputSource inputSource = new InputSource( inputStream ); try (InputStream inputStream = conn.getInputStream()) {
try { final StreamSource inputSource = new StreamSource( inputStream );
DocumentBuilder documentBuilder = documentBuilderFactory().newDocumentBuilder(); final ConfigurationBinder configurationBinder = new ConfigurationBinder( classLoaderService );
try { final Binding<JaxbPersistenceImpl> binding = configurationBinder.bind(
Document document = documentBuilder.parse( inputSource ); inputSource,
validate( document ); new Origin( SourceType.URL, resourceName )
return document; );
} return binding.getRoot();
catch (SAXException | IOException e) {
throw new PersistenceException( "Unexpected error parsing [" + resourceName + "]", e );
}
}
catch (ParserConfigurationException e) {
throw new PersistenceException(
"Unable to generate javax.xml.parsers.DocumentBuilder instance",
e
);
}
}
} }
catch (IOException e) { catch (IOException e) {
throw new PersistenceException( "Unable to obtain input stream from [" + resourceName + "]", e ); throw new PersistenceException( "Unable to obtain input stream from [" + resourceName + "]", e );
@ -496,82 +433,4 @@ public class PersistenceXmlParser {
} }
} }
/**
* Validate the document using the
*/
private void validate(Document document) {
// todo : add ability to disable validation...
final String version = document.getDocumentElement().getAttribute( "version" );
final Validator validator = new ConfigXsdSupport().jpaXsd( version ).getSchema().newValidator();
List<SAXException> errors = new ArrayList<>();
validator.setErrorHandler( new ErrorHandlerImpl( errors ) );
try {
validator.validate( new DOMSource( document ) );
}
catch (SAXException e) {
errors.add( e );
}
catch (IOException e) {
throw new PersistenceException( "Unable to validate persistence.xml", e );
}
if ( errors.size() != 0 ) {
//report all errors in the exception
StringBuilder errorMessage = new StringBuilder( );
for ( SAXException error : errors ) {
errorMessage.append( extractInfo( error ) ).append( '\n' );
}
throw new PersistenceException( "Invalid persistence.xml.\n" + errorMessage.toString() );
}
}
private DocumentBuilderFactory documentBuilderFactory;
private DocumentBuilderFactory documentBuilderFactory() {
if ( documentBuilderFactory == null ) {
documentBuilderFactory = buildDocumentBuilderFactory();
}
return documentBuilderFactory;
}
private DocumentBuilderFactory buildDocumentBuilderFactory() {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware( true );
return documentBuilderFactory;
}
public static class ErrorHandlerImpl implements ErrorHandler {
private List<SAXException> errors;
ErrorHandlerImpl(List<SAXException> errors) {
this.errors = errors;
}
public void error(SAXParseException error) {
errors.add( error );
}
public void fatalError(SAXParseException error) {
errors.add( error );
}
public void warning(SAXParseException warn) {
if ( LOG.isTraceEnabled() ) {
LOG.trace( extractInfo( warn ) );
}
}
}
private static String extractInfo(SAXException error) {
if ( error instanceof SAXParseException ) {
return "Error parsing XML [line : " + ( (SAXParseException) error ).getLineNumber()
+ ", column : " + ( (SAXParseException) error ).getColumnNumber()
+ "] : " + error.getMessage();
}
else {
return "Error parsing XML : " + error.getMessage();
}
}
} }

View File

@ -20,6 +20,49 @@
<anonymousTypeName prefix="Jaxb" suffix="Impl"/> <anonymousTypeName prefix="Jaxb" suffix="Impl"/>
</nameXmlTransform> </nameXmlTransform>
</schemaBindings> </schemaBindings>
</bindings>
<bindings node="//xsd:element[@name='persistence-unit']/xsd:complexType">
<bindings node=".//xsd:element[@name='mapping-file']">
<property name="mappingFiles"/>
</bindings>
<bindings node=".//xsd:element[@name='class']">
<property name="classes"/>
</bindings>
<bindings node=".//xsd:element[@name='jar-file']">
<property name="jarFiles"/>
</bindings>
<bindings node=".//xsd:element[@name='properties']">
<property name="propertyContainer"/>
<bindings node=".//xsd:element[@name='property']">
<property name="properties"/>
</bindings>
</bindings>
</bindings>
<!--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Marshalling of enum values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-->
<bindings node="//xsd:simpleType[@name='persistence-unit-transaction-type']">
<javaType name="jakarta.persistence.spi.PersistenceUnitTransactionType"
parseMethod="org.hibernate.boot.jaxb.cfg.internal.TransactionTypeMarshalling.fromXml"
printMethod="org.hibernate.boot.jaxb.cfg.internal.TransactionTypeMarshalling.toXml" />
</bindings>
<bindings node="//xsd:simpleType[@name='persistence-unit-caching-type']">
<javaType name="jakarta.persistence.SharedCacheMode"
parseMethod="org.hibernate.boot.jaxb.cfg.internal.SharedCacheModeMarshalling.fromXml"
printMethod="org.hibernate.boot.jaxb.cfg.internal.SharedCacheModeMarshalling.toXml" />
</bindings>
<bindings node="//xsd:simpleType[@name='persistence-unit-validation-mode-type']">
<javaType name="jakarta.persistence.ValidationMode"
parseMethod="org.hibernate.boot.jaxb.cfg.internal.ValidationModeMarshalling.fromXml"
printMethod="org.hibernate.boot.jaxb.cfg.internal.ValidationModeMarshalling.toXml" />
</bindings>
</bindings>
</bindings> </bindings>

View File

@ -70,9 +70,6 @@ public class JpaDescriptorParser {
private static final String DEFAULT_ORM_XML_LOCATION = "/META-INF/orm.xml"; private static final String DEFAULT_ORM_XML_LOCATION = "/META-INF/orm.xml";
private static final String SERIALIZATION_FILE_NAME = "Hibernate-Static-Metamodel-Generator.tmp"; private static final String SERIALIZATION_FILE_NAME = "Hibernate-Static-Metamodel-Generator.tmp";
private static final String PERSISTENCE_SCHEMA = "org/hibernate/xsd/cfg/persistence_3_0.xsd";
private final Context context; private final Context context;
private final List<JaxbEntityMappingsImpl> entityMappings; private final List<JaxbEntityMappingsImpl> entityMappings;
private final XmlParserHelper xmlParserHelper; private final XmlParserHelper xmlParserHelper;
@ -121,7 +118,7 @@ public class JpaDescriptorParser {
// get mapping file names from persistence.xml // get mapping file names from persistence.xml
List<JaxbPersistenceImpl.JaxbPersistenceUnitImpl> persistenceUnits = persistence.getPersistenceUnit(); List<JaxbPersistenceImpl.JaxbPersistenceUnitImpl> persistenceUnits = persistence.getPersistenceUnit();
for ( JaxbPersistenceImpl.JaxbPersistenceUnitImpl unit : persistenceUnits ) { for ( JaxbPersistenceImpl.JaxbPersistenceUnitImpl unit : persistenceUnits ) {
mappingFileNames.addAll( unit.getMappingFile() ); mappingFileNames.addAll( unit.getMappingFiles() );
} }
} }