Merge remote-tracking branch 'upstream5/master' into wip/6.0_merge_14

This commit is contained in:
Andrea Boriero 2019-11-22 09:05:57 +00:00
commit f1bf079122
34 changed files with 1985 additions and 59 deletions

View File

@ -17,7 +17,7 @@ buildscript {
classpath 'org.hibernate.build.gradle:gradle-xjc-plugin:1.0.2.Final'
classpath 'gradle.plugin.com.github.lburgazzoli:gradle-karaf-plugin:0.1.1'
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.7'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.3'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
classpath 'de.thetaphi:forbiddenapis:2.5'
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.1'
}

View File

@ -3,6 +3,36 @@ Hibernate 5 Changelog
Note: Please refer to JIRA to learn more about each issue.
Changes in 5.4.9.Final (November 14, 2019)
------------------------------------------------------------------------------------------------------------------------
https://hibernate.atlassian.net/projects/HHH/versions/31806/tab/release-report-done
** Bug
* [HHH-12030] - Symbol$TypeVariableSymbol cannot be cast to TypeElement
* [HHH-13307] - On release of batch it still contained JDBC statements using JTA
* [HHH-13433] - EntityManager.find() should only check for roll-back-only condition if there is an active JTA transaction, otherwise ORM should throw convert( e, lockOptions )
* [HHH-13614] - Allow the IntegratorProvider to be supplied via its FQN in the JPA persistence.xml
* [HHH-13670] - Missing from clause in query with joined inheritance, regression in 5.4.5
* [HHH-13687] - TenantSchemaResolver not called in integration test after upgrade from 5.4.4 to >=5.4.5
* [HHH-13690] - Multi-tenancy supporting session factories can not be created
* [HHH-13698] - Hibernate does not recognize MySQL 8 error code 3572 as PessimisticLockException
* [HHH-13700] - Configuration property CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT should not be passed to the JDBC connection properties
* [HHH-13705] - Enhancement as Proxy with inline dirty checking - flush of an @ManyToOne with an Embedded value having not null properties causes PropertyValueException
* [HHH-13710] - Wrong tenant-identifier in Envers temporary session
* [HHH-13712] - inheritance - select count query is not working with inheritance
* [HHH-13727] - h2 database with DATABASE_TO_UPPER=false throws org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "sequences" not found
** Task
* [HHH-13730] - Upgrade to Classmate 1.4.0
* [HHH-13731] - Upgrade to Classmate 1.5.1
* [HHH-13733] - Upgrade to Jandex 2.1.1.Final
** Improvement
* [HHH-13654] - Avoid clearing of collections when closing StatefulPersistenceContext
* [HHH-13723] - Hint sizing of ArrayList in ResultSetProcessingContextImpl
Changes in 5.4.8.Final (October 28, 2019)
------------------------------------------------------------------------------------------------------------------------

View File

@ -28,7 +28,7 @@ ext {
javassistVersion = '3.24.0-GA'
byteBuddyVersion = '1.10.2'
agroalVersion = '1.6'
agroalVersion = '1.7'
geolatteVersion = '1.4.0'
@ -55,8 +55,8 @@ ext {
// Annotations
commons_annotations: "org.hibernate.common:hibernate-commons-annotations:${hibernateCommonsVersion}",
jandex: 'org.jboss:jandex:2.0.5.Final',
classmate: 'com.fasterxml:classmate:1.3.4',
jandex: 'org.jboss:jandex:2.1.1.Final',
classmate: 'com.fasterxml:classmate:1.5.1',
// Dom4J
dom4j: 'org.dom4j:dom4j:2.1.1@jar',

View File

@ -104,7 +104,7 @@ public class H2Dialect extends Dialect {
if ( buildId >= 32 ) {
this.sequenceInformationExtractor = SequenceInformationExtractorH2DatabaseImpl.INSTANCE;
this.querySequenceString = "select * from INFORMATION_SCHEMA.sequences";
this.querySequenceString = "select * from INFORMATION_SCHEMA.SEQUENCES";
}
else {
this.sequenceInformationExtractor = SequenceInformationExtractorNoOpImpl.INSTANCE;

View File

@ -359,10 +359,7 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
}
this.defaultSessionOpenOptions = withOptions();
this.temporarySessionOpenOptions = withOptions()
.autoClose( false )
.flushMode( FlushMode.MANUAL )
.connectionHandlingMode( PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT );
this.temporarySessionOpenOptions = buildTemporarySessionOpenOptions();
this.fastSessionServices = new FastSessionServices( this );
this.observer.sessionFactoryCreated( this );
@ -385,6 +382,13 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
}
}
private SessionBuilder buildTemporarySessionOpenOptions() {
return withOptions()
.autoClose( false )
.flushMode( FlushMode.MANUAL )
.connectionHandlingMode( PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT );
}
private void primeSecondLevelCacheRegions(MetadataImplementor mappingMetadata) {
final Map<String, DomainDataRegionConfigImpl.Builder> regionConfigBuilders = new ConcurrentHashMap<>();
@ -515,11 +519,26 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
}
public Session openSession() throws HibernateException {
return this.defaultSessionOpenOptions.openSession();
final CurrentTenantIdentifierResolver currentTenantIdentifierResolver = getCurrentTenantIdentifierResolver();
//We can only use reuse the defaultSessionOpenOptions as a constant when there is no TenantIdentifierResolver
if ( currentTenantIdentifierResolver != null ) {
return this.withOptions().openSession();
}
else {
return this.defaultSessionOpenOptions.openSession();
}
}
public Session openTemporarySession() throws HibernateException {
return this.temporarySessionOpenOptions.openSession();
final CurrentTenantIdentifierResolver currentTenantIdentifierResolver = getCurrentTenantIdentifierResolver();
//We can only use reuse the defaultSessionOpenOptions as a constant when there is no TenantIdentifierResolver
if ( currentTenantIdentifierResolver != null ) {
return buildTemporarySessionOpenOptions()
.openSession();
}
else {
return this.temporarySessionOpenOptions.openSession();
}
}
public Session getCurrentSession() throws HibernateException {
@ -1365,8 +1384,9 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
public StatelessSessionBuilderImpl(SessionFactoryImpl sessionFactory) {
this.sessionFactory = sessionFactory;
if ( sessionFactory.getCurrentTenantIdentifierResolver() != null ) {
tenantIdentifier = sessionFactory.getCurrentTenantIdentifierResolver().resolveCurrentTenantIdentifier();
CurrentTenantIdentifierResolver tenantIdentifierResolver = sessionFactory.getCurrentTenantIdentifierResolver();
if ( tenantIdentifierResolver != null ) {
tenantIdentifier = tenantIdentifierResolver.resolveCurrentTenantIdentifier();
}
queryParametersValidationEnabled = sessionFactory.getSessionFactoryOptions().isQueryParametersValidationEnabled();
}

View File

@ -2851,7 +2851,13 @@ public final class SessionImpl
}
catch ( JDBCException e ) {
if ( accessTransaction().isActive() && accessTransaction().getRollbackOnly() ) {
// assume this is the similar to the WildFly / IronJacamar "feature" described under HHH-12472
// Assume this is the similar to the WildFly / IronJacamar "feature" described under HHH-12472.
// Just log the exception and return null.
if ( log.isDebugEnabled() ) {
log.debug( "JDBCException was thrown for a transaction marked for rollback; " +
"this is probably due to an operation failing fast due to the " +
"transaction marked for rollback.", e );
}
return null;
}
else {

View File

@ -277,37 +277,11 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
return;
}
MetadataBuilderContributor metadataBuilderContributor = null;
Class<? extends MetadataBuilderContributor> metadataBuilderContributorImplClass = null;
if ( metadataBuilderContributorSetting instanceof MetadataBuilderContributor ) {
metadataBuilderContributor = (MetadataBuilderContributor) metadataBuilderContributorSetting;
}
else if ( metadataBuilderContributorSetting instanceof Class ) {
metadataBuilderContributorImplClass = (Class<? extends MetadataBuilderContributor>) metadataBuilderContributorSetting;
}
else if ( metadataBuilderContributorSetting instanceof String ) {
final ClassLoaderService classLoaderService = standardServiceRegistry.getService( ClassLoaderService.class );
metadataBuilderContributorImplClass = classLoaderService.classForName( (String) metadataBuilderContributorSetting );
}
else {
throw new IllegalArgumentException(
"The provided " + METADATA_BUILDER_CONTRIBUTOR + " setting value [" + metadataBuilderContributorSetting + "] is not supported!"
);
}
if ( metadataBuilderContributorImplClass != null ) {
try {
metadataBuilderContributor = metadataBuilderContributorImplClass.newInstance();
}
catch (InstantiationException | IllegalAccessException e) {
throw new IllegalArgumentException(
"The MetadataBuilderContributor class [" + metadataBuilderContributorImplClass + "] could not be instantiated!",
e
);
}
}
MetadataBuilderContributor metadataBuilderContributor = loadSettingInstance(
METADATA_BUILDER_CONTRIBUTOR,
metadataBuilderContributorSetting,
MetadataBuilderContributor.class
);
if ( metadataBuilderContributor != null ) {
metadataBuilderContributor.contribute( metamodelBuilder );
@ -395,13 +369,8 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
ClassLoaderService providedClassLoaderService) {
final BootstrapServiceRegistryBuilder bsrBuilder = new BootstrapServiceRegistryBuilder();
final IntegratorProvider integratorProvider = (IntegratorProvider) integrationSettings.get( INTEGRATOR_PROVIDER );
if ( integratorProvider != null ) {
for ( Integrator integrator : integratorProvider.getIntegrators() ) {
bsrBuilder.applyIntegrator( integrator );
}
}
applyIntegrationProvider( integrationSettings, bsrBuilder );
final StrategyRegistrationProviderList strategyRegistrationProviderList
= (StrategyRegistrationProviderList) integrationSettings.get( STRATEGY_REGISTRATION_PROVIDERS );
if ( strategyRegistrationProviderList != null ) {
@ -465,6 +434,25 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
return bsrBuilder.build();
}
private void applyIntegrationProvider(Map integrationSettings, BootstrapServiceRegistryBuilder bsrBuilder) {
Object integrationSetting = integrationSettings.get( INTEGRATOR_PROVIDER );
if ( integrationSetting == null ) {
return;
}
final IntegratorProvider integratorProvider = loadSettingInstance(
INTEGRATOR_PROVIDER,
integrationSetting,
IntegratorProvider.class
);
if ( integratorProvider != null ) {
for ( Integrator integrator : integratorProvider.getIntegrators() ) {
bsrBuilder.applyIntegrator( integrator );
}
}
}
@SuppressWarnings("unchecked")
private MergedSettings mergeSettings(
PersistenceUnitDescriptor persistenceUnit,
Map<?,?> integrationSettings,
@ -1397,4 +1385,51 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
this.cacheRegionDefinitions.add( cacheRegionDefinition );
}
}
private <T> T loadSettingInstance(String settingName, Object settingValue, Class<T> clazz) {
T instance = null;
Class<? extends T> instanceClass = null;
if ( clazz.isAssignableFrom( settingValue.getClass() ) ) {
instance = (T) settingValue;
}
else if ( settingValue instanceof Class ) {
instanceClass = (Class<? extends T>) settingValue;
}
else if ( settingValue instanceof String ) {
String settingStringValue = (String) settingValue;
if ( standardServiceRegistry != null ) {
final ClassLoaderService classLoaderService = standardServiceRegistry.getService( ClassLoaderService.class );
instanceClass = classLoaderService.classForName( settingStringValue );
}
else {
try {
instanceClass = (Class<? extends T>) Class.forName( settingStringValue );
}
catch (ClassNotFoundException e) {
throw new IllegalArgumentException( "Can't load class: " + settingStringValue, e );
}
}
}
else {
throw new IllegalArgumentException(
"The provided " + settingName + " setting value [" + settingValue + "] is not supported!"
);
}
if ( instanceClass != null ) {
try {
instance = instanceClass.newInstance();
}
catch (InstantiationException | IllegalAccessException e) {
throw new IllegalArgumentException(
"The " + clazz.getSimpleName() +" class [" + instanceClass + "] could not be instantiated!",
e
);
}
}
return instance;
}
}

View File

@ -281,8 +281,9 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
// managing the running list of registrations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final int sizeHint = currentRowHydratedEntityRegistrationList.size();
if ( hydratedEntityRegistrationList == null ) {
hydratedEntityRegistrationList = new ArrayList<>();
hydratedEntityRegistrationList = new ArrayList<>( sizeHint );
}
hydratedEntityRegistrationList.addAll( currentRowHydratedEntityRegistrationList );

View File

@ -75,7 +75,16 @@ public abstract class Constraint implements RelationalModel, Exportable, Seriali
* @return String The generated name
*/
public static String generateName(String prefix, Table table, List<Column> columns) {
return generateName( prefix, table, columns.toArray( new Column[columns.size()] ) );
//N.B. legacy APIs are involved: can't trust that the columns List is actually
//containing Column instances - the generic type isn't consistently enforced.
ArrayList<Column> defensive = new ArrayList<>( columns.size() );
for ( Object o : columns ) {
if ( o instanceof Column ) {
defensive.add( (Column) o );
}
//else: others might be Formula instances. They don't need to be part of the name generation.
}
return generateName( prefix, table, defensive.toArray( new Column[0] ) );
}
/**

View File

@ -20,6 +20,7 @@ import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.spi.SelfDirtinessTracker;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.mapping.PersistentClass;
@ -140,8 +141,14 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc
final PersistenceContext persistenceContext = session.getPersistenceContext();
// first, instantiate the entity instance to use as the proxy
final PersistentAttributeInterceptable entity = (PersistentAttributeInterceptable) persister.getEntityTuplizer().instantiate( identifier, session );
final EntityTuplizer entityTuplizer = persister.getEntityTuplizer();
final PersistentAttributeInterceptable entity = (PersistentAttributeInterceptable) entityTuplizer
.instantiate( identifier, session );
// clear the fields that are marked as dirty in the dirtyness tracker
if ( entity instanceof SelfDirtinessTracker ) {
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
}
// add the entity (proxy) instance to the PC
persistenceContext.addEnhancedProxy( entityKey, entity );

View File

@ -0,0 +1,43 @@
/*
* 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.jpa.test.integrationprovider;
import java.util.Collections;
import java.util.List;
import org.hibernate.boot.Metadata;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.jpa.boot.spi.IntegratorProvider;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
/**
* @author Andrea Boriero
*/
public class DtoIntegratorProvider implements IntegratorProvider {
@Override
public List<Integrator> getIntegrators() {
return Collections.singletonList(
new Integrator() {
@Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
metadata.getImports().put( "PersonDto", PersonDto.class.getName() );
}
@Override
public void disintegrate(
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
}
}
);
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.jpa.test.integrationprovider;
import java.util.List;
import java.util.Map;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
/**
* @author Vlad Mihalcea
*/
@TestForIssue(jiraKey = "HHH-13614")
public class IntegrationProviderSettingByClassTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Person.class
};
}
@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
List<PersonDto> dtos = entityManager.createQuery(
"select new PersonDto(id, name) " +
"from Person", PersonDto.class )
.getResultList();
} );
}
@Override
protected void addMappings(Map settings) {
settings.put( EntityManagerFactoryBuilderImpl.INTEGRATOR_PROVIDER, DtoIntegratorProvider.class );
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.jpa.test.integrationprovider;
import java.util.List;
import java.util.Map;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
/**
* @author Vlad Mihalcea
*/
@TestForIssue(jiraKey = "HHH-13614")
public class IntegrationProviderSettingByObjectTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Person.class
};
}
@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
List<PersonDto> dtos = entityManager.createQuery(
"select new PersonDto(id, name) " +
"from Person", PersonDto.class )
.getResultList();
} );
}
@Override
protected void addMappings(Map settings) {
settings.put( EntityManagerFactoryBuilderImpl.INTEGRATOR_PROVIDER, new DtoIntegratorProvider() );
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.jpa.test.integrationprovider;
import java.util.List;
import java.util.Map;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
/**
* @author Vlad Mihalcea
*/
@TestForIssue(jiraKey = "HHH-13614")
public class IntegrationProviderSettingByStringTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Person.class
};
}
@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
List<PersonDto> dtos = entityManager.createQuery(
"select new PersonDto(id, name) " +
"from Person", PersonDto.class )
.getResultList();
} );
}
@Override
protected void addMappings(Map settings) {
settings.put( EntityManagerFactoryBuilderImpl.INTEGRATOR_PROVIDER, DtoIntegratorProvider.class.getName() );
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.jpa.test.integrationprovider;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* @author Andrea Boriero
*/
@Entity(name = "Person")
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

View File

@ -0,0 +1,37 @@
/*
* 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.jpa.test.integrationprovider;
/**
* @author Andrea Boriero
*/
public class PersonDto {
private Long id;
private String name;
public PersonDto(Long id, String name) {
this.id = id;
this.name = name;
}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,149 @@
/*
* 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.query.hhh13670;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Before;
import org.junit.Test;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Tuple;
import java.util.List;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@TestForIssue(jiraKey = "HHH-13670")
public class HHH13670Test extends BaseCoreFunctionalTestCase {
@Before
public void setUp() {
doInJPA(this::sessionFactory, em -> {
SubA a_1 = new SubA(1L);
SubA a_2 = new SubA(2L);
SubA a_3 = new SubA(3L);
SubA a_14 = em.getReference(SubA.class, 10L);
SubB b_4 = new SubB(4L, null);
SubB b_5 = new SubB(5L, a_3);
SubB b_6 = new SubB(6L, b_4);
SubB b_7 = new SubB(7L, a_14);
em.merge(a_1);
em.merge(a_2);
em.merge(a_3);
em.merge(b_4);
em.merge(b_5);
em.merge(b_6);
em.merge(b_7);
});
}
@Test
public void testDereferenceSuperClassAttributeInWithClause() {
doInJPA(this::sessionFactory, em -> {
em.createQuery("SELECT subB_0.id FROM SubB subB_0 LEFT JOIN subB_0.other subA_0 ON subA_0.id = subB_0.parent.id", Tuple.class).getResultList();
});
}
@Test
public void testRootTypeJoinWithGroupJoins() {
doInJPA(this::sessionFactory, em -> {
List<Tuple> resultList = em.createQuery("SELECT subB_0.id, subA_0.id, subB_0.id, subA_0.id FROM SubB subB_0 LEFT JOIN Super subA_0 ON subA_0.id = subB_0.parent.id ORDER BY subB_0.id ASC, subA_0.id ASC", Tuple.class)
.getResultList();
assertEquals("Rows omitted despite optional association should have rendered a left join", 4, resultList.size());
assertEquals((Long) 4L , resultList.get(0).get(0));
assertEquals((Long) 5L , resultList.get(1).get(0));
assertEquals((Long) 6L , resultList.get(2).get(0));
assertEquals((Long) 7L , resultList.get(3).get(0));
assertNull(resultList.get(0).get(1, Long.class));
assertEquals((Long) 3L , resultList.get(1).get(1, Long.class));
assertEquals((Long) 4L , resultList.get(2).get(1, Long.class));
assertNull("Missing entry in foreign table should not be returned", resultList.get(3).get(1, Long.class));
});
}
@Test
public void testSubTypeJoinWithTableGroupJoins() {
doInJPA(this::sessionFactory, em -> {
List<Tuple> resultList = em.createQuery("SELECT subB_0.id, subA_0.id, subB_0.id, subA_0.id FROM SubB subB_0 LEFT JOIN SubA subA_0 ON subA_0.id = subB_0.parent.id ORDER BY subB_0.id ASC, subA_0.id ASC", Tuple.class)
.getResultList();
assertEquals("Rows omitted despite optional association should have rendered a left join", 4, resultList.size());
assertEquals((Long) 4L, resultList.get(0).get(0));
assertEquals((Long) 5L, resultList.get(1).get(0));
assertEquals((Long) 6L, resultList.get(2).get(0));
assertEquals((Long) 7L, resultList.get(3).get(0));
assertNull(resultList.get(0).get(1, Long.class));
assertEquals((Long) 3L, resultList.get(1).get(1, Long.class));
assertNull("Another subtype than queried for was returned", resultList.get(2).get(1));
assertNull("Missing entry in foreign table should not be returned", resultList.get(3).get(1, Long.class));
});
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { Super.class, SubA.class, SubB.class };
}
@Entity(name = "Super")
@Inheritance(strategy = InheritanceType.JOINED)
public static class Super<SubType extends Super> {
@Id
@Column
Long id;
@JoinColumn(foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
@ManyToOne(targetEntity = Super.class, fetch = FetchType.LAZY)
SubType parent;
}
@Entity(name = "SubA")
public static class SubA extends Super {
SubA() {}
SubA(Long id) {
this.id = id;
}
}
@Entity(name = "SubB")
public static class SubB extends Super<SubA> {
@ManyToOne(fetch = FetchType.LAZY)
Super other;
SubB() {}
SubB(Long id, Super parent) {
this.id = id;
((Super) this).parent = parent;
}
}
}

View File

@ -0,0 +1,122 @@
/*
* 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.query.hhh13712;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Before;
import org.junit.Test;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Tuple;
import java.util.List;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@TestForIssue(jiraKey = "HHH-13712")
public class HHH13712Test extends BaseCoreFunctionalTestCase {
@Before
public void setUp() {
doInJPA(this::sessionFactory, em -> {
SomeOther a_1 = new SomeOther(1L);
SomeOther a_2 = new SomeOther(2L);
SomeOther a_3 = new SomeOther(3L);
SubObject b_5 = new SubObject(5L, a_1);
SubObject b_6 = new SubObject(6L, a_2);
SubObject b_7 = new SubObject(7L, a_3);
em.merge(a_1);
em.merge(a_2);
em.merge(a_3);
em.merge(b_5);
em.merge(b_6);
em.merge(b_7);
});
}
@Test
public void testJoinSuperclassAssociationOnly() {
doInJPA(this::sessionFactory, em -> {
List<Integer> actual = em.createQuery("SELECT 1 FROM SubObject sub LEFT JOIN sub.parent p", Integer.class).getResultList();
assertEquals(3, actual.size());
});
}
@Test
public void testJoinSuperclassAssociation() {
doInJPA(this::sessionFactory, em -> {
long actual = em.createQuery("SELECT COUNT(sub) FROM SubObject sub LEFT JOIN sub.parent p WHERE p.id = 1", Long.class).getSingleResult();
assertEquals(1L, actual);
});
}
@Test
public void testCountParentIds() {
doInJPA(this::sessionFactory, em -> {
long actual = em.createQuery("SELECT COUNT(distinct sub.parent.id) FROM SubObject sub", Long.class).getSingleResult();
assertEquals(3L, actual);
});
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { Super.class, SubObject.class, SomeOther.class };
}
@Entity(name = "Super")
@Inheritance(strategy = InheritanceType.JOINED)
public static class Super {
@Id
@Column
Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(nullable = false)
SomeOther parent;
}
@Entity(name = "SubObject")
public static class SubObject extends Super {
SubObject() {}
SubObject(Long id, SomeOther parent) {
this.id = id;
this.parent = parent;
}
}
@Entity(name = "SomeOther")
public static class SomeOther {
@Id
@Column
Long id;
SomeOther() {}
SomeOther(Long id) {
this.id = id;
}
}
}

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.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking;
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
/**
* @author Andrea Boriero
*/
public class DirtyCheckEnhancementContext extends EnhancerTestContext {
@Override
public boolean doExtendedEnhancement(UnloadedClass classDescriptor) {
return false;
}
}

View File

@ -0,0 +1,691 @@
/*
* 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.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.NaturalId;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.stat.Statistics;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Andrea Boriero
*/
@RunWith(BytecodeEnhancerRunner.class)
@CustomEnhancementContext({ DirtyCheckEnhancementContext.class, NoDirtyCheckEnhancementContext.class })
@TestForIssue(jiraKey = "HHH-13705")
public class ManyToOnePropertyAccessByFieldTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
super.configureStandardServiceRegistryBuilder( ssrb );
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" );
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
}
@Override
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
super.configureSessionFactoryBuilder( sfb );
sfb.applyStatisticsSupport( true );
sfb.applySecondLevelCacheSupport( false );
sfb.applyQueryCacheSupport( false );
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( User.class );
sources.addAnnotatedClass( Office.class );
sources.addAnnotatedClass( Client.class );
sources.addAnnotatedClass( Request.class );
sources.addAnnotatedClass( InternalRequest.class );
sources.addAnnotatedClass( Phone.class );
}
private Long userId;
private Long targetUserId;
private Long officeId;
@Before
public void setUp() {
inTransaction(
session -> {
Log log = new Log();
log.setCreationDate( OffsetDateTime.now() );
Office office = buildOffice( "The office", "And", Collections.emptySet() );
session.persist( office );
officeId = office.getId();
User user = new User();
user.setOffice( office );
user.setClient( office.getClient() );
user.setName( "Fab" );
user.setLog( log );
user.setEmail( "fab@hibernate.org" );
session.persist( user );
userId = user.getId();
user = new User();
user.setOffice( office );
user.setClient( office.getClient() );
user.setName( "And" );
user.setLog( log );
user.setEmail( "and@hibernate.org" );
session.persist( user );
targetUserId = user.getId();
}
);
}
@After
public void tearDown() {
inTransaction(
session -> {
session.createQuery( "delete from Request" ).executeUpdate();
session.createQuery( "delete from User" ).executeUpdate();
session.createQuery( "delete from Office" ).executeUpdate();
session.createQuery( "delete from Client" ).executeUpdate();
session.createQuery( "delete from Phone" ).executeUpdate();
}
);
}
@Test
public void testPersist() {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
InternalRequest internalRequest = new InternalRequest( 1L );
inTransaction(
session -> {
User user = session.find( User.class, userId );
internalRequest.setUser( user );
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
User targetUser = session.find( User.class, targetUserId );
assertThat( stats.getPrepareStatementCount(), is( 2L ) );
internalRequest.setTargetUser( targetUser );
session.persist( internalRequest );
}
);
assertThat( stats.getPrepareStatementCount(), is( 3L ) );
}
@Test
public void testDelete() {
Set<Phone> officePhones = new HashSet<>();
officePhones.add( new Phone( 1L, "landline", "028-234-9876" ) );
officePhones.add( new Phone( 2L, "mobile", "072-122-9876" ) );
Office office = buildOffice( "second office", "Fab", officePhones );
inTransaction(
session -> {
session.save( office );
}
);
inTransaction(
session -> {
Office result = session.find( Office.class, office.id );
session.delete( result );
}
);
inTransaction(
session -> {
List<Office> offices = session.createQuery( "from Office" ).list();
assertThat( offices.size(), is( 1 ) );
assertThat( offices.get( 0 ).getId(), is( officeId ) );
List<Phone> phones = session.createQuery( "from Phone" ).list();
assertThat( phones.size(), is( 0 ) );
}
);
}
@Test
public void testUpdate() {
InternalRequest internalRequest = new InternalRequest( 1L );
inTransaction(
session -> {
User user = session.find( User.class, userId );
internalRequest.setUser( user );
User targetUser = session.find( User.class, targetUserId );
internalRequest.setTargetUser( targetUser );
session.persist( internalRequest );
}
);
inTransaction(
session -> {
InternalRequest result = session.find( InternalRequest.class, internalRequest.getId() );
assertThat( result.getTargetUser().getId(), is( targetUserId ) );
assertThat( result.getUser().getId(), is( userId ) );
result.setUser( null );
}
);
inTransaction(
session -> {
InternalRequest result = session.find( InternalRequest.class, internalRequest.getId() );
assertThat( result.getTargetUser().getId(), is( targetUserId ) );
assertThat( result.getUser(), is( nullValue() ) );
User user = session.find( User.class, userId );
result.setTargetUser( user );
}
);
inTransaction(
session -> {
InternalRequest result = session.find( InternalRequest.class, internalRequest.getId() );
assertThat( result.getTargetUser().getId(), is( userId ) );
assertThat( result.getUser(), is( nullValue() ) );
User user = session.find( User.class, userId );
result.setUser( user );
Set<Phone> officePhones = new HashSet<>();
officePhones.add( new Phone( 1L, "landline", "028-234-9876" ) );
officePhones.add( new Phone( 2L, "mobile", "072-122-9876" ) );
Office office = buildOffice( "second office", "Fab", officePhones );
session.save( office );
List<Office> offices = new ArrayList<>();
offices.add( office );
user.setOffices( offices );
}
);
inTransaction(
session -> {
InternalRequest result = session.find( InternalRequest.class, internalRequest.getId() );
assertThat( result.getTargetUser().getId(), is( userId ) );
User user = result.getUser();
assertThat( user.getId(), is( userId ) );
List<Office> offices = user.getOffices();
assertThat( offices.size(), is( 1 ) );
Office office = offices.get( 0 );
assertThat( office.getPhones().size(), is( 2 ) );
}
);
}
private Office buildOffice(String officename, String clientName, Set<Phone> phones) {
Log log = new Log();
log.setCreationDate( OffsetDateTime.now() );
Office office;
office = new Office();
Client client = new Client();
client.setName( clientName );
client.setLog( log );
office.setName( officename );
office.setActive( true );
office.setDescription( officename );
office.setManaged( true );
office.setLog( log );
office.setClient( client );
office.setPhones( phones );
return office;
}
@Embeddable
public static class Log {
@Column(name = "`creationDate`", nullable = false)
private OffsetDateTime creationDate;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "`idCreator`")
private User creator;
public OffsetDateTime getCreationDate() {
return creationDate;
}
public void setCreationDate(OffsetDateTime creationDate) {
this.creationDate = creationDate;
}
public User getCreator() {
return creator;
}
public void setCreator(User creator) {
this.creator = creator;
}
}
@Entity(name = "User")
@Table(name = "`User`")
public static class User {
@Id
@GeneratedValue
private Long id;
@Column(length = 120, nullable = false)
private String name;
@Column(length = 200, nullable = false, unique = true)
private String email;
private String hash;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idOffice")
private Office office;
@OneToMany
private List<Office> offices;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "`idClient`")
private Client client;
@Embedded
private Log log = new Log();
public Long getId() {
return id;
}
public Office getOffice() {
return office;
}
public void setOffice(Office office) {
this.office = office;
}
public Log getLog() {
return log;
}
public void setLog(Log log) {
this.log = log;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getHash() {
return hash;
}
public void setHash(String hash) {
this.hash = hash;
}
public void setId(Long id) {
this.id = id;
}
public List<Office> getOffices() {
return offices;
}
public void setOffices(List<Office> offices) {
this.offices = offices;
}
}
@Entity(name = "Office")
public static class Office {
@Id
@GeneratedValue
private Long id;
@Column(length = 50, nullable = false)
private String name;
private String description;
@Column(nullable = false)
private Boolean isActive = true;
@Column(nullable = false)
private Boolean isManaged = false;
@ManyToOne(optional = false, cascade = CascadeType.ALL)
@JoinColumn(name = "idClient")
private Client client;
@OneToMany(cascade = CascadeType.ALL)
private Set<Phone> phones = new HashSet<>();
@Embedded
private Log log = new Log();
public Long getId() {
return id;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Boolean getActive() {
return isActive;
}
public void setActive(Boolean active) {
isActive = active;
}
public Boolean getManaged() {
return isManaged;
}
public void setManaged(Boolean managed) {
isManaged = managed;
}
public Log getLog() {
return log;
}
public void setLog(Log log) {
this.log = log;
}
public void setId(Long id) {
this.id = id;
}
public Set<Phone> getPhones() {
return phones;
}
public void setPhones(Set<Phone> phones) {
this.phones = phones;
}
}
@Entity(name = "Phone")
public static class Phone {
@Id
private Long id;
private String type;
@NaturalId
@Column(name = "`number`")
private String number;
public Phone() {
}
public Phone(Long id, String type, String number) {
this.id = id;
this.type = type;
this.number = number;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
@Entity(name = "Client")
public static class Client {
@Id
@GeneratedValue
private Long id;
private String name;
@Embedded
private Log log = new Log();
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setId(Long id) {
this.id = id;
}
public Log getLog() {
return log;
}
public void setLog(Log log) {
this.log = log;
}
}
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING, name = "type", length = 30)
@Cacheable
@Entity(name = "Request")
public static abstract class Request {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idUser")
private User user;
@Column(name = "`creationDate`", nullable = false)
private OffsetDateTime creationDate = OffsetDateTime.now();
@Enumerated(EnumType.STRING)
@Column(length = 30, nullable = false, name = "status")
private StatusRequest status = StatusRequest.REQUESTED;
Request() {
}
public Request(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public User getUser() {
return user;
}
public void setUser(User userSolicitacao) {
this.user = userSolicitacao;
}
public OffsetDateTime getCreationDate() {
return creationDate;
}
public void setCreationDate(OffsetDateTime creationDate) {
this.creationDate = creationDate;
}
public StatusRequest getStatus() {
return status;
}
public void setStatus(StatusRequest status) {
this.status = status;
}
public void setId(Long id) {
this.id = id;
}
}
@Entity(name = "InternalRequest")
@DiscriminatorValue(value = "INTERN")
public static class InternalRequest extends Request {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "`idTargetUser`")
private User targetUser;
InternalRequest() {
}
public InternalRequest(Long id) {
super( id );
}
public User getTargetUser() {
return targetUser;
}
public void setTargetUser(User targetUser) {
this.targetUser = targetUser;
}
}
public enum StatusRequest {
REQUESTED( "requested" ), WAITING( "Feedback waiting" );
private final String description;
StatusRequest(final String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
}

View File

@ -0,0 +1,195 @@
/*
* 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.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking;
import java.time.OffsetDateTime;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.stat.Statistics;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Andrea Boriero
*/
@RunWith(BytecodeEnhancerRunner.class)
@CustomEnhancementContext({ DirtyCheckEnhancementContext.class, NoDirtyCheckEnhancementContext.class })
@TestForIssue(jiraKey = "HHH-13705")
public class ManyToOneWithEmbeddedAndNotOptionalFieldTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
super.configureStandardServiceRegistryBuilder( ssrb );
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" );
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
}
@Override
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
super.configureSessionFactoryBuilder( sfb );
sfb.applyStatisticsSupport( true );
sfb.applySecondLevelCacheSupport( false );
sfb.applyQueryCacheSupport( false );
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( Client.class );
sources.addAnnotatedClass( User.class );
}
private Long userId;
@Before
public void setUp() {
User user = new User();
inTransaction(
session -> {
Log log = new Log();
log.setCreationDate( OffsetDateTime.now() );
Client client = new Client();
client.setName( "And" );
client.setLog( log );
session.save( client );
user.setName( "Fab" );
user.setClient( client );
session.save( user );
}
);
userId = user.getId();
}
@Test
public void load() {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
inTransaction(
session -> {
session.find( User.class, userId );
}
);
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
}
@Entity(name = "Client")
public static class Client {
@Id
@GeneratedValue
private Long id;
private String name;
@Embedded
private Log log = new Log();
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setId(Long id) {
this.id = id;
}
public Log getLog() {
return log;
}
public void setLog(Log log) {
this.log = log;
}
}
@Entity(name = "User")
@Table(name = "`User`")
public static class User {
@Id
@GeneratedValue
private Long id;
@Column(length = 120, nullable = false)
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "`idClient`")
private Client client;
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
}
@Embeddable
public static class Log {
@Column(name = "`creationDate`", nullable = false)
private OffsetDateTime creationDate;
public OffsetDateTime getCreationDate() {
return creationDate;
}
public void setCreationDate(OffsetDateTime creationDate) {
this.creationDate = creationDate;
}
}
}

View File

@ -0,0 +1,26 @@
/*
* 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.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking;
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
/**
* @author Andrea Boriero
*/
public class NoDirtyCheckEnhancementContext extends EnhancerTestContext {
@Override
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
return false;
}
@Override
public boolean doExtendedEnhancement(UnloadedClass classDescriptor) {
return false;
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.test.exceptionhandling;
import java.sql.SQLException;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.PersistenceException;
import org.hibernate.JDBCException;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.junit.Before;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@TestForIssue( jiraKey = "HHH-13737")
@RequiresDialect(H2Dialect.class)
public class NonActiveTransactionSessionFindJdbcExceptionHandlingTest extends BaseEntityManagerFunctionalTestCase {
@Test
public void testJdbcExceptionThrown() {
// delete "description" column so that a JDBCException caused by a SQLException is thrown when looking up the AnEntity
doInJPA(
this::entityManagerFactory,
entityManager -> {
entityManager.createNativeQuery( "alter table AnEntity drop column description" ).executeUpdate();
}
);
EntityManager entityManager = getOrCreateEntityManager();
try {
entityManager.find( AnEntity.class, 1 );
fail( "A PersistenceException should have been thrown." );
}
catch ( PersistenceException ex ) {
assertTrue( JDBCException.class.isInstance( ex.getCause() ) );
assertTrue( SQLException.class.isInstance( ex.getCause().getCause() ) );
}
finally {
entityManager.close();
}
}
@Before
public void setupData() {
doInJPA(
this::entityManagerFactory,
entityManager -> {
entityManager.persist( new AnEntity( 1, "description" ) );
}
);
}
@Override
@SuppressWarnings("unchecked")
protected void addMappings(Map settings) {
settings.put( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, true);
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { AnEntity.class };
}
@Entity(name = "AnEntity")
public static class AnEntity {
@Id
private int id;
@Column(name = "description")
private String description;
AnEntity() {
}
AnEntity(int id, String description) {
this.id = id;
this.description = description;
}
}
}

View File

@ -0,0 +1,25 @@
/*
* 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.test.mapping.joinformula;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class ChildEntity {
@Id
private Long id;
@Column(name = "PARENT_ID")
private Long parentId;
@Column
private String name;
}

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.test.mapping.joinformula;
import org.hibernate.Session;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
public class JoinFormulaTest extends BaseCoreFunctionalTestCase {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] {
ParentEntity.class,
ChildEntity.class
};
}
@Override
protected void configure(Configuration configuration) {
super.configure( configuration );
configuration.setProperty( AvailableSettings.SHOW_SQL, Boolean.TRUE.toString() );
configuration.setProperty( AvailableSettings.FORMAT_SQL, Boolean.TRUE.toString() );
}
@Test
public void hhh13722Test() {
try (Session s = openSession()) {
//Nothing to do: the test just needs to verify that
//this can boot.
}
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.test.mapping.joinformula;
import org.hibernate.annotations.JoinColumnOrFormula;
import org.hibernate.annotations.JoinColumnsOrFormulas;
import org.hibernate.annotations.JoinFormula;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
@Entity
public class ParentEntity {
@Id
private Long id;
@OneToOne(targetEntity = ChildEntity.class, optional = false)
@JoinColumnsOrFormulas({
@JoinColumnOrFormula(column = @JoinColumn(name = "ID", referencedColumnName = "PARENT_ID", insertable = false, updatable = false)),
@JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = "NAME", value = "'Tom'"))
})
private ChildEntity tom;
@OneToOne(targetEntity = ChildEntity.class, optional = false)
@JoinColumnsOrFormulas({
@JoinColumnOrFormula(column = @JoinColumn(name = "ID", referencedColumnName = "PARENT_ID", insertable = false, updatable = false)),
@JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = "NAME", value = "'Ben'"))
})
private ChildEntity ben;
}

View File

@ -193,9 +193,10 @@ public class DiscriminatorMultiTenancyTest extends BaseUnitTestCase {
}
}
public void doInHibernate(String tenant,
Consumer<Session> function) {
public void doInHibernate(String tenant, Consumer<Session> function) {
currentTenantResolver.currentTenantIdentifier = tenant;
TransactionUtil.doInHibernate( this::sessionFactory, tenant, function);
//Careful: do not use the #doInHibernate version of the method which takes a tenant: the goal of these tests is
// to verify that the CurrentTenantIdentifierResolver is being applied!
TransactionUtil.doInHibernate( this::sessionFactory, function);
}
}

View File

@ -35,6 +35,8 @@ import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.dialect.SybaseASE15Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.junit.Assert;
import org.jboss.logging.Logger;
/**
@ -44,6 +46,28 @@ public class TransactionUtil {
private static final Logger log = Logger.getLogger( TransactionUtil.class );
public static void doInHibernate(Supplier<SessionFactory> factorySupplier, Consumer<Session> function) {
final SessionFactory sessionFactory = factorySupplier.get();
Assert.assertNotNull( "SessionFactory is null in test!", sessionFactory );
//Make sure any error is propagated
try ( Session session = sessionFactory.openSession() ) {
final Transaction txn = session.getTransaction();
txn.begin();
try {
function.accept( session );
}
catch (Throwable e) {
try {
txn.rollback();
}
finally {
throw e;
}
}
txn.commit();
}
}
/**
* Hibernate transaction function
*

View File

@ -294,7 +294,13 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
TypeMirror collectionElementType = TypeUtils.getCollectionElementType(
declaredType, fqNameOfReturnType, null, context
);
returnedElement = (TypeElement) context.getTypeUtils().asElement( collectionElementType );
final Element collectionElement = context.getTypeUtils().asElement( collectionElementType );
if ( ElementKind.TYPE_PARAMETER.equals( collectionElement.getKind() ) ) {
return Boolean.FALSE;
}
returnedElement = (TypeElement) collectionElement;
}
if ( type.getQualifiedName().toString().equals( returnedElement.getQualifiedName().toString() ) ) {

View File

@ -0,0 +1,16 @@
/*
* 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.jpamodelgen.test.embeddable.generics;
import javax.persistence.Embeddable;
/**
* @author Chris Cranford
*/
@Embeddable
public class ChildEmbeddable extends ParentEmbeddable<MyTypeImpl> {
}

View File

@ -0,0 +1,42 @@
/*
* 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.jpamodelgen.test.embeddable.generics;
import org.hibernate.jpamodelgen.test.util.CompilationTest;
import org.hibernate.jpamodelgen.test.util.TestForIssue;
import org.hibernate.jpamodelgen.test.util.TestUtil;
import org.hibernate.jpamodelgen.test.util.WithClasses;
import org.junit.Test;
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor;
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertSetAttributeTypeInMetaModelFor;
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertSuperClassRelationShipInMetamodel;
/**
* @author Chris Cranford
*/
@TestForIssue(jiraKey = "HHH_12030")
public class EmbeddableGenericsTest extends CompilationTest {
@Test
@WithClasses({ ChildEmbeddable.class, ParentEmbeddable.class })
public void testGeneratingEmbeddablesWithGenerics() {
assertMetamodelClassGeneratedFor( ChildEmbeddable.class );
assertMetamodelClassGeneratedFor( ParentEmbeddable.class );
assertSetAttributeTypeInMetaModelFor(
ParentEmbeddable.class,
"fields",
MyTypeInterface.class,
"Expected Set<MyTypeInterface> for attribute named 'fields'"
);
assertSuperClassRelationShipInMetamodel(
ChildEmbeddable.class,
ParentEmbeddable.class
);
}
}

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.jpamodelgen.test.embeddable.generics;
/**
* @author Chris Cranford
*/
public class MyTypeImpl implements MyTypeInterface {
}

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.jpamodelgen.test.embeddable.generics;
/**
* @author Chris Cranford
*/
public interface MyTypeInterface {
}

View File

@ -0,0 +1,27 @@
/*
* 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.jpamodelgen.test.embeddable.generics;
import java.util.Set;
import javax.persistence.Embeddable;
/**
* @author Chris Cranford
*/
@Embeddable
public class ParentEmbeddable<MyType extends MyTypeInterface> {
private Set<MyType> fields;
public Set<MyType> getFields() {
return fields;
}
public void setFields(Set<MyType> fields) {
this.fields = fields;
}
}