Merge remote-tracking branch 'upstream/master' into wip/6.0

This commit is contained in:
Andrea Boriero 2019-12-09 12:07:23 +00:00
commit 79c83cf8ba
21 changed files with 877 additions and 32 deletions

View File

@ -127,7 +127,7 @@ Use the following command:
gradle clean compile -Pdb=pgsql
_*NOTE: If you are running tests against a JDBC driver that is not available via Maven central (generally due to license nonsense - Oracle, DB2, etc) be sure to add these drivers to your local Maven repo cache (~/.m2/repository) or (better) add it to a personal Maven repo server*_
_*NOTE: If you are running tests against a JDBC driver that is not available via Maven central be sure to add these drivers to your local Maven repo cache (~/.m2/repository) or (better) add it to a personal Maven repo server*_
Running database-specific tests from the IDE using "profiles"
-------------------------------------------------------------

View File

@ -3,6 +3,33 @@ Hibernate 5 Changelog
Note: Please refer to JIRA to learn more about each issue.
Changes in 5.4.10.Final (December 05, 2019)
------------------------------------------------------------------------------------------------------------------------
https://hibernate.atlassian.net/projects/HHH/versions/31811/tab/release-report-done
** Bug
* [HHH-9301] - Group by on alias doesn't replace alias
* [HHH-12895] - Extra LEFT JOIN generated with @ManyToOne and @JoinTable when projecting on main entity id
* [HHH-13355] - StaleStateException for updates to optional secondary table using saveOrUpdate
* [HHH-13365] - Entities in joined subclass table are not inserted with batch size > 0 using sequence-identity ID generator
* [HHH-13608] - Oracle8iDialect should use CASE_INSENSITIVE pattern matching when checking the statement type
* [HHH-13722] - ArrayStoreException in Constraint.generateName
* [HHH-13737] - Add debug logging and a test case for HHH-13433
* [HHH-13742] - Missing from clause with joined inheritance property in association subquery
* [HHH-13758] - Limit Handler for SQL server doesn't work with CTE queries with strings literals
* [HHH-13764] - Annotations are ignored during enhancement if they are on the getter instead of the field
** Task
* [HHH-13739] - Upgrade to Agroal 1.7
* [HHH-13761] - Debug logging of JPA compliance settings didn't log the value of the settings
* [HHH-13762] - Update vibur-dbcp dependency to 25.0
** Improvement
* [HHH-8091] - Hibernate produces SQL - "in ()" - which is invalid in at least Oracle, MySQL and Postgres
* [HHH-13755] - Update Hibernate Gradle Plugin example in the documentation
Changes in 6.0.0.Alpha1 (November 23, 2019)
------------------------------------------------------------------------------------------------------------------------
@ -30,7 +57,6 @@ https://hibernate.atlassian.net/projects/HHH/versions/31768/
* [HHH-11990] - Remove LogicalConnectionImplementor#makeShareableCopy
Changes in 5.4.9.Final (November 14, 2019)
------------------------------------------------------------------------------------------------------------------------

View File

@ -1,3 +1,5 @@
apply plugin: 'org.hibernate.orm'
ext {
hibernateVersion = 'hibernate-version-you-want'
}
@ -9,7 +11,9 @@ buildscript {
}
hibernate {
enhance {
// any configuration goes here
}
enhance {
enableLazyInitialization = true
enableDirtyTracking = true
enableAssociationManagement = true
}
}

View File

@ -30,6 +30,8 @@ ext {
agroalVersion = '1.7'
assertjVersion = '3.14.0'
geolatteVersion = '1.4.0'
// Wildfly version targeted by module ZIP; Arquillian/Shrinkwrap versions used for CDI testing and testing the module ZIP
@ -147,7 +149,7 @@ ext {
jcache: "javax.cache:cache-api:1.0.0",
proxool: "proxool:proxool:0.8.3",
hikaricp: "com.zaxxer:HikariCP:3.2.0",
vibur: "org.vibur:vibur-dbcp:22.2",
vibur: "org.vibur:vibur-dbcp:25.0",
agroal_api: "io.agroal:agroal-api:${agroalVersion}",
agroal_pool: "io.agroal:agroal-pool:${agroalVersion}",
@ -157,6 +159,8 @@ ext {
cdi: "javax.enterprise:cdi-api:${cdiVersion}",
weld: "org.jboss.weld.se:weld-se-shaded:${weldVersion}",
assertj: "org.assertj:assertj-core:${assertjVersion}",
// Arquillian/Shrinkwrap
arquillian_junit_container: "org.jboss.arquillian.junit:arquillian-junit-container:${arquillianVersion}",
arquillian_protocol_servlet: "org.jboss.arquillian.protocol:arquillian-protocol-servlet:${arquillianVersion}",

View File

@ -72,6 +72,7 @@ dependencies {
testCompile( libraries.mockito )
testCompile( libraries.mockito_inline )
testCompile( libraries.jodaTime )
testCompile( libraries.assertj )
testCompile( libraries.cdi ) {
// we need to force it to make sure we influence the one coming from arquillian

View File

@ -536,7 +536,7 @@ public class EnhancerImpl implements Enhancer {
}
annotationDescriptions.addAll( fieldDescription.getDeclaredAnnotations() );
return fieldDescription.getDeclaredAnnotations();
return new AnnotationList.Explicit( annotationDescriptions );
}
}
}

View File

@ -106,10 +106,10 @@ public final class Settings {
LOG.debugf( "Connection release mode: %s", sessionFactoryOptions.getConnectionReleaseMode() );
LOG.debugf( "Generate SQL with comments: %s", enabledDisabled( sessionFactoryOptions.isCommentsEnabled() ) );
LOG.debugf( "JPA compliance - query : ", enabledDisabled( sessionFactoryOptions.getJpaCompliance().isJpaQueryComplianceEnabled() ) );
LOG.debugf( "JPA compliance - closed-handling : ", enabledDisabled( sessionFactoryOptions.getJpaCompliance().isJpaClosedComplianceEnabled() ) );
LOG.debugf( "JPA compliance - lists : ", enabledDisabled( sessionFactoryOptions.getJpaCompliance().isJpaListComplianceEnabled() ) );
LOG.debugf( "JPA compliance - transactions : ", enabledDisabled( sessionFactoryOptions.getJpaCompliance().isJpaTransactionComplianceEnabled() ) );
LOG.debugf( "JPA compliance - query : %s", enabledDisabled( sessionFactoryOptions.getJpaCompliance().isJpaQueryComplianceEnabled() ) );
LOG.debugf( "JPA compliance - closed-handling : %s", enabledDisabled( sessionFactoryOptions.getJpaCompliance().isJpaClosedComplianceEnabled() ) );
LOG.debugf( "JPA compliance - lists : %s", enabledDisabled( sessionFactoryOptions.getJpaCompliance().isJpaListComplianceEnabled() ) );
LOG.debugf( "JPA compliance - transactions : %s", enabledDisabled( sessionFactoryOptions.getJpaCompliance().isJpaTransactionComplianceEnabled() ) );
}
}

View File

@ -585,7 +585,7 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
int index = offset;
boolean inString = false;
for ( ; index < sql.length(); ++index ) {
if ( sql.charAt( index ) == '\'' ) {
if ( sql.charAt( index ) == '\'' && !inString ) {
inString = true;
}
else if ( sql.charAt( index ) == '\'' && inString ) {

View File

@ -30,9 +30,4 @@ public abstract class AbstractPostInsertGenerator
public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect dialect) {
return null;
}
@Override
public boolean supportsJdbcBatchInserts() {
return false;
}
}

View File

@ -18,4 +18,9 @@ public interface PostInsertIdentifierGenerator extends IdentifierGenerator {
PostInsertIdentityPersister persister,
Dialect dialect,
boolean isGetGeneratedKeysEnabled) throws HibernateException;
@Override
default boolean supportsJdbcBatchInserts() {
return false;
}
}

View File

@ -3399,7 +3399,18 @@ public abstract class AbstractEntityPersister
final Expectation expectation = Expectations.appropriateExpectation( updateResultCheckStyles[j] );
final int jdbcBatchSizeToUse = session.getConfiguredJdbcBatchSize();
final boolean useBatch = expectation.canBeBatched() && isBatchable() && jdbcBatchSizeToUse > 1;
// IMPLEMENTATION NOTE: If Session#saveOrUpdate or #update is used to update an entity, then
// Hibernate does not have a database snapshot of the existing entity.
// As a result, oldFields will be null.
// Don't use a batch if oldFields == null and the jth table is optional (isNullableTable( j ),
// because there is no way to know that there is actually a row to update. If the update
// was batched in this case, the batch update would fail and there is no way to fallback to
// an insert.
final boolean useBatch =
expectation.canBeBatched() &&
isBatchable() &&
jdbcBatchSizeToUse > 1 &&
( oldFields != null || !isNullableTable( j ) );
if ( useBatch && updateBatchKey == null ) {
updateBatchKey = new BasicBatchKey(
getEntityName() + "#UPDATE",

View File

@ -8,26 +8,22 @@ package org.hibernate.jpa.test.criteria.basic;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hibernate.dialect.Oracle12cDialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.Oracle9Dialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.jpa.test.metamodel.AbstractMetamodelSpecificTest;
import org.hibernate.jpa.test.metamodel.CreditCard;
import org.hibernate.jpa.test.metamodel.CreditCard_;
import org.hibernate.jpa.test.metamodel.Customer_;
import org.hibernate.jpa.test.metamodel.Order;
import org.hibernate.jpa.test.metamodel.Order_;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.TestForIssue;
import org.junit.Before;
@ -297,4 +293,21 @@ public class PredicateTest extends AbstractMetamodelSpecificTest {
em.getTransaction().commit();
em.close();
}
@Test
@TestForIssue( jiraKey = "HHH-8901" )
@RequiresDialectFeature( DialectChecks.NotSupportsEmptyInListCheck.class )
public void testEmptyInPredicate() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
CriteriaQuery<Order> orderCriteria = builder.createQuery( Order.class );
Root<Order> orderRoot = orderCriteria.from( Order.class );
orderCriteria.select( orderRoot );
orderCriteria.where( builder.in( orderRoot.get("totalPrice") ) );
List<Order> orders = em.createQuery( orderCriteria ).getResultList();
assertTrue( orders.isEmpty() );
em.getTransaction().commit();
em.close();
}
}

View File

@ -0,0 +1,208 @@
/*
* 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.bytecode.enhance.internal.bytebuddy;
import java.lang.reflect.Method;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker;
import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
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 org.assertj.core.api.Assertions;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_ENTRY_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_ENTRY_GETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_GETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_SETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_GETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_SETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_CLEAR_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_GET_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_HAS_CHANGED_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_SUSPEND_NAME;
@TestForIssue(jiraKey = "HHH-13764")
@RunWith(BytecodeEnhancerRunner.class)
@EnhancementOptions(inlineDirtyChecking = true)
public class DirtyCheckingWithEmbeddedOnGetterTest {
@Test
public void shouldDeclareFieldsInEntityClass() {
assertThat( CardGame.class )
.hasDeclaredFields( ENTITY_ENTRY_FIELD_NAME, PREVIOUS_FIELD_NAME, NEXT_FIELD_NAME, TRACKER_FIELD_NAME );
}
@Test
public void shouldDeclareMethodsInEntityClass() {
assertThat( CardGame.class )
.hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "id", PERSISTENT_FIELD_WRITER_PREFIX + "id" )
.hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "name", PERSISTENT_FIELD_WRITER_PREFIX + "name" )
.hasDeclaredMethods( ENTITY_INSTANCE_GETTER_NAME, ENTITY_ENTRY_GETTER_NAME )
.hasDeclaredMethods( PREVIOUS_GETTER_NAME, PREVIOUS_SETTER_NAME, NEXT_GETTER_NAME, NEXT_SETTER_NAME )
.hasDeclaredMethods( TRACKER_HAS_CHANGED_NAME, TRACKER_CLEAR_NAME, TRACKER_SUSPEND_NAME, TRACKER_GET_NAME );
}
@Test
public void shouldDeclareFieldsInEmbeddedClass() {
assertThat( Component.class )
.hasDeclaredFields( TRACKER_COMPOSITE_FIELD_NAME );
}
@Test
public void shouldDeclareMethodsInEmbeddedClass() {
assertThat( Component.class )
.hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "component", PERSISTENT_FIELD_WRITER_PREFIX + "component" )
.hasDeclaredMethods( TRACKER_COMPOSITE_SET_OWNER, TRACKER_COMPOSITE_CLEAR_OWNER );
}
@Test
public void shouldCreateTheTracker() throws Exception {
CardGame entity = new CardGame( "MTG", "Magic the Gathering" );
assertThat( entity )
.extracting( NEXT_FIELD_NAME ).isNull();
assertThat( entity )
.extracting( PREVIOUS_FIELD_NAME ).isNull();
assertThat( entity )
.extracting( ENTITY_ENTRY_FIELD_NAME ).isNull();
assertThat( entity )
.extracting( TRACKER_FIELD_NAME ).isInstanceOf( SimpleFieldTracker.class );
assertThat( entity.getFirstPlayerToken() )
.extracting( TRACKER_COMPOSITE_FIELD_NAME ).isInstanceOf( CompositeOwnerTracker.class );
assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( true );
assertThat( entity ).extracting( TRACKER_GET_NAME )
.isEqualTo( new String[] { "name", "firstPlayerToken" } );
assertThat( entity.getFirstPlayerToken() ).extracting( TRACKER_COMPOSITE_FIELD_NAME + ".names" )
.isEqualTo( new String[] { "firstPlayerToken" } );
}
@Test
public void shouldResetTheTracker() throws Exception {
CardGame entity = new CardGame( "7WD", "7 WOnders duel" );
Method trackerClearMethod = CardGame.class.getMethod( TRACKER_CLEAR_NAME );
trackerClearMethod.invoke( entity );
assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( false );
assertThat( entity ).extracting( TRACKER_GET_NAME ).isEqualTo( new String[0] );
}
@Test
public void shouldUpdateTheTracker() throws Exception {
Assertions.setAllowExtractingPrivateFields( true );
CardGame entity = new CardGame( "SPL", "Splendor" );
Method trackerClearMethod = CardGame.class.getMethod( TRACKER_CLEAR_NAME );
trackerClearMethod.invoke( entity );
entity.setName( "Splendor: Cities of Splendor" );
assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( true );
assertThat( entity ).extracting( TRACKER_GET_NAME )
.isEqualTo( new String[] { "name", "firstPlayerToken" } );
trackerClearMethod.invoke( entity );
entity.setFirstPlayerToken( new Component( "FIRST PLAYER!!!!!!!!" ) );
assertThat( entity ).extracting( TRACKER_GET_NAME )
.isEqualTo( new String[] { "firstPlayerToken" } );
assertThat( entity.getFirstPlayerToken() ).extracting( TRACKER_COMPOSITE_FIELD_NAME + ".names" )
.isEqualTo( new String[] { "firstPlayerToken" } );
}
@Embeddable
public static class Component {
@Column(name = "first_player_token")
private String component;
public Component() {
}
private Component(String component) {
this.component = component;
}
public String getComponent() {
return component;
}
public void setComponent(String component) {
this.component = component;
}
}
@Entity(name = "CardGame")
public static class CardGame {
private String id;
private String name;
private Component firstPlayerToken;
public CardGame() {
}
private CardGame(String id, String name) {
this.id = id;
this.name = name;
this.firstPlayerToken = createEmbeddedValue( name );
}
@Id
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
this.firstPlayerToken = createEmbeddedValue( name );
}
@Embedded
public Component getFirstPlayerToken() {
return firstPlayerToken;
}
public void setFirstPlayerToken(Component firstPlayerToken) {
this.firstPlayerToken = firstPlayerToken;
}
private Component createEmbeddedValue(String name) {
return new Component( name + " first player token" );
}
}
}

View File

@ -0,0 +1,208 @@
/*
* 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.bytecode.enhance.internal.bytebuddy;
import java.lang.reflect.Method;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker;
import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
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 org.assertj.core.api.Assertions;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_ENTRY_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_ENTRY_GETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_GETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_SETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_GETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_SETTER_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_CLEAR_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_FIELD_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_GET_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_HAS_CHANGED_NAME;
import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_SUSPEND_NAME;
@TestForIssue(jiraKey = "HHH-13764")
@RunWith(BytecodeEnhancerRunner.class)
@EnhancementOptions(inlineDirtyChecking = true)
public class DirtyCheckingWithEmbeddedTest {
@Test
public void shouldDeclareFieldsInEntityClass() {
assertThat( CardGame.class )
.hasDeclaredFields( ENTITY_ENTRY_FIELD_NAME, PREVIOUS_FIELD_NAME, NEXT_FIELD_NAME, TRACKER_FIELD_NAME );
}
@Test
public void shouldDeclareMethodsInEntityClass() {
assertThat( CardGame.class )
.hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "id", PERSISTENT_FIELD_WRITER_PREFIX + "id" )
.hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "name", PERSISTENT_FIELD_WRITER_PREFIX + "name" )
.hasDeclaredMethods( ENTITY_INSTANCE_GETTER_NAME, ENTITY_ENTRY_GETTER_NAME )
.hasDeclaredMethods( PREVIOUS_GETTER_NAME, PREVIOUS_SETTER_NAME, NEXT_GETTER_NAME, NEXT_SETTER_NAME )
.hasDeclaredMethods( TRACKER_HAS_CHANGED_NAME, TRACKER_CLEAR_NAME, TRACKER_SUSPEND_NAME, TRACKER_GET_NAME );
}
@Test
public void shouldDeclareFieldsInEmbeddedClass() {
assertThat( Component.class )
.hasDeclaredFields( TRACKER_COMPOSITE_FIELD_NAME );
}
@Test
public void shouldDeclareMethodsInEmbeddedClass() {
assertThat( Component.class )
.hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "component", PERSISTENT_FIELD_WRITER_PREFIX + "component" )
.hasDeclaredMethods( TRACKER_COMPOSITE_SET_OWNER, TRACKER_COMPOSITE_CLEAR_OWNER );
}
@Test
public void shouldCreateTheTracker() throws Exception {
CardGame entity = new CardGame( "MTG", "Magic the Gathering" );
assertThat( entity )
.extracting( NEXT_FIELD_NAME ).isNull();
assertThat( entity )
.extracting( PREVIOUS_FIELD_NAME ).isNull();
assertThat( entity )
.extracting( ENTITY_ENTRY_FIELD_NAME ).isNull();
assertThat( entity )
.extracting( TRACKER_FIELD_NAME ).isInstanceOf( SimpleFieldTracker.class );
assertThat( entity.getFirstPlayerToken() )
.extracting( TRACKER_COMPOSITE_FIELD_NAME ).isInstanceOf( CompositeOwnerTracker.class );
assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( true );
assertThat( entity ).extracting( TRACKER_GET_NAME )
.isEqualTo( new String[] { "name", "firstPlayerToken" } );
assertThat( entity.getFirstPlayerToken() ).extracting( TRACKER_COMPOSITE_FIELD_NAME + ".names" )
.isEqualTo( new String[] { "firstPlayerToken" } );
}
@Test
public void shouldResetTheTracker() throws Exception {
CardGame entity = new CardGame( "7WD", "7 WOnders duel" );
Method trackerClearMethod = CardGame.class.getMethod( TRACKER_CLEAR_NAME );
trackerClearMethod.invoke( entity );
assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( false );
assertThat( entity ).extracting( TRACKER_GET_NAME ).isEqualTo( new String[0] );
}
@Test
public void shouldUpdateTheTracker() throws Exception {
Assertions.setAllowExtractingPrivateFields( true );
CardGame entity = new CardGame( "SPL", "Splendor" );
Method trackerClearMethod = CardGame.class.getMethod( TRACKER_CLEAR_NAME );
trackerClearMethod.invoke( entity );
entity.setName( "Splendor: Cities of Splendor" );
assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( true );
assertThat( entity ).extracting( TRACKER_GET_NAME )
.isEqualTo( new String[] { "name", "firstPlayerToken" } );
trackerClearMethod.invoke( entity );
entity.setFirstPlayerToken( new Component( "FIRST PLAYER!!!!!!!!" ) );
assertThat( entity ).extracting( TRACKER_GET_NAME )
.isEqualTo( new String[] { "firstPlayerToken" } );
assertThat( entity.getFirstPlayerToken() ).extracting( TRACKER_COMPOSITE_FIELD_NAME + ".names" )
.isEqualTo( new String[] { "firstPlayerToken" } );
}
@Embeddable
public static class Component {
@Column(name = "first_player_token")
private String component;
public Component() {
}
private Component(String component) {
this.component = component;
}
public String getComponent() {
return component;
}
public void setComponent(String component) {
this.component = component;
}
}
@Entity(name = "CardGame")
public static class CardGame {
@Id
private String id;
private String name;
@Embedded
private Component firstPlayerToken;
public CardGame() {
}
private CardGame(String id, String name) {
this.id = id;
this.name = name;
this.firstPlayerToken = createEmbeddedValue( name );
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
this.firstPlayerToken = createEmbeddedValue( name );
}
public Component getFirstPlayerToken() {
return firstPlayerToken;
}
public void setFirstPlayerToken(Component firstPlayerToken) {
this.firstPlayerToken = firstPlayerToken;
}
private Component createEmbeddedValue(String name) {
return new Component( name + " first player token" );
}
}
}

View File

@ -90,7 +90,7 @@ public class GroupByAliasTest extends BaseEntityManagerFunctionalTestCase {
List<Tuple> list = doInJPA(this::entityManagerFactory, entityManager -> {
return entityManager.createQuery(
"select p.association as id_alias, sum(p.age) " +
"from Person p group by id_alias order by id_alias", Tuple.class)
"from Person p group by id_alias, p.association.id, p.association.name order by id_alias", Tuple.class)
.getResultList();
});
@ -105,7 +105,7 @@ public class GroupByAliasTest extends BaseEntityManagerFunctionalTestCase {
List<Tuple> list = doInJPA(this::entityManagerFactory, entityManager -> {
return entityManager.createQuery(
"select p.id as id_alias_1, p.association as id_alias_2, sum(p.age) " +
"select p.id as id_alias_1, p.association.id as id_alias_2, sum(p.age) " +
"from Person p group by id_alias_1, id_alias_2 order by id_alias_1, id_alias_2 ", Tuple.class)
.getResultList();
});

View File

@ -0,0 +1,159 @@
/*
* 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.batch;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.SecondaryTable;
import javax.persistence.Version;
import org.hibernate.annotations.Table;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals;
public class OptionalSecondaryTableBatchTest extends BaseNonConfigCoreFunctionalTestCase {
private List<Company> companies;
@Test
public void testMerge() {
doInHibernate(
this::sessionFactory,
session -> {
for ( int i = 0 ; i < 10 ; i++ ) {
final Company company = companies.get( i );
company.taxNumber = 2 * i;
session.merge( company );
}
}
);
doInHibernate(
this::sessionFactory,
session -> {
for ( int i = 0 ; i < 10 ; i++ ) {
assertEquals( Integer.valueOf( 2 * i ), session.get( Company.class, i).taxNumber );
}
}
);
}
@Test
public void testSaveOrUpdate() {
doInHibernate(
this::sessionFactory,
session -> {
for ( int i = 0 ; i < 10 ; i++ ) {
final Company company = companies.get( i );
company.taxNumber = 2 * i;
session.saveOrUpdate( company );
}
}
);
doInHibernate(
this::sessionFactory,
session -> {
for ( int i = 0 ; i < 10 ; i++ ) {
assertEquals( Integer.valueOf( 2 * i ), session.get( Company.class, i).taxNumber );
}
}
);
}
@Test
public void testUpdate() {
doInHibernate(
this::sessionFactory,
session -> {
for ( int i = 0 ; i < 10 ; i++ ) {
final Company company = companies.get( i );
company.taxNumber = 2 * i;
session.update( company );
}
}
);
doInHibernate(
this::sessionFactory,
session -> {
for ( int i = 0 ; i < 10 ; i++ ) {
assertEquals( Integer.valueOf( 2 * i ), session.get( Company.class, i).taxNumber );
}
}
);
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { Company.class };
}
@Override
protected void addSettings(Map settings) {
super.addSettings( settings );
settings.put( AvailableSettings.STATEMENT_BATCH_SIZE, 5 );
}
@Before
public void setupData() {
companies = new ArrayList<>( 10 );
doInHibernate(
this::sessionFactory,
session -> {
for ( int i = 0; i < 10; i++ ) {
final Company company = new Company();
company.id = i;
if ( i % 2 == 0 ) {
company.taxNumber = i;
}
session.persist( company );
companies.add( company );
}
}
);
}
@After
public void cleanupData() {
doInHibernate(
this::sessionFactory,
session -> {
session.createQuery( "delete from Company" ).executeUpdate();
}
);
}
@Entity(name = "Company")
@SecondaryTable( name = "company_tax" )
@Table( appliesTo = "company_tax", optional = true)
public static class Company {
@Id
private int id;
@Version
@Column( name = "ver" )
private int version;
private String name;
@Column(table = "company_tax")
private Integer taxNumber;
}
}

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.test.generatedkeys.seqidentity;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Oracle9iDialect;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@TestForIssue( jiraKey = "HHH-13365" )
@RequiresDialect( Oracle9iDialect.class )
public class JoinedSequenceIdentityBatchTest extends BaseNonConfigCoreFunctionalTestCase {
@Test
public void testInsertAndUpdate() {
doInHibernate(
this::sessionFactory,
session -> {
FolderResource folder = new FolderResource();
folder.name = "PARENT";
session.persist( folder );
}
);
doInHibernate(
this::sessionFactory,
session -> {
List<FolderResource> folderResources = session.createQuery( "from FolderResource" ).getResultList();
assertEquals( 1, folderResources.size() );
final FolderResource folderResource = folderResources.get( 0 );
assertNull( folderResource.description );
folderResource.description = "A folder resource";
}
);
doInHibernate(
this::sessionFactory,
session -> {
List<FolderResource> folderResources = session.createQuery( "from FolderResource" ).getResultList();
assertEquals( 1, folderResources.size() );
final FolderResource folderResource = folderResources.get( 0 );
assertEquals( "A folder resource", folderResource.description );
}
);
}
@Override
@SuppressWarnings( "unchecked" )
protected void addSettings(Map settings) {
super.addSettings( settings );
settings.put( AvailableSettings.STATEMENT_BATCH_SIZE, "5" );
settings.put( AvailableSettings.USE_GET_GENERATED_KEYS, "true" );
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { Resource.class, FolderResource.class };
}
@Entity(name = "Resource")
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "WORKSPACE_RESOURCE")
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public static class Resource {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_WORKSPACE_RESOURCE")
@GenericGenerator(name = "SEQ_WORKSPACE_RESOURCE", strategy = "sequence-identity",
parameters = {@Parameter(name = "sequence", value = "SEQ_WORKSPACE_RESOURCE")})
@Column(name = "ID_WORKSPACE_RESOURCE", nullable = false, precision = 18)
private Long id;
@Column(name = "NAME", nullable = false, length = 256)
protected String name;
@Column(name = "RESOURCE_TYPE", nullable = false, length = 20)
protected String type;
}
@Entity(name = "FolderResource")
@Table(name = "WORKSPACE_RESOURCE_FOLDER")
@PrimaryKeyJoinColumn(name = "ID_WORKSPACE_RESOURCE_FOLDER")
@DiscriminatorValue("FOLDER")
public static class FolderResource extends Resource implements Serializable {
private String description;
public FolderResource()
{
super();
type = "FOLDER";
}
}
}

View File

@ -6,6 +6,18 @@
*/
package org.hibernate.test.hql;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hibernate.testing.junit4.ExtraAssertions.assertClassAssignability;
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Date;
@ -13,11 +25,11 @@ import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.QueryException;
@ -79,6 +91,18 @@ import org.hibernate.test.cid.LineItem;
import org.hibernate.test.cid.LineItem.Id;
import org.hibernate.test.cid.Order;
import org.hibernate.test.cid.Product;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.transform.Transformers;
import org.hibernate.type.ComponentType;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.Type;
import org.junit.Test;
import org.hamcrest.CoreMatchers;
@ -675,6 +699,35 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
session.close();
}
@Test
@TestForIssue( jiraKey = "HHH-8901" )
@RequiresDialectFeature(DialectChecks.NotSupportsEmptyInListCheck.class)
public void testEmptyInListForDialectsNotSupportsEmptyInList() {
Session session = openSession();
session.beginTransaction();
Human human = new Human();
human.setName( new Name( "Lukasz", null, "Antoniak" ) );
human.setNickName( "NONE" );
session.save( human );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
List results = session.createQuery( "from Human h where h.nickName in (:nickNames)" )
.setParameter("nickNames", Collections.emptySet() )
.list();
assertEquals( 0, results.size() );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
session.delete( human );
session.getTransaction().commit();
session.close();
}
@Test
@TestForIssue( jiraKey = "HHH-2851")
public void testMultipleRefsToSameParam() {
@ -958,7 +1011,7 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
// simple syntax checking...
Session s = openSession();
s.beginTransaction();
s.createQuery( "from Human h wherFe h.nickName = '1' || 'ov' || 'tha' || 'few'" ).list();
s.createQuery( "from Human h where h.nickName = '1' || 'ov' || 'tha' || 'few'" ).list();
s.getTransaction().commit();
s.close();
}

View File

@ -75,7 +75,7 @@ public class QueryHintTest extends BaseNonConfigCoreFunctionalTestCase {
// test Query w/ a simple Oracle optimizer hint
doInHibernate( this::sessionFactory, s -> {
Query query = s.createQuery( "FROM QueryHintTest$Employee e WHERE e.department.name = :departmentName" )
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
.addQueryHint( "ALL_ROWS" )
.setParameter( "departmentName", "Sales" );
List results = query.list();
@ -89,7 +89,7 @@ public class QueryHintTest extends BaseNonConfigCoreFunctionalTestCase {
// test multiple hints
doInHibernate( this::sessionFactory, s -> {
Query query = s.createQuery( "FROM QueryHintTest$Employee e WHERE e.department.name = :departmentName" )
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
.addQueryHint( "ALL_ROWS" )
.addQueryHint( "USE_CONCAT" )
.setParameter( "departmentName", "Sales" );
@ -104,7 +104,7 @@ public class QueryHintTest extends BaseNonConfigCoreFunctionalTestCase {
// ensure the insertion logic can handle a comment appended to the front
doInHibernate( this::sessionFactory, s -> {
Query query = s.createQuery( "FROM QueryHintTest$Employee e WHERE e.department.name = :departmentName" )
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
.setComment( "this is a test" )
.addQueryHint( "ALL_ROWS" )
.setParameter( "departmentName", "Sales" );
@ -147,7 +147,7 @@ public class QueryHintTest extends BaseNonConfigCoreFunctionalTestCase {
sqlStatementInterceptor.clear();
doInHibernate( this::sessionFactory, s -> {
Query query = s.createQuery( "FROM QueryHintTest$Employee e WHERE e.department.name = :departmentName" )
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
.addQueryHint( "ALL_ROWS" )
.setComment( "My_Query" )
.setParameter( "departmentName", "Sales" );

View File

@ -8,11 +8,15 @@ package org.hibernate.test.criteria;
import static org.junit.Assert.assertEquals;
import java.util.Collections;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
@ -42,4 +46,30 @@ public class InTest extends BaseCoreFunctionalTestCase {
tx.rollback();
session.close();
}
@Test
@TestForIssue( jiraKey = "HHH-8901" )
@RequiresDialectFeature(DialectChecks.NotSupportsEmptyInListCheck.class)
public void testEmptyInListForDialectNotSupportsEmptyInList() {
Session session = openSession();
Transaction tx = session.beginTransaction();
session.save( new Woman() );
session.save( new Man() );
session.flush();
tx.commit();
session.close();
session = openSession();
tx = session.beginTransaction();
List persons = session.createCriteria( Person.class ).add(
Restrictions.in( "name", Collections.emptySet() ) ).list();
assertEquals( 0, persons.size() );
tx.rollback();
session.close();
}
@Override
protected boolean isCleanupTestDataRequired() {
return true;
}
}

View File

@ -55,6 +55,12 @@ abstract public class DialectChecks {
}
}
public static class NotSupportsEmptyInListCheck implements DialectCheck {
public boolean isMatch(Dialect dialect) {
return !dialect.supportsEmptyInList();
}
}
public static class CaseSensitiveCheck implements DialectCheck {
public boolean isMatch(Dialect dialect) {
return dialect.areStringComparisonsCaseInsensitive();