HHH-15619, HHH-15620 Expose HBM query configs through respective hints and don't mark transformed HBM model as metadata complete

This commit is contained in:
Christian Beikov 2022-10-20 14:55:48 +02:00
parent ee7c2ee041
commit 771f338961
7 changed files with 190 additions and 7 deletions

View File

@ -205,7 +205,6 @@ public class HbmXmlTransformer {
final JaxbPersistenceUnitMetadata metadata = new JaxbPersistenceUnitMetadata();
ormRoot.setPersistenceUnitMetadata( metadata );
metadata.setXmlMappingMetadataComplete( new JaxbEmptyType() );
transfer( hbmXmlMapping::getPackage, ormRoot::setPackage );
transfer( hbmXmlMapping::getCatalog, ormRoot::setCatalog );

View File

@ -89,6 +89,7 @@ import org.hibernate.boot.jaxb.mapping.JaxbSecondaryTable;
import org.hibernate.boot.jaxb.mapping.JaxbSequenceGenerator;
import org.hibernate.boot.jaxb.mapping.JaxbSqlResultSetMapping;
import org.hibernate.boot.jaxb.mapping.JaxbStoredProcedureParameter;
import org.hibernate.boot.jaxb.mapping.JaxbSynchronizedTable;
import org.hibernate.boot.jaxb.mapping.JaxbTable;
import org.hibernate.boot.jaxb.mapping.JaxbTableGenerator;
import org.hibernate.boot.jaxb.mapping.JaxbUniqueConstraint;
@ -102,6 +103,7 @@ import org.hibernate.cfg.annotations.reflection.PersistentAttributeFilter;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jpa.AvailableHints;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
@ -2201,7 +2203,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
ann.setValue( "resultSetMappings", element.getResultSetMapping().toArray( new String[0] ) );
buildQueryHints( element.getHint(), ann );
buildQueryHints( element.getHint(), ann, Collections.emptyMap() );
namedStoredProcedureQueries.add( AnnotationFactory.create( ann ) );
}
return namedStoredProcedureQueries;
@ -2530,14 +2532,26 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
}
}
private static void buildQueryHints(List<JaxbQueryHint> elements, AnnotationDescriptor ann) {
List<QueryHint> queryHints = new ArrayList<>( elements.size() );
for ( JaxbQueryHint hint : elements ) {
private static void buildQueryHints(
List<JaxbQueryHint> elements,
AnnotationDescriptor ann,
Map<String, String> additionalHints) {
List<QueryHint> queryHints = new ArrayList<>( elements.size() + additionalHints.size() );
for ( Map.Entry<String, String> entry : additionalHints.entrySet() ) {
AnnotationDescriptor hintDescriptor = new AnnotationDescriptor( QueryHint.class );
hintDescriptor.setValue( "name", entry.getKey() );
hintDescriptor.setValue( "value", entry.getValue() );
queryHints.add( AnnotationFactory.create( hintDescriptor ) );
}
for ( JaxbQueryHint hint : elements ) {
String value = hint.getName();
if ( value == null ) {
throw new AnnotationException( "<hint> without name. " + SCHEMA_VALIDATION );
}
if ( additionalHints.containsKey( value ) ) {
continue;
}
AnnotationDescriptor hintDescriptor = new AnnotationDescriptor( QueryHint.class );
hintDescriptor.setValue( "name", value );
value = hint.getValue();
if ( value == null ) {
@ -2558,7 +2572,15 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
AnnotationDescriptor ann = new AnnotationDescriptor( NamedQuery.class );
copyAttribute( ann, "name", element.getName(), false );
copyAttribute( ann, "query", element.getQuery(), true );
buildQueryHints( element.getHint(), ann );
Map<String, String> additionalHints = new HashMap<>();
addHint( additionalHints, AvailableHints.HINT_CACHEABLE, element.isCacheable() );
addHint( additionalHints, AvailableHints.HINT_CACHE_MODE, element.getCacheMode() );
addHint( additionalHints, AvailableHints.HINT_CACHE_REGION, element.getCacheRegion() );
addHint( additionalHints, AvailableHints.HINT_COMMENT, element.getComment() );
addHint( additionalHints, AvailableHints.HINT_FETCH_SIZE, element.getFetchSize() );
addHint( additionalHints, AvailableHints.HINT_FLUSH_MODE, element.getFlushMode() );
addHint( additionalHints, AvailableHints.HINT_TIMEOUT, element.getTimeout() );
buildQueryHints( element.getHint(), ann, additionalHints );
copyAttribute( ann, "lock-mode", element.getLockMode(), false );
namedQueries.add( AnnotationFactory.create( ann ) );
}
@ -2574,7 +2596,16 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
AnnotationDescriptor ann = new AnnotationDescriptor( NamedNativeQuery.class );
copyAttribute( ann, "name", element.getName(), false );
copyAttribute( ann, "query", element.getQuery(), true );
buildQueryHints( element.getHint(), ann );
Map<String, String> additionalHints = new HashMap<>();
addHint( additionalHints, AvailableHints.HINT_CACHEABLE, element.isCacheable() );
addHint( additionalHints, AvailableHints.HINT_CACHE_MODE, element.getCacheMode() );
addHint( additionalHints, AvailableHints.HINT_CACHE_REGION, element.getCacheRegion() );
addHint( additionalHints, AvailableHints.HINT_COMMENT, element.getComment() );
addHint( additionalHints, AvailableHints.HINT_FETCH_SIZE, element.getFetchSize() );
addHint( additionalHints, AvailableHints.HINT_FLUSH_MODE, element.getFlushMode() );
addHint( additionalHints, AvailableHints.HINT_TIMEOUT, element.getTimeout() );
addSynchronizationsHint( additionalHints, element.getSynchronizations() );
buildQueryHints( element.getHint(), ann, additionalHints );
String clazzName = element.getResultClass();
if ( StringHelper.isNotEmpty( clazzName ) ) {
Class clazz;
@ -2594,6 +2625,27 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
return namedQueries;
}
private static void addHint(Map<String, String> hints, String hint, Object value) {
if ( value != null ) {
hints.put( hint, value.toString() );
}
}
private static void addSynchronizationsHint(
Map<String, String> hints,
List<JaxbSynchronizedTable> synchronizations) {
if ( synchronizations.isEmpty() ) {
return;
}
StringBuilder sb = new StringBuilder();
sb.append( synchronizations.get( 0 ).getTable() );
for ( int i = 1; i < synchronizations.size(); i++ ) {
sb.append( ' ' );
sb.append( synchronizations.get( i ).getTable() );
}
hints.put( AvailableHints.HINT_NATIVE_SPACES, sb.toString() );
}
private TableGenerator getTableGenerator(ManagedType root, XMLContext.Default defaults) {
return getTableGenerator(
root instanceof JaxbEntity ? ( (JaxbEntity) root ).getTableGenerator() : null,

View File

@ -0,0 +1,30 @@
package org.hibernate.orm.test.hbm.query;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
@Entity(name = "Bar")
@NamedQueries({
@NamedQuery(name = Bar.FIND_ALL, query = "select b from Bar b")
})
public class Bar {
public static final String FIND_ALL = "Bar.findAll";
@EmbeddedId
private BarPK id;
private String name;
public BarPK getID() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,22 @@
package org.hibernate.orm.test.hbm.query;
public class BarPK {
String id1;
String id2;
public String getId1() {
return id1;
}
public void setId1(String id1) {
this.id1 = id1;
}
public String getId2() {
return id2;
}
public void setId2(String id2) {
this.id2 = id2;
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.hbm.query;
import java.util.Map;
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sqm.spi.NamedSqmQueryMemento;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.jupiter.api.Assertions.assertTrue;
@RunWith(BytecodeEnhancerRunner.class)
@EnhancementOptions(inlineDirtyChecking = true, lazyLoading = true, extendedEnhancement = true)
public class HbmNamedQueryConfigurationTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected String[] getMappings() {
return new String[]{
"org/hibernate/orm/test/hbm/query/HbmOverridesAnnotation.orm.xml",
"org/hibernate/orm/test/hbm/query/HbmOverridesAnnotation.hbm.xml"
};
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected void addConfigOptions(Map options) {
options.put( "hibernate.enable_specj_proprietary_syntax", "true" );
options.put( "hibernate.transform_hbm_xml.enabled", "true" );
}
@Test
@TestForIssue( jiraKey = { "HHH-15619", "HHH-15620"} )
public void testHbmOverride() {
NamedObjectRepository namedObjectRepository = entityManagerFactory()
.getQueryEngine()
.getNamedObjectRepository();
NamedSqmQueryMemento sqmQueryMemento = namedObjectRepository.getSqmQueryMemento( Bar.FIND_ALL );
assertTrue( sqmQueryMemento.getCacheable() );
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!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.hbm.query">
<query name="Bar.findAll" cacheable="true">
select b from Bar b
</query>
</hibernate-mapping>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings
xmlns="http://java.sun.com/xml/ns/persistence/orm"
version="2.0">
<entity class="org.hibernate.orm.test.hbm.query.Bar">
<attributes>
<embedded-id name="id">
<attribute-override name="id1">
<column name="bar_id1"/>
</attribute-override>
<attribute-override name="id2">
<column name="bar_id2"/>
</attribute-override>
</embedded-id>
<basic name="name">
<column name="bar_name"/>
</basic>
</attributes>
</entity>
</entity-mappings>