HHH-18060 - HbXmlTransformer work

* non-aggregated composite id
* extends
This commit is contained in:
Steve Ebersole 2024-06-07 08:29:36 -05:00
parent 4d0422fe05
commit d25f028222
38 changed files with 1460 additions and 369 deletions

View File

@ -22,9 +22,11 @@ import org.hibernate.HibernateException;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.boot.archive.spi.InputStreamAccess; import org.hibernate.boot.archive.spi.InputStreamAccess;
import org.hibernate.boot.internal.MetadataBuilderImpl; import org.hibernate.boot.internal.MetadataBuilderImpl;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
import org.hibernate.boot.jaxb.internal.XmlSources; import org.hibernate.boot.jaxb.internal.XmlSources;
import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor;
import org.hibernate.boot.jaxb.spi.XmlSource; import org.hibernate.boot.jaxb.spi.XmlSource;
import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
@ -37,6 +39,8 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.SerializationException; import org.hibernate.type.SerializationException;
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
/** /**
* Entry point for working with sources of O/R mapping metadata, either * Entry point for working with sources of O/R mapping metadata, either
* in the form of annotated classes, or as XML mapping documents. * in the form of annotated classes, or as XML mapping documents.
@ -65,7 +69,9 @@ public class MetadataSources implements Serializable {
private XmlMappingBinderAccess xmlMappingBinderAccess; private XmlMappingBinderAccess xmlMappingBinderAccess;
private List<Binding<JaxbBindableMappingDescriptor>> xmlBindings; private List<Binding<JaxbEntityMappingsImpl>> mappingXmlBindings;
private List<Binding<JaxbHbmHibernateMapping>> hbmXmlBindings;
private LinkedHashSet<Class<?>> annotatedClasses; private LinkedHashSet<Class<?>> annotatedClasses;
private LinkedHashSet<String> annotatedClassNames; private LinkedHashSet<String> annotatedClassNames;
private LinkedHashSet<String> annotatedPackages; private LinkedHashSet<String> annotatedPackages;
@ -121,8 +127,36 @@ public class MetadataSources implements Serializable {
return xmlMappingBinderAccess; return xmlMappingBinderAccess;
} }
/**
* @deprecated Prefer {@linkplain #getMappingXmlBindings()} and/or {@linkplain #getHbmXmlBindings()}
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@Deprecated(since = "7.0")
public List<Binding<JaxbBindableMappingDescriptor>> getXmlBindings() { public List<Binding<JaxbBindableMappingDescriptor>> getXmlBindings() {
return xmlBindings == null ? Collections.emptyList() : xmlBindings; if ( mappingXmlBindings == null && hbmXmlBindings == null ) {
return Collections.emptyList();
}
if ( hbmXmlBindings == null ) {
return (List) mappingXmlBindings;
}
if ( mappingXmlBindings == null ) {
return (List) hbmXmlBindings;
}
final ArrayList<Binding<JaxbBindableMappingDescriptor>> combined = arrayList( mappingXmlBindings.size() + hbmXmlBindings.size() );
combined.addAll( (List) mappingXmlBindings );
combined.addAll( (List) hbmXmlBindings );
return combined;
}
public List<Binding<JaxbEntityMappingsImpl>> getMappingXmlBindings() {
return mappingXmlBindings == null ? Collections.emptyList() : mappingXmlBindings;
}
public List<Binding<JaxbHbmHibernateMapping>> getHbmXmlBindings() {
return hbmXmlBindings == null ? Collections.emptyList() : hbmXmlBindings;
} }
public Collection<String> getAnnotatedPackages() { public Collection<String> getAnnotatedPackages() {
@ -329,7 +363,7 @@ public class MetadataSources implements Serializable {
public MetadataSources addResource(String name) { public MetadataSources addResource(String name) {
final XmlSource xmlSource = XmlSources.fromResource( name, classLoaderService ); final XmlSource xmlSource = XmlSources.fromResource( name, classLoaderService );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); addXmlBinding( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -359,7 +393,7 @@ public class MetadataSources implements Serializable {
public MetadataSources addFile(File file) { public MetadataSources addFile(File file) {
final XmlSource xmlSource = XmlSources.fromFile( file ); final XmlSource xmlSource = XmlSources.fromFile( file );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); addXmlBinding( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -372,8 +406,45 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addXmlBinding(Binding<?> binding) { public MetadataSources addXmlBinding(Binding<?> binding) {
if ( binding.getRoot() instanceof JaxbEntityMappingsImpl ) {
//noinspection unchecked //noinspection unchecked
getXmlBindingsForWrite().add( (Binding<JaxbBindableMappingDescriptor>) binding ); return addMappingXmlBinding( (Binding<JaxbEntityMappingsImpl>) binding );
}
else if ( binding.getRoot() instanceof JaxbHbmHibernateMapping ) {
//noinspection unchecked
return addHbmXmlBinding( (Binding<JaxbHbmHibernateMapping>) binding );
}
throw new UnsupportedOperationException( "Unknown type of binding : " + binding.getRoot() );
}
/**
* Add a {@linkplain Binding binding} for {@linkplain JaxbEntityMappingsImpl mapping.xsd} document
*
* @param binding The binding
*
* @return this (for method chaining purposes)
*/
public MetadataSources addMappingXmlBinding(Binding<JaxbEntityMappingsImpl> binding) {
if ( mappingXmlBindings == null ) {
mappingXmlBindings = new ArrayList<>();
}
mappingXmlBindings.add( binding );
return this;
}
/**
* Add a {@linkplain Binding binding} for {@linkplain JaxbHbmHibernateMapping hbm.xsd} document
*
* @param binding The binding
*
* @return this (for method chaining purposes)
*/
public MetadataSources addHbmXmlBinding(Binding<JaxbHbmHibernateMapping> binding) {
if ( hbmXmlBindings == null ) {
hbmXmlBindings = new ArrayList<>();
}
hbmXmlBindings.add( binding );
return this; return this;
} }
@ -444,7 +515,7 @@ public class MetadataSources implements Serializable {
public MetadataSources addCacheableFile(File file, File cacheDirectory) { public MetadataSources addCacheableFile(File file, File cacheDirectory) {
final XmlSource xmlSource = XmlSources.fromCacheableFile( file, cacheDirectory ); final XmlSource xmlSource = XmlSources.fromCacheableFile( file, cacheDirectory );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); addXmlBinding( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -464,7 +535,7 @@ public class MetadataSources implements Serializable {
public MetadataSources addCacheableFileStrictly(File file) throws SerializationException { public MetadataSources addCacheableFileStrictly(File file) throws SerializationException {
final XmlSource xmlSource = XmlSources.fromCacheableFile( file, true ); final XmlSource xmlSource = XmlSources.fromCacheableFile( file, true );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); addXmlBinding( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -484,7 +555,7 @@ public class MetadataSources implements Serializable {
public MetadataSources addCacheableFileStrictly(File file, File cacheDir) throws SerializationException { public MetadataSources addCacheableFileStrictly(File file, File cacheDir) throws SerializationException {
final XmlSource xmlSource = XmlSources.fromCacheableFile( file, cacheDir, true ); final XmlSource xmlSource = XmlSources.fromCacheableFile( file, cacheDir, true );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); addXmlBinding( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -498,7 +569,7 @@ public class MetadataSources implements Serializable {
public MetadataSources addInputStream(InputStreamAccess xmlInputStreamAccess) { public MetadataSources addInputStream(InputStreamAccess xmlInputStreamAccess) {
final XmlSource xmlSource = XmlSources.fromStream( xmlInputStreamAccess ); final XmlSource xmlSource = XmlSources.fromStream( xmlInputStreamAccess );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); addXmlBinding( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -512,7 +583,7 @@ public class MetadataSources implements Serializable {
public MetadataSources addInputStream(InputStream xmlInputStream) { public MetadataSources addInputStream(InputStream xmlInputStream) {
final XmlSource xmlSource = XmlSources.fromStream( xmlInputStream ); final XmlSource xmlSource = XmlSources.fromStream( xmlInputStream );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); addXmlBinding( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -526,7 +597,7 @@ public class MetadataSources implements Serializable {
public MetadataSources addURL(URL url) { public MetadataSources addURL(URL url) {
final XmlSource xmlSource = XmlSources.fromUrl( url ); final XmlSource xmlSource = XmlSources.fromUrl( url );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); addXmlBinding( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -544,18 +615,11 @@ public class MetadataSources implements Serializable {
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
XmlSources.fromJar( XmlSources.fromJar(
jar, jar,
xmlSource -> getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ) xmlSource -> addXmlBinding( xmlSource.doBind( binderAccess.getMappingBinder() ) )
); );
return this; return this;
} }
private List<Binding<JaxbBindableMappingDescriptor>> getXmlBindingsForWrite() {
if ( xmlBindings == null ) {
xmlBindings = new ArrayList<>();
}
return xmlBindings;
}
/** /**
* Read all {@code .hbm.xml} mapping documents from a directory tree. * Read all {@code .hbm.xml} mapping documents from a directory tree.
* <p> * <p>

View File

@ -83,6 +83,7 @@ import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmRootEntityType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSecondaryTableType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSecondaryTableType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSetType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSetType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSimpleIdType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSimpleIdType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSubclassEntityBaseDefinition;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSynchronizeType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSynchronizeType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmTimestampAttributeType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmTimestampAttributeType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmUnionSubclassEntityType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmUnionSubclassEntityType;
@ -155,6 +156,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbTableImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbTransientImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbTransientImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbUserTypeImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbUserTypeImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbVersionImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbVersionImpl;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
@ -170,54 +172,65 @@ import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller; import jakarta.xml.bind.Marshaller;
import static org.hibernate.boot.jaxb.hbm.transform.HbmTransformationLogging.TRANSFORMATION_LOGGER; import static org.hibernate.boot.jaxb.hbm.transform.HbmTransformationLogging.TRANSFORMATION_LOGGER;
import static org.hibernate.internal.util.StringHelper.coalesce;
import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.internal.util.StringHelper.isNotEmpty;
/** /**
* Transforms a JAXB binding of a hbm.xml file into a unified orm.xml representation * Transforms {@code hbm.xml} {@linkplain JaxbHbmHibernateMapping JAXB} bindings into
* {@code mapping.xml} {@linkplain JaxbEntityMappingsImpl JAXB} bindings
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Brett Meyer * @author Brett Meyer
*
* @implNote This transformation happens on the JAXB model level creating
* a {@link JaxbEntityMappingsImpl} "copy" of the {@link JaxbHbmHibernateMapping}
* representation
*/ */
public class HbmXmlTransformer { public class HbmXmlTransformer {
/** /**
* Main entry into hbm.xml transformation * Transforms a list of {@code hbm.xml} JAXB bindings into a list of {@code mapping.xml} JAXB bindings
* *
* @param hbmXmlMapping The hbm.xml mapping to be transformed * @param hbmXmlBindings The list of {@code hbm.xml} JAXB bindings
* @param origin The origin of the hbm.xml mapping * @param unsupportedFeatureHandling How to handle {@code hbm.xml} features we don't transform
* @return The transformed representation *
* @return The list of {@code mapping.xml} JAXB bindings
*/ */
public static JaxbEntityMappingsImpl transform(JaxbHbmHibernateMapping hbmXmlMapping, Origin origin, Options options) { public static List<Binding<JaxbEntityMappingsImpl>> transform(
return new HbmXmlTransformer( hbmXmlMapping, origin, options ).doTransform(); List<Binding<JaxbHbmHibernateMapping>> hbmXmlBindings,
UnsupportedFeatureHandling unsupportedFeatureHandling) {
final TransformationState transformationState = new TransformationState( hbmXmlBindings );
TransformationPreprocessor.preprocessHbmXml( hbmXmlBindings, transformationState );
for ( int i = 0; i < hbmXmlBindings.size(); i++ ) {
final Binding<JaxbHbmHibernateMapping> hbmJaxbBinding = hbmXmlBindings.get( i );
final Binding<JaxbEntityMappingsImpl> mappingJaxbBinding = transformationState.getMappingBindings().get( i );
final HbmXmlTransformer hbmXmlTransformer = new HbmXmlTransformer(
hbmJaxbBinding,
mappingJaxbBinding,
transformationState,
unsupportedFeatureHandling
);
hbmXmlTransformer.doTransform();
} }
public interface Options { return transformationState.getMappingBindings();
UnsupportedFeatureHandling unsupportedFeatureHandling();
} }
private final Origin origin; private final Origin origin;
private final JaxbHbmHibernateMapping hbmXmlMapping; private final JaxbHbmHibernateMapping hbmXmlMapping;
private final JaxbEntityMappingsImpl ormRoot; private final JaxbEntityMappingsImpl ormRoot;
private final TransformationState transformationState;
private final UnsupportedFeatureHandling unsupportedFeatureHandling;
private final Options options;
public HbmXmlTransformer(JaxbHbmHibernateMapping hbmXmlMapping, Origin origin, Options options) {
this.origin = origin;
this.hbmXmlMapping = hbmXmlMapping;
this.options = options;
this.ormRoot = new JaxbEntityMappingsImpl();
this.ormRoot.setDescription(
"mapping.xml document auto-generated from legacy hbm.xml format via transformation - " + origin.getName()
);
private HbmXmlTransformer(
Binding<JaxbHbmHibernateMapping> hbmJaxbBinding,
Binding<JaxbEntityMappingsImpl> mappingJaxbBinding,
TransformationState transformationState,
UnsupportedFeatureHandling unsupportedFeatureHandling) {
this.origin = hbmJaxbBinding.getOrigin();
this.hbmXmlMapping = hbmJaxbBinding.getRoot();
this.ormRoot = mappingJaxbBinding.getRoot();
this.transformationState = transformationState;
this.unsupportedFeatureHandling = unsupportedFeatureHandling;
} }
private JaxbEntityMappingsImpl doTransform() { private void doTransform() {
TRANSFORMATION_LOGGER.tracef( TRANSFORMATION_LOGGER.tracef(
"Starting hbm.xml transformation - `%s`", "Starting hbm.xml transformation - `%s`",
origin origin
@ -247,7 +260,6 @@ public class HbmXmlTransformer {
if ( TRANSFORMATION_LOGGER.isDebugEnabled() ) { if ( TRANSFORMATION_LOGGER.isDebugEnabled() ) {
dumpTransformed( origin, ormRoot ); dumpTransformed( origin, ormRoot );
} }
return ormRoot;
} }
private static void dumpTransformed(Origin origin, JaxbEntityMappingsImpl ormRoot) { private static void dumpTransformed(Origin origin, JaxbEntityMappingsImpl ormRoot) {
@ -293,7 +305,7 @@ public class HbmXmlTransformer {
} }
private void handleUnsupported(PickHandler pickHandler, String message, Object... messageArgs) { private void handleUnsupported(PickHandler pickHandler, String message, Object... messageArgs) {
switch ( options.unsupportedFeatureHandling() ) { switch ( unsupportedFeatureHandling ) {
case ERROR -> throw new UnsupportedOperationException( case ERROR -> throw new UnsupportedOperationException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
@ -807,32 +819,28 @@ public class HbmXmlTransformer {
// 2) ?? Have abstract hbm class mappings become MappedSuperclass mappings ?? // 2) ?? Have abstract hbm class mappings become MappedSuperclass mappings ??
for ( JaxbHbmRootEntityType hbmClass : hbmXmlMapping.getClazz() ) { for ( JaxbHbmRootEntityType hbmClass : hbmXmlMapping.getClazz() ) {
final JaxbEntityImpl entity = new JaxbEntityImpl(); final JaxbEntityImpl entity = transformationState.getEntityXref().get( hbmClass );
ormRoot.getEntities().add( entity );
transferRootEntity( hbmClass, entity ); transferRootEntity( hbmClass, entity );
} }
for ( JaxbHbmDiscriminatorSubclassEntityType hbmSubclass : hbmXmlMapping.getSubclass() ) { for ( JaxbHbmDiscriminatorSubclassEntityType hbmSubclass : hbmXmlMapping.getSubclass() ) {
final JaxbEntityImpl entity = new JaxbEntityImpl(); final JaxbEntityImpl entity = transformationState.getEntityXref().get( hbmSubclass );
ormRoot.getEntities().add( entity );
transferDiscriminatorSubclass( hbmSubclass, entity ); transferDiscriminatorSubclass( hbmSubclass, entity );
} }
for ( JaxbHbmJoinedSubclassEntityType hbmSubclass : hbmXmlMapping.getJoinedSubclass() ) { for ( JaxbHbmJoinedSubclassEntityType hbmSubclass : hbmXmlMapping.getJoinedSubclass() ) {
final JaxbEntityImpl entity = new JaxbEntityImpl(); final JaxbEntityImpl entity = transformationState.getEntityXref().get( hbmSubclass );
ormRoot.getEntities().add( entity );
transferJoinedSubclass( hbmSubclass, entity ); transferJoinedSubclass( hbmSubclass, entity );
} }
for ( JaxbHbmUnionSubclassEntityType hbmSubclass : hbmXmlMapping.getUnionSubclass() ) { for ( JaxbHbmUnionSubclassEntityType hbmSubclass : hbmXmlMapping.getUnionSubclass() ) {
final JaxbEntityImpl entity = new JaxbEntityImpl(); final JaxbEntityImpl entity = transformationState.getEntityXref().get( hbmSubclass );
ormRoot.getEntities().add( entity );
transferUnionSubclass( hbmSubclass, entity ); transferUnionSubclass( hbmSubclass, entity );
} }
} }
private String extractEntityName(EntityInfo entityInfo) { private static String extractEntityName(EntityInfo entityInfo) {
if ( entityInfo.getEntityName() != null ) { if ( entityInfo.getEntityName() != null ) {
return entityInfo.getEntityName(); return entityInfo.getEntityName();
} }
@ -901,12 +909,12 @@ public class HbmXmlTransformer {
entity.setSqlRestriction( hbmClass.getWhere() ); entity.setSqlRestriction( hbmClass.getWhere() );
if ( !hbmClass.getTuplizer().isEmpty() ) { if ( !hbmClass.getTuplizer().isEmpty() ) {
if ( options.unsupportedFeatureHandling() == UnsupportedFeatureHandling.ERROR ) { if ( unsupportedFeatureHandling == UnsupportedFeatureHandling.ERROR ) {
throw new MappingException( "HBM transformation: Tuplizer not supported", origin ); throw new MappingException( "HBM transformation: Tuplizer not supported", origin );
} }
TRANSFORMATION_LOGGER.logf( TRANSFORMATION_LOGGER.logf(
options.unsupportedFeatureHandling() == UnsupportedFeatureHandling.WARN unsupportedFeatureHandling == UnsupportedFeatureHandling.WARN
? Logger.Level.WARN ? Logger.Level.WARN
: Logger.Level.DEBUG, : Logger.Level.DEBUG,
"Transformation of <tuplizer/> is not supported - `%s`", "Transformation of <tuplizer/> is not supported - `%s`",
@ -950,26 +958,17 @@ public class HbmXmlTransformer {
} }
for ( JaxbHbmJoinedSubclassEntityType hbmSubclass : hbmClass.getJoinedSubclass() ) { for ( JaxbHbmJoinedSubclassEntityType hbmSubclass : hbmClass.getJoinedSubclass() ) {
entity.setInheritance( new JaxbInheritanceImpl() ); final JaxbEntityImpl subclassEntity = transformationState.getEntityXref().get( hbmSubclass );
entity.getInheritance().setStrategy( InheritanceType.JOINED );
final JaxbEntityImpl subclassEntity = new JaxbEntityImpl();
ormRoot.getEntities().add( subclassEntity );
transferJoinedSubclass( hbmSubclass, subclassEntity ); transferJoinedSubclass( hbmSubclass, subclassEntity );
} }
for (JaxbHbmUnionSubclassEntityType hbmSubclass : hbmClass.getUnionSubclass() ) { for (JaxbHbmUnionSubclassEntityType hbmSubclass : hbmClass.getUnionSubclass() ) {
entity.setInheritance( new JaxbInheritanceImpl() ); final JaxbEntityImpl subclassEntity = transformationState.getEntityXref().get( hbmSubclass );
entity.getInheritance().setStrategy( InheritanceType.TABLE_PER_CLASS );
final JaxbEntityImpl subclassEntity = new JaxbEntityImpl();
ormRoot.getEntities().add( subclassEntity );
transferUnionSubclass( hbmSubclass, subclassEntity ); transferUnionSubclass( hbmSubclass, subclassEntity );
} }
for ( JaxbHbmDiscriminatorSubclassEntityType hbmSubclass : hbmClass.getSubclass() ) { for ( JaxbHbmDiscriminatorSubclassEntityType hbmSubclass : hbmClass.getSubclass() ) {
final JaxbEntityImpl subclassEntity = new JaxbEntityImpl(); final JaxbEntityImpl subclassEntity = transformationState.getEntityXref().get( hbmSubclass );
ormRoot.getEntities().add( subclassEntity );
transferDiscriminatorSubclass( hbmSubclass, subclassEntity ); transferDiscriminatorSubclass( hbmSubclass, subclassEntity );
} }
@ -1023,6 +1022,19 @@ public class HbmXmlTransformer {
transfer( hbmClass::getEntityName, entity::setName ); transfer( hbmClass::getEntityName, entity::setName );
transfer( hbmClass::getName, entity::setClazz ); transfer( hbmClass::getName, entity::setClazz );
if ( StringHelper.isEmpty( entity.getExtends() ) ) {
if ( hbmClass instanceof JaxbHbmSubclassEntityBaseDefinition hbmSubclass ) {
if ( StringHelper.isNotEmpty( hbmSubclass.getExtends() ) ) {
entity.setExtends( TransformationState.requireEntityReferenceName(
hbmSubclass.getExtends(),
hbmXmlMapping,
transformationState.getEntityMap(),
origin
) );
}
}
}
if ( hbmClass instanceof Discriminatable discriminatable ) { if ( hbmClass instanceof Discriminatable discriminatable ) {
transfer( discriminatable::getDiscriminatorValue, entity::setDiscriminatorValue ); transfer( discriminatable::getDiscriminatorValue, entity::setDiscriminatorValue );
} }
@ -1081,6 +1093,13 @@ public class HbmXmlTransformer {
transferBaseEntityInformation( hbmSubclass, subclassEntity ); transferBaseEntityInformation( hbmSubclass, subclassEntity );
transferEntityElementAttributes( hbmSubclass, subclassEntity ); transferEntityElementAttributes( hbmSubclass, subclassEntity );
if ( !hbmSubclass.getSubclass().isEmpty() ) {
for ( JaxbHbmDiscriminatorSubclassEntityType nestedHbmSubclass : hbmSubclass.getSubclass() ) {
final JaxbEntityImpl nestedSubclassEntity = transformationState.getEntityXref().get( nestedHbmSubclass );
transferDiscriminatorSubclass( nestedHbmSubclass, nestedSubclassEntity );
}
}
} }
private void transferJoinedSubclass(JaxbHbmJoinedSubclassEntityType hbmSubclass, JaxbEntityImpl subclassEntity) { private void transferJoinedSubclass(JaxbHbmJoinedSubclassEntityType hbmSubclass, JaxbEntityImpl subclassEntity) {
@ -1113,11 +1132,8 @@ public class HbmXmlTransformer {
} }
if ( !hbmSubclass.getJoinedSubclass().isEmpty() ) { if ( !hbmSubclass.getJoinedSubclass().isEmpty() ) {
subclassEntity.setInheritance( new JaxbInheritanceImpl() );
subclassEntity.getInheritance().setStrategy( InheritanceType.JOINED );
for ( JaxbHbmJoinedSubclassEntityType nestedHbmSubclass : hbmSubclass.getJoinedSubclass() ) { for ( JaxbHbmJoinedSubclassEntityType nestedHbmSubclass : hbmSubclass.getJoinedSubclass() ) {
final JaxbEntityImpl nestedSubclassEntity = new JaxbEntityImpl(); final JaxbEntityImpl nestedSubclassEntity = transformationState.getEntityXref().get( nestedHbmSubclass );
ormRoot.getEntities().add( nestedSubclassEntity );
transferJoinedSubclass( nestedHbmSubclass, nestedSubclassEntity ); transferJoinedSubclass( nestedHbmSubclass, nestedSubclassEntity );
} }
} }
@ -1284,7 +1300,15 @@ public class HbmXmlTransformer {
attributes.getEmbeddedAttributes().add( transformEmbedded( jaxbEmbeddable, hbmComponent ) ); attributes.getEmbeddedAttributes().add( transformEmbedded( jaxbEmbeddable, hbmComponent ) );
} }
else if ( hbmAttributeMapping instanceof JaxbHbmPropertiesType hbmProperties ) { else if ( hbmAttributeMapping instanceof JaxbHbmPropertiesType hbmProperties ) {
transferAttributes( hbmProperties.getAttributes(), attributes ); // while we could simply "unwrap" the <properties/> itself and inline the attributes,
// <properties/> is most often used to create a target for property-ref mappings - that
// we could not support without a new sort of annotation - e.g.
//
// @interface PropertyGroup {
// String name();
// String[] propertyNames();
// }
handleUnsupported( "<properties/> mappings not supported for transformation [name=%s]", hbmProperties.getName() );
} }
else if ( hbmAttributeMapping instanceof JaxbHbmDynamicComponentType ) { else if ( hbmAttributeMapping instanceof JaxbHbmDynamicComponentType ) {
final String name = ( (JaxbHbmDynamicComponentType) hbmAttributeMapping ).getName(); final String name = ( (JaxbHbmDynamicComponentType) hbmAttributeMapping ).getName();
@ -2401,11 +2425,8 @@ public class HbmXmlTransformer {
} }
if ( !hbmSubclass.getUnionSubclass().isEmpty() ) { if ( !hbmSubclass.getUnionSubclass().isEmpty() ) {
subclassEntity.setInheritance( new JaxbInheritanceImpl() );
subclassEntity.getInheritance().setStrategy( InheritanceType.TABLE_PER_CLASS );
for ( JaxbHbmUnionSubclassEntityType nestedHbmSubclass : hbmSubclass.getUnionSubclass() ) { for ( JaxbHbmUnionSubclassEntityType nestedHbmSubclass : hbmSubclass.getUnionSubclass() ) {
final JaxbEntityImpl nestedSubclassEntity = new JaxbEntityImpl(); final JaxbEntityImpl nestedSubclassEntity = transformationState.getEntityXref().get( nestedHbmSubclass );
ormRoot.getEntities().add( nestedSubclassEntity );
transferUnionSubclass( nestedHbmSubclass, nestedSubclassEntity ); transferUnionSubclass( nestedHbmSubclass, nestedSubclassEntity );
} }
} }

View File

@ -0,0 +1,368 @@
/*
* 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.hbm.transform;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.hibernate.boot.MappingException;
import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.hbm.spi.EntityInfo;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmDiscriminatorSubclassEntityType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmEntityBaseDefinition;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmJoinedSubclassEntityType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSubclassEntityBaseDefinition;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmUnionSubclassEntityType;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbInheritanceImpl;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import jakarta.persistence.InheritanceType;
/**
* @author Steve Ebersole
*/
public class TransformationPreprocessor {
static void preprocessHbmXml(
List<Binding<JaxbHbmHibernateMapping>> hbmXmlBindings,
TransformationState transformationState) {
final EntityMappingConsumer entityMappingConsumer = new EntityMappingConsumer( transformationState );
final Map<String, JaxbEntityImpl> rootClassesMap = new HashMap<>();
processStructuredHierarchies( hbmXmlBindings, rootClassesMap, entityMappingConsumer );
processSeparatedHierarchies( hbmXmlBindings, rootClassesMap, entityMappingConsumer );
}
private static void processStructuredHierarchies(
Collection<Binding<JaxbHbmHibernateMapping>> hbmXmlBindings,
Map<String, JaxbEntityImpl> rootClassesMap,
EntityMappingConsumer entityMappingConsumer) {
hbmXmlBindings.forEach( (hbmBinding) -> {
processStructuredHierarchies( rootClassesMap, entityMappingConsumer, hbmBinding );
} );
}
private static void processStructuredHierarchies(
Map<String, JaxbEntityImpl> rootClassesMap,
EntityMappingConsumer entityMappingConsumer,
Binding<JaxbHbmHibernateMapping> hbmBinding) {
final JaxbHbmHibernateMapping hibernateMapping = hbmBinding.getRoot();
hibernateMapping.getClazz().forEach( (hbmRoot) -> {
final JaxbEntityImpl rootJaxbEntity = makeJaxbEntity( hbmRoot, hibernateMapping );
final String entityName = determineEntityName( hbmRoot, hibernateMapping );
entityMappingConsumer.accept( hbmBinding, entityName, hbmRoot, rootJaxbEntity );
rootClassesMap.put( entityName, rootJaxbEntity );
if ( CollectionHelper.isNotEmpty( hbmRoot.getSubclass() ) ) {
applyInheritanceStrategy( entityName, rootJaxbEntity, InheritanceType.SINGLE_TABLE );
processStructuredDiscriminatorSubclasses(
hbmRoot.getSubclass(),
entityName,
hbmBinding,
entityMappingConsumer
);
}
if ( CollectionHelper.isNotEmpty( hbmRoot.getJoinedSubclass() ) ) {
applyInheritanceStrategy( entityName, rootJaxbEntity, InheritanceType.JOINED );
processStructuredJoinedSubclasses(
hbmRoot.getJoinedSubclass(),
entityName,
hbmBinding,
entityMappingConsumer
);
}
if ( CollectionHelper.isNotEmpty( hbmRoot.getUnionSubclass() ) ) {
applyInheritanceStrategy( entityName, rootJaxbEntity, InheritanceType.TABLE_PER_CLASS );
processStructuredUnionSubclasses(
hbmRoot.getUnionSubclass(),
entityName,
hbmBinding,
entityMappingConsumer
);
}
} );
}
private static void applyInheritanceStrategy(String entityName, JaxbEntityImpl rootJaxbEntity, InheritanceType strategy) {
final JaxbInheritanceImpl existing = rootJaxbEntity.getInheritance();
if ( existing != null ) {
if ( existing.getStrategy() != null && existing.getStrategy() != strategy ) {
throw new IllegalStateException( String.format(
Locale.ROOT,
"Root entity `%s` defined a mix of inheritance strategies; at least %s and %s",
entityName,
strategy,
existing.getStrategy()
) );
}
existing.setStrategy( strategy );
}
else {
final JaxbInheritanceImpl created = new JaxbInheritanceImpl();
created.setStrategy( strategy );
rootJaxbEntity.setInheritance( created );
}
}
private static void processStructuredDiscriminatorSubclasses(
List<JaxbHbmDiscriminatorSubclassEntityType> hbmSubclasses,
String superEntityName,
Binding<JaxbHbmHibernateMapping> hbmBinding,
EntityMappingConsumer entityMappingConsumer) {
hbmSubclasses.forEach( (hbmSubclass) -> {
final JaxbEntityImpl subclassJaxbEntity = makeJaxbEntity( hbmSubclass, hbmBinding.getRoot() );
final String subclassEntityName = determineEntityName( hbmSubclass, hbmBinding.getRoot() );
entityMappingConsumer.accept( hbmBinding, subclassEntityName, hbmSubclass, subclassJaxbEntity );
subclassJaxbEntity.setExtends( superEntityName );
if ( CollectionHelper.isNotEmpty( hbmSubclass.getSubclass() ) ) {
processStructuredDiscriminatorSubclasses(
hbmSubclass.getSubclass(),
subclassEntityName,
hbmBinding,
entityMappingConsumer
);
}
} );
}
private static void processStructuredJoinedSubclasses(
List<JaxbHbmJoinedSubclassEntityType> hbmSubclasses,
String superEntityName,
Binding<JaxbHbmHibernateMapping> hbmBinding,
EntityMappingConsumer entityMappingConsumer) {
hbmSubclasses.forEach( (hbmSubclass) -> {
final JaxbEntityImpl subclassJaxbEntity = makeJaxbEntity( hbmSubclass, hbmBinding.getRoot() );
final String subclassEntityName = determineEntityName( hbmSubclass, hbmBinding.getRoot() );
entityMappingConsumer.accept( hbmBinding, subclassEntityName, hbmSubclass, subclassJaxbEntity );
subclassJaxbEntity.setExtends( superEntityName );
if ( CollectionHelper.isNotEmpty( hbmSubclass.getJoinedSubclass() ) ) {
processStructuredJoinedSubclasses(
hbmSubclass.getJoinedSubclass(),
subclassEntityName,
hbmBinding,
entityMappingConsumer
);
}
} );
}
private static void processStructuredUnionSubclasses(
List<JaxbHbmUnionSubclassEntityType> hbmSubclasses,
String superEntityName,
Binding<JaxbHbmHibernateMapping> hbmBinding,
EntityMappingConsumer entityMappingConsumer) {
hbmSubclasses.forEach( (hbmSubclass) -> {
final JaxbEntityImpl subclassJaxbEntity = makeJaxbEntity( hbmSubclass, hbmBinding.getRoot() );
final String subclassEntityName = determineEntityName( hbmSubclass, hbmBinding.getRoot() );
entityMappingConsumer.accept( hbmBinding, subclassEntityName, hbmSubclass, subclassJaxbEntity );
subclassJaxbEntity.setExtends( superEntityName );
if ( CollectionHelper.isNotEmpty( hbmSubclass.getUnionSubclass() ) ) {
processStructuredUnionSubclasses(
hbmSubclass.getUnionSubclass(),
subclassEntityName,
hbmBinding,
entityMappingConsumer
);
}
} );
}
private static void processSeparatedHierarchies(
Collection<Binding<JaxbHbmHibernateMapping>> hbmXmlBindings,
Map<String, JaxbEntityImpl> rootClassesMap,
EntityMappingConsumer entityMappingConsumer) {
hbmXmlBindings.forEach( (hbmBinding) -> {
processSeparatedHierarchies( rootClassesMap, entityMappingConsumer, hbmBinding );
} );
}
private static void processSeparatedHierarchies(
Map<String, JaxbEntityImpl> rootClassesMap,
EntityMappingConsumer entityMappingConsumer,
Binding<JaxbHbmHibernateMapping> hbmBinding) {
final JaxbHbmHibernateMapping hibernateMapping = hbmBinding.getRoot();
processTopLevelDiscriminatedSubclasses( rootClassesMap, entityMappingConsumer, hbmBinding, hibernateMapping );
processTopLevelJoinedSubclasses( rootClassesMap, entityMappingConsumer, hbmBinding, hibernateMapping );
processTopLevelUnionSubclasses( rootClassesMap, entityMappingConsumer, hbmBinding, hibernateMapping );
}
private static void processTopLevelDiscriminatedSubclasses(
Map<String, JaxbEntityImpl> rootClassesMap,
EntityMappingConsumer entityMappingConsumer,
Binding<JaxbHbmHibernateMapping> hbmBinding,
JaxbHbmHibernateMapping hibernateMapping) {
hibernateMapping.getSubclass().forEach( (hbmSubclass) -> {
final String entityName = determineEntityName( hbmSubclass, hibernateMapping );
applyExtendedInheritanceStrategy(
entityName,
InheritanceType.SINGLE_TABLE,
hbmSubclass,
hibernateMapping,
rootClassesMap,
hbmBinding.getOrigin()
);
final JaxbEntityImpl jaxbEntity = makeJaxbEntity( hbmSubclass, hibernateMapping );
entityMappingConsumer.accept( hbmBinding, entityName, hbmSubclass, jaxbEntity );
if ( CollectionHelper.isNotEmpty( hbmSubclass.getSubclass() ) ) {
processStructuredDiscriminatorSubclasses(
hbmSubclass.getSubclass(),
entityName,
hbmBinding,
entityMappingConsumer
);
}
} );
}
private static void processTopLevelJoinedSubclasses(
Map<String, JaxbEntityImpl> rootClassesMap,
EntityMappingConsumer entityMappingConsumer,
Binding<JaxbHbmHibernateMapping> hbmBinding,
JaxbHbmHibernateMapping hibernateMapping) {
hibernateMapping.getJoinedSubclass().forEach( (hbmSubclass) -> {
final String entityName = determineEntityName( hbmSubclass, hibernateMapping );
applyExtendedInheritanceStrategy(
entityName,
InheritanceType.JOINED,
hbmSubclass,
hibernateMapping,
rootClassesMap,
hbmBinding.getOrigin()
);
final JaxbEntityImpl jaxbEntity = makeJaxbEntity( hbmSubclass, hibernateMapping );
entityMappingConsumer.accept( hbmBinding, entityName, hbmSubclass, jaxbEntity );
if ( CollectionHelper.isNotEmpty( hbmSubclass.getJoinedSubclass() ) ) {
processStructuredJoinedSubclasses(
hbmSubclass.getJoinedSubclass(),
entityName,
hbmBinding,
entityMappingConsumer
);
}
} );
}
private static void processTopLevelUnionSubclasses(
Map<String, JaxbEntityImpl> rootClassesMap,
EntityMappingConsumer entityMappingConsumer,
Binding<JaxbHbmHibernateMapping> hbmBinding,
JaxbHbmHibernateMapping hibernateMapping) {
hibernateMapping.getUnionSubclass().forEach( (hbmSubclass) -> {
final String entityName = determineEntityName( hbmSubclass, hibernateMapping );
applyExtendedInheritanceStrategy(
entityName,
InheritanceType.TABLE_PER_CLASS,
hbmSubclass,
hibernateMapping,
rootClassesMap,
hbmBinding.getOrigin()
);
final JaxbEntityImpl jaxbEntity = makeJaxbEntity( hbmSubclass, hibernateMapping );
entityMappingConsumer.accept( hbmBinding, entityName, hbmSubclass, jaxbEntity );
if ( CollectionHelper.isNotEmpty( hbmSubclass.getUnionSubclass() ) ) {
processStructuredUnionSubclasses(
hbmSubclass.getUnionSubclass(),
entityName,
hbmBinding,
entityMappingConsumer
);
}
} );
}
private static void applyExtendedInheritanceStrategy(
String entityName,
InheritanceType strategy,
JaxbHbmSubclassEntityBaseDefinition hbmSubclass,
JaxbHbmHibernateMapping hibernateMapping,
Map<String, JaxbEntityImpl> rootClassesMap,
Origin origin) {
if ( StringHelper.isEmpty( hbmSubclass.getExtends() ) ) {
throw new MappingException( "Separated inheritance mapping did not specify extends", origin );
}
// we only have something to do here if the extends names a root entity
final JaxbEntityImpl superRoot = TransformationState.resolveEntityReference(
hbmSubclass.getExtends(),
hibernateMapping,
rootClassesMap
);
if ( superRoot != null ) {
applyInheritanceStrategy( entityName, superRoot, strategy );
}
}
private static JaxbEntityImpl makeJaxbEntity(
JaxbHbmEntityBaseDefinition hbmEntity,
JaxbHbmHibernateMapping hibernateMapping) {
final JaxbEntityImpl jaxbEntity = new JaxbEntityImpl();
if ( StringHelper.isNotEmpty( hbmEntity.getName() ) ) {
jaxbEntity.setClazz( StringHelper.qualifyConditionallyIfNot( hibernateMapping.getPackage(), hbmEntity.getName() ) );
}
if ( StringHelper.isNotEmpty( hbmEntity.getEntityName() ) ) {
jaxbEntity.setName( hbmEntity.getEntityName() );
}
return jaxbEntity;
}
private static String determineEntityName(EntityInfo entityInfo, JaxbHbmHibernateMapping hibernateMapping) {
if ( entityInfo.getEntityName() != null ) {
return entityInfo.getEntityName();
}
return StringHelper.qualifyConditionallyIfNot( hibernateMapping.getPackage(), entityInfo.getName() );
}
private record EntityMappingConsumer(TransformationState transformationState) {
public void accept(
Binding<JaxbHbmHibernateMapping> hbmBinding,
String registrationName,
JaxbHbmEntityBaseDefinition hbmEntity,
JaxbEntityImpl mappingEntity) {
final Binding<JaxbEntityMappingsImpl> mappingBinding = resolveMappingBinding( hbmBinding );
mappingBinding.getRoot().getEntities().add( mappingEntity );
transformationState.getEntityXref().put( hbmEntity, mappingEntity );
transformationState.getEntityMap().put( registrationName, mappingEntity );
}
private Binding<JaxbEntityMappingsImpl> resolveMappingBinding(Binding<JaxbHbmHibernateMapping> hbmBinding) {
for ( int i = 0; i < transformationState.getHbmBindings().size(); i++ ) {
if ( hbmBinding == transformationState.getHbmBindings().get( i ) ) {
return transformationState.getMappingBindings().get( i );
}
}
throw new IllegalStateException( "Could not resolve corresponding mapping binding : " + hbmBinding );
}
}
}

View File

@ -0,0 +1,137 @@
/*
* 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.hbm.transform;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmEntityBaseDefinition;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
/**
* @author Steve Ebersole
*/
class TransformationState {
private final List<Binding<JaxbHbmHibernateMapping>> hbmBindings;
private final List<Binding<JaxbEntityMappingsImpl>> mappingBindings;
private final Map<String, JaxbEntityImpl> entityMap = new HashMap<>();
private final Map<JaxbHbmEntityBaseDefinition, JaxbEntityImpl> entityXref = new HashMap<>();
public TransformationState(List<Binding<JaxbHbmHibernateMapping>> hbmBindings) {
this.hbmBindings = hbmBindings;
this.mappingBindings = CollectionHelper.arrayList( hbmBindings.size() );
for ( Binding<JaxbHbmHibernateMapping> hbmBinding : this.hbmBindings ) {
final JaxbEntityMappingsImpl mappingRoot = new JaxbEntityMappingsImpl();
mappingRoot.setDescription( String.format(
Locale.ROOT,
"Generated by Hibernate HbmXmlTransformer from %s (%s)",
hbmBinding.getOrigin().getName(),
hbmBinding.getOrigin().getType()
) );
mappingBindings.add( new Binding<>( mappingRoot, hbmBinding.getOrigin() ) );
}
}
public static String resolveEntityReferenceName(
String referenceName,
JaxbHbmHibernateMapping hibernateMapping,
Map<String,JaxbEntityImpl> entityMap) {
// First try it as a direct key reference; this covers the case of:
// 1. entity-name
// 2. fully-qualified name
final JaxbEntityImpl byDirectName = entityMap.get( referenceName );
if ( byDirectName != null ) {
return referenceName;
}
// Next, try as an implicitly qualified name
if ( StringHelper.isNotEmpty( hibernateMapping.getPackage() ) ) {
final String qualifiedName = StringHelper.qualify( hibernateMapping.getPackage(), referenceName );
final JaxbEntityImpl byQualifiedName = entityMap.get( qualifiedName );
if ( byQualifiedName != null ) {
return qualifiedName;
}
}
return null;
}
public static String requireEntityReferenceName(
String referenceName,
JaxbHbmHibernateMapping hibernateMapping,
Map<String,JaxbEntityImpl> entityMap,
Origin origin) {
final String resolved = resolveEntityReferenceName( referenceName, hibernateMapping, entityMap );
if ( resolved == null ) {
throw new UnknownEntityReferenceException( referenceName, origin );
}
return resolved;
}
public static JaxbEntityImpl resolveEntityReference(
String referenceName,
JaxbHbmHibernateMapping hibernateMapping,
Map<String,JaxbEntityImpl> entityMap) {
// First try it as a direct key reference; this covers the case of:
// 1. entity-name
// 2. fully-qualified name
final JaxbEntityImpl byDirectName = entityMap.get( referenceName );
if ( byDirectName != null ) {
return byDirectName;
}
// Next, try as an implicitly qualified name
if ( StringHelper.isNotEmpty( hibernateMapping.getPackage() ) ) {
final String qualifiedName = StringHelper.qualify( hibernateMapping.getPackage(), referenceName );
final JaxbEntityImpl byQualifiedName = entityMap.get( qualifiedName );
if ( byQualifiedName != null ) {
return byQualifiedName;
}
}
return null;
}
public static JaxbEntityImpl requireEntityReference(
String referenceName,
JaxbHbmHibernateMapping hibernateMapping,
Map<String,JaxbEntityImpl> entityMap,
Origin origin) {
final JaxbEntityImpl resolved = resolveEntityReference( referenceName, hibernateMapping, entityMap );
if ( resolved == null ) {
throw new UnknownEntityReferenceException( referenceName, origin );
}
return resolved;
}
public List<Binding<JaxbHbmHibernateMapping>> getHbmBindings() {
return hbmBindings;
}
public List<Binding<JaxbEntityMappingsImpl>> getMappingBindings() {
return mappingBindings;
}
public Map<String, JaxbEntityImpl> getEntityMap() {
return entityMap;
}
public Map<JaxbHbmEntityBaseDefinition, JaxbEntityImpl> getEntityXref() {
return entityXref;
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.hbm.transform;
import java.util.Locale;
import org.hibernate.MappingException;
import org.hibernate.boot.jaxb.Origin;
/**
* We encountered a reference to an entity by name which we cannot resolve
*
* @author Steve Ebersole
*/
public class UnknownEntityReferenceException extends MappingException {
public UnknownEntityReferenceException(String name, Origin origin) {
super( String.format(
Locale.ROOT,
"Could not resolve entity name `%s` : %s (%s)",
name,
origin.getName(),
origin.getType()
) );
}
}

View File

@ -15,22 +15,19 @@ import javax.xml.stream.events.StartElement;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.boot.ResourceStreamLocator; import org.hibernate.boot.ResourceStreamLocator;
import org.hibernate.boot.UnsupportedOrmXsdVersionException; import org.hibernate.boot.UnsupportedOrmXsdVersionException;
import org.hibernate.boot.jaxb.JaxbLogger;
import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer;
import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling; import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling;
import org.hibernate.boot.jaxb.internal.stax.HbmEventReader; import org.hibernate.boot.jaxb.internal.stax.HbmEventReader;
import org.hibernate.boot.jaxb.internal.stax.JpaOrmXmlEventReader; import org.hibernate.boot.jaxb.internal.stax.JpaOrmXmlEventReader;
import org.hibernate.boot.jaxb.internal.stax.MappingEventReader; import org.hibernate.boot.jaxb.internal.stax.MappingEventReader;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor;
import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.xsd.MappingXsdSupport; import org.hibernate.boot.xsd.MappingXsdSupport;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.internal.util.config.ConfigurationException; import org.hibernate.internal.util.config.ConfigurationException;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;
@ -62,8 +59,6 @@ public class MappingBinder extends AbstractBinder<JaxbBindableMappingDescriptor>
public interface Options { public interface Options {
boolean validateMappings(); boolean validateMappings();
boolean transformHbmMappings();
} }
public static final Options VALIDATING = new Options() { public static final Options VALIDATING = new Options() {
@ -71,11 +66,6 @@ public class MappingBinder extends AbstractBinder<JaxbBindableMappingDescriptor>
public boolean validateMappings() { public boolean validateMappings() {
return true; return true;
} }
@Override
public boolean transformHbmMappings() {
return false;
}
}; };
public static final Options NON_VALIDATING = new Options() { public static final Options NON_VALIDATING = new Options() {
@ -83,11 +73,6 @@ public class MappingBinder extends AbstractBinder<JaxbBindableMappingDescriptor>
public boolean validateMappings() { public boolean validateMappings() {
return true; return true;
} }
@Override
public boolean transformHbmMappings() {
return false;
}
}; };
/** /**
@ -131,15 +116,6 @@ public class MappingBinder extends AbstractBinder<JaxbBindableMappingDescriptor>
} }
return BOOLEAN.convert( setting ); return BOOLEAN.convert( setting );
} }
@Override
public boolean transformHbmMappings() {
final Object setting = settingsAccess.apply( AvailableSettings.TRANSFORM_HBM_XML );
if ( setting == null ) {
return false;
}
return BOOLEAN.convert( setting );
}
}; };
this.unsupportedHandlingAccess = () -> { this.unsupportedHandlingAccess = () -> {
@ -178,11 +154,6 @@ public class MappingBinder extends AbstractBinder<JaxbBindableMappingDescriptor>
public boolean validateMappings() { public boolean validateMappings() {
return false; return false;
} }
@Override
public boolean transformHbmMappings() {
return false;
}
}, },
unsupportedHandling unsupportedHandling
); );
@ -219,13 +190,6 @@ public class MappingBinder extends AbstractBinder<JaxbBindableMappingDescriptor>
origin origin
); );
if ( optionsAccess.get().transformHbmMappings() ) {
JaxbLogger.JAXB_LOGGER.tracef( "Performing on-the-fly hbm.xml -> mapping.xml transformation - %s ", origin );
//noinspection unchecked
return new Binding<>( (X) HbmXmlTransformer.transform( hbmBindings, origin, unsupportedHandlingAccess::get ), origin );
}
DeprecationLogger.DEPRECATION_LOGGER.logDeprecatedHbmXmlProcessing( origin.getType(), origin.getName() );
//noinspection unchecked //noinspection unchecked
return new Binding<>( (X) hbmBindings, origin ); return new Binding<>( (X) hbmBindings, origin );
} }
@ -241,6 +205,7 @@ public class MappingBinder extends AbstractBinder<JaxbBindableMappingDescriptor>
mappingJaxbContext(), mappingJaxbContext(),
origin origin
); );
//noinspection unchecked //noinspection unchecked
return new Binding<>( (X) bindingRoot, origin ); return new Binding<>( (X) bindingRoot, origin );
} }

View File

@ -16,15 +16,27 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.boot.BootLogging;
import org.hibernate.boot.MetadataSources; import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor; import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer;
import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.process.spi.ManagedResources; import org.hibernate.boot.model.process.spi.ManagedResources;
import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.MappingSettings;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.internal.log.DeprecationLogger;
import jakarta.persistence.AttributeConverter; import jakarta.persistence.AttributeConverter;
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -42,11 +54,53 @@ public class ManagedResourcesImpl implements ManagedResources {
impl.annotatedClassReferences.addAll( sources.getAnnotatedClasses() ); impl.annotatedClassReferences.addAll( sources.getAnnotatedClasses() );
impl.annotatedClassNames.addAll( sources.getAnnotatedClassNames() ); impl.annotatedClassNames.addAll( sources.getAnnotatedClassNames() );
impl.annotatedPackageNames.addAll( sources.getAnnotatedPackages() ); impl.annotatedPackageNames.addAll( sources.getAnnotatedPackages() );
impl.mappingFileBindings.addAll( sources.getXmlBindings() ); handleXmlMappings( sources, impl, bootstrapContext );
impl.extraQueryImports = sources.getExtraQueryImports(); impl.extraQueryImports = sources.getExtraQueryImports();
return impl; return impl;
} }
@SuppressWarnings({ "rawtypes", "unchecked" })
private static void handleXmlMappings(
MetadataSources sources,
ManagedResourcesImpl impl,
BootstrapContext bootstrapContext) {
impl.mappingFileBindings.addAll( (List) sources.getMappingXmlBindings() );
if ( !bootstrapContext.getMetadataBuildingOptions().isXmlMappingEnabled() ) {
BootLogging.BOOT_LOGGER.debugf(
"Ignoring %s XML mappings due to `%s`",
sources.getMappingXmlBindings().size(),
MappingSettings.XML_MAPPING_ENABLED
);
return;
}
final ConfigurationService configurationService = bootstrapContext.getServiceRegistry().getService( ConfigurationService.class );
// NOTE : the configurationService nullness checking is here for a few tests using mocks
final boolean transformHbm = configurationService != null
&& configurationService.getSetting( MappingSettings.TRANSFORM_HBM_XML, BOOLEAN,false );
if ( !transformHbm ) {
// we are not transforming hbm.xml to mapping.xml, so just add the hbm.xml bindings as-is
impl.mappingFileBindings.addAll( (List) sources.getHbmXmlBindings() );
for ( Binding<JaxbHbmHibernateMapping> hbmXmlBinding : sources.getHbmXmlBindings() ) {
final Origin origin = hbmXmlBinding.getOrigin();
DeprecationLogger.DEPRECATION_LOGGER.logDeprecatedHbmXmlProcessing( origin.getType(), origin.getName() );
}
}
else {
// do the transformations
final List<Binding<JaxbEntityMappingsImpl>> transformed = HbmXmlTransformer.transform(
sources.getHbmXmlBindings(),
UnsupportedFeatureHandling.fromSetting(
configurationService.getSettings().get( AvailableSettings.TRANSFORM_HBM_XML_FEATURE_HANDLING ),
UnsupportedFeatureHandling.ERROR
)
);
impl.mappingFileBindings.addAll( (List) transformed );
}
}
public ManagedResourcesImpl() { public ManagedResourcesImpl() {
} }

View File

@ -576,11 +576,6 @@ public class MetadataBuildingProcess {
public boolean validateMappings() { public boolean validateMappings() {
return false; return false;
} }
@Override
public boolean transformHbmMappings() {
return false;
}
} }
); );
} }

View File

@ -9,11 +9,15 @@ package org.hibernate.boot.model.source.internal.annotations;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.SourceType; import org.hibernate.boot.jaxb.SourceType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer;
import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling;
import org.hibernate.boot.jaxb.internal.MappingBinder; import org.hibernate.boot.jaxb.internal.MappingBinder;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.jaxb.spi.Binding;
@ -85,6 +89,7 @@ public class AdditionalManagedResourcesImpl implements ManagedResources {
public static class Builder { public static class Builder {
private final MappingBinder mappingBinder; private final MappingBinder mappingBinder;
private final boolean transformHbmMappings;
private List<Class<?>> classes; private List<Class<?>> classes;
private List<ClassDetails> classDetails; private List<ClassDetails> classDetails;
@ -92,35 +97,26 @@ public class AdditionalManagedResourcesImpl implements ManagedResources {
private Collection<Binding<JaxbBindableMappingDescriptor>> xmlMappings; private Collection<Binding<JaxbBindableMappingDescriptor>> xmlMappings;
public Builder(boolean validateMappings, boolean transformHbmMappings) { public Builder(boolean validateMappings, boolean transformHbmMappings) {
this( new MappingBinder.Options() { this( transformHbmMappings, new MappingBinder.Options() {
@Override @Override
public boolean validateMappings() { public boolean validateMappings() {
return validateMappings; return validateMappings;
} }
@Override
public boolean transformHbmMappings() {
return transformHbmMappings;
}
} ); } );
} }
public Builder() { public Builder() {
this( new MappingBinder.Options() { this( false, new MappingBinder.Options() {
@Override @Override
public boolean validateMappings() { public boolean validateMappings() {
return false; return false;
} }
@Override
public boolean transformHbmMappings() {
return false;
}
} ); } );
} }
public Builder(MappingBinder.Options options) { public Builder(boolean transformHbmMappings, MappingBinder.Options options) {
mappingBinder = new MappingBinder( this.transformHbmMappings = transformHbmMappings;
this.mappingBinder = new MappingBinder(
(resourceName) -> Builder.class.getClassLoader().getResourceAsStream( resourceName ), (resourceName) -> Builder.class.getClassLoader().getResourceAsStream( resourceName ),
options options
); );
@ -163,6 +159,28 @@ public class AdditionalManagedResourcesImpl implements ManagedResources {
} }
public ManagedResources build() { public ManagedResources build() {
if ( CollectionHelper.isNotEmpty( xmlMappings ) ) {
if ( transformHbmMappings ) {
final List<Binding<JaxbHbmHibernateMapping>> hbmBindings = new ArrayList<>();
final Iterator<Binding<JaxbBindableMappingDescriptor>> iterator = xmlMappings.iterator();
while ( iterator.hasNext() ) {
final Binding<JaxbBindableMappingDescriptor> xmlBinding = iterator.next();
if ( xmlBinding.getRoot() instanceof JaxbHbmHibernateMapping ) {
//noinspection rawtypes,unchecked
hbmBindings.add( (Binding) xmlBinding );
iterator.remove();
}
}
if ( !hbmBindings.isEmpty() ) {
final List<Binding<JaxbEntityMappingsImpl>> transformed = HbmXmlTransformer.transform(
hbmBindings,
UnsupportedFeatureHandling.ERROR
);
//noinspection rawtypes,unchecked
xmlMappings.addAll( (List) transformed );
}
}
}
return new AdditionalManagedResourcesImpl( classes, classDetails, packageNames, xmlMappings ); return new AdditionalManagedResourcesImpl( classes, classDetails, packageNames, xmlMappings );
} }

View File

@ -12,6 +12,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.hibernate.MappingException;
import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; import org.hibernate.boot.internal.MetadataBuildingContextRootImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor; import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
@ -229,6 +230,14 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc
List<XClass> clazzHierarchy = new ArrayList<>(); List<XClass> clazzHierarchy = new ArrayList<>();
for ( ClassDetails clazz : classes ) { for ( ClassDetails clazz : classes ) {
if ( clazz.isInterface() ) {
if ( clazz.hasDirectAnnotationUsage( Entity.class ) ) {
throw new MappingException( "Only classes (not interfaces) may be mapped as @Entity : " + clazz.getName() );
}
if ( clazz.hasDirectAnnotationUsage( MappedSuperclass.class ) ) {
throw new MappingException( "Only classes (not interfaces) may be mapped as @MappedSuperclass : " + clazz.getName() );
}
}
if ( clazz.hasDirectAnnotationUsage( MappedSuperclass.class ) ) { if ( clazz.hasDirectAnnotationUsage( MappedSuperclass.class ) ) {
if ( debug ) { if ( debug ) {
log.debugf( log.debugf(

View File

@ -10,6 +10,7 @@ import java.lang.reflect.Modifier;
import java.util.List; import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.hibernate.MappingException;
import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributesContainer; import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributesContainer;
import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributesContainerImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributesContainerImpl;
@ -59,7 +60,9 @@ import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies;
import jakarta.persistence.Access; import jakarta.persistence.Access;
import jakarta.persistence.AccessType; import jakarta.persistence.AccessType;
import jakarta.persistence.EmbeddedId; import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import static org.hibernate.boot.models.xml.XmlProcessLogging.XML_PROCESS_LOGGER; import static org.hibernate.boot.models.xml.XmlProcessLogging.XML_PROCESS_LOGGER;
import static org.hibernate.internal.util.NullnessHelper.coalesce; import static org.hibernate.internal.util.NullnessHelper.coalesce;
@ -123,6 +126,9 @@ public class ManagedTypeProcessor {
defaultAccessTypeFromDefaultAccessor( xmlDocumentContext ), defaultAccessTypeFromDefaultAccessor( xmlDocumentContext ),
AccessType.PROPERTY AccessType.PROPERTY
); );
if ( classDetails.isInterface() ) {
throw new MappingException( "Only classes (not interfaces) may be mapped as @Entity : " + classDetails.getName() );
}
} }
classDetails.clearMemberAnnotationUsages(); classDetails.clearMemberAnnotationUsages();

View File

@ -351,10 +351,9 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
if ( classLoader == null ) { if ( classLoader == null ) {
throw persistenceException( "Enhancement requires a temp class loader, but none was given." ); throw persistenceException( "Enhancement requires a temp class loader, but none was given." );
} }
for ( Binding<JaxbBindableMappingDescriptor> binding : metadataSources.getXmlBindings() ) {
final JaxbBindableMappingDescriptor root = binding.getRoot(); for ( Binding<JaxbHbmHibernateMapping> binding : metadataSources.getHbmXmlBindings() ) {
if ( root instanceof JaxbHbmHibernateMapping ) { final JaxbHbmHibernateMapping hibernateMapping = binding.getRoot();
final JaxbHbmHibernateMapping hibernateMapping = (JaxbHbmHibernateMapping) root;
final String packageName = hibernateMapping.getPackage(); final String packageName = hibernateMapping.getPackage();
for ( JaxbHbmRootEntityType clazz : hibernateMapping.getClazz() ) { for ( JaxbHbmRootEntityType clazz : hibernateMapping.getClazz() ) {
final String className; final String className;
@ -372,7 +371,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
} }
} }
} }
}
for ( String annotatedClassName : metadataSources.getAnnotatedClassNames() ) { for ( String annotatedClassName : metadataSources.getAnnotatedClassNames() ) {
classTransformer.discoverTypes( classLoader, annotatedClassName ); classTransformer.discoverTypes( classLoader, annotatedClassName );
} }

View File

@ -10,6 +10,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader; import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Collections;
import java.util.List;
import javax.xml.stream.XMLEventFactory; import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventReader;
@ -21,6 +23,7 @@ import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer;
import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling; import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling;
import org.hibernate.boot.jaxb.internal.stax.HbmEventReader; import org.hibernate.boot.jaxb.internal.stax.HbmEventReader;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.xsd.MappingXsdSupport; import org.hibernate.boot.xsd.MappingXsdSupport;
import org.hibernate.orm.test.boot.jaxb.JaxbHelper; import org.hibernate.orm.test.boot.jaxb.JaxbHelper;
@ -57,11 +60,12 @@ public class TransformationHelper {
assertThat( hbmMapping ).isNotNull(); assertThat( hbmMapping ).isNotNull();
assertThat( hbmMapping.getClazz() ).hasSize( 1 ); assertThat( hbmMapping.getClazz() ).hasSize( 1 );
return HbmXmlTransformer.transform( final List<Binding<JaxbEntityMappingsImpl>> transformed = HbmXmlTransformer.transform(
hbmMapping, Collections.singletonList( new Binding<>( hbmMapping, new Origin( SourceType.RESOURCE, resourceName ) ) ),
new Origin( SourceType.RESOURCE, resourceName ), UnsupportedFeatureHandling.ERROR
() -> UnsupportedFeatureHandling.ERROR
); );
return transformed.get(0).getRoot();
} }
catch (JAXBException e) { catch (JAXBException e) {
throw new RuntimeException( "Error during JAXB processing", e ); throw new RuntimeException( "Error during JAXB processing", e );

View File

@ -8,6 +8,8 @@ package org.hibernate.orm.test.boot.jaxb.mapping;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import javax.xml.stream.XMLEventFactory; import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventReader;
@ -19,6 +21,7 @@ import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling;
import org.hibernate.boot.jaxb.internal.stax.HbmEventReader; import org.hibernate.boot.jaxb.internal.stax.HbmEventReader;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.xsd.MappingXsdSupport; import org.hibernate.boot.xsd.MappingXsdSupport;
import org.hibernate.orm.test.boot.jaxb.JaxbHelper; import org.hibernate.orm.test.boot.jaxb.JaxbHelper;
@ -56,11 +59,11 @@ public class HbmTransformationJaxbTests {
assertThat( hbmMapping ).isNotNull(); assertThat( hbmMapping ).isNotNull();
assertThat( hbmMapping.getClazz() ).hasSize( 1 ); assertThat( hbmMapping.getClazz() ).hasSize( 1 );
final JaxbEntityMappingsImpl transformed = HbmXmlTransformer.transform( final List<Binding<JaxbEntityMappingsImpl>> transformedBindingList = HbmXmlTransformer.transform(
hbmMapping, Collections.singletonList( new Binding<>( hbmMapping, new Origin( SourceType.RESOURCE, resourceName ) ) ),
new Origin( SourceType.RESOURCE, resourceName ), UnsupportedFeatureHandling.ERROR
() -> UnsupportedFeatureHandling.ERROR
); );
final JaxbEntityMappingsImpl transformed = transformedBindingList.get( 0 ).getRoot();
assertThat( transformed ).isNotNull(); assertThat( transformed ).isNotNull();
assertThat( transformed.getEntities() ).hasSize( 1 ); assertThat( transformed.getEntities() ).hasSize( 1 );

View File

@ -0,0 +1,73 @@
/*
* 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.orm.test.boot.models.hbm._extends;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.cfg.MappingSettings;
import org.hibernate.orm.test.boot.jaxb.hbm.TransformationHelper;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.Test;
import jakarta.persistence.InheritanceType;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Steve Ebersole
*/
@SuppressWarnings("JUnitMalformedDeclaration")
public class ExtendsTests {
@ServiceRegistry(settings = @Setting(name = MappingSettings.TRANSFORM_HBM_XML, value = "true"))
@Test
void testDiscriminatedStructured(ServiceRegistryScope registryScope) {
final JaxbEntityMappingsImpl transformed = TransformationHelper.transform(
"mappings/models/hbm/extends/discriminated-structured.xml",
registryScope.getRegistry()
);
verifyHierarchy( transformed, InheritanceType.SINGLE_TABLE );
}
@ServiceRegistry(settings = @Setting(name = MappingSettings.TRANSFORM_HBM_XML, value = "true"))
@Test
void testDiscriminatedSeparated(ServiceRegistryScope registryScope) {
final JaxbEntityMappingsImpl transformed = TransformationHelper.transform(
"mappings/models/hbm/extends/discriminated-separate.xml",
registryScope.getRegistry()
);
verifyHierarchy( transformed, InheritanceType.SINGLE_TABLE );
}
private void verifyHierarchy(JaxbEntityMappingsImpl transformed, InheritanceType inheritanceType) {
assertThat( transformed ).isNotNull();
assertThat( transformed.getEntities() ).hasSize( 3 );
for ( JaxbEntityImpl jaxbEntity : transformed.getEntities() ) {
if ( "org.hibernate.test.hbm._extends.Root".equals( jaxbEntity.getClazz() ) ) {
assertThat( jaxbEntity.getInheritance() ).isNotNull();
assertThat( jaxbEntity.getInheritance().getStrategy() ).isEqualTo( inheritanceType );
assertThat( jaxbEntity.getExtends() ).isNull();
assertThat( jaxbEntity.getDiscriminatorColumn().getName() ).isEqualTo( "the_type" );
assertThat( jaxbEntity.getDiscriminatorValue() ).isEqualTo( "R" );
}
else if ( "org.hibernate.test.hbm._extends.Branch".equals( jaxbEntity.getName() ) ) {
assertThat( jaxbEntity.getInheritance() ).isNull();
assertThat( jaxbEntity.getDiscriminatorValue() ).isEqualTo( "B" );
assertThat( jaxbEntity.getExtends() ).isEqualTo( "org.hibernate.test.hbm._extends.Root" );
}
else if ( "org.hibernate.test.hbm._extends.Leaf".equals( jaxbEntity.getName() ) ) {
assertThat( jaxbEntity.getInheritance() ).isNull();
assertThat( jaxbEntity.getDiscriminatorValue() ).isEqualTo( "L" );
assertThat( jaxbEntity.getExtends() ).isEqualTo( "org.hibernate.test.hbm._extends.Branch" );
}
}
}
}

View File

@ -1,59 +0,0 @@
/*
* 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.orm.test.boot.models.hbm.ecid;
import org.hibernate.cfg.MappingSettings;
import org.hibernate.orm.test.abstractembeddedcomponents.cid.AbstractCompositeIdTest;
import org.hibernate.orm.test.abstractembeddedcomponents.cid.MyInterfaceImpl;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
/**
* @see AbstractCompositeIdTest
*
* @author Steve Ebersole
*/
@SuppressWarnings("JUnitMalformedDeclaration")
@ServiceRegistry(settings = @Setting(name= MappingSettings.TRANSFORM_HBM_XML, value="true"))
@DomainModel( xmlMappings = "org/hibernate/orm/test/abstractembeddedcomponents/cid/Mappings.hbm.xml" )
@SessionFactory
@FailureExpected
public class EmbeddedCompositeIdentifierOnAbstractClassTests {
@Test
public void testTransformedHbmXml(SessionFactoryScope scope) {
MyInterfaceImpl myInterface = new MyInterfaceImpl();
myInterface.setKey1( "key1" );
myInterface.setKey2( "key2" );
myInterface.setName( "test" );
scope.inTransaction(
session -> {
// test persistence
session.persist( myInterface );
session.flush();
// test loading
session.createQuery( "from MyInterface" ).list();
}
);
}
@AfterEach
void dropTestData(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
session.createMutationQuery( "delete MyInterface" ).executeUpdate();
} );
}
}

View File

@ -1,49 +0,0 @@
/*
* 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.orm.test.boot.models.hbm.ecid;
/**
* @author Steve Ebersole
*/
public class Login {
private String system;
private String username;
private String email;
public Login() {
}
public Login(String system, String username, String email) {
this.system = system;
this.username = username;
this.email = email;
}
public String getSystem() {
return system;
}
public void setSystem(String system) {
this.system = system;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}

View File

@ -1,40 +0,0 @@
/*
* 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.orm.test.boot.models.hbm.ecid;
import java.util.List;
import org.hibernate.cfg.MappingSettings;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Steve Ebersole
*/
@SuppressWarnings("JUnitMalformedDeclaration")
@ServiceRegistry(settings = @Setting(name= MappingSettings.TRANSFORM_HBM_XML, value="true"))
@DomainModel(xmlMappings = "mappings/models/hbm/ecid/standard-ecid.hbm.xml")
@SessionFactory
public class StandardNonAggregatedIdTests {
@Test
void simpleTest(SessionFactoryScope scope) {
final Login login = new Login( "prod", "john", "john@doe.com" );
scope.inTransaction( (session) -> session.persist( login ) );
scope.inTransaction( (session) -> {
final List<Login> logins = session.createSelectionQuery( "from Login", Login.class ).list();
assertThat( logins ).hasSize( 1 );
} );
}
}

View File

@ -0,0 +1,21 @@
/*
* 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.orm.test.boot.models.hbm.intf;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
/**
* @author Steve Ebersole
*/
@Entity
public interface IPerson {
@Id
Integer getId();
String getName();
void setName(String name);
}

View File

@ -0,0 +1,59 @@
/*
* 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.orm.test.boot.models.hbm.intf;
import org.hibernate.MappingException;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cfg.MappingSettings;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for mapping interfaces as managed classes.
*
* @implNote This is something {@code hbm.xml} supported, and we want to make sure it fails in
* a consistent manner.
*
* @author Steve Ebersole
*/
@SuppressWarnings("JUnitMalformedDeclaration")
public class InterfaceMappingTests {
@ServiceRegistry
@Test
void testInterfaceAsEntity(ServiceRegistryScope registryScope) {
try (StandardServiceRegistry serviceRegistry = registryScope.getRegistry()) {
final Metadata metadata = new MetadataSources( serviceRegistry )
.addAnnotatedClasses( IPerson.class, Person.class )
.buildMetadata();
}
catch (MappingException expected) {
assertThat( expected.getMessage() ).startsWith( "Only classes (not interfaces) may be mapped as @Entity :" );
assertThat( expected.getMessage() ).endsWith( IPerson.class.getName() );
}
}
@ServiceRegistry(settings = @Setting(name = MappingSettings.TRANSFORM_HBM_XML, value = "true"))
@Test
void testTransformedHbmXml(ServiceRegistryScope registryScope) {
try (StandardServiceRegistry serviceRegistry = registryScope.getRegistry()) {
final Metadata metadata = new MetadataSources( serviceRegistry )
.addResource( "mappings/models/hbm/intf/mapped-interface.hbm.xml" )
.buildMetadata();
}
catch (MappingException expected) {
assertThat( expected.getMessage() ).startsWith( "Only classes (not interfaces) may be mapped as @Entity :" );
assertThat( expected.getMessage() ).endsWith( IPerson.class.getName() );
}
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.orm.test.boot.models.hbm.intf;
import jakarta.persistence.Entity;
/**
* @author Steve Ebersole
*/
@Entity
public class Person implements IPerson {
private Integer id;
private String name;
public Person() {
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
@Override
public Integer getId() {
return id;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,13 @@
/*
* 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.orm.test.boot.models.hbm.properties;
/**
* @author Steve Ebersole
*/
public class Address {
}

View File

@ -0,0 +1,15 @@
/*
* 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.orm.test.boot.models.hbm.properties;
/**
* Tests for {@code hbm.xml} {@code <properties/>} grouping element
*
* @author Steve Ebersole
*/
public class PropertiesGroupingTests {
}

View File

@ -0,0 +1,13 @@
/*
* 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.orm.test.boot.models.hbm.properties;
/**
* @author Steve Ebersole
*/
public class Server {
}

View File

@ -0,0 +1,160 @@
/*
* 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.orm.test.boot.models.hbm.propertyref;
import java.util.List;
import org.hibernate.boot.InvalidMappingException;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cfg.MappingSettings;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.ToOne;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.DomainModelScope;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@code hbm.xml} {@code <properties/>} grouping element
*
* @author Steve Ebersole
*/
@SuppressWarnings("JUnitMalformedDeclaration")
public class GroupedPropertyRefTests {
@Test
@DomainModel(annotatedClasses = {Person.class, Account.class}, xmlMappings = "mappings/models/hbm/propertyref/properties.hbm.xml" )
@SessionFactory
void testHbmXml(DomainModelScope domainModelScope, SessionFactoryScope sessionFactoryScope) {
// baseline test for straight hbm.xml handling
try {
verify( domainModelScope, sessionFactoryScope );
}
finally {
sessionFactoryScope.inTransaction( (session) -> {
session.createMutationQuery( "delete GroupedPropertyRefTests$Account" ).executeUpdate();
session.createMutationQuery( "delete GroupedPropertyRefTests$Person" ).executeUpdate();
} );
}
}
private void verify(DomainModelScope domainModelScope, SessionFactoryScope sessionFactoryScope) {
final PersistentClass accountMapping = domainModelScope.getEntityBinding( Account.class );
final Property ownerProperty = accountMapping.getProperty( "owner" );
final ToOne ownerPropertyValue = (ToOne) ownerProperty.getValue();
assertThat( ownerPropertyValue.getReferencedPropertyName() ).isEqualTo( "name" );
sessionFactoryScope.inTransaction( (session) -> {
final Person john = new Person( 1, "John", "Doe" );
final Account account = new Account( 1, "savings", john );
session.persist( john );
session.persist( account );
} );
sessionFactoryScope.inTransaction( (session) -> {
final List<Account> accounts = session.createSelectionQuery(
"from GroupedPropertyRefTests$Account a join fetch a.owner",
Account.class ).list();
assertThat( accounts ).hasSize( 1 );
} );
}
@Test
@ServiceRegistry(settings = @Setting(name= MappingSettings.TRANSFORM_HBM_XML, value="true"))
void testTransformed(ServiceRegistryScope registryScope) {
// test the transformation - should be an error as this is unsupported
try {
final StandardServiceRegistry serviceRegistry = registryScope.getRegistry();
final MetadataSources metadataSources = new MetadataSources( serviceRegistry );
metadataSources.addResource( "mappings/models/hbm/propertyref/properties.hbm.xml" );
}
catch (InvalidMappingException expected) {
assertThat( expected.getCause() ).isInstanceOf( UnsupportedOperationException.class );
assertThat( expected.getCause().getMessage() ).startsWith( "<properties/>" );
}
}
public static class Person {
private Integer id;
private String firstName;
private String lastName;
public Person() {
}
public Person(Integer id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public Integer getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public static class Account {
private Integer id;
private String name;
private Person owner;
public Account() {
}
public Account(Integer id, String name, Person owner) {
this.id = id;
this.name = name;
this.owner = owner;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
}
}

View File

@ -12,6 +12,7 @@ import org.hibernate.boot.internal.MetadataBuilderImpl;
import org.hibernate.boot.model.process.spi.ManagedResources; import org.hibernate.boot.model.process.spi.ManagedResources;
import org.hibernate.boot.model.source.internal.annotations.AdditionalManagedResourcesImpl; import org.hibernate.boot.model.source.internal.annotations.AdditionalManagedResourcesImpl;
import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cfg.MappingSettings;
import org.hibernate.mapping.Column; import org.hibernate.mapping.Column;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetails;
@ -22,6 +23,7 @@ import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.DomainModelScope; import org.hibernate.testing.orm.junit.DomainModelScope;
import org.hibernate.testing.orm.junit.ServiceRegistry; import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.ServiceRegistryScope; import org.hibernate.testing.orm.junit.ServiceRegistryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -59,7 +61,7 @@ public class ModelTests {
assertThat( transformerAnn.write() ).isEqualTo( "? * 100.00" ); assertThat( transformerAnn.write() ).isEqualTo( "? * 100.00" );
} }
@ServiceRegistry @ServiceRegistry(settings = @Setting(name = MappingSettings.TRANSFORM_HBM_XML, value = "true"))
@Test @Test
void testHbmXml(ServiceRegistryScope scope) { void testHbmXml(ServiceRegistryScope scope) {
final ManagedResources managedResources = new AdditionalManagedResourcesImpl.Builder( true, true ) final ManagedResources managedResources = new AdditionalManagedResourcesImpl.Builder( true, true )

View File

@ -35,12 +35,18 @@ import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataBuildingOptions;
import org.hibernate.boot.spi.XmlMappingBinderAccess; import org.hibernate.boot.spi.XmlMappingBinderAccess;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.config.internal.ConfigurationServiceInitiator;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.Logger; import org.hibernate.testing.orm.junit.Logger;
import org.hibernate.testing.orm.junit.MessageKeyInspection; import org.hibernate.testing.orm.junit.MessageKeyInspection;
import org.hibernate.testing.orm.junit.MessageKeyWatcher; import org.hibernate.testing.orm.junit.MessageKeyWatcher;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -70,6 +76,7 @@ public class ScanningCoordinatorTest {
private BootstrapContext bootstrapContext = Mockito.mock( BootstrapContext.class ); private BootstrapContext bootstrapContext = Mockito.mock( BootstrapContext.class );
private ClassmateContext classmateContext = new ClassmateContext(); private ClassmateContext classmateContext = new ClassmateContext();
private XmlMappingBinderAccess xmlMappingBinderAccess = Mockito.mock( XmlMappingBinderAccess.class ); private XmlMappingBinderAccess xmlMappingBinderAccess = Mockito.mock( XmlMappingBinderAccess.class );
private MetadataBuildingOptions metadataBuildingOptions = Mockito.mock( MetadataBuildingOptions.class );
private ScanEnvironment scanEnvironment = Mockito.mock( ScanEnvironment.class ); private ScanEnvironment scanEnvironment = Mockito.mock( ScanEnvironment.class );
private StandardServiceRegistry serviceRegistry = Mockito.mock( StandardServiceRegistry.class ); private StandardServiceRegistry serviceRegistry = Mockito.mock( StandardServiceRegistry.class );
@ -87,8 +94,12 @@ public class ScanningCoordinatorTest {
when( bootstrapContext.getScanEnvironment() ).thenReturn( scanEnvironment ); when( bootstrapContext.getScanEnvironment() ).thenReturn( scanEnvironment );
when( bootstrapContext.getClassmateContext() ).thenReturn( classmateContext ); when( bootstrapContext.getClassmateContext() ).thenReturn( classmateContext );
when( bootstrapContext.getServiceRegistry() ).thenReturn( serviceRegistry ); when( bootstrapContext.getServiceRegistry() ).thenReturn( serviceRegistry );
when( bootstrapContext.getMetadataBuildingOptions() ).thenReturn( metadataBuildingOptions );
when( serviceRegistry.requireService( ClassLoaderService.class ) ).thenReturn( classLoaderService ); when( serviceRegistry.requireService( ClassLoaderService.class ) ).thenReturn( classLoaderService );
when( metadataBuildingOptions.isXmlMappingEnabled() ).thenReturn( true );
when( scanEnvironment.getExplicitlyListedClassNames() ).thenReturn( when( scanEnvironment.getExplicitlyListedClassNames() ).thenReturn(
Arrays.asList( "a.b.C" ) ); Arrays.asList( "a.b.C" ) );

View File

@ -16,6 +16,8 @@ hibernate.connection.autocommit false
hibernate.connection.initial_pool_size 0 hibernate.connection.initial_pool_size 0
hibernate.connection.pool_size 5 hibernate.connection.pool_size 5
hibernate.transform_hbm_xml.enabled true
hibernate.show_sql true hibernate.show_sql true
hibernate.format_sql true hibernate.format_sql true
hibernate.highlight_sql true hibernate.highlight_sql true

View File

@ -1,22 +0,0 @@
<?xml version="1.0"?>
<!--
~ 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>.
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.hibernate.orm.test.boot.models.hbm.ecid.Login" table="user_logins">
<composite-id>
<key-property name="system"/>
<key-property name="username"/>
</composite-id>
<property name="email"/>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<!--
~ 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.
-->
<!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.hbm._extends">
<subclass entity-name="Leaf" discriminator-value="L" extends="Branch">
</subclass>
<subclass entity-name="Branch" discriminator-value="B" extends="Root">
</subclass>
<class entity-name="Root" discriminator-value="R">
<id/>
<discriminator column="the_type"/>
<property name="name"/>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<!--
~ 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.
-->
<!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.hbm._extends">
<class entity-name="Root" discriminator-value="R">
<id/>
<discriminator column="the_type"/>
<property name="name"/>
<subclass entity-name="Branch" discriminator-value="B">
<subclass entity-name="Leaf" discriminator-value="L">
</subclass>
</subclass>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<!--
~ 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.
-->
<!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.orm.test.boot.models.hbm.intf">
<class name="IPerson" abstract="true">
<id/>
<discriminator/>
<property name="name"/>
<subclass name="Person" discriminator-value="P"/>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!--
~ 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>.
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Address" table="addresses">
<id name="id"/>
<properties name="uniqueAddress">
<property name="addressType" column="ADDRESS_TYPE" type="string" insert="false" update="false" length="30"/>
<many-to-one name="server" column="SERVER_ID" class="Server" not-null="true"/>
</properties>
</class>
<class name="Server" table="servers">
<id name="id"/>
<property name="serverType" type="string" column="SERVER_TYPE" length="10" update="false" insert="false"/>
<many-to-one name="address"
class="Address"
property-ref="uniqueAddress"
cascade="all"
unique="true"
update="false"
insert="false">
<column name="address_type"/>
<column name="server_id"/>
</many-to-one>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<!--
~ 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.
-->
<!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.orm.test.boot.models.hbm.propertyref"
default-access="field">
<class name="GroupedPropertyRefTests$Person" table="persons">
<id name="id"/>
<properties name="name">
<property name="firstName" column="fname"/>
<property name="lastName" column="lname"/>
</properties>
</class>
<class name="GroupedPropertyRefTests$Account" table="accounts">
<id name="id"/>
<property name="name"/>
<many-to-one name="owner" property-ref="name">
<column name="owner_name_first"/>
<column name="owner_name_last"/>
</many-to-one>
</class>
</hibernate-mapping>

View File

@ -179,6 +179,15 @@ Hibernate can use the persistence-unit name for binding into JNDI as well, but `
must be explicitly set to true. must be explicitly set to true.
[[hbm-transform]]
== hbm.xml Transformation
Previous versions of Hibernate performed transformations of `hbm.xml` files (with `` enabled)
one file at a time. This is now done across the entire set of `hbm.xml` files at once.
While most users will never see this change, it might impact integrations which tie-in to
XML processing.
[[todo]] [[todo]]
== Todos (dev) == Todos (dev)

View File

@ -72,7 +72,7 @@ dependencyResolutionManagement {
def byteBuddyVersion = version "byteBuddy", "1.14.18" def byteBuddyVersion = version "byteBuddy", "1.14.18"
def classmateVersion = version "classmate", "1.5.1" def classmateVersion = version "classmate", "1.5.1"
def geolatteVersion = version "geolatte", "1.9.1" def geolatteVersion = version "geolatte", "1.9.1"
def hibernateModelsVersion = version "hibernateModels", "0.8.4" def hibernateModelsVersion = version "hibernateModels", "0.8.5"
def jandexVersion = version "jandex", "3.2.0" def jandexVersion = version "jandex", "3.2.0"
def hcannVersion = version "hcann", "7.0.1.Final" def hcannVersion = version "hcann", "7.0.1.Final"
def jacksonVersion = version "jackson", "2.17.0" def jacksonVersion = version "jackson", "2.17.0"

View File

@ -0,0 +1,28 @@
/*
* 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.orm.tooling.gradle.misc;
import java.io.File;
import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.SourceType;
/**
* @author Steve Ebersole
*/
public class OriginImpl extends Origin {
private final File hbmXmlFile;
public OriginImpl(File hbmXmlFile) {
super( SourceType.FILE, hbmXmlFile.getAbsolutePath() );
this.hbmXmlFile = hbmXmlFile;
}
public File getHbmXmlFile() {
return hbmXmlFile;
}
}

View File

@ -9,9 +9,12 @@ package org.hibernate.orm.tooling.gradle.misc;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.provider.Property; import org.gradle.api.provider.Property;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.OutputDirectory;
@ -19,7 +22,6 @@ import org.gradle.api.tasks.SourceTask;
import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskAction;
import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.SourceType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer; import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer;
import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling; import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling;
@ -53,6 +55,7 @@ import jakarta.xml.bind.Marshaller;
* replacing the original (destructive). * replacing the original (destructive).
* @see org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer * @see org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer
*/ */
@CacheableTask
public abstract class TransformHbmXmlTask extends SourceTask { public abstract class TransformHbmXmlTask extends SourceTask {
private final Property<TransformationNaming> renaming; private final Property<TransformationNaming> renaming;
private final Property<UnsupportedFeatureHandling> unsupportedFeatures; private final Property<UnsupportedFeatureHandling> unsupportedFeatures;
@ -127,15 +130,24 @@ public abstract class TransformHbmXmlTask extends SourceTask {
throw new RuntimeException( "Unable to create JAXB Marshaller", e ); throw new RuntimeException( "Unable to create JAXB Marshaller", e );
} }
getSource().forEach( (hbmXmlFile) -> transformFile( mappingBinder, marshaller, hbmXmlFile ) ); final List<Binding<JaxbHbmHibernateMapping>> hbmBindings = new ArrayList<>();
} getSource().forEach( (hbmXmlFile) -> {
final Origin origin = new OriginImpl( hbmXmlFile );
final Binding<JaxbHbmHibernateMapping> hbmBinding = bindMapping( mappingBinder, hbmXmlFile, origin );
hbmBindings.add( hbmBinding );
} );
private void transformFile(MappingBinder mappingBinder, Marshaller marshaller, File hbmXmlFile) { final List<Binding<JaxbEntityMappingsImpl>> transformedBindings = HbmXmlTransformer.transform(
final Origin origin = new Origin( SourceType.FILE, hbmXmlFile.getAbsolutePath() ); hbmBindings,
final Binding<JaxbHbmHibernateMapping> binding = bindMapping( mappingBinder, hbmXmlFile, origin ); unsupportedFeatures.get()
if ( binding == null ) { );
return;
} for ( int i = 0; i < hbmBindings.size(); i++ ) {
final Binding<JaxbHbmHibernateMapping> hbmBinding = hbmBindings.get( i );
final Binding<JaxbEntityMappingsImpl> transformedBinding = transformedBindings.get( i );
final OriginImpl origin = (OriginImpl) hbmBinding.getOrigin();
final File hbmXmlFile = origin.getHbmXmlFile();
if ( deleteHbmFiles.getOrElse( false ) ) { if ( deleteHbmFiles.getOrElse( false ) ) {
final boolean deleted = hbmXmlFile.delete(); final boolean deleted = hbmXmlFile.delete();
@ -144,16 +156,12 @@ public abstract class TransformHbmXmlTask extends SourceTask {
} }
} }
final HbmXmlTransformer.Options transformationOptions = unsupportedFeatures::get;
final JaxbEntityMappingsImpl transformed = HbmXmlTransformer.transform( binding.getRoot(), origin, transformationOptions );
final String copyName = determineCopyName( hbmXmlFile ); final String copyName = determineCopyName( hbmXmlFile );
final File copyFile = determineCopyFile( copyName, hbmXmlFile ); final File copyFile = determineCopyFile( copyName, hbmXmlFile );
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
copyFile.getParentFile().mkdirs(); copyFile.getParentFile().mkdirs();
try { try {
marshaller.marshal( transformed, copyFile ); marshaller.marshal( transformedBinding.getRoot(), copyFile );
} }
catch (JAXBException e) { catch (JAXBException e) {
throw new RuntimeException( throw new RuntimeException(
@ -162,6 +170,7 @@ public abstract class TransformHbmXmlTask extends SourceTask {
); );
} }
} }
}
private Binding<JaxbHbmHibernateMapping> bindMapping(MappingBinder mappingBinder, File hbmXmlFile, Origin origin) { private Binding<JaxbHbmHibernateMapping> bindMapping(MappingBinder mappingBinder, File hbmXmlFile, Origin origin) {
try ( final FileInputStream fileStream = new FileInputStream( hbmXmlFile ) ) { try ( final FileInputStream fileStream = new FileInputStream( hbmXmlFile ) ) {