Merge branch master into wip/6.0
This commit is contained in:
commit
90f18b3137
|
@ -21,19 +21,18 @@ While we try to keep requirements for contributing to a minimum, there are a few
|
|||
we ask that you mind.
|
||||
|
||||
For code contributions, these guidelines include:
|
||||
* respect the project code style - find templates for [Eclipse](https://community.jboss.org/docs/DOC-16649)
|
||||
and [IntelliJ IDEA](https://community.jboss.org/docs/DOC-15468)
|
||||
* respect the project code style - find templates for [IntelliJ IDEA](https://community.jboss.org/docs/DOC-15468) or [Eclipse](https://community.jboss.org/docs/DOC-16649)
|
||||
* have a corresponding JIRA issue and the key for this JIRA issue should be used in the commit message
|
||||
* have a set of appropriate tests. For bug reports, the tests reproduce the initial reported bug
|
||||
and illustrates that the solution actually fixes the bug. For features/enhancements, the
|
||||
tests illustrate the feature working as intended. In both cases the tests are incorporated into
|
||||
the project to protect against regressions.
|
||||
the project to protect against regressions
|
||||
* if applicable, documentation is updated to reflect the introduced changes
|
||||
* the code compiles and the tests pass (`./gradlew clean build`)
|
||||
|
||||
For documentation contributions, mainly just respect the project code style, especially in regards
|
||||
to use of tabs - as mentioned above, code style templates are available for both Eclipse and IntelliJ
|
||||
IDEA IDEs. Ideally these contributions would also have a corresponding JIRA issue, although this
|
||||
to use of tabs - as mentioned above, code style templates are available for both IntelliJ IDEA and Eclipse
|
||||
IDEs. Ideally these contributions would also have a corresponding JIRA issue, although this
|
||||
is less necessary for documentation contributions.
|
||||
|
||||
|
||||
|
@ -42,12 +41,12 @@ is less necessary for documentation contributions.
|
|||
If you are just getting started with Git, GitHub and/or contributing to Hibernate via
|
||||
GitHub there are a few pre-requisite steps to follow:
|
||||
|
||||
* Make sure you have a [Hibernate JIRA account](https://hibernate.atlassian.net)
|
||||
* Make sure you have a [GitHub account](https://github.com/signup/free)
|
||||
* [Fork](https://help.github.com/articles/fork-a-repo) the Hibernate repository. As discussed in
|
||||
* make sure you have a [Hibernate JIRA account](https://hibernate.atlassian.net)
|
||||
* make sure you have a [GitHub account](https://github.com/signup/free)
|
||||
* [fork](https://help.github.com/articles/fork-a-repo) the Hibernate repository. As discussed in
|
||||
the linked page, this also includes:
|
||||
* [Set](https://help.github.com/articles/set-up-git) up your local git install
|
||||
* Clone your fork
|
||||
* [set up your local git install](https://help.github.com/articles/set-up-git)
|
||||
* clone your fork
|
||||
* See the wiki pages for setting up your IDE, whether you use
|
||||
[IntelliJ IDEA](https://community.jboss.org/wiki/ContributingToHibernateUsingIntelliJ)
|
||||
or [Eclipse](https://community.jboss.org/wiki/ContributingToHibernateUsingEclipse)<sup>(1)</sup>.
|
||||
|
@ -59,7 +58,7 @@ Create a [topic branch](http://git-scm.com/book/en/Git-Branching-Branching-Workf
|
|||
on which you will work. The convention is to incorporate the JIRA issue key in the name of this branch,
|
||||
although this is more of a mnemonic strategy than a hard-and-fast rule - but doing so helps:
|
||||
* remember what each branch is for
|
||||
* isolate the work from other contributions you may be working on.
|
||||
* isolate the work from other contributions you may be working on
|
||||
|
||||
_If there is not already a JIRA issue covering the work you want to do, create one._
|
||||
|
||||
|
@ -69,17 +68,17 @@ on the JIRA HHH-123 : `git checkout -b HHH-123 master`
|
|||
|
||||
## Code
|
||||
|
||||
Do yo thing!
|
||||
Do your thing!
|
||||
|
||||
|
||||
## Commit
|
||||
|
||||
* Make commits of logical units.
|
||||
* Be sure to use the JIRA issue key in the commit message. This is how JIRA will pick
|
||||
up the related commits and display them on the JIRA issue.
|
||||
* Make sure you have added the necessary tests for your changes.
|
||||
* Run _all_ the tests to assure nothing else was accidentally broken.
|
||||
* Make sure your source does not violate the checkstyles.
|
||||
* make commits of logical units
|
||||
* be sure to **use the JIRA issue key** in the commit message. This is how JIRA will pick
|
||||
up the related commits and display them on the JIRA issue
|
||||
* make sure you have added the necessary tests for your changes
|
||||
* run _all_ the tests to assure nothing else was accidentally broken
|
||||
* make sure your source does not violate the _checkstyles_
|
||||
|
||||
_Prior to committing, if you want to pull in the latest upstream changes (highly
|
||||
appreciated btw), please use rebasing rather than merging. Merging creates
|
||||
|
@ -87,10 +86,9 @@ appreciated btw), please use rebasing rather than merging. Merging creates
|
|||
|
||||
## Submit
|
||||
|
||||
* Push your changes to the topic branch in your fork of the repository.
|
||||
* Initiate a [pull request](http://help.github.com/articles/creating-a-pull-request)
|
||||
* Update the JIRA issue, adding a comment including a link to the created pull request
|
||||
_if the JIRA key was not used in the commit message_.
|
||||
* push your changes to the topic branch in your fork of the repository
|
||||
* initiate a [pull request](http://help.github.com/articles/creating-a-pull-request)
|
||||
* update the JIRA issue by providing the PR link in the **Pull Request** column on the right
|
||||
|
||||
|
||||
It is important that this topic branch on your fork:
|
||||
|
@ -98,9 +96,9 @@ It is important that this topic branch on your fork:
|
|||
* be isolated to just the work on this one JIRA issue, or multiple issues if they are
|
||||
related and also fixed/implemented by this work. The main point is to not push
|
||||
commits for more than one PR to a single branch - GitHub PRs are linked to
|
||||
a branch rather than specific commits.
|
||||
a branch rather than specific commits
|
||||
* remain until the PR is closed. Once the underlying branch is deleted the corresponding
|
||||
PR will be closed, if not already, and the changes will be lost.
|
||||
PR will be closed, if not already, and the changes will be lost
|
||||
|
||||
# Notes
|
||||
<sup>(1)</sup> Gradle `eclipse` plugin is no longer supported, so the recommended way to import the project in your IDE is with the proper IDE tools/plugins. Don't try to run `./gradlew clean eclipse --refresh-dependencies` from the command line as you'll get an error because `eclipse` no longer exists
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Keep all these properties in sync unless you know what you are doing!
|
||||
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8
|
||||
toolchain.compiler.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8
|
||||
# Needs add-opens because of https://github.com/gradle/gradle/issues/15538
|
||||
toolchain.compiler.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8 --add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
|
||||
toolchain.javadoc.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8
|
||||
toolchain.launcher.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8
|
||||
|
||||
|
@ -13,4 +14,4 @@ toolchain.launcher.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOf
|
|||
org.gradle.java.installations.auto-detect=false
|
||||
# We can't rely on Gradle's auto-download of JDKs as it doesn't support EA releases.
|
||||
# See https://github.com/gradle/gradle/blob/fc7ea24f3c525d8d12a4346eb0f15976a6be9414/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/install/internal/AdoptOpenJdkRemoteBinary.java#L114
|
||||
org.gradle.java.installations.auto-download=false
|
||||
org.gradle.java.installations.auto-download=false
|
||||
|
|
|
@ -251,7 +251,7 @@ if ( gradle.ext.javaToolchainEnabled ) {
|
|||
}
|
||||
|
||||
// Configure JVM Options
|
||||
jvmArgs.addAll( getProperty( 'toolchain.launcher.jvmargs' ).toString().split( ' ' ) )
|
||||
jvmArgs( getProperty( 'toolchain.launcher.jvmargs' ).toString().split( ' ' ) )
|
||||
|
||||
// Display version of Java tools
|
||||
doFirst {
|
||||
|
|
|
@ -23,7 +23,7 @@ ext {
|
|||
elVersion = '3.0.1-b09'
|
||||
|
||||
cdiVersion = '2.0'
|
||||
weldVersion = '3.0.0.Final'
|
||||
weldVersion = '3.1.5.Final'
|
||||
|
||||
javassistVersion = '3.27.0-GA'
|
||||
byteBuddyVersion = '1.10.17'
|
||||
|
@ -49,6 +49,8 @@ ext {
|
|||
|
||||
antlrVersion = '4.8-1'
|
||||
|
||||
micrometerVersion = '1.6.1'
|
||||
|
||||
libraries = [
|
||||
// Ant
|
||||
ant: 'org.apache.ant:ant:1.8.2',
|
||||
|
@ -155,6 +157,7 @@ ext {
|
|||
vibur: "org.vibur:vibur-dbcp:25.0",
|
||||
agroal_api: "io.agroal:agroal-api:${agroalVersion}",
|
||||
agroal_pool: "io.agroal:agroal-pool:${agroalVersion}",
|
||||
micrometer: "io.micrometer:micrometer-core:1.6.1",
|
||||
|
||||
atomikos: "com.atomikos:transactions:4.0.6",
|
||||
atomikos_jta: "com.atomikos:transactions-jta:4.0.6",
|
||||
|
|
|
@ -263,6 +263,15 @@ task generateEnversStaticMetamodel(
|
|||
|
||||
test {
|
||||
systemProperty 'file.encoding', 'utf-8'
|
||||
|
||||
if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) {
|
||||
// See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set
|
||||
jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] )
|
||||
// Weld needs this to generate proxies
|
||||
jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] )
|
||||
jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] )
|
||||
}
|
||||
|
||||
beforeTest { descriptor ->
|
||||
//println "Starting test: " + descriptor
|
||||
}
|
||||
|
|
|
@ -201,23 +201,24 @@ public class ScanningCoordinator {
|
|||
nonLocatedMappingFileNames.addAll( explicitMappingFileNames );
|
||||
}
|
||||
|
||||
for ( MappingFileDescriptor mappingFileDescriptor : scanResult.getLocatedMappingFiles() ) {
|
||||
managedResources.addXmlBinding( xmlMappingBinderAccess.bind( mappingFileDescriptor.getStreamAccess() ) );
|
||||
nonLocatedMappingFileNames.remove( mappingFileDescriptor.getName() );
|
||||
}
|
||||
|
||||
for ( String name : nonLocatedMappingFileNames ) {
|
||||
final URL url = classLoaderService.locateResource( name );
|
||||
if ( url == null ) {
|
||||
throw new MappingException(
|
||||
"Unable to resolve explicitly named mapping-file : " + name,
|
||||
new Origin( SourceType.RESOURCE, name )
|
||||
);
|
||||
if ( xmlMappingBinderAccess != null ) { // xml mapping is not disabled
|
||||
for ( MappingFileDescriptor mappingFileDescriptor : scanResult.getLocatedMappingFiles() ) {
|
||||
managedResources.addXmlBinding( xmlMappingBinderAccess.bind( mappingFileDescriptor.getStreamAccess() ) );
|
||||
nonLocatedMappingFileNames.remove( mappingFileDescriptor.getName() );
|
||||
}
|
||||
final UrlInputStreamAccess inputStreamAccess = new UrlInputStreamAccess( url );
|
||||
managedResources.addXmlBinding( xmlMappingBinderAccess.bind( inputStreamAccess ) );
|
||||
}
|
||||
|
||||
for ( String name : nonLocatedMappingFileNames ) {
|
||||
final URL url = classLoaderService.locateResource( name );
|
||||
if ( url == null ) {
|
||||
throw new MappingException(
|
||||
"Unable to resolve explicitly named mapping-file : " + name,
|
||||
new Origin( SourceType.RESOURCE, name )
|
||||
);
|
||||
}
|
||||
final UrlInputStreamAccess inputStreamAccess = new UrlInputStreamAccess( url );
|
||||
managedResources.addXmlBinding( xmlMappingBinderAccess.bind( inputStreamAccess ) );
|
||||
}
|
||||
}
|
||||
|
||||
// classes and packages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -289,28 +289,30 @@ public class MetadataBuildingProcess {
|
|||
|
||||
metadataCollector.processSecondPasses( rootMetadataBuildingContext );
|
||||
|
||||
Iterable<AdditionalJaxbMappingProducer> producers = classLoaderService.loadJavaServices( AdditionalJaxbMappingProducer.class );
|
||||
if ( producers != null ) {
|
||||
final EntityHierarchyBuilder hierarchyBuilder = new EntityHierarchyBuilder();
|
||||
// final MappingBinder mappingBinder = new MappingBinder( true );
|
||||
// We need to disable validation here. It seems Envers is not producing valid (according to schema) XML
|
||||
final MappingBinder mappingBinder = options.isXmlMappingEnabled() ? new MappingBinder( classLoaderService, false ) : null;
|
||||
for ( AdditionalJaxbMappingProducer producer : producers ) {
|
||||
log.tracef( "Calling AdditionalJaxbMappingProducer : %s", producer );
|
||||
Collection<MappingDocument> additionalMappings = producer.produceAdditionalMappings(
|
||||
metadataCollector,
|
||||
jandexView,
|
||||
mappingBinder,
|
||||
rootMetadataBuildingContext
|
||||
);
|
||||
for ( MappingDocument mappingDocument : additionalMappings ) {
|
||||
hierarchyBuilder.indexMappingDocument( mappingDocument );
|
||||
if ( options.isXmlMappingEnabled() ) {
|
||||
Iterable<AdditionalJaxbMappingProducer> producers = classLoaderService.loadJavaServices( AdditionalJaxbMappingProducer.class );
|
||||
if ( producers != null ) {
|
||||
final EntityHierarchyBuilder hierarchyBuilder = new EntityHierarchyBuilder();
|
||||
// final MappingBinder mappingBinder = new MappingBinder( true );
|
||||
// We need to disable validation here. It seems Envers is not producing valid (according to schema) XML
|
||||
final MappingBinder mappingBinder = new MappingBinder( classLoaderService, false );
|
||||
for ( AdditionalJaxbMappingProducer producer : producers ) {
|
||||
log.tracef( "Calling AdditionalJaxbMappingProducer : %s", producer );
|
||||
Collection<MappingDocument> additionalMappings = producer.produceAdditionalMappings(
|
||||
metadataCollector,
|
||||
jandexView,
|
||||
mappingBinder,
|
||||
rootMetadataBuildingContext
|
||||
);
|
||||
for ( MappingDocument mappingDocument : additionalMappings ) {
|
||||
hierarchyBuilder.indexMappingDocument( mappingDocument );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModelBinder binder = ModelBinder.prepare( rootMetadataBuildingContext );
|
||||
for ( EntityHierarchySourceImpl entityHierarchySource : hierarchyBuilder.buildHierarchies() ) {
|
||||
binder.bindEntityHierarchy( entityHierarchySource );
|
||||
ModelBinder binder = ModelBinder.prepare( rootMetadataBuildingContext );
|
||||
for ( EntityHierarchySourceImpl entityHierarchySource : hierarchyBuilder.buildHierarchies() ) {
|
||||
binder.bindEntityHierarchy( entityHierarchySource );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.hibernate.proxy.ProxyConfiguration;
|
|||
import org.hibernate.proxy.ProxyFactory;
|
||||
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.ClassFileVersion;
|
||||
import net.bytebuddy.TypeCache;
|
||||
import net.bytebuddy.asm.AsmVisitorWrapper.ForDeclaredMethods;
|
||||
import net.bytebuddy.asm.MemberSubstitution;
|
||||
|
@ -71,7 +72,11 @@ public final class ByteBuddyState {
|
|||
private final TypeCache<TypeCache.SimpleKey> basicProxyCache;
|
||||
|
||||
ByteBuddyState() {
|
||||
this.byteBuddy = new ByteBuddy().with( TypeValidation.DISABLED );
|
||||
this( ClassFileVersion.ofThisVm( ClassFileVersion.JAVA_V8 ) );
|
||||
}
|
||||
|
||||
ByteBuddyState(ClassFileVersion classFileVersion) {
|
||||
this.byteBuddy = new ByteBuddy( classFileVersion ).with( TypeValidation.DISABLED );
|
||||
|
||||
this.proxyCache = new TypeCache.WithInlineExpunction<TypeCache.SimpleKey>( TypeCache.Sort.WEAK );
|
||||
this.basicProxyCache = new TypeCache.WithInlineExpunction<TypeCache.SimpleKey>( TypeCache.Sort.WEAK );
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.hibernate.bytecode.spi.ProxyFactoryFactory;
|
|||
import org.hibernate.bytecode.spi.ReflectionOptimizer;
|
||||
import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyHelper;
|
||||
|
||||
import net.bytebuddy.ClassFileVersion;
|
||||
import net.bytebuddy.NamingStrategy;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
|
@ -49,8 +50,21 @@ public class BytecodeProviderImpl implements BytecodeProvider {
|
|||
|
||||
private final ByteBuddyProxyHelper byteBuddyProxyHelper;
|
||||
|
||||
/**
|
||||
* Constructs a ByteBuddy BytecodeProvider instance which attempts to auto-detect the target JVM version
|
||||
* from the currently running one, with a fallback on Java 8.
|
||||
*/
|
||||
public BytecodeProviderImpl() {
|
||||
this.byteBuddyState = new ByteBuddyState();
|
||||
this( ClassFileVersion.ofThisVm( ClassFileVersion.JAVA_V8 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ByteBuddy BytecodeProvider instance which aims to produce code compatible
|
||||
* with the specified target JVM version.
|
||||
* @param targetCompatibleJVM
|
||||
*/
|
||||
public BytecodeProviderImpl(ClassFileVersion targetCompatibleJVM) {
|
||||
this.byteBuddyState = new ByteBuddyState( targetCompatibleJVM );
|
||||
this.byteBuddyProxyHelper = new ByteBuddyProxyHelper( byteBuddyState );
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.hibernate.annotations.LazyGroup;
|
|||
import org.hibernate.annotations.Loader;
|
||||
import org.hibernate.annotations.ManyToAny;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
import org.hibernate.annotations.OptimisticLock;
|
||||
import org.hibernate.annotations.OrderBy;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
|
@ -104,6 +105,7 @@ import org.hibernate.mapping.KeyValue;
|
|||
import org.hibernate.mapping.ManyToOne;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
|
||||
|
@ -557,7 +559,9 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
//TODO reduce tableBinder != null and oneToMany
|
||||
XClass collectionType = getCollectionType();
|
||||
if ( inheritanceStatePerClass == null) throw new AssertionFailure( "inheritanceStatePerClass not set" );
|
||||
if ( inheritanceStatePerClass == null) {
|
||||
throw new AssertionFailure( "inheritanceStatePerClass not set" );
|
||||
}
|
||||
SecondPass sp = getSecondPass(
|
||||
fkJoinColumns,
|
||||
joinColumns,
|
||||
|
@ -606,7 +610,9 @@ public abstract class CollectionBinder {
|
|||
binder.setUpdatable( updatable );
|
||||
Property prop = binder.makeProperty();
|
||||
//we don't care about the join stuffs because the column is on the association table.
|
||||
if (! declaringClassSet) throw new AssertionFailure( "DeclaringClass is not set in CollectionBinder while binding" );
|
||||
if (! declaringClassSet) {
|
||||
throw new AssertionFailure( "DeclaringClass is not set in CollectionBinder while binding" );
|
||||
}
|
||||
propertyHolder.addProperty( prop, declaringClass );
|
||||
}
|
||||
|
||||
|
@ -614,7 +620,7 @@ public abstract class CollectionBinder {
|
|||
boolean hadOrderBy = false;
|
||||
boolean hadExplicitSort = false;
|
||||
|
||||
Class<? extends Comparator> comparatorClass = null;
|
||||
Class<? extends Comparator<?>> comparatorClass = null;
|
||||
|
||||
if ( jpaOrderBy == null && sqlOrderBy == null ) {
|
||||
if ( deprecatedSort != null ) {
|
||||
|
@ -779,8 +785,9 @@ public abstract class CollectionBinder {
|
|||
final TableBinder assocTableBinder,
|
||||
final MetadataBuildingContext buildingContext) {
|
||||
return new CollectionSecondPass( buildingContext, collection ) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) throws MappingException {
|
||||
public void secondPass(Map persistentClasses, Map inheritedMetas) throws MappingException {
|
||||
bindStarToManySecondPass(
|
||||
persistentClasses,
|
||||
collType,
|
||||
|
@ -803,7 +810,7 @@ public abstract class CollectionBinder {
|
|||
* return true if it's a Fk, false if it's an association table
|
||||
*/
|
||||
protected boolean bindStarToManySecondPass(
|
||||
Map persistentClasses,
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
XClass collType,
|
||||
Ejb3JoinColumn[] fkJoinColumns,
|
||||
Ejb3JoinColumn[] keyColumns,
|
||||
|
@ -815,7 +822,7 @@ public abstract class CollectionBinder {
|
|||
TableBinder associationTableBinder,
|
||||
boolean ignoreNotFound,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
PersistentClass persistentClass = (PersistentClass) persistentClasses.get( collType.getName() );
|
||||
PersistentClass persistentClass = persistentClasses.get( collType.getName() );
|
||||
boolean reversePropertyInJoin = false;
|
||||
if ( persistentClass != null && StringHelper.isNotEmpty( this.mappedBy ) ) {
|
||||
try {
|
||||
|
@ -876,7 +883,7 @@ public abstract class CollectionBinder {
|
|||
|
||||
protected void bindOneToManySecondPass(
|
||||
Collection collection,
|
||||
Map persistentClasses,
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
Ejb3JoinColumn[] fkJoinColumns,
|
||||
XClass collectionType,
|
||||
boolean cascadeDeleteEnabled,
|
||||
|
@ -898,7 +905,7 @@ public abstract class CollectionBinder {
|
|||
oneToMany.setIgnoreNotFound( ignoreNotFound );
|
||||
|
||||
String assocClass = oneToMany.getReferencedEntityName();
|
||||
PersistentClass associatedClass = (PersistentClass) persistentClasses.get( assocClass );
|
||||
PersistentClass associatedClass = persistentClasses.get( assocClass );
|
||||
if ( jpaOrderBy != null ) {
|
||||
final String orderByFragment = buildOrderByClauseFromHql(
|
||||
jpaOrderBy.value(),
|
||||
|
@ -1215,8 +1222,8 @@ public abstract class CollectionBinder {
|
|||
key.setForeignKeyName( StringHelper.nullIfEmpty( collectionTableAnn.foreignKey().name() ) );
|
||||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( collectionTableAnn.foreignKey().foreignKeyDefinition() ) );
|
||||
if ( key.getForeignKeyName() == null &&
|
||||
key.getForeignKeyDefinition() == null &&
|
||||
collectionTableAnn.joinColumns().length == 1 ) {
|
||||
key.getForeignKeyDefinition() == null &&
|
||||
collectionTableAnn.joinColumns().length == 1 ) {
|
||||
JoinColumn joinColumn = collectionTableAnn.joinColumns()[0];
|
||||
key.setForeignKeyName( StringHelper.nullIfEmpty( joinColumn.foreignKey().name() ) );
|
||||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumn.foreignKey().foreignKeyDefinition() ) );
|
||||
|
@ -1261,15 +1268,25 @@ public abstract class CollectionBinder {
|
|||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( fkOverride.foreignKeyDefinition() ) );
|
||||
}
|
||||
else {
|
||||
final JoinColumn joinColumnAnn = property.getAnnotation( JoinColumn.class );
|
||||
if ( joinColumnAnn != null ) {
|
||||
if ( joinColumnAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT
|
||||
|| joinColumnAnn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) {
|
||||
key.setForeignKeyName( "none" );
|
||||
}
|
||||
else {
|
||||
key.setForeignKeyName( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().name() ) );
|
||||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().foreignKeyDefinition() ) );
|
||||
final OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class );
|
||||
final OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
|
||||
if ( oneToManyAnn != null && !oneToManyAnn.mappedBy().isEmpty()
|
||||
&& ( onDeleteAnn == null || onDeleteAnn.action() != OnDeleteAction.CASCADE ) ) {
|
||||
// foreign key should be up to @ManyToOne side
|
||||
// @OnDelete generate "on delete cascade" foreign key
|
||||
key.setForeignKeyName( "none" );
|
||||
}
|
||||
else {
|
||||
final JoinColumn joinColumnAnn = property.getAnnotation( JoinColumn.class );
|
||||
if ( joinColumnAnn != null ) {
|
||||
if ( joinColumnAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT
|
||||
|| joinColumnAnn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) {
|
||||
key.setForeignKeyName( "none" );
|
||||
}
|
||||
else {
|
||||
key.setForeignKeyName( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().name() ) );
|
||||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().foreignKeyDefinition() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1283,7 +1300,7 @@ public abstract class CollectionBinder {
|
|||
|
||||
private void bindManyToManySecondPass(
|
||||
Collection collValue,
|
||||
Map persistentClasses,
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
Ejb3JoinColumn[] joinColumns,
|
||||
Ejb3JoinColumn[] inverseJoinColumns,
|
||||
Ejb3Column[] elementColumns,
|
||||
|
@ -1299,7 +1316,7 @@ public abstract class CollectionBinder {
|
|||
throw new IllegalArgumentException( "null was passed for argument property" );
|
||||
}
|
||||
|
||||
final PersistentClass collectionEntity = (PersistentClass) persistentClasses.get( collType.getName() );
|
||||
final PersistentClass collectionEntity = persistentClasses.get( collType.getName() );
|
||||
final String hqlOrderBy = extractHqlOrderBy( jpaOrderBy );
|
||||
|
||||
boolean isCollectionOfEntities = collectionEntity != null;
|
||||
|
@ -1732,13 +1749,13 @@ public abstract class CollectionBinder {
|
|||
final String mappedBy = columns[0].getMappedBy();
|
||||
if ( StringHelper.isNotEmpty( mappedBy ) ) {
|
||||
final Property property = referencedEntity.getRecursiveProperty( mappedBy );
|
||||
Iterator mappedByColumns;
|
||||
Iterator<Selectable> mappedByColumns;
|
||||
if ( property.getValue() instanceof Collection ) {
|
||||
mappedByColumns = ( (Collection) property.getValue() ).getKey().getColumnIterator();
|
||||
}
|
||||
else {
|
||||
//find the appropriate reference key, can be in a join
|
||||
Iterator joinsIt = referencedEntity.getJoinIterator();
|
||||
Iterator<Join> joinsIt = referencedEntity.getJoinIterator();
|
||||
KeyValue key = null;
|
||||
while ( joinsIt.hasNext() ) {
|
||||
Join join = (Join) joinsIt.next();
|
||||
|
@ -1747,7 +1764,9 @@ public abstract class CollectionBinder {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ( key == null ) key = property.getPersistentClass().getIdentifier();
|
||||
if ( key == null ) {
|
||||
key = property.getPersistentClass().getIdentifier();
|
||||
}
|
||||
mappedByColumns = key.getColumnIterator();
|
||||
}
|
||||
while ( mappedByColumns.hasNext() ) {
|
||||
|
|
|
@ -788,6 +788,13 @@ public class PostgreSQLDialect extends Dialect {
|
|||
super.augmentRecognizedTableTypes( tableTypesList );
|
||||
if ( getVersion() >= 930 ) {
|
||||
tableTypesList.add( "MATERIALIZED VIEW" );
|
||||
|
||||
/*
|
||||
PostgreSQL 10 and later adds support for Partition table.
|
||||
*/
|
||||
if ( getVersion() >= 1000 ) {
|
||||
tableTypesList.add( "PARTITIONED TABLE" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2540,7 +2540,8 @@ public abstract class AbstractEntityPersister
|
|||
mutablePropertiesIndexes.stream().forEach( i -> {
|
||||
// This is kindly borrowed from org.hibernate.type.TypeHelper.findDirty
|
||||
final boolean dirty = currentState[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY &&
|
||||
( previousState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ||
|
||||
// Consider mutable properties as dirty if we don't have a previous state
|
||||
( previousState == null || previousState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ||
|
||||
( propertyCheckability[i]
|
||||
&& propertyTypes[i].isDirty(
|
||||
previousState[i],
|
||||
|
|
|
@ -142,9 +142,8 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc
|
|||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
|
||||
// first, instantiate the entity instance to use as the proxy
|
||||
final EntityTuplizer entityTuplizer = persister.getEntityTuplizer();
|
||||
final PersistentAttributeInterceptable entity = (PersistentAttributeInterceptable) entityTuplizer
|
||||
.instantiate( identifier, session );
|
||||
final PersistentAttributeInterceptable entity = (PersistentAttributeInterceptable) persister.getRepresentationStrategy().getInstantiator().instantiate(
|
||||
session.getFactory() );
|
||||
|
||||
// clear the fields that are marked as dirty in the dirtiness tracker
|
||||
if ( entity instanceof SelfDirtinessTracker ) {
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* 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.annotations.derivedidentities.bidirectional;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
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;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
public class OneToOneEagerDerivedIdFetchModeSelectTest extends BaseCoreFunctionalTestCase {
|
||||
private Foo foo;
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14390")
|
||||
@FailureExpected(jiraKey = "HHH-14390")
|
||||
public void testQuery() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo.id = :id" )
|
||||
.setParameter( "id", foo.getId() )
|
||||
.uniqueResult();
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14390")
|
||||
@FailureExpected(jiraKey = "HHH-14390")
|
||||
public void testQueryById() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo = :foo" )
|
||||
.setParameter( "foo", foo )
|
||||
.uniqueResult();
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-14389")
|
||||
public void testFindById() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = session.find( Bar.class, foo );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertSame( foo, newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14390")
|
||||
@FailureExpected(jiraKey = "HHH-14390")
|
||||
public void testFindByPrimaryKey() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = session.find( Bar.class, foo.getId() );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupData() {
|
||||
this.foo = doInHibernate( this::sessionFactory, session -> {
|
||||
Foo foo = new Foo();
|
||||
session.persist( foo );
|
||||
|
||||
Bar bar = new Bar();
|
||||
bar.setFoo( foo );
|
||||
bar.setDetails( "Some details" );
|
||||
|
||||
foo.setBar( bar );
|
||||
|
||||
session.persist( bar );
|
||||
|
||||
session.flush();
|
||||
|
||||
assertNotNull( foo.getId() );
|
||||
assertEquals( foo.getId(), bar.getFoo().getId() );
|
||||
|
||||
return foo;
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanupData() {
|
||||
this.foo = null;
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
session.createQuery( "delete from Bar" );
|
||||
session.createQuery( "delete from Foo" );
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Foo.class,
|
||||
Bar.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Entity(name = "Foo")
|
||||
public static class Foo implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToOne(mappedBy = "foo", cascade = CascadeType.ALL)
|
||||
private Bar bar;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Bar getBar() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
public void setBar(Bar bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Bar")
|
||||
public static class Bar implements Serializable {
|
||||
|
||||
@Id
|
||||
@OneToOne(fetch = FetchType.EAGER)
|
||||
@Fetch(FetchMode.SELECT)
|
||||
@JoinColumn(name = "BAR_ID")
|
||||
private Foo foo;
|
||||
|
||||
private String details;
|
||||
|
||||
public Foo getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(Foo foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
public String getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(String details) {
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* 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.annotations.derivedidentities.bidirectional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
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;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
public class OneToOneLazyDerivedIdFetchModeSelectTest extends BaseCoreFunctionalTestCase {
|
||||
private Foo foo;
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-14390")
|
||||
public void testQuery() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo.id = :id" )
|
||||
.setParameter( "id", foo.getId() )
|
||||
.uniqueResult();
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14390")
|
||||
public void testQueryById() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo = :foo" )
|
||||
.setParameter( "foo", foo )
|
||||
.uniqueResult();
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-14389")
|
||||
public void testFindById() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = session.find( Bar.class, foo );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertSame( foo, newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14390")
|
||||
public void testFindByPrimaryKey() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = session.find( Bar.class, foo.getId() );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupData() {
|
||||
this.foo = doInHibernate( this::sessionFactory, session -> {
|
||||
Foo foo = new Foo();
|
||||
session.persist( foo );
|
||||
|
||||
Bar bar = new Bar();
|
||||
bar.setFoo( foo );
|
||||
bar.setDetails( "Some details" );
|
||||
|
||||
foo.setBar( bar );
|
||||
|
||||
session.persist( bar );
|
||||
|
||||
session.flush();
|
||||
|
||||
assertNotNull( foo.getId() );
|
||||
assertEquals( foo.getId(), bar.getFoo().getId() );
|
||||
|
||||
return foo;
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanupData() {
|
||||
this.foo = null;
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
session.createQuery( "delete from Bar" );
|
||||
session.createQuery( "delete from Foo" );
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Foo.class,
|
||||
Bar.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Entity(name = "Foo")
|
||||
public static class Foo implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToOne(mappedBy = "foo", cascade = CascadeType.ALL)
|
||||
private Bar bar;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Bar getBar() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
public void setBar(Bar bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Bar")
|
||||
public static class Bar implements Serializable {
|
||||
|
||||
@Id
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@Fetch(FetchMode.SELECT)
|
||||
@JoinColumn(name = "BAR_ID")
|
||||
private Foo foo;
|
||||
|
||||
private String details;
|
||||
|
||||
public Foo getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(Foo foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
public String getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(String details) {
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,6 +51,85 @@ public class OneToOneWithDerivedIdentityTest extends BaseCoreFunctionalTestCase
|
|||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14389")
|
||||
public void testQueryById() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
Bar bar = new Bar();
|
||||
bar.setDetails( "Some details" );
|
||||
Foo foo = new Foo();
|
||||
foo.setBar( bar );
|
||||
bar.setFoo( foo );
|
||||
s.persist( foo );
|
||||
s.flush();
|
||||
assertNotNull( foo.getId() );
|
||||
assertEquals( foo.getId(), bar.getFoo().getId() );
|
||||
|
||||
s.clear();
|
||||
Bar newBar = ( Bar ) s.createQuery( "SELECT b FROM Bar b WHERE b.foo = :foo" )
|
||||
.setParameter( "foo", foo )
|
||||
.uniqueResult();
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14389")
|
||||
@FailureExpected( jiraKey = "HHH-14389")
|
||||
public void testFindById() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
Bar bar = new Bar();
|
||||
bar.setDetails( "Some details" );
|
||||
Foo foo = new Foo();
|
||||
foo.setBar( bar );
|
||||
bar.setFoo( foo );
|
||||
s.persist( foo );
|
||||
s.flush();
|
||||
assertNotNull( foo.getId() );
|
||||
assertEquals( foo.getId(), bar.getFoo().getId() );
|
||||
|
||||
s.clear();
|
||||
Bar newBar = s.find( Bar.class, foo );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertSame( foo, newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14389")
|
||||
public void testFindByPrimaryKey() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
Bar bar = new Bar();
|
||||
bar.setDetails( "Some details" );
|
||||
Foo foo = new Foo();
|
||||
foo.setBar( bar );
|
||||
bar.setFoo( foo );
|
||||
s.persist( foo );
|
||||
s.flush();
|
||||
assertNotNull( foo.getId() );
|
||||
assertEquals( foo.getId(), bar.getFoo().getId() );
|
||||
|
||||
s.clear();
|
||||
Bar newBar = s.find( Bar.class, foo.getId() );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-10476")
|
||||
public void testInsertFooAndBarWithDerivedIdPC() {
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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.annotations.derivedidentities.unidirectional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
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;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
public class OneToOneEagerDerivedIdFetchModeSelectTest extends BaseCoreFunctionalTestCase {
|
||||
private Foo foo;
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-14390")
|
||||
public void testQuery() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo.id = :id" )
|
||||
.setParameter( "id", foo.getId() )
|
||||
.uniqueResult();
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14390")
|
||||
public void testQueryById() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo = :foo" )
|
||||
.setParameter( "foo", foo )
|
||||
.uniqueResult();
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-14389")
|
||||
public void testFindById() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = session.find( Bar.class, foo );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertSame( foo, newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14390")
|
||||
public void testFindByPrimaryKey() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = session.find( Bar.class, foo.getId() );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupData() {
|
||||
this.foo = doInHibernate( this::sessionFactory, session -> {
|
||||
Foo foo = new Foo();
|
||||
session.persist( foo );
|
||||
|
||||
Bar bar = new Bar();
|
||||
bar.setFoo( foo );
|
||||
bar.setDetails( "Some details" );
|
||||
session.persist( bar );
|
||||
|
||||
session.flush();
|
||||
|
||||
assertNotNull( foo.getId() );
|
||||
assertEquals( foo.getId(), bar.getFoo().getId() );
|
||||
|
||||
return foo;
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanupData() {
|
||||
this.foo = null;
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
session.createQuery( "delete from Bar" );
|
||||
session.createQuery( "delete from Foo" );
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Foo.class,
|
||||
Bar.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Entity(name = "Foo")
|
||||
public static class Foo implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Bar")
|
||||
public static class Bar implements Serializable {
|
||||
|
||||
@Id
|
||||
@OneToOne(fetch = FetchType.EAGER)
|
||||
@Fetch(FetchMode.SELECT)
|
||||
@JoinColumn(name = "BAR_ID")
|
||||
private Foo foo;
|
||||
|
||||
private String details;
|
||||
|
||||
public Foo getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(Foo foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
public String getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(String details) {
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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.annotations.derivedidentities.unidirectional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
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;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
public class OneToOneLazyDerivedIdFetchModeSelectTest extends BaseCoreFunctionalTestCase {
|
||||
private Foo foo;
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-14390")
|
||||
public void testQuery() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo.id = :id" )
|
||||
.setParameter( "id", foo.getId() )
|
||||
.uniqueResult();
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14390")
|
||||
public void testQueryById() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo = :foo" )
|
||||
.setParameter( "foo", foo )
|
||||
.uniqueResult();
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-14389")
|
||||
public void testFindById() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = session.find( Bar.class, foo );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertSame( foo, newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14390")
|
||||
public void testFindByPrimaryKey() {
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Bar newBar = session.find( Bar.class, foo.getId() );
|
||||
assertNotNull( newBar );
|
||||
assertNotNull( newBar.getFoo() );
|
||||
assertEquals( foo.getId(), newBar.getFoo().getId() );
|
||||
assertEquals( "Some details", newBar.getDetails() );
|
||||
});
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupData() {
|
||||
this.foo = doInHibernate( this::sessionFactory, session -> {
|
||||
Foo foo = new Foo();
|
||||
session.persist( foo );
|
||||
|
||||
Bar bar = new Bar();
|
||||
bar.setFoo( foo );
|
||||
bar.setDetails( "Some details" );
|
||||
session.persist( bar );
|
||||
|
||||
session.flush();
|
||||
|
||||
assertNotNull( foo.getId() );
|
||||
assertEquals( foo.getId(), bar.getFoo().getId() );
|
||||
|
||||
return foo;
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanupData() {
|
||||
this.foo = null;
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
session.createQuery( "delete from Bar" );
|
||||
session.createQuery( "delete from Foo" );
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Foo.class,
|
||||
Bar.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Entity(name = "Foo")
|
||||
public static class Foo implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Bar")
|
||||
public static class Bar implements Serializable {
|
||||
|
||||
@Id
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@Fetch(FetchMode.SELECT)
|
||||
@JoinColumn(name = "BAR_ID")
|
||||
private Foo foo;
|
||||
|
||||
private String details;
|
||||
|
||||
public Foo getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(Foo foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
public String getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(String details) {
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ package org.hibernate.test.annotations.selectbeforeupdate;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
|
@ -280,6 +281,7 @@ public class UpdateDetachedTest extends BaseCoreFunctionalTestCase{
|
|||
|
||||
@Embeddable
|
||||
public static class Comment {
|
||||
@Column(name = "bar_comment")
|
||||
private String comment;
|
||||
private String author;
|
||||
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.bytecode.enhancement.dirty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderBy;
|
||||
import javax.persistence.OrderColumn;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.boot.internal.SessionFactoryBuilderImpl;
|
||||
import org.hibernate.boot.internal.SessionFactoryOptionsBuilder;
|
||||
import org.hibernate.boot.spi.SessionFactoryBuilderService;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-14360")
|
||||
@RunWith(BytecodeEnhancerRunner.class)
|
||||
public class DirtyTrackingPersistTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { HotherEntity.class, Hentity.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
super.configure( configuration );
|
||||
configuration.getStandardServiceRegistryBuilder().addService(
|
||||
SessionFactoryBuilderService.class,
|
||||
(SessionFactoryBuilderService) (metadata, bootstrapContext) -> {
|
||||
SessionFactoryOptionsBuilder optionsBuilder = new SessionFactoryOptionsBuilder(
|
||||
metadata.getMetadataBuildingOptions().getServiceRegistry(),
|
||||
bootstrapContext
|
||||
);
|
||||
optionsBuilder.enableCollectionInDefaultFetchGroup( true );
|
||||
return new SessionFactoryBuilderImpl( metadata, optionsBuilder );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Hentity hentity = new Hentity();
|
||||
HotherEntity hotherEntity = new HotherEntity();
|
||||
hentity.setLineItems( new ArrayList<>( Collections.singletonList( hotherEntity ) ) );
|
||||
hentity.setNextRevUNs( new ArrayList<>( Collections.singletonList( "something" ) ) );
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
session.persist( hentity );
|
||||
} );
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
hentity.bumpNumber();
|
||||
session.saveOrUpdate( hentity );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity(name = "HotherEntity")
|
||||
public static class HotherEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
@Basic
|
||||
private Long clicId;
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Long getClicId() {
|
||||
return clicId;
|
||||
}
|
||||
|
||||
public void setClicId(Long clicId) {
|
||||
this.clicId = clicId;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Hentity")
|
||||
public static class Hentity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ElementCollection
|
||||
@OrderColumn(name = "nextRevUN_index")
|
||||
private List<String> nextRevUNs;
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@JoinColumn(name = "clicId")
|
||||
@OrderBy("id asc")
|
||||
protected List<HotherEntity> lineItems;
|
||||
|
||||
@Basic
|
||||
private Long aNumber;
|
||||
|
||||
@Temporal(value = TemporalType.TIMESTAMP)
|
||||
private Date createDate;
|
||||
|
||||
@Temporal(value = TemporalType.TIMESTAMP)
|
||||
private Date deleteDate;
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<String> getNextRevUNs() {
|
||||
return nextRevUNs;
|
||||
}
|
||||
|
||||
public void setNextRevUNs(List<String> nextRevUNs) {
|
||||
this.nextRevUNs = nextRevUNs;
|
||||
}
|
||||
|
||||
public List<HotherEntity> getLineItems() {
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
public void setLineItems(List<HotherEntity> lineItems) {
|
||||
this.lineItems = lineItems;
|
||||
}
|
||||
|
||||
public Date getCreateDate() {
|
||||
return createDate;
|
||||
}
|
||||
|
||||
public void setCreateDate(Date createDate) {
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
public Date getDeleteDate() {
|
||||
return deleteDate;
|
||||
}
|
||||
|
||||
public void setDeleteDate(Date deleteDate) {
|
||||
this.deleteDate = deleteDate;
|
||||
}
|
||||
|
||||
public void bumpNumber() {
|
||||
aNumber = aNumber == null ? 0 : aNumber++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,29 +40,24 @@ public abstract class AbstractKey extends ModelEntity
|
|||
String name;
|
||||
|
||||
@OneToMany(targetEntity = RoleEntity.class, mappedBy = "key", fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("R")
|
||||
protected Set<RoleEntity> roles = new LinkedHashSet<>();
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("PR")
|
||||
@JoinColumn
|
||||
protected AbstractKey register;
|
||||
|
||||
@OneToMany(targetEntity = AbstractKey.class, mappedBy = "register", fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("RK")
|
||||
protected Set<AbstractKey> keys = new LinkedHashSet();
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("PP")
|
||||
@JoinColumn
|
||||
protected AbstractKey parent;
|
||||
|
||||
@OneToMany(targetEntity = AbstractKey.class, mappedBy = "parent", fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("PK")
|
||||
protected Set<AbstractKey> otherKeys = new LinkedHashSet();
|
||||
|
||||
|
|
|
@ -52,7 +52,6 @@ public class Activity extends BaseEntity {
|
|||
}
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("Instruction")
|
||||
@JoinColumn(name = "Instruction_Id")
|
||||
public Instruction getInstruction() {
|
||||
|
@ -66,7 +65,6 @@ public class Activity extends BaseEntity {
|
|||
|
||||
@SuppressWarnings("unused")
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("webApplication")
|
||||
@JoinColumn(name="web_app_oid")
|
||||
public WebApplication getWebApplication() {
|
||||
|
|
|
@ -246,7 +246,6 @@ public class BatchFetchProxyTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
private String name;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Employer employer;
|
||||
}
|
||||
|
||||
|
|
|
@ -211,7 +211,6 @@ public class BidirectionalProxyTest extends BaseNonConfigCoreFunctionalTestCase
|
|||
}
|
||||
|
||||
@ManyToOne(fetch= FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("aEntity")
|
||||
@JoinColumn(name="aEntity")
|
||||
protected AEntity aChildEntity = null;
|
||||
|
@ -249,7 +248,6 @@ public class BidirectionalProxyTest extends BaseNonConfigCoreFunctionalTestCase
|
|||
}
|
||||
|
||||
@ManyToOne(fetch= FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("aEntity")
|
||||
@JoinColumn(name="aEntity")
|
||||
protected AChildEntity aChildEntity = null;
|
||||
|
|
|
@ -212,7 +212,6 @@ public class EntitySharedInCollectionAndToOneTest extends BaseNonConfigCoreFunct
|
|||
private CodeTable codeTable;
|
||||
|
||||
@OneToOne( mappedBy = "defaultItem", fetch=FetchType.LAZY )
|
||||
@LazyToOne( LazyToOneOption.NO_PROXY )
|
||||
@LazyGroup( "defaultItemInverse" )
|
||||
protected CodeTable defaultItemInverse;
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
|
@ -199,6 +200,7 @@ public class FetchGraphTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-13658")
|
||||
public void testRandomAccess() {
|
||||
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
||||
stats.clear();
|
||||
|
@ -787,14 +789,10 @@ public class FetchGraphTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
|
||||
// ****** Relations *****************
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
// @LazyToOne(LazyToOneOption.PROXY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("a")
|
||||
public AEntity a;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
// @LazyToOne(LazyToOneOption.PROXY)
|
||||
@LazyGroup("c")
|
||||
public CEntity c;
|
||||
|
||||
|
@ -802,7 +800,6 @@ public class FetchGraphTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
public Set<BEntity> bs;
|
||||
|
||||
@OneToOne(mappedBy = "d", fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("e")
|
||||
private EEntity e;
|
||||
|
||||
|
|
|
@ -264,19 +264,15 @@ public class LazyToOnesNoProxyFactoryWithSubclassesStatefulTest extends BaseNonC
|
|||
private String id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Animal animal = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Primate primate = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Human human = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Human otherHuman = null;
|
||||
|
||||
protected OtherEntity() {
|
||||
|
|
|
@ -264,19 +264,15 @@ public class LazyToOnesNoProxyFactoryWithSubclassesStatelessTest extends BaseNon
|
|||
private String id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Animal animal = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Primate primate = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Human human = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Human otherHuman = null;
|
||||
|
||||
protected OtherEntity() {
|
||||
|
|
|
@ -831,15 +831,12 @@ public class LazyToOnesProxyMergeWithSubclassesTest extends BaseNonConfigCoreFun
|
|||
private String id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Animal animal = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Primate primate = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Human human = null;
|
||||
|
||||
protected OtherEntity() {
|
||||
|
|
|
@ -298,15 +298,12 @@ public class LazyToOnesProxyWithSubclassesStatelessTest extends BaseNonConfigCor
|
|||
private String id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Animal animal = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Primate primate = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Human human = null;
|
||||
|
||||
protected OtherEntity() {
|
||||
|
|
|
@ -366,15 +366,12 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
|||
private String id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Animal animal = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Primate primate = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Human human = null;
|
||||
|
||||
protected OtherEntity() {
|
||||
|
|
|
@ -180,7 +180,6 @@ public class LoadANonExistingEntityTest extends BaseNonConfigCoreFunctionalTestC
|
|||
private String name;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Employer employer;
|
||||
}
|
||||
|
||||
|
|
|
@ -203,7 +203,6 @@ public class LoadANonExistingNotFoundBatchEntityTest extends BaseNonConfigCoreFu
|
|||
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@JoinColumn(foreignKey = @ForeignKey(value= ConstraintMode.NO_CONSTRAINT))
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@NotFound(action=NotFoundAction.IGNORE)
|
||||
private Employer employer;
|
||||
}
|
||||
|
|
|
@ -183,7 +183,6 @@ public class LoadANonExistingNotFoundEntityTest extends BaseNonConfigCoreFunctio
|
|||
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@JoinColumn(foreignKey = @ForeignKey(value= ConstraintMode.NO_CONSTRAINT))
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@NotFound(action=NotFoundAction.IGNORE)
|
||||
private Employer employer;
|
||||
}
|
||||
|
|
|
@ -153,7 +153,6 @@ public class MapsIdProxyBidirectionalTest extends BaseNonConfigCoreFunctionalTes
|
|||
|
||||
@MapsId
|
||||
@OneToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Employer employer;
|
||||
|
||||
private String info;
|
||||
|
@ -165,7 +164,6 @@ public class MapsIdProxyBidirectionalTest extends BaseNonConfigCoreFunctionalTes
|
|||
private int id;
|
||||
|
||||
@OneToOne(optional = false, fetch = FetchType.LAZY, mappedBy = "employer", cascade = CascadeType.ALL)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private EmployerInfo employerInfo;
|
||||
|
||||
private String name;
|
||||
|
|
|
@ -122,7 +122,6 @@ public class MapsIdProxyUnidirectionalTest extends BaseNonConfigCoreFunctionalTe
|
|||
|
||||
@MapsId
|
||||
@OneToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Employer employer;
|
||||
|
||||
}
|
||||
|
|
|
@ -177,7 +177,6 @@ public class MergeDetachedToProxyTest extends BaseNonConfigCoreFunctionalTestCas
|
|||
private int id;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private BEntity bEntity;
|
||||
}
|
||||
|
||||
|
|
|
@ -302,7 +302,6 @@ public class QueryScrollingWithInheritanceProxyEagerManyToOneTest extends BaseNo
|
|||
private String id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@JoinColumn(name = "Employee_Id")
|
||||
protected Employee employee = null;
|
||||
|
||||
|
|
|
@ -302,12 +302,10 @@ public class QueryScrollingWithInheritanceProxyTest extends BaseNonConfigCoreFun
|
|||
private String id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@JoinColumn(name = "Employee_Id")
|
||||
protected Employee employee = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@JoinColumn(name = "EmployeeParent_Id")
|
||||
protected EmployeeParent employeeParent = null;
|
||||
|
||||
|
|
|
@ -283,7 +283,6 @@ public class SimpleUpdateTestWithLazyLoading extends BaseNonConfigCoreFunctional
|
|||
Long id;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
Parent parent;
|
||||
|
||||
@OneToMany
|
||||
|
|
|
@ -235,7 +235,6 @@ public class SimpleUpdateTestWithLazyLoadingAndInlineDirtyTracking extends BaseN
|
|||
Long id;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
Parent parent;
|
||||
|
||||
@OneToMany
|
||||
|
|
|
@ -59,7 +59,6 @@ public class WebApplication extends BaseEntity {
|
|||
}
|
||||
|
||||
@OneToMany(mappedBy="webApplication", fetch= FetchType.LAZY)
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
@LazyGroup("app_activity_group")
|
||||
// @CollectionType(type="baseutil.technology.hibernate.IskvLinkedSetCollectionType")
|
||||
public Set<Activity> getActivities() {
|
||||
|
|
|
@ -23,6 +23,7 @@ public class TestEntity {
|
|||
private Long id;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "t_date")
|
||||
private Date date;
|
||||
|
||||
@Basic
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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.foreignkeys.disabled;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @author Yanming Zhou
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-14229")
|
||||
public class OneToManyBidirectionalForeignKeyTest {
|
||||
|
||||
private static final String TABLE_NAME_PLAIN = "plain";
|
||||
private static final String TABLE_NAME_WITH_ON_DELETE = "cascade_delete";
|
||||
|
||||
@Test
|
||||
public void testForeignKeyShouldNotBeCreated() {
|
||||
Metadata metadata = new MetadataSources(new StandardServiceRegistryBuilder().build())
|
||||
.addAnnotatedClass(PlainTreeEntity.class).addAnnotatedClass(TreeEntityWithOnDelete.class)
|
||||
.buildMetadata();
|
||||
assertTrue(findTable(metadata, TABLE_NAME_PLAIN).getForeignKeys().isEmpty());
|
||||
assertFalse(findTable(metadata, TABLE_NAME_WITH_ON_DELETE).getForeignKeys().isEmpty());
|
||||
}
|
||||
|
||||
private static Table findTable(Metadata metadata, String tableName) {
|
||||
return StreamSupport.stream(metadata.getDatabase().getNamespaces().spliterator(), false)
|
||||
.flatMap(namespace -> namespace.getTables().stream()).filter(t -> t.getName().equals(tableName))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@javax.persistence.Table(name = TABLE_NAME_PLAIN)
|
||||
public static class PlainTreeEntity {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
|
||||
private PlainTreeEntity parent;
|
||||
|
||||
@OneToMany(mappedBy = "parent")
|
||||
// workaround
|
||||
// @org.hibernate.annotations.ForeignKey(name = "none")
|
||||
private Collection<PlainTreeEntity> children = new ArrayList<>(0);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@javax.persistence.Table(name = TABLE_NAME_WITH_ON_DELETE)
|
||||
public static class TreeEntityWithOnDelete {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
|
||||
private TreeEntityWithOnDelete parent;
|
||||
|
||||
@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
private Collection<TreeEntityWithOnDelete> children = new ArrayList<>(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,375 @@
|
|||
package org.hibernate.test.join;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
public class OuterJoinTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{ A.class, B.class, C.class, D.class, Association.class };
|
||||
}
|
||||
|
||||
|
||||
@MappedSuperclass
|
||||
public static class BaseEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "key_id")
|
||||
Long key;
|
||||
|
||||
String value;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
Association association;
|
||||
|
||||
public BaseEntity() {
|
||||
}
|
||||
|
||||
public BaseEntity(Long key, String value, Association association) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.association = association;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "A")
|
||||
@Table(name = "a")
|
||||
public static class A extends BaseEntity {
|
||||
|
||||
@OneToOne
|
||||
@PrimaryKeyJoinColumn(columnDefinition = "association_key", referencedColumnName = "key_id")
|
||||
private C cAssociationByKey;
|
||||
|
||||
public A() {
|
||||
}
|
||||
|
||||
public A(Long key, String value, Association association) {
|
||||
super(key, value, association);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Entity(name = "B")
|
||||
@Table(name = "b")
|
||||
public static class B extends BaseEntity {
|
||||
public B() {
|
||||
}
|
||||
|
||||
public B(Long key, String value, Association association) {
|
||||
super(key, value, association);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "C")
|
||||
@Table(name = "c")
|
||||
public static class C extends BaseEntity {
|
||||
public C() {
|
||||
}
|
||||
|
||||
public C(Long key, String value, Association association) {
|
||||
super(key, value, association);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "D")
|
||||
@Table(name = "d")
|
||||
public static class D extends BaseEntity {
|
||||
public D() {
|
||||
}
|
||||
|
||||
public D(Long key, String value, Association association) {
|
||||
super(key, value, association);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "Association")
|
||||
@Table(name = "association")
|
||||
public static class Association {
|
||||
|
||||
@Id
|
||||
@Column(name = "key_id")
|
||||
private Long key;
|
||||
|
||||
private String value;
|
||||
|
||||
public Association() {
|
||||
}
|
||||
|
||||
public Association(Long key, String value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
Association association = new Association(1l, "association");
|
||||
em.merge(association);
|
||||
|
||||
em.merge(new A(1L, "a", association));
|
||||
em.merge(new A(2L, "b", association));
|
||||
em.merge(new A(3L, "c", association));
|
||||
|
||||
em.merge(new B(1L, "d", association));
|
||||
em.merge(new B(2L, "e", association));
|
||||
em.merge(new B(3L, "f", association));
|
||||
|
||||
em.merge(new C(1L, "g", association));
|
||||
em.merge(new C(2L, "h", association));
|
||||
em.merge(new C(4L, "j", association));
|
||||
|
||||
em.merge(new D(1L, "k", association));
|
||||
em.merge(new D(2L, "l", association));
|
||||
em.merge(new D(4L, "m", association));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinOrderWithRightJoin() {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT COALESCE(a.key, b.key, c.key, d.key), a.value, b.value, c.value, d.value " +
|
||||
"FROM A a " +
|
||||
"INNER JOIN B b ON a.key = b.key " +
|
||||
"RIGHT JOIN C c ON a.key = c.key " +
|
||||
"INNER JOIN D d ON d.key = c.key " +
|
||||
"ORDER BY COALESCE(a.key, b.key, c.key, d.key) ASC", Tuple.class)
|
||||
.getResultList();
|
||||
|
||||
assertEquals(3, resultList.size());
|
||||
|
||||
assertEquals("a", resultList.get(0).get(1));
|
||||
assertEquals("d", resultList.get(0).get(2));
|
||||
assertEquals("g", resultList.get(0).get(3));
|
||||
assertEquals("k", resultList.get(0).get(4));
|
||||
|
||||
assertEquals("b", resultList.get(1).get(1));
|
||||
assertEquals("e", resultList.get(1).get(2));
|
||||
assertEquals("h", resultList.get(1).get(3));
|
||||
assertEquals("l", resultList.get(1).get(4));
|
||||
|
||||
assertNull(resultList.get(2).get(1));
|
||||
assertNull(resultList.get(2).get(2));
|
||||
assertEquals("j", resultList.get(2).get(3));
|
||||
assertEquals("m", resultList.get(2).get(4));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinOrderWithRightNormalJoin() {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT COALESCE(a.key, b.key, c.key, d.key), a.value, b.value, c.value, d.value " +
|
||||
"FROM A a " +
|
||||
"INNER JOIN B b ON a.key = b.key " +
|
||||
"RIGHT JOIN a.cAssociationByKey c " +
|
||||
"INNER JOIN D d ON d.key = c.key " +
|
||||
"ORDER BY COALESCE(a.key, b.key, c.key, d.key) ASC", Tuple.class)
|
||||
.getResultList();
|
||||
|
||||
assertEquals(3, resultList.size());
|
||||
|
||||
assertEquals("a", resultList.get(0).get(1));
|
||||
assertEquals("d", resultList.get(0).get(2));
|
||||
assertEquals("g", resultList.get(0).get(3));
|
||||
assertEquals("k", resultList.get(0).get(4));
|
||||
|
||||
assertEquals("b", resultList.get(1).get(1));
|
||||
assertEquals("e", resultList.get(1).get(2));
|
||||
assertEquals("h", resultList.get(1).get(3));
|
||||
assertEquals("l", resultList.get(1).get(4));
|
||||
|
||||
assertNull(resultList.get(2).get(1));
|
||||
assertNull(resultList.get(2).get(2));
|
||||
assertEquals("j", resultList.get(2).get(3));
|
||||
assertEquals("m", resultList.get(2).get(4));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinOrderWithRightJoinWithIdDereference() {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT COALESCE(a.key, b.key, c.key, d.key), a.value, b.value, c.value, d.value " +
|
||||
"FROM A a " +
|
||||
"INNER JOIN B b ON a.key = b.key AND a.association.key = b.association.key " +
|
||||
"RIGHT JOIN C c ON a.key = c.key AND a.association.key = c.association.key " +
|
||||
"INNER JOIN D d ON d.key = c.key AND d.association.key = c.association.key " +
|
||||
"ORDER BY COALESCE(a.key, b.key, c.key, d.key) ASC", Tuple.class).getResultList();
|
||||
|
||||
assertEquals(3, resultList.size());
|
||||
|
||||
assertEquals("a", resultList.get(0).get(1));
|
||||
assertEquals("d", resultList.get(0).get(2));
|
||||
assertEquals("g", resultList.get(0).get(3));
|
||||
assertEquals("k", resultList.get(0).get(4));
|
||||
|
||||
assertEquals("b", resultList.get(1).get(1));
|
||||
assertEquals("e", resultList.get(1).get(2));
|
||||
assertEquals("h", resultList.get(1).get(3));
|
||||
assertEquals("l", resultList.get(1).get(4));
|
||||
|
||||
assertNull(resultList.get(2).get(1));
|
||||
assertNull(resultList.get(2).get(2));
|
||||
assertEquals("j", resultList.get(2).get(3));
|
||||
assertEquals("m", resultList.get(2).get(4));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinOrderWithRightNormalJoinWithIdDereference() {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT COALESCE(a.key, b.key, c.key, d.key), a.value, b.value, c.value, d.value " +
|
||||
"FROM A a " +
|
||||
"INNER JOIN B b ON a.key = b.key AND a.association.key = b.association.key " +
|
||||
"RIGHT JOIN a.cAssociationByKey c ON a.key = c.key AND a.association.key = c.association.key " +
|
||||
"INNER JOIN D d ON d.key = c.key AND d.association.key = c.association.key " +
|
||||
"ORDER BY COALESCE(a.key, b.key, c.key, d.key) ASC", Tuple.class).getResultList();
|
||||
|
||||
assertEquals(3, resultList.size());
|
||||
|
||||
assertEquals("a", resultList.get(0).get(1));
|
||||
assertEquals("d", resultList.get(0).get(2));
|
||||
assertEquals("g", resultList.get(0).get(3));
|
||||
assertEquals("k", resultList.get(0).get(4));
|
||||
|
||||
assertEquals("b", resultList.get(1).get(1));
|
||||
assertEquals("e", resultList.get(1).get(2));
|
||||
assertEquals("h", resultList.get(1).get(3));
|
||||
assertEquals("l", resultList.get(1).get(4));
|
||||
|
||||
assertNull(resultList.get(2).get(1));
|
||||
assertNull(resultList.get(2).get(2));
|
||||
assertEquals("j", resultList.get(2).get(3));
|
||||
assertEquals("m", resultList.get(2).get(4));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinOrderWithRightJoinWithInnerImplicitJoins() {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT COALESCE(a.key,b.key,c.key,d.key) AS key, a.value AS aValue, b.value AS bValue, c.value AS cValue, d.value AS dValue " +
|
||||
"FROM A a JOIN a.association association_1 JOIN B b ON (EXISTS (SELECT 1 FROM b.association _synth_subquery_0 WHERE a.key = b.key AND association_1.value = _synth_subquery_0.value))" +
|
||||
"RIGHT JOIN C c ON (EXISTS (SELECT 1 FROM c.association _synth_subquery_0 WHERE a.key = c.key AND association_1.value = _synth_subquery_0.value)) " +
|
||||
"JOIN c.association association_5 " +
|
||||
"JOIN D d ON (EXISTS (SELECT 1 FROM d.association _synth_subquery_0 WHERE d.key = c.key AND _synth_subquery_0.value = association_5.value))" +
|
||||
" ORDER BY COALESCE(a.key,b.key,c.key,d.key) ASC", Tuple.class).getResultList();
|
||||
|
||||
assertEquals(3, resultList.size());
|
||||
|
||||
assertEquals("a", resultList.get(0).get(1));
|
||||
assertEquals("d", resultList.get(0).get(2));
|
||||
assertEquals("g", resultList.get(0).get(3));
|
||||
assertEquals("k", resultList.get(0).get(4));
|
||||
|
||||
assertEquals("b", resultList.get(1).get(1));
|
||||
assertEquals("e", resultList.get(1).get(2));
|
||||
assertEquals("h", resultList.get(1).get(3));
|
||||
assertEquals("l", resultList.get(1).get(4));
|
||||
|
||||
assertNull(resultList.get(2).get(1));
|
||||
assertNull(resultList.get(2).get(2));
|
||||
assertEquals("j", resultList.get(2).get(3));
|
||||
assertEquals("m", resultList.get(2).get(4));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Hibernate doesn't support implicit joins")
|
||||
public void testJoinOrderWithRightNormalJoinWithInnerImplicitJoins() {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT COALESCE(a.key, b.key, c.key, d.key), a.value, b.value, c.value, d.value " +
|
||||
"FROM A a " +
|
||||
"INNER JOIN B b ON a.key = b.key AND a.association.value = b.association.value " +
|
||||
"RIGHT JOIN a.cAssociationByKey c ON a.key = c.key AND a.association.value = c.association.value " +
|
||||
"INNER JOIN D d ON d.key = c.key AND d.association.value = c.association.value " +
|
||||
"ORDER BY COALESCE(a.key, b.key, c.key, d.key) ASC", Tuple.class).getResultList();
|
||||
|
||||
assertEquals(3, resultList.size());
|
||||
|
||||
assertEquals("a", resultList.get(0).get(1));
|
||||
assertEquals("d", resultList.get(0).get(2));
|
||||
assertEquals("g", resultList.get(0).get(3));
|
||||
assertEquals("k", resultList.get(0).get(4));
|
||||
|
||||
assertEquals("b", resultList.get(1).get(1));
|
||||
assertEquals("e", resultList.get(1).get(2));
|
||||
assertEquals("h", resultList.get(1).get(3));
|
||||
assertEquals("l", resultList.get(1).get(4));
|
||||
|
||||
assertNull(resultList.get(2).get(1));
|
||||
assertNull(resultList.get(2).get(2));
|
||||
assertEquals("j", resultList.get(2).get(3));
|
||||
assertEquals("m", resultList.get(2).get(4));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinOrderWithRightJoinWithNonOptionalAssociationProjections() {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT COALESCE(a.key, b.key, c.key, d.key), a.value, b.value, c.value, d.value " +
|
||||
"FROM A a " +
|
||||
"INNER JOIN B b ON a.key = b.key " +
|
||||
"RIGHT JOIN C c ON a.key = c.key " +
|
||||
"INNER JOIN D d ON d.key = c.key " +
|
||||
"ORDER BY COALESCE(a.key, b.key, c.key, d.key) ASC", Tuple.class).getResultList();
|
||||
|
||||
assertEquals(3, resultList.size());
|
||||
|
||||
assertEquals("a", resultList.get(0).get(1));
|
||||
assertEquals("d", resultList.get(0).get(2));
|
||||
assertEquals("g", resultList.get(0).get(3));
|
||||
assertEquals("k", resultList.get(0).get(4));
|
||||
|
||||
assertEquals("b", resultList.get(1).get(1));
|
||||
assertEquals("e", resultList.get(1).get(2));
|
||||
assertEquals("h", resultList.get(1).get(3));
|
||||
assertEquals("l", resultList.get(1).get(4));
|
||||
|
||||
assertNull(resultList.get(2).get(1));
|
||||
assertNull(resultList.get(2).get(2));
|
||||
assertEquals("j", resultList.get(2).get(3));
|
||||
assertEquals("m", resultList.get(2).get(4));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinOrderWithRightNormalJoinWithNonOptionalAssociationProjections() {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT COALESCE(a.key, b.key, c.key, d.key), a.value, b.value, c.value, d.value " +
|
||||
"FROM A a " +
|
||||
"INNER JOIN B b ON a.key = b.key " +
|
||||
"RIGHT JOIN a.cAssociationByKey c ON a.key = c.key " +
|
||||
"INNER JOIN D d ON d.key = c.key " +
|
||||
"ORDER BY COALESCE(a.key, b.key, c.key, d.key) ASC", Tuple.class).getResultList();
|
||||
|
||||
assertEquals(3, resultList.size());
|
||||
|
||||
assertEquals("a", resultList.get(0).get(1));
|
||||
assertEquals("d", resultList.get(0).get(2));
|
||||
assertEquals("g", resultList.get(0).get(3));
|
||||
assertEquals("k", resultList.get(0).get(4));
|
||||
|
||||
assertEquals("b", resultList.get(1).get(1));
|
||||
assertEquals("e", resultList.get(1).get(2));
|
||||
assertEquals("h", resultList.get(1).get(3));
|
||||
assertEquals("l", resultList.get(1).get(4));
|
||||
|
||||
assertNull(resultList.get(2).get(1));
|
||||
assertNull(resultList.get(2).get(2));
|
||||
assertEquals("j", resultList.get(2).get(3));
|
||||
assertEquals("m", resultList.get(2).get(4));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.mapping.lazytoone;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity( name = "Airport" )
|
||||
@Table( name = "airport" )
|
||||
public class Airport {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String code;
|
||||
|
||||
public Airport() {
|
||||
}
|
||||
|
||||
public Airport(Integer id, String code) {
|
||||
this.id = id;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.mapping.lazytoone;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hibernate.annotations.LazyToOneOption.NO_PROXY;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity( name = "Flight" )
|
||||
@Table( name = "flight" )
|
||||
public class Flight {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String number;
|
||||
|
||||
@ManyToOne( fetch = LAZY )
|
||||
private Airport origination;
|
||||
|
||||
@ManyToOne( fetch = LAZY )
|
||||
@LazyToOne( NO_PROXY )
|
||||
private Airport destination;
|
||||
|
||||
public Flight() {
|
||||
}
|
||||
|
||||
public Flight(Integer id, String number) {
|
||||
this.id = id;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Flight(Integer id, String number, Airport origination, Airport destination) {
|
||||
this.id = id;
|
||||
this.number = number;
|
||||
this.origination = origination;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Airport getOrigination() {
|
||||
return origination;
|
||||
}
|
||||
|
||||
public void setOrigination(Airport origination) {
|
||||
this.origination = origination;
|
||||
}
|
||||
|
||||
public Airport getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public void setDestination(Airport destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.mapping.lazytoone;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Same as {@link LazyToOneTest} except here we have bytecode-enhanced entities
|
||||
* via {@link BytecodeEnhancerRunner}
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class InstrumentedLazyToOneTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Airport.class, Flight.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareTest() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Airport austin = new Airport( 1, "AUS" );
|
||||
final Airport baltimore = new Airport( 2, "BWI" );
|
||||
|
||||
final Flight flight1 = new Flight( 1, "ABC-123", austin, baltimore );
|
||||
final Flight flight2 = new Flight( 2, "ABC-987", baltimore, austin );
|
||||
|
||||
session.persist( austin );
|
||||
session.persist( baltimore );
|
||||
|
||||
session.persist( flight1 );
|
||||
session.persist( flight2 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupTestData() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Flight" ).executeUpdate();
|
||||
session.createQuery( "delete Airport" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-13658", message = "Flight#origination is not treated as lazy. Not sure why exactly" )
|
||||
public void testEnhancedButProxyNotAllowed() {
|
||||
final StatisticsImplementor statistics = sessionFactory().getStatistics();
|
||||
statistics.clear();
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Flight flight1 = session.byId( Flight.class ).load( 1 );
|
||||
|
||||
// unlike the other 2 tests we should get 2 db queries here
|
||||
assertThat( statistics.getPrepareStatementCount(), is( 2L ) );
|
||||
|
||||
assertThat( Hibernate.isInitialized( flight1 ), is( true ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "origination" ), is( true ) );
|
||||
// this should be a non-enhanced proxy
|
||||
assertThat( Hibernate.isInitialized( flight1.getOrigination() ), is( false ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "destination" ), is( false ) );
|
||||
// the NO_PROXY here should trigger an EAGER load
|
||||
assertThat( Hibernate.isInitialized( flight1.getDestination() ), is( false ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.mapping.lazytoone;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Same as {@link InstrumentedLazyToOneTest} except here we enable bytecode-enhanced proxies
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class InstrumentedProxyLazyToOneTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Airport.class, Flight.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareTest() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Airport austin = new Airport( 1, "AUS" );
|
||||
final Airport baltimore = new Airport( 2, "BWI" );
|
||||
|
||||
final Flight flight1 = new Flight( 1, "ABC-123", austin, baltimore );
|
||||
final Flight flight2 = new Flight( 2, "ABC-987", baltimore, austin );
|
||||
|
||||
session.persist( austin );
|
||||
session.persist( baltimore );
|
||||
|
||||
session.persist( flight1 );
|
||||
session.persist( flight2 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupTestData() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Flight" ).executeUpdate();
|
||||
session.createQuery( "delete Airport" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnhancedWithProxy() {
|
||||
final StatisticsImplementor statistics = sessionFactory().getStatistics();
|
||||
statistics.clear();
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Flight flight1 = session.byId( Flight.class ).load( 1 );
|
||||
|
||||
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
|
||||
|
||||
assertThat( Hibernate.isInitialized( flight1 ), is( true ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "origination" ), is( true ) );
|
||||
assertThat( Hibernate.isInitialized( flight1.getOrigination() ), is( false ) );
|
||||
// let's make sure these `Hibernate` calls pass for the right reasons...
|
||||
assertThat( flight1.getOrigination(), instanceOf( PersistentAttributeInterceptable.class ) );
|
||||
final PersistentAttributeInterceptable originationProxy = (PersistentAttributeInterceptable) flight1.getOrigination();
|
||||
assertThat( originationProxy.$$_hibernate_getInterceptor(), notNullValue() );
|
||||
assertThat( originationProxy.$$_hibernate_getInterceptor(), instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "destination" ), is( true ) );
|
||||
assertThat( Hibernate.isInitialized( flight1.getDestination() ), is( false ) );
|
||||
// let's make sure these `Hibernate` calls pass for the right reasons...
|
||||
assertThat( flight1.getDestination(), instanceOf( PersistentAttributeInterceptable.class ) );
|
||||
final PersistentAttributeInterceptable destinationProxy = (PersistentAttributeInterceptable) flight1.getDestination();
|
||||
assertThat( destinationProxy.$$_hibernate_getInterceptor(), notNullValue() );
|
||||
assertThat( destinationProxy.$$_hibernate_getInterceptor(), instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.mapping.lazytoone;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LazyToOneTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Airport.class, Flight.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareTest() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Airport austin = new Airport( 1, "AUS" );
|
||||
final Airport baltimore = new Airport( 2, "BWI" );
|
||||
|
||||
final Flight flight1 = new Flight( 1, "ABC-123", austin, baltimore );
|
||||
final Flight flight2 = new Flight( 2, "ABC-987", baltimore, austin );
|
||||
|
||||
session.persist( austin );
|
||||
session.persist( baltimore );
|
||||
|
||||
session.persist( flight1 );
|
||||
session.persist( flight2 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupTestData() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Flight" ).executeUpdate();
|
||||
session.createQuery( "delete Airport" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonEnhanced() {
|
||||
final StatisticsImplementor statistics = sessionFactory().getStatistics();
|
||||
statistics.clear();
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Flight flight1 = session.byId( Flight.class ).load( 1 );
|
||||
|
||||
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
|
||||
|
||||
assertThat( Hibernate.isInitialized( flight1 ), is( true ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "origination" ), is( true ) );
|
||||
assertThat( Hibernate.isInitialized( flight1.getOrigination() ), is( false ) );
|
||||
assertThat( flight1.getOrigination(), instanceOf( HibernateProxy.class ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "destination" ), is( true ) );
|
||||
assertThat( Hibernate.isInitialized( flight1.getDestination() ), is( false ) );
|
||||
assertThat( flight1.getDestination(), instanceOf( HibernateProxy.class ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.bytecode.javassist;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class Bean {
|
||||
private String someString;
|
||||
private Long someLong;
|
||||
private Integer someInteger;
|
||||
private Date someDate;
|
||||
private long somelong;
|
||||
private int someint;
|
||||
private Object someObject;
|
||||
|
||||
|
||||
public String getSomeString() {
|
||||
return someString;
|
||||
}
|
||||
|
||||
public void setSomeString(String someString) {
|
||||
this.someString = someString;
|
||||
}
|
||||
|
||||
public Long getSomeLong() {
|
||||
return someLong;
|
||||
}
|
||||
|
||||
public void setSomeLong(Long someLong) {
|
||||
this.someLong = someLong;
|
||||
}
|
||||
|
||||
public Integer getSomeInteger() {
|
||||
return someInteger;
|
||||
}
|
||||
|
||||
public void setSomeInteger(Integer someInteger) {
|
||||
this.someInteger = someInteger;
|
||||
}
|
||||
|
||||
public Date getSomeDate() {
|
||||
return someDate;
|
||||
}
|
||||
|
||||
public void setSomeDate(Date someDate) {
|
||||
this.someDate = someDate;
|
||||
}
|
||||
|
||||
public long getSomelong() {
|
||||
return somelong;
|
||||
}
|
||||
|
||||
public void setSomelong(long somelong) {
|
||||
this.somelong = somelong;
|
||||
}
|
||||
|
||||
public int getSomeint() {
|
||||
return someint;
|
||||
}
|
||||
|
||||
public void setSomeint(int someint) {
|
||||
this.someint = someint;
|
||||
}
|
||||
|
||||
public Object getSomeObject() {
|
||||
return someObject;
|
||||
}
|
||||
|
||||
public void setSomeObject(Object someObject) {
|
||||
this.someObject = someObject;
|
||||
}
|
||||
|
||||
public void throwException() throws ParseException {
|
||||
throw new ParseException( "you asked for it...", 0 );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.bytecode.javassist;
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl;
|
||||
import org.hibernate.property.access.spi.Getter;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.property.access.spi.Setter;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BeanReflectionHelper {
|
||||
|
||||
public static final Object[] TEST_VALUES = new Object[] {
|
||||
"hello", new Long(1), new Integer(1), new Date(), new Long(1), new Integer(1), new Object()
|
||||
};
|
||||
|
||||
private static final String[] getterNames = new String[7];
|
||||
private static final String[] setterNames = new String[7];
|
||||
private static final Class[] types = new Class[7];
|
||||
|
||||
static {
|
||||
final PropertyAccessStrategyBasicImpl propertyAccessStrategy = new PropertyAccessStrategyBasicImpl();
|
||||
|
||||
PropertyAccess propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someString" );
|
||||
Getter getter = propertyAccess.getGetter();
|
||||
Setter setter = propertyAccess.getSetter();
|
||||
getterNames[0] = getter.getMethodName();
|
||||
types[0] = getter.getReturnType();
|
||||
setterNames[0] = setter.getMethodName();
|
||||
|
||||
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someLong" );
|
||||
getter = propertyAccess.getGetter();
|
||||
setter = propertyAccess.getSetter();
|
||||
getterNames[1] = getter.getMethodName();
|
||||
types[1] = getter.getReturnType();
|
||||
setterNames[1] = setter.getMethodName();
|
||||
|
||||
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someInteger" );
|
||||
getter = propertyAccess.getGetter();
|
||||
setter = propertyAccess.getSetter();
|
||||
getterNames[2] = getter.getMethodName();
|
||||
types[2] = getter.getReturnType();
|
||||
setterNames[2] = setter.getMethodName();
|
||||
|
||||
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someDate" );
|
||||
getter = propertyAccess.getGetter();
|
||||
setter = propertyAccess.getSetter();
|
||||
getterNames[3] = getter.getMethodName();
|
||||
types[3] = getter.getReturnType();
|
||||
setterNames[3] = setter.getMethodName();
|
||||
|
||||
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "somelong" );
|
||||
getter = propertyAccess.getGetter();
|
||||
setter = propertyAccess.getSetter();
|
||||
getterNames[4] = getter.getMethodName();
|
||||
types[4] = getter.getReturnType();
|
||||
setterNames[4] = setter.getMethodName();
|
||||
|
||||
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someint" );
|
||||
getter = propertyAccess.getGetter();
|
||||
setter = propertyAccess.getSetter();
|
||||
getterNames[5] = getter.getMethodName();
|
||||
types[5] = getter.getReturnType();
|
||||
setterNames[5] = setter.getMethodName();
|
||||
|
||||
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someObject" );
|
||||
getter = propertyAccess.getGetter();
|
||||
setter = propertyAccess.getSetter();
|
||||
getterNames[6] = getter.getMethodName();
|
||||
types[6] = getter.getReturnType();
|
||||
setterNames[6] = setter.getMethodName();
|
||||
}
|
||||
|
||||
public static String[] getGetterNames() {
|
||||
return getterNames;
|
||||
}
|
||||
|
||||
public static String[] getSetterNames() {
|
||||
return setterNames;
|
||||
}
|
||||
|
||||
public static Class[] getTypes() {
|
||||
return types;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.bytecode.javassist;
|
||||
|
||||
import org.hibernate.bytecode.internal.javassist.BulkAccessor;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
// Extracted from org.hibernate.test.bytecode.ReflectionOptimizerTest.
|
||||
// I (Yoann) don't know what this tests does, but it's definitely specific to javassist.
|
||||
public class BulkAccessorTest extends BaseUnitTestCase {
|
||||
|
||||
@Test
|
||||
public void testBulkAccessorDirectly() {
|
||||
BulkAccessor bulkAccessor = BulkAccessor.create(
|
||||
Bean.class,
|
||||
BeanReflectionHelper.getGetterNames(),
|
||||
BeanReflectionHelper.getSetterNames(),
|
||||
BeanReflectionHelper.getTypes()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,11 +9,14 @@ package org.hibernate.envers.boot.internal;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.EntitiesConfigurator;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
|
@ -36,6 +39,8 @@ import org.hibernate.service.spi.Stoppable;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.cfg.AvailableSettings.XML_MAPPING_ENABLED;
|
||||
|
||||
/**
|
||||
* Provides central access to Envers' configuration.
|
||||
*
|
||||
|
@ -84,6 +89,11 @@ public class EnversServiceImpl implements EnversService, Configurable, Stoppable
|
|||
);
|
||||
}
|
||||
this.integrationEnabled = ConfigurationHelper.getBoolean( INTEGRATION_ENABLED, configurationValues, true );
|
||||
boolean xmlMappingEnabled = ConfigurationHelper.getBoolean( XML_MAPPING_ENABLED, configurationValues, true );
|
||||
if ( this.integrationEnabled && !xmlMappingEnabled ) {
|
||||
throw new HibernateException( "Hibernate Envers currently requires XML mapping to be enabled. Please don't disable setting `" + XML_MAPPING_ENABLED + "`; alternatively disable Hibernate Envers." );
|
||||
}
|
||||
|
||||
log.infof( "Envers integration enabled? : %s", integrationEnabled );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
description = 'Integration for Micrometer metrics into Hibernate as a metrics collection package'
|
||||
|
||||
apply from: rootProject.file( 'gradle/published-java-module.gradle' )
|
||||
|
||||
|
||||
dependencies {
|
||||
compile project( ':hibernate-core' )
|
||||
compile( libraries.jpa )
|
||||
compile( libraries.micrometer )
|
||||
|
||||
testCompile project( ':hibernate-testing' )
|
||||
testCompile( libraries.mockito )
|
||||
testCompile( libraries.mockito_inline )
|
||||
testAnnotationProcessor( project( ':hibernate-jpamodelgen' ) )
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
// resources inherently exclude sources
|
||||
test {
|
||||
resources {
|
||||
setSrcDirs( ['src/test/java','src/test/resources'] )
|
||||
}
|
||||
}
|
||||
|
||||
testJavassist {
|
||||
java {
|
||||
compileClasspath += main.output + test.output
|
||||
runtimeClasspath += main.output + test.output
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
* 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.stat;
|
||||
|
||||
import io.micrometer.core.instrument.FunctionCounter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import io.micrometer.core.instrument.TimeGauge;
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import io.micrometer.core.lang.NonNullApi;
|
||||
import io.micrometer.core.lang.NonNullFields;
|
||||
import io.micrometer.core.lang.Nullable;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.stat.Statistics;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
|
||||
/**
|
||||
* A {@link MeterBinder} implementation that provides Hibernate metrics. It exposes the
|
||||
* same statistics as would be exposed when calling {@link Statistics#logSummary()}.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
public class HibernateMetrics implements MeterBinder {
|
||||
|
||||
private static final String SESSION_FACTORY_TAG_NAME = "entityManagerFactory";
|
||||
|
||||
private final String cacheFactoryPrefix;
|
||||
private final Iterable<Tag> tags;
|
||||
|
||||
@Nullable
|
||||
private final Statistics statistics;
|
||||
|
||||
/**
|
||||
* Create {@code HibernateMetrics} and bind to the specified meter registry.
|
||||
*
|
||||
* @param registry meter registry to use
|
||||
* @param sessionFactory session factory to use
|
||||
* @param sessionFactoryName session factory name as a tag value
|
||||
* @param tags additional tags
|
||||
*/
|
||||
public static void monitor(
|
||||
MeterRegistry registry,
|
||||
SessionFactory sessionFactory,
|
||||
String sessionFactoryName,
|
||||
String... tags) {
|
||||
monitor( registry, sessionFactory, sessionFactoryName, Tags.of( tags ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@code HibernateMetrics} and bind to the specified meter registry.
|
||||
*
|
||||
* @param registry meter registry to use
|
||||
* @param sessionFactory session factory to use
|
||||
* @param sessionFactoryName session factory name as a tag value
|
||||
* @param tags additional tags
|
||||
*/
|
||||
public static void monitor(
|
||||
MeterRegistry registry,
|
||||
SessionFactory sessionFactory,
|
||||
String sessionFactoryName,
|
||||
Iterable<Tag> tags) {
|
||||
new HibernateMetrics( sessionFactory, sessionFactoryName, tags ).bindTo( registry );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code HibernateMetrics}.
|
||||
*
|
||||
* @param sessionFactory session factory to use
|
||||
* @param sessionFactoryName session factory name as a tag value
|
||||
* @param tags additional tags
|
||||
*/
|
||||
public HibernateMetrics(SessionFactory sessionFactory, String sessionFactoryName, Iterable<Tag> tags) {
|
||||
this.tags = Tags.concat( tags, SESSION_FACTORY_TAG_NAME, sessionFactoryName );
|
||||
this.cacheFactoryPrefix = sessionFactory.getSessionFactoryOptions().getCacheRegionPrefix();
|
||||
Statistics statistics = sessionFactory.getStatistics();
|
||||
this.statistics = statistics.isStatisticsEnabled() ? statistics : null;
|
||||
}
|
||||
|
||||
private void counter(
|
||||
MeterRegistry registry,
|
||||
String name,
|
||||
String description,
|
||||
ToDoubleFunction<Statistics> f,
|
||||
String... extraTags) {
|
||||
if ( this.statistics == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
FunctionCounter.builder( name, statistics, f )
|
||||
.tags( tags )
|
||||
.tags( extraTags )
|
||||
.description( description )
|
||||
.register( registry );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTo(MeterRegistry registry) {
|
||||
if ( this.statistics == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Session statistics
|
||||
counter(registry, "hibernate.sessions.open", "Sessions opened", Statistics::getSessionOpenCount );
|
||||
counter(registry, "hibernate.sessions.closed", "Sessions closed", Statistics::getSessionCloseCount );
|
||||
|
||||
// Transaction statistics
|
||||
counter(registry, "hibernate.transactions", "The number of transactions we know to have been successful",
|
||||
Statistics::getSuccessfulTransactionCount, "result", "success"
|
||||
);
|
||||
counter(registry, "hibernate.transactions", "The number of transactions we know to have failed",
|
||||
s -> s.getTransactionCount() - s.getSuccessfulTransactionCount(), "result", "failure"
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.optimistic.failures",
|
||||
"The number of StaleObjectStateExceptions that have occurred",
|
||||
Statistics::getOptimisticFailureCount
|
||||
);
|
||||
|
||||
counter(registry,
|
||||
"hibernate.flushes",
|
||||
"The global number of flushes executed by sessions (either implicit or explicit)",
|
||||
Statistics::getFlushCount
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.connections.obtained",
|
||||
"Get the global number of connections asked by the sessions " +
|
||||
"(the actual number of connections used may be much smaller depending " +
|
||||
"whether you use a connection pool or not)",
|
||||
Statistics::getConnectCount
|
||||
);
|
||||
|
||||
// Statements
|
||||
counter(registry, "hibernate.statements", "The number of prepared statements that were acquired",
|
||||
Statistics::getPrepareStatementCount, "status", "prepared"
|
||||
);
|
||||
counter(registry, "hibernate.statements", "The number of prepared statements that were released",
|
||||
Statistics::getCloseStatementCount, "status", "closed"
|
||||
);
|
||||
|
||||
// Second Level Caching
|
||||
// AWKWARD: getSecondLevelCacheRegionNames is the only way to retrieve a list of names
|
||||
// The returned names are all qualified.
|
||||
// getDomainDataRegionStatistics wants unqualified names,
|
||||
// there are no "public" methods to unqualify the names
|
||||
Arrays.stream( statistics.getSecondLevelCacheRegionNames() )
|
||||
.map(s -> {
|
||||
if ( cacheFactoryPrefix != null ) {
|
||||
return s.replaceAll( cacheFactoryPrefix + ".", "" );
|
||||
}
|
||||
return s;
|
||||
})
|
||||
.filter( this::hasDomainDataRegionStatistics )
|
||||
.forEach( regionName -> {
|
||||
counter(registry,
|
||||
"hibernate.second.level.cache.requests",
|
||||
"The number of cacheable entities/collections successfully retrieved from the cache",
|
||||
stats -> stats.getDomainDataRegionStatistics( regionName ).getHitCount(),
|
||||
"region",
|
||||
regionName,
|
||||
"result",
|
||||
"hit"
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.second.level.cache.requests",
|
||||
"The number of cacheable entities/collections not found in the cache and loaded from the database",
|
||||
stats -> stats.getDomainDataRegionStatistics( regionName ).getMissCount(),
|
||||
"region",
|
||||
regionName,
|
||||
"result",
|
||||
"miss"
|
||||
);
|
||||
counter(
|
||||
registry,
|
||||
"hibernate.second.level.cache.puts",
|
||||
"The number of cacheable entities/collections put in the cache",
|
||||
stats -> stats.getDomainDataRegionStatistics( regionName ).getPutCount(),
|
||||
"region",
|
||||
regionName
|
||||
);
|
||||
} );
|
||||
|
||||
// Entity information
|
||||
counter(registry,
|
||||
"hibernate.entities.deletes",
|
||||
"The number of entity deletes",
|
||||
Statistics::getEntityDeleteCount
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.entities.fetches",
|
||||
"The number of entity fetches",
|
||||
Statistics::getEntityFetchCount
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.entities.inserts",
|
||||
"The number of entity inserts",
|
||||
Statistics::getEntityInsertCount
|
||||
);
|
||||
counter(registry, "hibernate.entities.loads", "The number of entity loads", Statistics::getEntityLoadCount );
|
||||
counter(registry,
|
||||
"hibernate.entities.updates",
|
||||
"The number of entity updates",
|
||||
Statistics::getEntityUpdateCount
|
||||
);
|
||||
|
||||
// Collections
|
||||
counter(registry,
|
||||
"hibernate.collections.deletes",
|
||||
"The number of collection deletes",
|
||||
Statistics::getCollectionRemoveCount
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.collections.fetches",
|
||||
"The number of collection fetches",
|
||||
Statistics::getCollectionFetchCount
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.collections.loads",
|
||||
"The number of collection loads",
|
||||
Statistics::getCollectionLoadCount
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.collections.recreates",
|
||||
"The number of collections recreated",
|
||||
Statistics::getCollectionRecreateCount
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.collections.updates",
|
||||
"The number of collection updates",
|
||||
Statistics::getCollectionUpdateCount
|
||||
);
|
||||
|
||||
// Natural Id cache
|
||||
counter(registry,
|
||||
"hibernate.cache.natural.id.requests",
|
||||
"The number of cached naturalId lookups successfully retrieved from cache",
|
||||
Statistics::getNaturalIdCacheHitCount,
|
||||
"result",
|
||||
"hit"
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.cache.natural.id.requests",
|
||||
"The number of cached naturalId lookups not found in cache",
|
||||
Statistics::getNaturalIdCacheMissCount,
|
||||
"result",
|
||||
"miss"
|
||||
);
|
||||
counter(registry, "hibernate.cache.natural.id.puts", "The number of cacheable naturalId lookups put in cache",
|
||||
Statistics::getNaturalIdCachePutCount
|
||||
);
|
||||
|
||||
counter(registry,
|
||||
"hibernate.query.natural.id.executions",
|
||||
"The number of naturalId queries executed against the database",
|
||||
Statistics::getNaturalIdQueryExecutionCount
|
||||
);
|
||||
|
||||
TimeGauge.builder(
|
||||
"hibernate.query.natural.id.executions.max",
|
||||
statistics,
|
||||
TimeUnit.MILLISECONDS,
|
||||
Statistics::getNaturalIdQueryExecutionMaxTime
|
||||
)
|
||||
.description( "The maximum query time for naturalId queries executed against the database" )
|
||||
.tags( tags )
|
||||
.register( registry );
|
||||
|
||||
// Query statistics
|
||||
counter(registry,
|
||||
"hibernate.query.executions",
|
||||
"The number of executed queries",
|
||||
Statistics::getQueryExecutionCount
|
||||
);
|
||||
|
||||
TimeGauge.builder(
|
||||
"hibernate.query.executions.max",
|
||||
statistics,
|
||||
TimeUnit.MILLISECONDS,
|
||||
Statistics::getQueryExecutionMaxTime
|
||||
)
|
||||
.description( "The time of the slowest query" )
|
||||
.tags( tags )
|
||||
.register( registry );
|
||||
|
||||
// Update timestamp cache
|
||||
counter(registry,
|
||||
"hibernate.cache.update.timestamps.requests",
|
||||
"The number of timestamps successfully retrieved from cache",
|
||||
Statistics::getUpdateTimestampsCacheHitCount,
|
||||
"result",
|
||||
"hit"
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.cache.update.timestamps.requests",
|
||||
"The number of tables for which no update timestamps was not found in cache",
|
||||
Statistics::getUpdateTimestampsCacheMissCount,
|
||||
"result",
|
||||
"miss"
|
||||
);
|
||||
counter(registry, "hibernate.cache.update.timestamps.puts", "The number of timestamps put in cache",
|
||||
Statistics::getUpdateTimestampsCachePutCount
|
||||
);
|
||||
|
||||
// Query Caching
|
||||
counter(registry,
|
||||
"hibernate.cache.query.requests",
|
||||
"The number of cached queries successfully retrieved from cache",
|
||||
Statistics::getQueryCacheHitCount,
|
||||
"result",
|
||||
"hit"
|
||||
);
|
||||
counter(registry, "hibernate.cache.query.requests", "The number of cached queries not found in cache",
|
||||
Statistics::getQueryCacheMissCount, "result", "miss"
|
||||
);
|
||||
counter(registry, "hibernate.cache.query.puts", "The number of cacheable queries put in cache",
|
||||
Statistics::getQueryCachePutCount
|
||||
);
|
||||
counter(registry,
|
||||
"hibernate.cache.query.plan",
|
||||
"The global number of query plans successfully retrieved from cache",
|
||||
Statistics::getQueryPlanCacheHitCount,
|
||||
"result",
|
||||
"hit"
|
||||
);
|
||||
counter(registry, "hibernate.cache.query.plan", "The global number of query plans lookups not found in cache",
|
||||
Statistics::getQueryPlanCacheMissCount, "result", "miss"
|
||||
);
|
||||
}
|
||||
|
||||
private boolean hasDomainDataRegionStatistics(String regionName) {
|
||||
// This appears to be a _qualified
|
||||
// In 5.3, getDomainDataRegionStatistics (a new method) will throw an IllegalArgumentException
|
||||
// if the region can't be resolved.
|
||||
try {
|
||||
return statistics.getDomainDataRegionStatistics( regionName ) != null;
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap the {@link SessionFactory} from {@link EntityManagerFactory}.
|
||||
*
|
||||
* @param entityManagerFactory {@link EntityManagerFactory} to unwrap
|
||||
*
|
||||
* @return unwrapped {@link SessionFactory}
|
||||
*/
|
||||
@Nullable
|
||||
private SessionFactory unwrap(EntityManagerFactory entityManagerFactory) {
|
||||
try {
|
||||
return entityManagerFactory.unwrap( SessionFactory.class );
|
||||
}
|
||||
catch (PersistenceException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* 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.stat;
|
||||
|
||||
import io.micrometer.core.instrument.*;
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import io.micrometer.core.lang.NonNullApi;
|
||||
import io.micrometer.core.lang.NonNullFields;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
||||
import org.hibernate.event.spi.EventType;
|
||||
import org.hibernate.event.spi.PostLoadEvent;
|
||||
import org.hibernate.event.spi.PostLoadEventListener;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A {@link MeterBinder} implementation that provides Hibernate query metrics. It exposes the
|
||||
* same statistics as would be exposed when calling {@link Statistics#getQueryStatistics(String)}.
|
||||
* Note that only SELECT queries are recorded in {@link QueryStatistics}.
|
||||
* <p>
|
||||
* Be aware of the potential for high cardinality of unique Hibernate queries executed by your
|
||||
* application when considering using this {@link MeterBinder}.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
public class HibernateQueryMetrics implements MeterBinder {
|
||||
|
||||
private static final String SESSION_FACTORY_TAG_NAME = "entityManagerFactory";
|
||||
|
||||
private final Iterable<Tag> tags;
|
||||
|
||||
private final SessionFactory sessionFactory;
|
||||
|
||||
/**
|
||||
* Create {@code HibernateQueryMetrics} and bind to the specified meter registry.
|
||||
*
|
||||
* @param registry meter registry to use
|
||||
* @param sessionFactory session factory to use
|
||||
* @param sessionFactoryName session factory name as a tag value
|
||||
* @param tags additional tags
|
||||
*/
|
||||
public static void monitor(
|
||||
MeterRegistry registry,
|
||||
SessionFactory sessionFactory,
|
||||
String sessionFactoryName,
|
||||
String... tags) {
|
||||
monitor( registry, sessionFactory, sessionFactoryName, Tags.of( tags ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@code HibernateQueryMetrics} and bind to the specified meter registry.
|
||||
*
|
||||
* @param registry meter registry to use
|
||||
* @param sessionFactory session factory to use
|
||||
* @param sessionFactoryName session factory name as a tag value
|
||||
* @param tags additional tags
|
||||
*/
|
||||
public static void monitor(
|
||||
MeterRegistry registry,
|
||||
SessionFactory sessionFactory,
|
||||
String sessionFactoryName,
|
||||
Iterable<Tag> tags) {
|
||||
new HibernateQueryMetrics( sessionFactory, sessionFactoryName, tags ).bindTo( registry );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code HibernateQueryMetrics}.
|
||||
*
|
||||
* @param sessionFactory session factory to use
|
||||
* @param sessionFactoryName session factory name as a tag value
|
||||
* @param tags additional tags
|
||||
*/
|
||||
public HibernateQueryMetrics(SessionFactory sessionFactory, String sessionFactoryName, Iterable<Tag> tags) {
|
||||
this.tags = Tags.concat( tags, SESSION_FACTORY_TAG_NAME, sessionFactoryName );
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTo(MeterRegistry meterRegistry) {
|
||||
if ( sessionFactory instanceof SessionFactoryImplementor ) {
|
||||
EventListenerRegistry eventListenerRegistry = ( (SessionFactoryImplementor) sessionFactory ).getServiceRegistry()
|
||||
.getService( EventListenerRegistry.class );
|
||||
MetricsEventHandler metricsEventHandler = new MetricsEventHandler( meterRegistry );
|
||||
eventListenerRegistry.appendListeners( EventType.POST_LOAD, metricsEventHandler );
|
||||
}
|
||||
}
|
||||
|
||||
class MetricsEventHandler implements PostLoadEventListener {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
|
||||
MetricsEventHandler(MeterRegistry meterRegistry) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostLoad(PostLoadEvent event) {
|
||||
registerQueryMetric( event.getSession().getFactory().getStatistics() );
|
||||
}
|
||||
|
||||
void registerQueryMetric(Statistics statistics) {
|
||||
for ( String query : statistics.getQueries() ) {
|
||||
QueryStatistics queryStatistics = statistics.getQueryStatistics( query );
|
||||
|
||||
FunctionCounter.builder(
|
||||
"hibernate.query.cache.requests",
|
||||
queryStatistics,
|
||||
QueryStatistics::getCacheHitCount
|
||||
)
|
||||
.tags( tags )
|
||||
.tags( "result", "hit", "query", query )
|
||||
.description( "Number of query cache hits" )
|
||||
.register( meterRegistry );
|
||||
|
||||
FunctionCounter.builder(
|
||||
"hibernate.query.cache.requests",
|
||||
queryStatistics,
|
||||
QueryStatistics::getCacheMissCount
|
||||
)
|
||||
.tags( tags )
|
||||
.tags( "result", "miss", "query", query )
|
||||
.description( "Number of query cache misses" )
|
||||
.register( meterRegistry );
|
||||
|
||||
FunctionCounter.builder(
|
||||
"hibernate.query.cache.puts",
|
||||
queryStatistics,
|
||||
QueryStatistics::getCachePutCount
|
||||
)
|
||||
.tags( tags )
|
||||
.tags( "query", query )
|
||||
.description( "Number of cache puts for a query" )
|
||||
.register( meterRegistry );
|
||||
|
||||
FunctionTimer.builder(
|
||||
"hibernate.query.execution.total",
|
||||
queryStatistics,
|
||||
QueryStatistics::getExecutionCount,
|
||||
QueryStatistics::getExecutionTotalTime,
|
||||
TimeUnit.MILLISECONDS
|
||||
)
|
||||
.tags( tags )
|
||||
.tags( "query", query )
|
||||
.description( "Query executions" )
|
||||
.register( meterRegistry );
|
||||
|
||||
TimeGauge.builder(
|
||||
"hibernate.query.execution.max",
|
||||
queryStatistics,
|
||||
TimeUnit.MILLISECONDS,
|
||||
QueryStatistics::getExecutionMaxTime
|
||||
)
|
||||
.tags( tags )
|
||||
.tags( "query", query )
|
||||
.description( "Query maximum execution time" )
|
||||
.register( meterRegistry );
|
||||
|
||||
TimeGauge.builder(
|
||||
"hibernate.query.execution.min",
|
||||
queryStatistics,
|
||||
TimeUnit.MILLISECONDS,
|
||||
QueryStatistics::getExecutionMinTime
|
||||
)
|
||||
.tags( tags )
|
||||
.tags( "query", query )
|
||||
.description( "Query minimum execution time" )
|
||||
.register( meterRegistry );
|
||||
|
||||
FunctionCounter.builder(
|
||||
"hibernate.query.execution.rows",
|
||||
queryStatistics,
|
||||
QueryStatistics::getExecutionRowCount
|
||||
)
|
||||
.tags( tags )
|
||||
.tags( "query", query )
|
||||
.description( "Number of rows processed for a query" )
|
||||
.register( meterRegistry );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.stat;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
|
||||
@Entity
|
||||
@Table( name = "t_acct" )
|
||||
public class Account {
|
||||
@EmbeddedId
|
||||
private AccountId accountId;
|
||||
|
||||
@Basic( optional = false )
|
||||
@NaturalId
|
||||
private String shortCode;
|
||||
|
||||
protected Account() {
|
||||
}
|
||||
|
||||
public Account(AccountId accountId, String shortCode) {
|
||||
this.accountId = accountId;
|
||||
this.shortCode = shortCode;
|
||||
}
|
||||
|
||||
public AccountId getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public String getShortCode() {
|
||||
return shortCode;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.stat;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
@Embeddable
|
||||
public class AccountId implements java.io.Serializable {
|
||||
private final int id;
|
||||
|
||||
protected AccountId() {
|
||||
this.id = 0;
|
||||
}
|
||||
|
||||
public AccountId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
public int intValue() {
|
||||
return id;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AccountId other = (AccountId) obj;
|
||||
if (other != null && id != other.id)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.test.stat;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.stat.HibernateMetrics;
|
||||
|
||||
import org.hibernate.testing.cache.CachingRegionFactory;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
|
||||
/**
|
||||
* @author Erin Schnabel
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MicrometerCacheStatisticsTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources metadataSources) {
|
||||
super.applyMetadataSources( metadataSources );
|
||||
metadataSources.addAnnotatedClass( Person.class );
|
||||
metadataSources.addAnnotatedClass( Account.class );
|
||||
metadataSources.addAnnotatedClass( AccountId.class );
|
||||
}
|
||||
|
||||
private static final String REGION = "TheRegion";
|
||||
private static final String PREFIX = "test";
|
||||
|
||||
private SimpleMeterRegistry registry = new SimpleMeterRegistry();
|
||||
private HibernateMetrics hibernateMetrics;
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, true );
|
||||
ssrb.applySetting( AvailableSettings.USE_QUERY_CACHE, true );
|
||||
ssrb.applySetting( AvailableSettings.CACHE_REGION_FACTORY, new CachingRegionFactory() );
|
||||
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
super.addSettings( settings );
|
||||
settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" );
|
||||
settings.put( AvailableSettings.USE_QUERY_CACHE, "true" );
|
||||
settings.put( AvailableSettings.CACHE_REGION_FACTORY, new CachingRegionFactory() );
|
||||
|
||||
settings.put( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
settings.put( AvailableSettings.HBM2DDL_AUTO, "create-drop" );
|
||||
settings.put( AvailableSettings.SESSION_FACTORY_NAME, "something" );
|
||||
settings.put( AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, "false" );
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUpMetrics() {
|
||||
hibernateMetrics = new HibernateMetrics(sessionFactory(),
|
||||
sessionFactory().getName(),
|
||||
Tags.empty() );
|
||||
hibernateMetrics.bindTo( registry );
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUpMetrics() {
|
||||
registry.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMicrometerMetrics() {
|
||||
Assert.assertNotNull(registry.get("hibernate.sessions.open").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.sessions.closed").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.transactions").tags("result", "success").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.transactions").tags("result", "failure").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.optimistic.failures").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.flushes").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.connections.obtained").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.statements").tags("status", "prepared").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.statements").tags("status", "closed").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.second.level.cache.requests").tags("result", "hit", "region", REGION));
|
||||
Assert.assertNotNull(registry.get("hibernate.second.level.cache.requests").tags("result", "miss", "region", REGION));
|
||||
Assert.assertNotNull(registry.get("hibernate.second.level.cache.puts").tags("region", REGION).functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.deletes").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.fetches").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.inserts").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.loads").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.updates").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.deletes").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.fetches").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.loads").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.recreates").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.updates").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.natural.id.requests").tags("result", "hit").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.natural.id.requests").tags("result", "miss").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.natural.id.puts").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.query.natural.id.executions").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.query.natural.id.executions.max").timeGauge());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.query.executions").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.query.executions.max").timeGauge());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.update.timestamps.requests").tags("result", "hit").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.update.timestamps.requests").tags("result", "miss").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.update.timestamps.puts").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.requests").tags("result", "hit").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.requests").tags("result", "miss").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.puts").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.plan").tags("result", "hit").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.plan").tags("result", "miss").functionCounter());
|
||||
|
||||
// prepare some test data...
|
||||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
Person person = new Person( 1, "testAcct");
|
||||
session.save( person );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
Assert.assertEquals( 1, registry.get("hibernate.sessions.open").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.sessions.closed").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.entities.inserts").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.transactions").tags("result", "success").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.cache.natural.id.puts").functionCounter().count(), 0);
|
||||
Assert.assertEquals(2, registry.get("hibernate.second.level.cache.puts").tags("region", REGION).functionCounter().count(), 0);
|
||||
|
||||
final String queryString = "select p from Person p";
|
||||
inTransaction(
|
||||
// Only way to generate query region (to be accessible via stats) is to execute the query
|
||||
s -> s.createQuery( queryString ).setCacheable( true ).setCacheRegion( REGION ).list()
|
||||
);
|
||||
|
||||
Assert.assertEquals( 2, registry.get("hibernate.sessions.open").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 2, registry.get("hibernate.sessions.closed").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 0, registry.get("hibernate.entities.deletes").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 2, registry.get("hibernate.transactions").tags("result", "success").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.cache.natural.id.puts").functionCounter().count(), 0);
|
||||
Assert.assertEquals(3, registry.get("hibernate.second.level.cache.puts").tags("region", REGION).functionCounter().count(), 0);
|
||||
|
||||
// clean up
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
session.delete( person );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
Assert.assertEquals( 3, registry.get("hibernate.sessions.open").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 3, registry.get("hibernate.sessions.closed").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.entities.deletes").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 3, registry.get("hibernate.transactions").tags("result", "success").functionCounter().count(), 0 );
|
||||
}
|
||||
|
||||
@Entity( name = "Person" )
|
||||
@Table( name = "persons" )
|
||||
@Cacheable
|
||||
@Cache( region = REGION, usage = CacheConcurrencyStrategy.READ_WRITE )
|
||||
@NaturalIdCache( region = REGION )
|
||||
public static class Person {
|
||||
@Id
|
||||
public Integer id;
|
||||
|
||||
@NaturalId
|
||||
public String name;
|
||||
|
||||
protected Person() {
|
||||
}
|
||||
|
||||
public Person(int id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@ElementCollection
|
||||
@Cache( region = REGION, usage = CacheConcurrencyStrategy.READ_WRITE )
|
||||
public List<String> nickNames;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* 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.stat;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.stat.HibernateMetrics;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import io.micrometer.core.instrument.search.MeterNotFoundException;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Erin Schnabel
|
||||
* @author Donnchadh O Donnabhain
|
||||
*/
|
||||
public class MicrometerStatisticsTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { Account.class, AccountId.class };
|
||||
}
|
||||
|
||||
private SimpleMeterRegistry registry = new SimpleMeterRegistry();
|
||||
private HibernateMetrics hibernateMetrics;
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
super.configure( configuration );
|
||||
|
||||
configuration.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
configuration.setProperty( Environment.USE_QUERY_CACHE, "false" );
|
||||
configuration.setProperty( Environment.GENERATE_STATISTICS, "true" );
|
||||
configuration.setProperty( Environment.SESSION_FACTORY_NAME, "something" );
|
||||
configuration.setProperty( Environment.SESSION_FACTORY_NAME_IS_JNDI, "false" );
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUpMetrics() {
|
||||
hibernateMetrics = new HibernateMetrics(sessionFactory(),
|
||||
sessionFactory().getName(),
|
||||
Tags.empty() );
|
||||
hibernateMetrics.bindTo( registry );
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUpMetrics() {
|
||||
registry.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMicrometerMetrics() {
|
||||
Assert.assertNotNull(registry.get("hibernate.sessions.open").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.sessions.closed").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.transactions").tags("result", "success").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.transactions").tags("result", "failure").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.optimistic.failures").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.flushes").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.connections.obtained").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.statements").tags("status", "prepared").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.statements").tags("status", "closed").functionCounter());
|
||||
|
||||
// Second level cache disabled
|
||||
verifyMeterNotFoundException("hibernate.second.level.cache.requests");
|
||||
verifyMeterNotFoundException("hibernate.second.level.cache.puts");
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.deletes").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.fetches").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.inserts").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.loads").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.entities.updates").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.deletes").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.fetches").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.loads").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.recreates").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.collections.updates").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.natural.id.requests").tags("result", "hit").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.natural.id.requests").tags("result", "miss").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.natural.id.puts").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.query.natural.id.executions").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.query.natural.id.executions.max").timeGauge());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.query.executions").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.query.executions.max").timeGauge());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.update.timestamps.requests").tags("result", "hit").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.update.timestamps.requests").tags("result", "miss").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.update.timestamps.puts").functionCounter());
|
||||
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.requests").tags("result", "hit").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.requests").tags("result", "miss").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.puts").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.plan").tags("result", "hit").functionCounter());
|
||||
Assert.assertNotNull(registry.get("hibernate.cache.query.plan").tags("result", "miss").functionCounter());
|
||||
|
||||
// prepare some test data...
|
||||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
Account account = new Account( new AccountId( 1), "testAcct");
|
||||
session.save( account );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
Assert.assertEquals( 1, registry.get("hibernate.sessions.open").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.sessions.closed").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.entities.inserts").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.transactions").tags("result", "success").functionCounter().count(), 0 );
|
||||
|
||||
// clean up
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
session.delete( account );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
Assert.assertEquals( 2, registry.get("hibernate.sessions.open").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 2, registry.get("hibernate.sessions.closed").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 1, registry.get("hibernate.entities.deletes").functionCounter().count(), 0 );
|
||||
Assert.assertEquals( 2, registry.get("hibernate.transactions").tags("result", "success").functionCounter().count(), 0 );
|
||||
}
|
||||
|
||||
void verifyMeterNotFoundException(String name) {
|
||||
try {
|
||||
registry.get(name).meter();
|
||||
Assert.fail(name + " should not have been found");
|
||||
} catch(MeterNotFoundException mnfe) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#
|
||||
# Hibernate, Relational Persistence for Idiomatic Java
|
||||
#
|
||||
# License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
# See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
|
||||
hibernate.dialect @db.dialect@
|
||||
hibernate.connection.driver_class @jdbc.driver@
|
||||
hibernate.connection.url @jdbc.url@
|
||||
hibernate.connection.username @jdbc.user@
|
||||
hibernate.connection.password @jdbc.pass@
|
||||
|
||||
hibernate.connection.pool_size 5
|
||||
|
||||
hibernate.show_sql false
|
||||
hibernate.format_sql true
|
||||
|
||||
hibernate.max_fetch_depth 5
|
||||
|
||||
hibernate.cache.region_prefix hibernate.test
|
||||
hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFactory
|
||||
|
||||
javax.persistence.validation.mode=NONE
|
||||
hibernate.service.allow_crawling=false
|
||||
hibernate.session.events.log=true
|
||||
hibernate.hql.bulk_id_strategy.global_temporary.drop_tables=true
|
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
# 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>.
|
||||
#
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
|
||||
|
||||
log4j.rootLogger=info, stdout
|
||||
|
||||
log4j.logger.org.hibernate.stat=trace
|
||||
|
||||
log4j.logger.org.hibernate.tool.hbm2ddl=trace
|
||||
log4j.logger.org.hibernate.SQL=debug
|
||||
log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace
|
||||
log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace
|
|
@ -15,3 +15,15 @@ dependencies {
|
|||
compile( libraries.proxool )
|
||||
testCompile project( ':hibernate-testing' )
|
||||
}
|
||||
|
||||
test {
|
||||
if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) {
|
||||
// Proxool needs this to define classes for some reason. Stack trace:
|
||||
// at org.logicalcobwebs.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:372)
|
||||
// at org.logicalcobwebs.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:193)
|
||||
// at org.logicalcobwebs.cglib.core.KeyFactory$Generator.create(KeyFactory.java:177)
|
||||
// at org.logicalcobwebs.cglib.core.KeyFactory.create(KeyFactory.java:149)
|
||||
// at org.logicalcobwebs.cglib.proxy.Enhancer.<clinit>(Enhancer.java:96)
|
||||
jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] )
|
||||
}
|
||||
}
|
|
@ -106,7 +106,7 @@ include 'hibernate-agroal'
|
|||
include 'hibernate-jcache'
|
||||
include 'hibernate-ehcache'
|
||||
include 'hibernate-infinispan'
|
||||
|
||||
include 'hibernate-micrometer'
|
||||
include 'hibernate-graalvm'
|
||||
|
||||
// The plugin used to generate Java modules was compiled using JDK11.
|
||||
|
|
|
@ -134,3 +134,9 @@ else {
|
|||
" Using the JDK that runs Gradle for Groovy compilation." )
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) {
|
||||
// Needs add-opens because Gradle uses illegal accesses to inject... mocks? Something like that.
|
||||
jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] )
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue