Merge remote-tracking branch 'upstream/master' into wip/6.0_merge_46
This commit is contained in:
commit
9ba18b8c5d
|
@ -182,4 +182,4 @@ The `QueryStatistics` instance, which you can get via the `getQueryStatistics(St
|
||||||
|
|
||||||
`getPlanCacheHitCount`:: The number of query plans successfully fetched from the cache.
|
`getPlanCacheHitCount`:: The number of query plans successfully fetched from the cache.
|
||||||
`getQueryPlanCacheMissCount`:: The number of query plans *not* fetched from the cache.
|
`getQueryPlanCacheMissCount`:: The number of query plans *not* fetched from the cache.
|
||||||
`getQueryPlanCacheMissCount`:: The overall time spent to compile the plan for this particular query.
|
`getPlanCompilationTotalMicroseconds`:: The overall time spent to compile the plan for this particular query.
|
||||||
|
|
|
@ -7,8 +7,15 @@
|
||||||
|
|
||||||
apply plugin: 'base'
|
apply plugin: 'base'
|
||||||
|
|
||||||
|
File versionFile = file( "${rootProject.projectDir}/gradle/version.properties" )
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
ormVersion = new HibernateVersion( '6.0.0-SNAPSHOT', project )
|
ormVersionFile = versionFile
|
||||||
|
ormVersion = HibernateVersion.fromFile( versionFile, project )
|
||||||
|
// Override during releases
|
||||||
|
if ( project.hasProperty( 'releaseVersion' ) ) {
|
||||||
|
ormVersion = new HibernateVersion( project.releaseVersion, project )
|
||||||
|
}
|
||||||
baselineJavaVersion = '1.8'
|
baselineJavaVersion = '1.8'
|
||||||
jpaVersion = new JpaVersion('2.2')
|
jpaVersion = new JpaVersion('2.2')
|
||||||
}
|
}
|
||||||
|
@ -54,6 +61,22 @@ class HibernateVersion {
|
||||||
this.osgiVersion = isSnapshot ? family + '.' + hibernateVersionComponents[2] + '.SNAPSHOT' : fullName
|
this.osgiVersion = isSnapshot ? family + '.' + hibernateVersionComponents[2] + '.SNAPSHOT' : fullName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HibernateVersion fromFile(File file, Project project){
|
||||||
|
def fullName = readVersionProperties(file)
|
||||||
|
return new HibernateVersion(fullName, project)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readVersionProperties(File file) {
|
||||||
|
if ( !file.exists() ) {
|
||||||
|
throw new GradleException( "Version file $file.canonicalPath does not exists" )
|
||||||
|
}
|
||||||
|
Properties versionProperties = new Properties()
|
||||||
|
file.withInputStream {
|
||||||
|
stream -> versionProperties.load( stream )
|
||||||
|
}
|
||||||
|
return versionProperties.hibernateVersion
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String toString() {
|
String toString() {
|
||||||
return this.fullName
|
return this.fullName
|
||||||
|
|
|
@ -266,6 +266,7 @@ publishing {
|
||||||
task ciBuild( dependsOn: [test, publish] )
|
task ciBuild( dependsOn: [test, publish] )
|
||||||
|
|
||||||
task release( dependsOn: [test, bintrayUpload] )
|
task release( dependsOn: [test, bintrayUpload] )
|
||||||
|
bintrayUpload.mustRunAfter test
|
||||||
|
|
||||||
afterEvaluate { Project project ->
|
afterEvaluate { Project project ->
|
||||||
project.rootProject.subprojects { Project subproject ->
|
project.rootProject.subprojects { Project subproject ->
|
||||||
|
|
|
@ -14,8 +14,10 @@ apply plugin: 'com.jfrog.bintray'
|
||||||
|
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
bintrayUser = project.hasProperty( 'PERSONAL_BINTRAY_USER' ) ? project.property( 'PERSONAL_BINTRAY_USER' ) : null
|
bintrayUser = project.findProperty( 'PERSONAL_BINTRAY_USER' )
|
||||||
bintrayKey = project.hasProperty( 'PERSONAL_BINTRAY_API_KEY' ) ? project.property( 'PERSONAL_BINTRAY_API_KEY' ) : null
|
bintrayKey = project.findProperty( 'PERSONAL_BINTRAY_API_KEY' )
|
||||||
|
sonatypeOssrhUser = project.findProperty( 'SONATYPE_OSSRH_USER' )
|
||||||
|
sonatypeOssrhPassword = project.findProperty( 'SONATYPE_OSSRH_PASSWORD' )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,6 +61,8 @@ bintray {
|
||||||
]
|
]
|
||||||
mavenCentralSync {
|
mavenCentralSync {
|
||||||
sync = true
|
sync = true
|
||||||
|
user = project.sonatypeOssrhUser
|
||||||
|
password = project.sonatypeOssrhPassword
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
hibernateVersion=6.0.0-SNAPSHOT
|
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.dialect;
|
package org.hibernate.dialect;
|
||||||
|
|
||||||
|
import java.sql.Types;
|
||||||
|
|
||||||
import org.hibernate.PessimisticLockException;
|
import org.hibernate.PessimisticLockException;
|
||||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
@ -35,6 +37,8 @@ import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||||
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
|
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
|
||||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorH2DatabaseImpl;
|
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorH2DatabaseImpl;
|
||||||
|
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
|
||||||
|
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
|
||||||
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
@ -55,6 +59,9 @@ public class H2Dialect extends Dialect {
|
||||||
|
|
||||||
private final boolean cascadeConstraints;
|
private final boolean cascadeConstraints;
|
||||||
|
|
||||||
|
private final SequenceInformationExtractor sequenceInformationExtractor;
|
||||||
|
private final String querySequenceString;
|
||||||
|
|
||||||
public H2Dialect() {
|
public H2Dialect() {
|
||||||
this(0, 0);
|
this(0, 0);
|
||||||
}
|
}
|
||||||
|
@ -80,6 +87,18 @@ public class H2Dialect extends Dialect {
|
||||||
getDefaultProperties().setProperty( AvailableSettings.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
|
getDefaultProperties().setProperty( AvailableSettings.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
|
||||||
// http://code.google.com/p/h2database/issues/detail?id=235
|
// http://code.google.com/p/h2database/issues/detail?id=235
|
||||||
getDefaultProperties().setProperty( AvailableSettings.NON_CONTEXTUAL_LOB_CREATION, "true" );
|
getDefaultProperties().setProperty( AvailableSettings.NON_CONTEXTUAL_LOB_CREATION, "true" );
|
||||||
|
|
||||||
|
if ( buildId >= 32 ) {
|
||||||
|
this.sequenceInformationExtractor = buildId >= 201
|
||||||
|
? SequenceInformationExtractorLegacyImpl.INSTANCE
|
||||||
|
: SequenceInformationExtractorH2DatabaseImpl.INSTANCE;
|
||||||
|
this.querySequenceString = "select * from INFORMATION_SCHEMA.SEQUENCES";
|
||||||
|
registerColumnType( Types.DECIMAL, "numeric($p,$s)" );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.sequenceInformationExtractor = SequenceInformationExtractorNoOpImpl.INSTANCE;
|
||||||
|
this.querySequenceString = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int parseBuildId(DialectResolutionInfo info) {
|
private static int parseBuildId(DialectResolutionInfo info) {
|
||||||
|
@ -215,12 +234,12 @@ public class H2Dialect extends Dialect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getQuerySequencesString() {
|
public String getQuerySequencesString() {
|
||||||
return "select * from information_schema.sequences";
|
return querySequenceString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SequenceInformationExtractor getSequenceInformationExtractor() {
|
public SequenceInformationExtractor getSequenceInformationExtractor() {
|
||||||
return SequenceInformationExtractorH2DatabaseImpl.INSTANCE;
|
return sequenceInformationExtractor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -31,13 +31,13 @@ import org.hibernate.event.spi.PostLoadEventListener;
|
||||||
import org.hibernate.event.spi.PreLoadEvent;
|
import org.hibernate.event.spi.PreLoadEvent;
|
||||||
import org.hibernate.event.spi.PreLoadEventListener;
|
import org.hibernate.event.spi.PreLoadEventListener;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.FastSessionServices;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
import org.hibernate.pretty.MessageHelper;
|
||||||
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.stat.internal.StatsHelper;
|
import org.hibernate.stat.internal.StatsHelper;
|
||||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
import org.hibernate.type.EntityType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.type.TypeHelper;
|
import org.hibernate.type.TypeHelper;
|
||||||
|
|
||||||
|
@ -116,18 +116,13 @@ public final class TwoPhaseLoad {
|
||||||
final boolean readOnly,
|
final boolean readOnly,
|
||||||
final SharedSessionContractImplementor session,
|
final SharedSessionContractImplementor session,
|
||||||
final PreLoadEvent preLoadEvent) {
|
final PreLoadEvent preLoadEvent) {
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
|
||||||
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
|
|
||||||
if ( entityEntry == null ) {
|
|
||||||
throw new AssertionFailure( "possible non-threadsafe access to the session" );
|
|
||||||
}
|
|
||||||
final EventListenerGroup<PreLoadEventListener> listenerGroup = session
|
final EventListenerGroup<PreLoadEventListener> listenerGroup = session
|
||||||
.getFactory()
|
.getFactory()
|
||||||
.getServiceRegistry()
|
.getServiceRegistry()
|
||||||
.getService( EventListenerRegistry.class )
|
.getService( EventListenerRegistry.class )
|
||||||
.getEventListenerGroup( EventType.PRE_LOAD );
|
.getEventListenerGroup( EventType.PRE_LOAD );
|
||||||
final Iterable<PreLoadEventListener> listeners = listenerGroup.listeners();
|
final Iterable<PreLoadEventListener> listeners = listenerGroup.listeners();
|
||||||
doInitializeEntity( entity, entityEntry, readOnly, session, preLoadEvent, listeners );
|
initializeEntity( entity, readOnly, session, preLoadEvent, listeners, EntityResolver.DEFAULT );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,22 +145,46 @@ public final class TwoPhaseLoad {
|
||||||
final SharedSessionContractImplementor session,
|
final SharedSessionContractImplementor session,
|
||||||
final PreLoadEvent preLoadEvent,
|
final PreLoadEvent preLoadEvent,
|
||||||
final Iterable<PreLoadEventListener> preLoadEventListeners) {
|
final Iterable<PreLoadEventListener> preLoadEventListeners) {
|
||||||
|
initializeEntity( entity, readOnly, session, preLoadEvent, preLoadEventListeners, EntityResolver.DEFAULT );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the second step of 2-phase load. Fully initialize the entity
|
||||||
|
* instance.
|
||||||
|
* <p/>
|
||||||
|
* After processing a JDBC result set, we "resolve" all the associations
|
||||||
|
* between the entities which were instantiated and had their state
|
||||||
|
* "hydrated" into an array
|
||||||
|
*
|
||||||
|
* @param entity The entity being loaded
|
||||||
|
* @param readOnly Is the entity being loaded as read-only
|
||||||
|
* @param session The Session
|
||||||
|
* @param preLoadEvent The (re-used) pre-load event
|
||||||
|
* @param preLoadEventListeners the pre-load event listeners
|
||||||
|
* @param entityResolver the resolver used for to-one entity associations
|
||||||
|
* (not used when an entity is a bytecode-enhanced lazy entity)
|
||||||
|
*/
|
||||||
|
public static void initializeEntity(
|
||||||
|
final Object entity,
|
||||||
|
final boolean readOnly,
|
||||||
|
final SharedSessionContractImplementor session,
|
||||||
|
final PreLoadEvent preLoadEvent,
|
||||||
|
final Iterable<PreLoadEventListener> preLoadEventListeners,
|
||||||
|
final EntityResolver entityResolver) {
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
|
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
|
||||||
if ( entityEntry == null ) {
|
if ( entityEntry == null ) {
|
||||||
throw new AssertionFailure( "possible non-threadsafe access to the session" );
|
throw new AssertionFailure( "possible non-threadsafe access to the session" );
|
||||||
}
|
}
|
||||||
doInitializeEntity( entity, entityEntry, readOnly, session, preLoadEvent, preLoadEventListeners );
|
initializeEntityEntryLoadedState( entity, entityEntry, session, entityResolver );
|
||||||
|
initializeEntityFromEntityEntryLoadedState( entity, entityEntry, readOnly, session, preLoadEvent, preLoadEventListeners );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void doInitializeEntity(
|
public static void initializeEntityEntryLoadedState(
|
||||||
final Object entity,
|
final Object entity,
|
||||||
final EntityEntry entityEntry,
|
final EntityEntry entityEntry,
|
||||||
final boolean readOnly,
|
|
||||||
final SharedSessionContractImplementor session,
|
final SharedSessionContractImplementor session,
|
||||||
final PreLoadEvent preLoadEvent,
|
final EntityResolver entityResolver) throws HibernateException {
|
||||||
final Iterable<PreLoadEventListener> preLoadEventListeners) throws HibernateException {
|
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
|
||||||
final EntityPersister persister = entityEntry.getPersister();
|
final EntityPersister persister = entityEntry.getPersister();
|
||||||
final Object id = entityEntry.getId();
|
final Object id = entityEntry.getId();
|
||||||
final Object[] hydratedState = entityEntry.getLoadedState();
|
final Object[] hydratedState = entityEntry.getLoadedState();
|
||||||
|
@ -221,7 +240,9 @@ public final class TwoPhaseLoad {
|
||||||
|
|
||||||
// we know value != LazyPropertyInitializer.UNFETCHED_PROPERTY
|
// we know value != LazyPropertyInitializer.UNFETCHED_PROPERTY
|
||||||
Boolean overridingEager = getOverridingEager( session, entityName, propertyNames[i], types[i], debugEnabled );
|
Boolean overridingEager = getOverridingEager( session, entityName, propertyNames[i], types[i], debugEnabled );
|
||||||
hydratedState[i] = types[i].resolve( value, session, entity, overridingEager );
|
hydratedState[i] = types[i].isEntityType()
|
||||||
|
? entityResolver.resolve( (EntityType) types[i], value, session, entity, overridingEager )
|
||||||
|
: types[i].resolve( value, session, entity, overridingEager );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( debugEnabled ) {
|
if ( debugEnabled ) {
|
||||||
|
@ -229,6 +250,22 @@ public final class TwoPhaseLoad {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void initializeEntityFromEntityEntryLoadedState(
|
||||||
|
final Object entity,
|
||||||
|
final EntityEntry entityEntry,
|
||||||
|
final boolean readOnly,
|
||||||
|
final SharedSessionContractImplementor session,
|
||||||
|
final PreLoadEvent preLoadEvent,
|
||||||
|
final Iterable<PreLoadEventListener> preLoadEventListeners) throws HibernateException {
|
||||||
|
|
||||||
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
|
final EntityPersister persister = entityEntry.getPersister();
|
||||||
|
final Object id = entityEntry.getId();
|
||||||
|
final Object[] hydratedState = entityEntry.getLoadedState();
|
||||||
|
|
||||||
|
final boolean debugEnabled = LOG.isDebugEnabled();
|
||||||
|
|
||||||
//Must occur after resolving identifiers!
|
//Must occur after resolving identifiers!
|
||||||
if ( session.isEventSource() ) {
|
if ( session.isEventSource() ) {
|
||||||
|
@ -531,4 +568,23 @@ public final class TwoPhaseLoad {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementations determine how a to-one associations is resolved.
|
||||||
|
*
|
||||||
|
* @see #initializeEntity(Object, boolean, SharedSessionContractImplementor, PreLoadEvent, Iterable, EntityResolver)
|
||||||
|
*/
|
||||||
|
public interface EntityResolver {
|
||||||
|
|
||||||
|
Object resolve(
|
||||||
|
EntityType entityType,
|
||||||
|
Object value,
|
||||||
|
SharedSessionContractImplementor session,
|
||||||
|
Object owner,
|
||||||
|
Boolean overridingEager
|
||||||
|
);
|
||||||
|
|
||||||
|
EntityResolver DEFAULT = (entityType, value, session, owner, overridingEager) ->
|
||||||
|
entityType.resolve( value, session, owner, overridingEager );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ import org.hibernate.type.Type;
|
||||||
public final class ReflectHelper {
|
public final class ReflectHelper {
|
||||||
|
|
||||||
private static final Pattern JAVA_CONSTANT_PATTERN = Pattern.compile(
|
private static final Pattern JAVA_CONSTANT_PATTERN = Pattern.compile(
|
||||||
"[a-z\\d]+\\.([A-Z]{1}[a-z\\d]+)+\\$?([A-Z]{1}[a-z\\d]+)*\\.[A-Z_\\$]+", Pattern.UNICODE_CHARACTER_CLASS);
|
"[a-z\\d]+\\.([A-Z]+[a-z\\d]+)+\\$?([A-Z]{1}[a-z\\d]+)*\\.[A-Z_\\$]+", Pattern.UNICODE_CHARACTER_CLASS);
|
||||||
|
|
||||||
public static final Class[] NO_PARAM_SIGNATURE = new Class[0];
|
public static final Class[] NO_PARAM_SIGNATURE = new Class[0];
|
||||||
public static final Object[] NO_PARAMS = new Object[0];
|
public static final Object[] NO_PARAMS = new Object[0];
|
||||||
|
|
|
@ -437,6 +437,18 @@ public abstract class EntityType extends AbstractType implements AssociationType
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Would an entity be eagerly loaded given the value provided for {@code overridingEager}?
|
||||||
|
*
|
||||||
|
* @param overridingEager can override eager from the mapping.
|
||||||
|
*
|
||||||
|
* @return If {@code overridingEager} is null, then it does not override.
|
||||||
|
* If true or false then it overrides the mapping value.
|
||||||
|
*/
|
||||||
|
public boolean isEager(Boolean overridingEager) {
|
||||||
|
return overridingEager != null ? overridingEager : this.eager;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getSemiResolvedType(SessionFactoryImplementor factory) {
|
public Type getSemiResolvedType(SessionFactoryImplementor factory) {
|
||||||
return getAssociatedEntityPersister( factory ).getIdentifierType();
|
return getAssociatedEntityPersister( factory ).getIdentifierType();
|
||||||
|
@ -648,12 +660,10 @@ public abstract class EntityType extends AbstractType implements AssociationType
|
||||||
getAssociatedEntityPersister( session.getFactory() )
|
getAssociatedEntityPersister( session.getFactory() )
|
||||||
.isInstrumented();
|
.isInstrumented();
|
||||||
|
|
||||||
boolean eager = overridingEager != null ? overridingEager : this.eager;
|
|
||||||
|
|
||||||
Object proxyOrEntity = session.internalLoad(
|
Object proxyOrEntity = session.internalLoad(
|
||||||
getAssociatedEntityName(),
|
getAssociatedEntityName(),
|
||||||
id,
|
id,
|
||||||
eager,
|
isEager( overridingEager ),
|
||||||
isNullable()
|
isNullable()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@ public class JdbcTypeJavaClassMappings {
|
||||||
workMap.put( BigDecimal.class, Types.NUMERIC );
|
workMap.put( BigDecimal.class, Types.NUMERIC );
|
||||||
workMap.put( BigInteger.class, Types.NUMERIC );
|
workMap.put( BigInteger.class, Types.NUMERIC );
|
||||||
workMap.put( Boolean.class, Types.BIT );
|
workMap.put( Boolean.class, Types.BIT );
|
||||||
|
workMap.put( Byte.class, Types.TINYINT );
|
||||||
workMap.put( Short.class, Types.SMALLINT );
|
workMap.put( Short.class, Types.SMALLINT );
|
||||||
workMap.put( Integer.class, Types.INTEGER );
|
workMap.put( Integer.class, Types.INTEGER );
|
||||||
workMap.put( Long.class, Types.BIGINT );
|
workMap.put( Long.class, Types.BIGINT );
|
||||||
|
|
|
@ -230,4 +230,15 @@ public class ReflectHelperTest {
|
||||||
public void test_setMethod_nestedInterfaces_on_superclasses() {
|
public void test_setMethod_nestedInterfaces_on_superclasses() {
|
||||||
assertNotNull( ReflectHelper.findSetterMethod( E.class, "id", String.class ) );
|
assertNotNull( ReflectHelper.findSetterMethod( E.class, "id", String.class ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestForIssue(jiraKey = "HHH-14059")
|
||||||
|
@Test
|
||||||
|
public void test_getConstantValue_UpperCaseEnum() {
|
||||||
|
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( true );
|
||||||
|
|
||||||
|
when( classLoaderServiceMock.classForName( "com.example.UStatus" ) ).thenReturn( (Class) Status.class );
|
||||||
|
Object value = ReflectHelper.getConstantValue( "com.example.UStatus.OFF", sessionFactoryImplementorMock);
|
||||||
|
assertEquals( OFF, value );
|
||||||
|
verify(classLoaderServiceMock, times(1)).classForName( eq("com.example.UStatus") );
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -16,10 +16,11 @@ import org.xml.sax.EntityResolver;
|
||||||
/**
|
/**
|
||||||
* Small helper class that lazily loads DOM and SAX reader and keep them for fast use afterwards.
|
* Small helper class that lazily loads DOM and SAX reader and keep them for fast use afterwards.
|
||||||
*
|
*
|
||||||
* @deprecated Currently only used for integration with HCANN. The rest of Hibernate uses StAX now
|
* This was part of Hibernate ORM core, but moved into the testsuite helpers to not expose
|
||||||
* for XML processing. See {@link org.hibernate.boot.jaxb.internal.stax}
|
* access to the dom4j types. It's also used by Hibernate Envers, so we will need two copies
|
||||||
|
* until Envers is able to remove its reliance on dom4j.
|
||||||
|
* The rest of Hibernate uses StAX now for XML processing. See {@link org.hibernate.boot.jaxb.internal.stax}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public final class XMLHelper {
|
public final class XMLHelper {
|
||||||
private final DocumentFactory documentFactory;
|
private final DocumentFactory documentFactory;
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* 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.criteria.literal;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.PostgreSQL81Dialect;
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.hibernate.testing.SkipForDialect;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
@TestForIssue( jiraKey = "HHH-14077")
|
||||||
|
public class CriteriaLiteralWithSingleQuoteTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void literalSingleQuoteTest() throws Exception {
|
||||||
|
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Object> query = cb.createQuery();
|
||||||
|
query.select( cb.literal( '\'' ) ).from( Student.class );
|
||||||
|
Object object = entityManager.createQuery( query ).getSingleResult();
|
||||||
|
assertEquals( "'", object );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void literalProjectionTest() throws Exception {
|
||||||
|
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Object> query = cb.createQuery();
|
||||||
|
query.multiselect( cb.literal( "' || aValue || '" ) ).from( Student.class );
|
||||||
|
Object object = entityManager.createQuery( query ).getSingleResult();
|
||||||
|
assertEquals( "' || aValue || '", object );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SkipForDialect(value = PostgreSQL81Dialect.class, comment = "PostgreSQL does not support literals in group by statement")
|
||||||
|
public void testLiteralProjectionAndGroupBy() throws Exception {
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
|
||||||
|
final String literal = "' || aValue || '";
|
||||||
|
|
||||||
|
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Object> query = cb.createQuery();
|
||||||
|
query.multiselect( cb.literal( literal ) )
|
||||||
|
.from( Student.class );
|
||||||
|
query.groupBy( cb.literal( literal ) );
|
||||||
|
|
||||||
|
Object object = entityManager.createQuery( query ).getSingleResult();
|
||||||
|
assertEquals( literal, object );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setupData() {
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
Student student = new Student();
|
||||||
|
student.setAValue( "A Value" );
|
||||||
|
entityManager.persist( student );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanupData() {
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory,
|
||||||
|
entityManager -> {
|
||||||
|
entityManager.createQuery( "delete from Student" );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Student.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Student")
|
||||||
|
@Table(name = "Students")
|
||||||
|
public static class Student {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String aValue;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAValue() {
|
||||||
|
return aValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAValue(String value) {
|
||||||
|
this.aValue = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,7 +90,7 @@ public class CompositeIdFkGeneratedValueIdentityTest extends BaseCoreFunctionalT
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "HeadI")
|
||||||
public static class HeadI {
|
public static class HeadI {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -100,7 +100,7 @@ public class CompositeIdFkGeneratedValueIdentityTest extends BaseCoreFunctionalT
|
||||||
private String name;
|
private String name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "NodeI")
|
||||||
@IdClass(NodeI.PK.class)
|
@IdClass(NodeI.PK.class)
|
||||||
public static class NodeI {
|
public static class NodeI {
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ public class CompositeIdFkGeneratedValueIdentityTest extends BaseCoreFunctionalT
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "ComplexNodeI")
|
||||||
@IdClass(ComplexNodeI.PK.class)
|
@IdClass(ComplexNodeI.PK.class)
|
||||||
public static class ComplexNodeI {
|
public static class ComplexNodeI {
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "Head")
|
||||||
public static class Head {
|
public static class Head {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -253,7 +253,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
private String name;
|
private String name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "Node")
|
||||||
@IdClass(CompositeIdFkGeneratedValueTest.Node.PK.class)
|
@IdClass(CompositeIdFkGeneratedValueTest.Node.PK.class)
|
||||||
public static class Node {
|
public static class Node {
|
||||||
|
|
||||||
|
@ -300,8 +300,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Entity(name = "HeadS")
|
||||||
@Entity
|
|
||||||
public static class HeadS {
|
public static class HeadS {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -311,7 +310,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
private String name;
|
private String name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "NodeS")
|
||||||
@IdClass(CompositeIdFkGeneratedValueTest.NodeS.PK.class)
|
@IdClass(CompositeIdFkGeneratedValueTest.NodeS.PK.class)
|
||||||
public static class NodeS {
|
public static class NodeS {
|
||||||
|
|
||||||
|
@ -359,7 +358,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "HeadA")
|
||||||
public static class HeadA {
|
public static class HeadA {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -369,7 +368,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
private String name;
|
private String name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "NodeA")
|
||||||
@IdClass(CompositeIdFkGeneratedValueTest.NodeA.PK.class)
|
@IdClass(CompositeIdFkGeneratedValueTest.NodeA.PK.class)
|
||||||
public static class NodeA {
|
public static class NodeA {
|
||||||
|
|
||||||
|
@ -417,7 +416,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "HeadT")
|
||||||
public static class HeadT {
|
public static class HeadT {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -427,7 +426,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
private String name;
|
private String name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "NodeT")
|
||||||
@IdClass(CompositeIdFkGeneratedValueTest.NodeT.PK.class)
|
@IdClass(CompositeIdFkGeneratedValueTest.NodeT.PK.class)
|
||||||
public static class NodeT {
|
public static class NodeT {
|
||||||
|
|
||||||
|
@ -475,7 +474,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "ComplexNodeS")
|
||||||
@IdClass(CompositeIdFkGeneratedValueTest.ComplexNodeS.PK.class)
|
@IdClass(CompositeIdFkGeneratedValueTest.ComplexNodeS.PK.class)
|
||||||
public static class ComplexNodeS {
|
public static class ComplexNodeS {
|
||||||
|
|
||||||
|
@ -526,7 +525,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "ComplexNodeT")
|
||||||
@IdClass(CompositeIdFkGeneratedValueTest.ComplexNodeT.PK.class)
|
@IdClass(CompositeIdFkGeneratedValueTest.ComplexNodeT.PK.class)
|
||||||
public static class ComplexNodeT {
|
public static class ComplexNodeT {
|
||||||
|
|
||||||
|
@ -577,7 +576,7 @@ public class CompositeIdFkGeneratedValueTest extends BaseCoreFunctionalTestCase
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "ComplexNodeA")
|
||||||
@IdClass(CompositeIdFkGeneratedValueTest.ComplexNodeA.PK.class)
|
@IdClass(CompositeIdFkGeneratedValueTest.ComplexNodeA.PK.class)
|
||||||
public static class ComplexNodeA {
|
public static class ComplexNodeA {
|
||||||
|
|
||||||
|
|
|
@ -306,6 +306,52 @@ public class AttributeConverterTest extends BaseUnitTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-14021")
|
||||||
|
public void testBasicByteUsage() {
|
||||||
|
Configuration cfg = new Configuration();
|
||||||
|
cfg.addAttributeConverter( EnumToByteConverter.class, false );
|
||||||
|
cfg.addAnnotatedClass( Tester4.class );
|
||||||
|
cfg.setProperty( AvailableSettings.HBM2DDL_AUTO, "create-drop" );
|
||||||
|
cfg.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||||
|
|
||||||
|
SessionFactory sf = cfg.buildSessionFactory();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Session session = sf.openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
session.save( new Tester4( 1L, "George", 150, ConvertibleEnum.DEFAULT ) );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
sf.getStatistics().clear();
|
||||||
|
session = sf.openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
session.get( Tester4.class, 1L );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
assertEquals( 0, sf.getStatistics().getEntityUpdateCount() );
|
||||||
|
|
||||||
|
session = sf.openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
Tester4 t4 = (Tester4) session.get( Tester4.class, 1L );
|
||||||
|
t4.convertibleEnum = ConvertibleEnum.VALUE;
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
session = sf.openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
t4 = (Tester4) session.get( Tester4.class, 1L );
|
||||||
|
assertEquals( ConvertibleEnum.VALUE, t4.convertibleEnum );
|
||||||
|
session.delete( t4 );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
sf.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8866")
|
@TestForIssue(jiraKey = "HHH-8866")
|
||||||
public void testEnumConverter() {
|
public void testEnumConverter() {
|
||||||
|
@ -432,6 +478,8 @@ public class AttributeConverterTest extends BaseUnitTestCase {
|
||||||
private String name;
|
private String name;
|
||||||
@Convert( converter = IntegerToVarcharConverter.class )
|
@Convert( converter = IntegerToVarcharConverter.class )
|
||||||
private Integer code;
|
private Integer code;
|
||||||
|
@Convert( converter = EnumToByteConverter.class )
|
||||||
|
private ConvertibleEnum convertibleEnum;
|
||||||
|
|
||||||
public Tester4() {
|
public Tester4() {
|
||||||
}
|
}
|
||||||
|
@ -441,6 +489,13 @@ public class AttributeConverterTest extends BaseUnitTestCase {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Tester4(Long id, String name, Integer code, ConvertibleEnum convertibleEnum) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.code = code;
|
||||||
|
this.convertibleEnum = convertibleEnum;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This class is for mimicking an Instant from Java 8, which a converter might convert to a java.sql.Timestamp
|
// This class is for mimicking an Instant from Java 8, which a converter might convert to a java.sql.Timestamp
|
||||||
|
@ -601,4 +656,17 @@ public class AttributeConverterTest extends BaseUnitTestCase {
|
||||||
return Instant.fromJavaMillis( dbData.getTime() );
|
return Instant.fromJavaMillis( dbData.getTime() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Converter( autoApply = true )
|
||||||
|
public static class EnumToByteConverter implements AttributeConverter<ConvertibleEnum, Byte> {
|
||||||
|
@Override
|
||||||
|
public Byte convertToDatabaseColumn(ConvertibleEnum attribute) {
|
||||||
|
return attribute == null ? null : (byte) attribute.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConvertibleEnum convertToEntityAttribute(Byte dbData) {
|
||||||
|
return dbData == null ? null : ConvertibleEnum.values()[dbData];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import org.hibernate.envers.internal.revisioninfo.RevisionInfoNumberReader;
|
||||||
import org.hibernate.envers.internal.revisioninfo.RevisionInfoQueryCreator;
|
import org.hibernate.envers.internal.revisioninfo.RevisionInfoQueryCreator;
|
||||||
import org.hibernate.envers.internal.synchronization.AuditProcessManager;
|
import org.hibernate.envers.internal.synchronization.AuditProcessManager;
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
import org.hibernate.envers.strategy.AuditStrategy;
|
||||||
import org.hibernate.internal.util.xml.XMLHelper;
|
|
||||||
import org.hibernate.service.Service;
|
import org.hibernate.service.Service;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
|
@ -56,8 +55,6 @@ public interface EnversService extends Service {
|
||||||
|
|
||||||
void initialize(MetadataImplementor metadata, MappingCollector mappingCollector);
|
void initialize(MetadataImplementor metadata, MappingCollector mappingCollector);
|
||||||
|
|
||||||
XMLHelper getXmlHelper();
|
|
||||||
|
|
||||||
GlobalConfiguration getGlobalConfiguration();
|
GlobalConfiguration getGlobalConfiguration();
|
||||||
|
|
||||||
AuditEntitiesConfiguration getAuditEntitiesConfiguration();
|
AuditEntitiesConfiguration getAuditEntitiesConfiguration();
|
||||||
|
|
|
@ -30,7 +30,6 @@ import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
import org.hibernate.envers.strategy.AuditStrategy;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||||
import org.hibernate.internal.util.xml.XMLHelper;
|
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.service.spi.Configurable;
|
import org.hibernate.service.spi.Configurable;
|
||||||
import org.hibernate.service.spi.Stoppable;
|
import org.hibernate.service.spi.Stoppable;
|
||||||
|
@ -74,8 +73,6 @@ public class EnversServiceImpl implements EnversService, Configurable, Stoppable
|
||||||
private RevisionInfoNumberReader revisionInfoNumberReader;
|
private RevisionInfoNumberReader revisionInfoNumberReader;
|
||||||
private ModifiedEntityNamesReader modifiedEntityNamesReader;
|
private ModifiedEntityNamesReader modifiedEntityNamesReader;
|
||||||
|
|
||||||
private XMLHelper xmlHelper;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(Map configurationValues) {
|
public void configure(Map configurationValues) {
|
||||||
if ( configurationValues.containsKey( LEGACY_AUTO_REGISTER ) ) {
|
if ( configurationValues.containsKey( LEGACY_AUTO_REGISTER ) ) {
|
||||||
|
@ -111,7 +108,6 @@ public class EnversServiceImpl implements EnversService, Configurable, Stoppable
|
||||||
|
|
||||||
this.serviceRegistry = metadata.getMetadataBuildingOptions().getServiceRegistry();
|
this.serviceRegistry = metadata.getMetadataBuildingOptions().getServiceRegistry();
|
||||||
this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
||||||
this.xmlHelper = new XMLHelper();
|
|
||||||
|
|
||||||
doInitialize( metadata, mappingCollector, serviceRegistry );
|
doInitialize( metadata, mappingCollector, serviceRegistry );
|
||||||
}
|
}
|
||||||
|
@ -186,11 +182,6 @@ public class EnversServiceImpl implements EnversService, Configurable, Stoppable
|
||||||
return strategy;
|
return strategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public XMLHelper getXmlHelper() {
|
|
||||||
return xmlHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a class by name, preferring our ClassLoader and then the ClassLoaderService.
|
* Load a class by name, preferring our ClassLoader and then the ClassLoaderService.
|
||||||
*
|
*
|
||||||
|
|
|
@ -55,6 +55,8 @@ public class RevisionInfoConfiguration {
|
||||||
private Type revisionInfoTimestampType;
|
private Type revisionInfoTimestampType;
|
||||||
private GlobalConfiguration globalCfg;
|
private GlobalConfiguration globalCfg;
|
||||||
|
|
||||||
|
private XMLHelper xmlHelper;
|
||||||
|
|
||||||
private String revisionPropType;
|
private String revisionPropType;
|
||||||
private String revisionPropSqlType;
|
private String revisionPropSqlType;
|
||||||
|
|
||||||
|
@ -75,7 +77,7 @@ public class RevisionInfoConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Document generateDefaultRevisionInfoXmlMapping() {
|
private Document generateDefaultRevisionInfoXmlMapping() {
|
||||||
final Document document = globalCfg.getEnversService().getXmlHelper().getDocumentFactory().createDocument();
|
final Document document = getXmlHelper().getDocumentFactory().createDocument();
|
||||||
|
|
||||||
final Element classMapping = MetadataTools.createEntity(
|
final Element classMapping = MetadataTools.createEntity(
|
||||||
document,
|
document,
|
||||||
|
@ -120,6 +122,13 @@ public class RevisionInfoConfiguration {
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private XMLHelper getXmlHelper() {
|
||||||
|
if ( this.xmlHelper == null ) {
|
||||||
|
this.xmlHelper = new XMLHelper();
|
||||||
|
}
|
||||||
|
return this.xmlHelper;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates mapping that represents a set of primitive types.<br />
|
* Generates mapping that represents a set of primitive types.<br />
|
||||||
* <code>
|
* <code>
|
||||||
|
@ -158,7 +167,7 @@ public class RevisionInfoConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Element generateRevisionInfoRelationMapping() {
|
private Element generateRevisionInfoRelationMapping() {
|
||||||
final Document document = globalCfg.getEnversService().getXmlHelper().getDocumentFactory().createDocument();
|
final Document document = getXmlHelper().getDocumentFactory().createDocument();
|
||||||
final Element revRelMapping = document.addElement( "key-many-to-one" );
|
final Element revRelMapping = document.addElement( "key-many-to-one" );
|
||||||
revRelMapping.addAttribute( "type", revisionPropType );
|
revRelMapping.addAttribute( "type", revisionPropType );
|
||||||
revRelMapping.addAttribute( "class", revisionInfoEntityName );
|
revRelMapping.addAttribute( "class", revisionInfoEntityName );
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.envers.configuration.internal;
|
||||||
|
|
||||||
|
import org.dom4j.DocumentFactory;
|
||||||
|
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Small helper class that lazily loads DOM factory and keep them for fast use afterwards.
|
||||||
|
*
|
||||||
|
* This was part of Hibernate ORM core, but is used exclusively by Hibernate Envers now:
|
||||||
|
* keep visibility lower so to not expose Dom4j to public API.
|
||||||
|
* The rest of Hibernate uses StAX now for XML processing. See {@link org.hibernate.boot.jaxb.internal.stax}
|
||||||
|
*/
|
||||||
|
final class XMLHelper {
|
||||||
|
private final DocumentFactory documentFactory;
|
||||||
|
|
||||||
|
XMLHelper() {
|
||||||
|
PrivilegedAction<DocumentFactory> action = new PrivilegedAction<DocumentFactory>() {
|
||||||
|
public DocumentFactory run() {
|
||||||
|
final ClassLoader originalTccl = Thread.currentThread().getContextClassLoader();
|
||||||
|
try {
|
||||||
|
// We need to make sure we get DocumentFactory
|
||||||
|
// loaded from the same ClassLoader that loads
|
||||||
|
// Hibernate classes, to make sure we get the
|
||||||
|
// proper version of DocumentFactory, This class
|
||||||
|
// is "internal", and should only be used for XML
|
||||||
|
// files generated by Envers.
|
||||||
|
|
||||||
|
// Using the (Hibernate) ClassLoader that loads
|
||||||
|
// this Class will avoid collisions in the case
|
||||||
|
// that DocumentFactory can be loaded from,
|
||||||
|
// for example, the application ClassLoader.
|
||||||
|
Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader() );
|
||||||
|
return DocumentFactory.getInstance();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Thread.currentThread().setContextClassLoader( originalTccl );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.documentFactory = System.getSecurityManager() != null
|
||||||
|
? AccessController.doPrivileged( action )
|
||||||
|
: action.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentFactory getDocumentFactory() {
|
||||||
|
return documentFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
|
import groovy.json.JsonSlurper
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
|
@ -9,11 +13,52 @@ apply from: rootProject.file( 'gradle/base-information.gradle' )
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'distribution'
|
apply plugin: 'distribution'
|
||||||
|
|
||||||
|
ext {
|
||||||
|
if ( !project.hasProperty( 'gitRemote' ) ) {
|
||||||
|
gitRemote = 'origin'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
idea.module {
|
idea.module {
|
||||||
}
|
}
|
||||||
|
|
||||||
final File documentationDir = mkdir( "${project.buildDir}/documentation" );
|
final File documentationDir = mkdir( "${project.buildDir}/documentation" );
|
||||||
|
|
||||||
|
task releaseChecks() {
|
||||||
|
doFirst {
|
||||||
|
if ( !project.hasProperty('releaseVersion') || !project.hasProperty('developmentVersion')
|
||||||
|
|| !project.hasProperty('gitRemote') ||!project.hasProperty('gitBranch') ) {
|
||||||
|
throw new GradleException(
|
||||||
|
"Release tasks require all of the following properties to be set:"
|
||||||
|
+ "'releaseVersion', 'developmentVersion', 'gitRemote', 'gitBranch'."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.lifecycle( "Checking that the working tree is clean..." )
|
||||||
|
String uncommittedFiles = executeGitCommand( 'status', '--porcelain' )
|
||||||
|
if ( !uncommittedFiles.isEmpty() ) {
|
||||||
|
throw new GradleException(
|
||||||
|
"Cannot release because there are uncommitted or untracked files in the working tree."
|
||||||
|
+ "\nCommit or stash your changes first."
|
||||||
|
+ "\nUncommitted files:\n" + uncommittedFiles
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.lifecycle( "Switching to branch '${project.gitBranch}'..." )
|
||||||
|
executeGitCommand( 'checkout', project.gitBranch )
|
||||||
|
|
||||||
|
logger.lifecycle( "Checking that all commits are pushed..." )
|
||||||
|
String diffWithUpstream = executeGitCommand( 'diff', '@{u}' )
|
||||||
|
if ( !diffWithUpstream.isEmpty() ) {
|
||||||
|
throw new GradleException(
|
||||||
|
"Cannot release because there are commits on the branch to release that haven't been pushed yet."
|
||||||
|
+ "\nPush your commits to the branch to release first."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assembles all documentation into the {buildDir}/documentation directory.
|
* Assembles all documentation into the {buildDir}/documentation directory.
|
||||||
*
|
*
|
||||||
|
@ -243,5 +288,181 @@ artifacts {
|
||||||
bundles distZip
|
bundles distZip
|
||||||
}
|
}
|
||||||
|
|
||||||
task release( dependsOn: [uploadDocumentation, uploadBundlesSourceForge] )
|
task release( dependsOn: [releaseChecks, uploadDocumentation, uploadBundlesSourceForge] )
|
||||||
|
|
||||||
|
task changeLogFile( dependsOn: [releaseChecks] ) {
|
||||||
|
group = "Release"
|
||||||
|
description = "Updates the changelog.txt file"
|
||||||
|
|
||||||
|
doFirst {
|
||||||
|
logger.lifecycle( "Appending version '${project.releaseVersion}' to changelog..." )
|
||||||
|
ChangeLogFile.update( ormVersion.fullName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
task addVersionCommit( dependsOn: [changeLogFile] ) {
|
||||||
|
group = "Release"
|
||||||
|
description = "Adds a commit for the released version and push the changes to github"
|
||||||
|
doFirst{
|
||||||
|
logger.lifecycle( "Updating version to '${project.releaseVersion}'..." )
|
||||||
|
project.ormVersionFile.text = "hibernateVersion=${project.releaseVersion}"
|
||||||
|
|
||||||
|
logger.lifecycle( "Adding commit to update version to '${project.releaseVersion}'..." )
|
||||||
|
executeGitCommand( 'add', '.' )
|
||||||
|
executeGitCommand( 'commit', '-m', project.ormVersion.fullName )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release.mustRunAfter addVersionCommit
|
||||||
|
|
||||||
|
rootProject.subprojects.each { Project subProject ->
|
||||||
|
if ( !this.name.equals( subProject.name ) ) {
|
||||||
|
if ( subProject.tasks.findByName( 'release' ) ) {
|
||||||
|
this.tasks.release.dependsOn( subProject.tasks.release )
|
||||||
|
subProject.tasks.release.mustRunAfter( this.tasks.addVersionCommit )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task ciRelease( dependsOn: [releaseChecks, addVersionCommit, release] ) {
|
||||||
|
group = "Release"
|
||||||
|
description = "Performs a release: the hibernate version is set and the changelog.txt file updated, the changes are pushed to github, then the release is performed, tagged and the hibernate version is set to the development one."
|
||||||
|
doLast {
|
||||||
|
String tag = null
|
||||||
|
if ( !project.hasProperty( 'noTag' ) ) {
|
||||||
|
tag = project.ormVersion.fullName
|
||||||
|
// the release is tagged and the tag is pushed to github
|
||||||
|
if ( tag.endsWith( ".Final" ) ) {
|
||||||
|
tag = tag.replace( ".Final", "" )
|
||||||
|
}
|
||||||
|
logger.lifecycle( "Tagging '${tag}'..." )
|
||||||
|
executeGitCommand( 'tag', tag )
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.lifecycle( "Adding commit to update version to '${project.developmentVersion}'..." )
|
||||||
|
project.ormVersionFile.text = "hibernateVersion=${project.developmentVersion}"
|
||||||
|
executeGitCommand( 'add', '.')
|
||||||
|
executeGitCommand( 'commit', '-m', project.developmentVersion )
|
||||||
|
|
||||||
|
if ( tag != null ) {
|
||||||
|
logger.lifecycle("Pushing branch and tag to remote '${project.gitRemote}'...")
|
||||||
|
executeGitCommand( 'push', '--atomic', project.gitRemote , project.gitBranch, tag )
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger.lifecycle("Pushing branch to remote '${project.gitRemote}'...")
|
||||||
|
executeGitCommand( 'push', project.gitRemote , project.gitBranch )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String executeGitCommand(Object ... subcommand){
|
||||||
|
List<Object> command = ['git']
|
||||||
|
Collections.addAll( command, subcommand )
|
||||||
|
def proc = command.execute()
|
||||||
|
def code = proc.waitFor()
|
||||||
|
def stdout = inputStreamToString( proc.getInputStream() )
|
||||||
|
def stderr = inputStreamToString( proc.getErrorStream() )
|
||||||
|
if ( code != 0 ) {
|
||||||
|
throw new GradleException( "An error occurred while executing " + command + "\n\nstdout:\n" + stdout + "\n\nstderr:\n" + stderr )
|
||||||
|
}
|
||||||
|
return stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
static String inputStreamToString(InputStream inputStream) {
|
||||||
|
inputStream.withCloseable { ins ->
|
||||||
|
new BufferedInputStream(ins).withCloseable { bis ->
|
||||||
|
new ByteArrayOutputStream().withCloseable { buf ->
|
||||||
|
int result = bis.read();
|
||||||
|
while (result != -1) {
|
||||||
|
buf.write((byte) result);
|
||||||
|
result = bis.read();
|
||||||
|
}
|
||||||
|
return buf.toString( StandardCharsets.UTF_8.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChangeLogFile {
|
||||||
|
|
||||||
|
// Get the Release Notes from Jira and add them to the Hibernate changelog.txt file
|
||||||
|
static void update(String releaseVersion) {
|
||||||
|
def text = ""
|
||||||
|
File changelog = new File( "changelog.txt" )
|
||||||
|
def newReleaseNoteBlock = getNewReleaseNoteBlock(releaseVersion)
|
||||||
|
changelog.eachLine {
|
||||||
|
line ->
|
||||||
|
if ( line.startsWith( "Note:" ) ) {
|
||||||
|
text += line + System.lineSeparator() + System.lineSeparator() + newReleaseNoteBlock
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text += line + System.lineSeparator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changelog.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Release Notes from Jira
|
||||||
|
static String getNewReleaseNoteBlock(String releaseVersion) {
|
||||||
|
def restReleaseVersion;
|
||||||
|
if ( releaseVersion.endsWith( ".Final" ) ) {
|
||||||
|
restReleaseVersion = releaseVersion.replace( ".Final", "" )
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
restReleaseVersion = releaseVersion
|
||||||
|
}
|
||||||
|
def apiString = "https://hibernate.atlassian.net/rest/api/2/search/?jql=project=HHH%20AND%20fixVersion=${restReleaseVersion}%20order%20by%20issuetype%20ASC"
|
||||||
|
def apiUrl = new URL( apiString )
|
||||||
|
def releseNotes = new JsonSlurper().parse( apiUrl )
|
||||||
|
|
||||||
|
|
||||||
|
def releaseDate = new Date().format( 'MMMM dd, YYYY' )
|
||||||
|
def versionId = releseNotes.issues.get( 0 ).fields.fixVersions.get( 0 ).id
|
||||||
|
ReleaseNote releaseNotes = new ReleaseNote( releaseVersion, releaseDate, versionId )
|
||||||
|
|
||||||
|
def issuetype
|
||||||
|
releseNotes.issues.each {
|
||||||
|
issue ->
|
||||||
|
if ( issuetype != issue.fields.issuetype.name ) {
|
||||||
|
issuetype = issue.fields.issuetype.name
|
||||||
|
releaseNotes.addEmptyLine();
|
||||||
|
releaseNotes.addLine( "** ${issue.fields.issuetype.name}" )
|
||||||
|
}
|
||||||
|
releaseNotes.addLine( " * [" + issue.key + "] - " + issue.fields.summary )
|
||||||
|
}
|
||||||
|
releaseNotes.addEmptyLine()
|
||||||
|
return releaseNotes.notes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReleaseNote {
|
||||||
|
String notes;
|
||||||
|
String notesHeaderSeparator = "------------------------------------------------------------------------------------------------------------------------"
|
||||||
|
|
||||||
|
ReleaseNote(String releaseVersion, String releaseDate, String versionId) {
|
||||||
|
notes = "Changes in ${releaseVersion} (${releaseDate})" + System.lineSeparator()
|
||||||
|
addHeaderSeparator()
|
||||||
|
addEmptyLine()
|
||||||
|
addLine( "https://hibernate.atlassian.net/projects/HHH/versions/${versionId}" )
|
||||||
|
}
|
||||||
|
|
||||||
|
void addLine(String text) {
|
||||||
|
notes += text + System.lineSeparator()
|
||||||
|
}
|
||||||
|
|
||||||
|
void addHeaderSeparator() {
|
||||||
|
addLine( notesHeaderSeparator )
|
||||||
|
}
|
||||||
|
|
||||||
|
void addEmptyLine() {
|
||||||
|
notes += System.lineSeparator()
|
||||||
|
}
|
||||||
|
|
||||||
|
void addEmptyLines(int numberOfLines) {
|
||||||
|
for ( i in 1..numberOfLines ) {
|
||||||
|
notes += System.lineSeparator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue