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.
|
we ask that you mind.
|
||||||
|
|
||||||
For code contributions, these guidelines include:
|
For code contributions, these guidelines include:
|
||||||
* respect the project code style - find templates for [Eclipse](https://community.jboss.org/docs/DOC-16649)
|
* 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)
|
||||||
and [IntelliJ IDEA](https://community.jboss.org/docs/DOC-15468)
|
|
||||||
* have a corresponding JIRA issue and the key for this JIRA issue should be used in the commit message
|
* 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
|
* 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
|
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
|
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
|
* if applicable, documentation is updated to reflect the introduced changes
|
||||||
* the code compiles and the tests pass (`./gradlew clean build`)
|
* the code compiles and the tests pass (`./gradlew clean build`)
|
||||||
|
|
||||||
For documentation contributions, mainly just respect the project code style, especially in regards
|
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
|
to use of tabs - as mentioned above, code style templates are available for both IntelliJ IDEA and Eclipse
|
||||||
IDEA IDEs. Ideally these contributions would also have a corresponding JIRA issue, although this
|
IDEs. Ideally these contributions would also have a corresponding JIRA issue, although this
|
||||||
is less necessary for documentation contributions.
|
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
|
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:
|
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 [Hibernate JIRA account](https://hibernate.atlassian.net)
|
||||||
* Make sure you have a [GitHub account](https://github.com/signup/free)
|
* 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
|
* [fork](https://help.github.com/articles/fork-a-repo) the Hibernate repository. As discussed in
|
||||||
the linked page, this also includes:
|
the linked page, this also includes:
|
||||||
* [Set](https://help.github.com/articles/set-up-git) up your local git install
|
* [set up your local git install](https://help.github.com/articles/set-up-git)
|
||||||
* Clone your fork
|
* clone your fork
|
||||||
* See the wiki pages for setting up your IDE, whether you use
|
* See the wiki pages for setting up your IDE, whether you use
|
||||||
[IntelliJ IDEA](https://community.jboss.org/wiki/ContributingToHibernateUsingIntelliJ)
|
[IntelliJ IDEA](https://community.jboss.org/wiki/ContributingToHibernateUsingIntelliJ)
|
||||||
or [Eclipse](https://community.jboss.org/wiki/ContributingToHibernateUsingEclipse)<sup>(1)</sup>.
|
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,
|
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:
|
although this is more of a mnemonic strategy than a hard-and-fast rule - but doing so helps:
|
||||||
* remember what each branch is for
|
* 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._
|
_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
|
## Code
|
||||||
|
|
||||||
Do yo thing!
|
Do your thing!
|
||||||
|
|
||||||
|
|
||||||
## Commit
|
## Commit
|
||||||
|
|
||||||
* Make commits of logical units.
|
* make commits of logical units
|
||||||
* Be sure to use the JIRA issue key in the commit message. This is how JIRA will pick
|
* 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.
|
up the related commits and display them on the JIRA issue
|
||||||
* Make sure you have added the necessary tests for your changes.
|
* make sure you have added the necessary tests for your changes
|
||||||
* Run _all_ the tests to assure nothing else was accidentally broken.
|
* run _all_ the tests to assure nothing else was accidentally broken
|
||||||
* Make sure your source does not violate the checkstyles.
|
* make sure your source does not violate the _checkstyles_
|
||||||
|
|
||||||
_Prior to committing, if you want to pull in the latest upstream changes (highly
|
_Prior to committing, if you want to pull in the latest upstream changes (highly
|
||||||
appreciated btw), please use rebasing rather than merging. Merging creates
|
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
|
## Submit
|
||||||
|
|
||||||
* Push your changes to the topic branch in your fork of the repository.
|
* 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)
|
* 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
|
* update the JIRA issue by providing the PR link in the **Pull Request** column on the right
|
||||||
_if the JIRA key was not used in the commit message_.
|
|
||||||
|
|
||||||
|
|
||||||
It is important that this topic branch on your fork:
|
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
|
* 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
|
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
|
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
|
* 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
|
# 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
|
<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!
|
# 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
|
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.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
|
toolchain.launcher.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8
|
||||||
|
|
||||||
|
|
|
@ -251,7 +251,7 @@ if ( gradle.ext.javaToolchainEnabled ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure JVM Options
|
// Configure JVM Options
|
||||||
jvmArgs.addAll( getProperty( 'toolchain.launcher.jvmargs' ).toString().split( ' ' ) )
|
jvmArgs( getProperty( 'toolchain.launcher.jvmargs' ).toString().split( ' ' ) )
|
||||||
|
|
||||||
// Display version of Java tools
|
// Display version of Java tools
|
||||||
doFirst {
|
doFirst {
|
||||||
|
|
|
@ -23,7 +23,7 @@ ext {
|
||||||
elVersion = '3.0.1-b09'
|
elVersion = '3.0.1-b09'
|
||||||
|
|
||||||
cdiVersion = '2.0'
|
cdiVersion = '2.0'
|
||||||
weldVersion = '3.0.0.Final'
|
weldVersion = '3.1.5.Final'
|
||||||
|
|
||||||
javassistVersion = '3.27.0-GA'
|
javassistVersion = '3.27.0-GA'
|
||||||
byteBuddyVersion = '1.10.17'
|
byteBuddyVersion = '1.10.17'
|
||||||
|
@ -49,6 +49,8 @@ ext {
|
||||||
|
|
||||||
antlrVersion = '4.8-1'
|
antlrVersion = '4.8-1'
|
||||||
|
|
||||||
|
micrometerVersion = '1.6.1'
|
||||||
|
|
||||||
libraries = [
|
libraries = [
|
||||||
// Ant
|
// Ant
|
||||||
ant: 'org.apache.ant:ant:1.8.2',
|
ant: 'org.apache.ant:ant:1.8.2',
|
||||||
|
@ -155,6 +157,7 @@ ext {
|
||||||
vibur: "org.vibur:vibur-dbcp:25.0",
|
vibur: "org.vibur:vibur-dbcp:25.0",
|
||||||
agroal_api: "io.agroal:agroal-api:${agroalVersion}",
|
agroal_api: "io.agroal:agroal-api:${agroalVersion}",
|
||||||
agroal_pool: "io.agroal:agroal-pool:${agroalVersion}",
|
agroal_pool: "io.agroal:agroal-pool:${agroalVersion}",
|
||||||
|
micrometer: "io.micrometer:micrometer-core:1.6.1",
|
||||||
|
|
||||||
atomikos: "com.atomikos:transactions:4.0.6",
|
atomikos: "com.atomikos:transactions:4.0.6",
|
||||||
atomikos_jta: "com.atomikos:transactions-jta:4.0.6",
|
atomikos_jta: "com.atomikos:transactions-jta:4.0.6",
|
||||||
|
|
|
@ -263,6 +263,15 @@ task generateEnversStaticMetamodel(
|
||||||
|
|
||||||
test {
|
test {
|
||||||
systemProperty 'file.encoding', 'utf-8'
|
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 ->
|
beforeTest { descriptor ->
|
||||||
//println "Starting test: " + descriptor
|
//println "Starting test: " + descriptor
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,23 +201,24 @@ public class ScanningCoordinator {
|
||||||
nonLocatedMappingFileNames.addAll( explicitMappingFileNames );
|
nonLocatedMappingFileNames.addAll( explicitMappingFileNames );
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( MappingFileDescriptor mappingFileDescriptor : scanResult.getLocatedMappingFiles() ) {
|
if ( xmlMappingBinderAccess != null ) { // xml mapping is not disabled
|
||||||
managedResources.addXmlBinding( xmlMappingBinderAccess.bind( mappingFileDescriptor.getStreamAccess() ) );
|
for ( MappingFileDescriptor mappingFileDescriptor : scanResult.getLocatedMappingFiles() ) {
|
||||||
nonLocatedMappingFileNames.remove( mappingFileDescriptor.getName() );
|
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 )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// classes and packages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -289,28 +289,30 @@ public class MetadataBuildingProcess {
|
||||||
|
|
||||||
metadataCollector.processSecondPasses( rootMetadataBuildingContext );
|
metadataCollector.processSecondPasses( rootMetadataBuildingContext );
|
||||||
|
|
||||||
Iterable<AdditionalJaxbMappingProducer> producers = classLoaderService.loadJavaServices( AdditionalJaxbMappingProducer.class );
|
if ( options.isXmlMappingEnabled() ) {
|
||||||
if ( producers != null ) {
|
Iterable<AdditionalJaxbMappingProducer> producers = classLoaderService.loadJavaServices( AdditionalJaxbMappingProducer.class );
|
||||||
final EntityHierarchyBuilder hierarchyBuilder = new EntityHierarchyBuilder();
|
if ( producers != null ) {
|
||||||
// final MappingBinder mappingBinder = new MappingBinder( true );
|
final EntityHierarchyBuilder hierarchyBuilder = new EntityHierarchyBuilder();
|
||||||
// We need to disable validation here. It seems Envers is not producing valid (according to schema) XML
|
// final MappingBinder mappingBinder = new MappingBinder( true );
|
||||||
final MappingBinder mappingBinder = options.isXmlMappingEnabled() ? new MappingBinder( classLoaderService, false ) : null;
|
// We need to disable validation here. It seems Envers is not producing valid (according to schema) XML
|
||||||
for ( AdditionalJaxbMappingProducer producer : producers ) {
|
final MappingBinder mappingBinder = new MappingBinder( classLoaderService, false );
|
||||||
log.tracef( "Calling AdditionalJaxbMappingProducer : %s", producer );
|
for ( AdditionalJaxbMappingProducer producer : producers ) {
|
||||||
Collection<MappingDocument> additionalMappings = producer.produceAdditionalMappings(
|
log.tracef( "Calling AdditionalJaxbMappingProducer : %s", producer );
|
||||||
metadataCollector,
|
Collection<MappingDocument> additionalMappings = producer.produceAdditionalMappings(
|
||||||
jandexView,
|
metadataCollector,
|
||||||
mappingBinder,
|
jandexView,
|
||||||
rootMetadataBuildingContext
|
mappingBinder,
|
||||||
);
|
rootMetadataBuildingContext
|
||||||
for ( MappingDocument mappingDocument : additionalMappings ) {
|
);
|
||||||
hierarchyBuilder.indexMappingDocument( mappingDocument );
|
for ( MappingDocument mappingDocument : additionalMappings ) {
|
||||||
|
hierarchyBuilder.indexMappingDocument( mappingDocument );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ModelBinder binder = ModelBinder.prepare( rootMetadataBuildingContext );
|
ModelBinder binder = ModelBinder.prepare( rootMetadataBuildingContext );
|
||||||
for ( EntityHierarchySourceImpl entityHierarchySource : hierarchyBuilder.buildHierarchies() ) {
|
for ( EntityHierarchySourceImpl entityHierarchySource : hierarchyBuilder.buildHierarchies() ) {
|
||||||
binder.bindEntityHierarchy( entityHierarchySource );
|
binder.bindEntityHierarchy( entityHierarchySource );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.hibernate.proxy.ProxyConfiguration;
|
||||||
import org.hibernate.proxy.ProxyFactory;
|
import org.hibernate.proxy.ProxyFactory;
|
||||||
|
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
|
import net.bytebuddy.ClassFileVersion;
|
||||||
import net.bytebuddy.TypeCache;
|
import net.bytebuddy.TypeCache;
|
||||||
import net.bytebuddy.asm.AsmVisitorWrapper.ForDeclaredMethods;
|
import net.bytebuddy.asm.AsmVisitorWrapper.ForDeclaredMethods;
|
||||||
import net.bytebuddy.asm.MemberSubstitution;
|
import net.bytebuddy.asm.MemberSubstitution;
|
||||||
|
@ -71,7 +72,11 @@ public final class ByteBuddyState {
|
||||||
private final TypeCache<TypeCache.SimpleKey> basicProxyCache;
|
private final TypeCache<TypeCache.SimpleKey> basicProxyCache;
|
||||||
|
|
||||||
ByteBuddyState() {
|
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.proxyCache = new TypeCache.WithInlineExpunction<TypeCache.SimpleKey>( TypeCache.Sort.WEAK );
|
||||||
this.basicProxyCache = 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.bytecode.spi.ReflectionOptimizer;
|
||||||
import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyHelper;
|
import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyHelper;
|
||||||
|
|
||||||
|
import net.bytebuddy.ClassFileVersion;
|
||||||
import net.bytebuddy.NamingStrategy;
|
import net.bytebuddy.NamingStrategy;
|
||||||
import net.bytebuddy.description.method.MethodDescription;
|
import net.bytebuddy.description.method.MethodDescription;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
@ -49,8 +50,21 @@ public class BytecodeProviderImpl implements BytecodeProvider {
|
||||||
|
|
||||||
private final ByteBuddyProxyHelper byteBuddyProxyHelper;
|
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() {
|
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 );
|
this.byteBuddyProxyHelper = new ByteBuddyProxyHelper( byteBuddyState );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ import org.hibernate.annotations.LazyGroup;
|
||||||
import org.hibernate.annotations.Loader;
|
import org.hibernate.annotations.Loader;
|
||||||
import org.hibernate.annotations.ManyToAny;
|
import org.hibernate.annotations.ManyToAny;
|
||||||
import org.hibernate.annotations.OnDelete;
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
import org.hibernate.annotations.OptimisticLock;
|
import org.hibernate.annotations.OptimisticLock;
|
||||||
import org.hibernate.annotations.OrderBy;
|
import org.hibernate.annotations.OrderBy;
|
||||||
import org.hibernate.annotations.Parameter;
|
import org.hibernate.annotations.Parameter;
|
||||||
|
@ -104,6 +105,7 @@ import org.hibernate.mapping.KeyValue;
|
||||||
import org.hibernate.mapping.ManyToOne;
|
import org.hibernate.mapping.ManyToOne;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
|
import org.hibernate.mapping.Selectable;
|
||||||
import org.hibernate.mapping.SimpleValue;
|
import org.hibernate.mapping.SimpleValue;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
|
|
||||||
|
@ -557,7 +559,9 @@ public abstract class CollectionBinder {
|
||||||
}
|
}
|
||||||
//TODO reduce tableBinder != null and oneToMany
|
//TODO reduce tableBinder != null and oneToMany
|
||||||
XClass collectionType = getCollectionType();
|
XClass collectionType = getCollectionType();
|
||||||
if ( inheritanceStatePerClass == null) throw new AssertionFailure( "inheritanceStatePerClass not set" );
|
if ( inheritanceStatePerClass == null) {
|
||||||
|
throw new AssertionFailure( "inheritanceStatePerClass not set" );
|
||||||
|
}
|
||||||
SecondPass sp = getSecondPass(
|
SecondPass sp = getSecondPass(
|
||||||
fkJoinColumns,
|
fkJoinColumns,
|
||||||
joinColumns,
|
joinColumns,
|
||||||
|
@ -606,7 +610,9 @@ public abstract class CollectionBinder {
|
||||||
binder.setUpdatable( updatable );
|
binder.setUpdatable( updatable );
|
||||||
Property prop = binder.makeProperty();
|
Property prop = binder.makeProperty();
|
||||||
//we don't care about the join stuffs because the column is on the association table.
|
//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 );
|
propertyHolder.addProperty( prop, declaringClass );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,7 +620,7 @@ public abstract class CollectionBinder {
|
||||||
boolean hadOrderBy = false;
|
boolean hadOrderBy = false;
|
||||||
boolean hadExplicitSort = false;
|
boolean hadExplicitSort = false;
|
||||||
|
|
||||||
Class<? extends Comparator> comparatorClass = null;
|
Class<? extends Comparator<?>> comparatorClass = null;
|
||||||
|
|
||||||
if ( jpaOrderBy == null && sqlOrderBy == null ) {
|
if ( jpaOrderBy == null && sqlOrderBy == null ) {
|
||||||
if ( deprecatedSort != null ) {
|
if ( deprecatedSort != null ) {
|
||||||
|
@ -779,8 +785,9 @@ public abstract class CollectionBinder {
|
||||||
final TableBinder assocTableBinder,
|
final TableBinder assocTableBinder,
|
||||||
final MetadataBuildingContext buildingContext) {
|
final MetadataBuildingContext buildingContext) {
|
||||||
return new CollectionSecondPass( buildingContext, collection ) {
|
return new CollectionSecondPass( buildingContext, collection ) {
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) throws MappingException {
|
public void secondPass(Map persistentClasses, Map inheritedMetas) throws MappingException {
|
||||||
bindStarToManySecondPass(
|
bindStarToManySecondPass(
|
||||||
persistentClasses,
|
persistentClasses,
|
||||||
collType,
|
collType,
|
||||||
|
@ -803,7 +810,7 @@ public abstract class CollectionBinder {
|
||||||
* return true if it's a Fk, false if it's an association table
|
* return true if it's a Fk, false if it's an association table
|
||||||
*/
|
*/
|
||||||
protected boolean bindStarToManySecondPass(
|
protected boolean bindStarToManySecondPass(
|
||||||
Map persistentClasses,
|
Map<String, PersistentClass> persistentClasses,
|
||||||
XClass collType,
|
XClass collType,
|
||||||
Ejb3JoinColumn[] fkJoinColumns,
|
Ejb3JoinColumn[] fkJoinColumns,
|
||||||
Ejb3JoinColumn[] keyColumns,
|
Ejb3JoinColumn[] keyColumns,
|
||||||
|
@ -815,7 +822,7 @@ public abstract class CollectionBinder {
|
||||||
TableBinder associationTableBinder,
|
TableBinder associationTableBinder,
|
||||||
boolean ignoreNotFound,
|
boolean ignoreNotFound,
|
||||||
MetadataBuildingContext buildingContext) {
|
MetadataBuildingContext buildingContext) {
|
||||||
PersistentClass persistentClass = (PersistentClass) persistentClasses.get( collType.getName() );
|
PersistentClass persistentClass = persistentClasses.get( collType.getName() );
|
||||||
boolean reversePropertyInJoin = false;
|
boolean reversePropertyInJoin = false;
|
||||||
if ( persistentClass != null && StringHelper.isNotEmpty( this.mappedBy ) ) {
|
if ( persistentClass != null && StringHelper.isNotEmpty( this.mappedBy ) ) {
|
||||||
try {
|
try {
|
||||||
|
@ -876,7 +883,7 @@ public abstract class CollectionBinder {
|
||||||
|
|
||||||
protected void bindOneToManySecondPass(
|
protected void bindOneToManySecondPass(
|
||||||
Collection collection,
|
Collection collection,
|
||||||
Map persistentClasses,
|
Map<String, PersistentClass> persistentClasses,
|
||||||
Ejb3JoinColumn[] fkJoinColumns,
|
Ejb3JoinColumn[] fkJoinColumns,
|
||||||
XClass collectionType,
|
XClass collectionType,
|
||||||
boolean cascadeDeleteEnabled,
|
boolean cascadeDeleteEnabled,
|
||||||
|
@ -898,7 +905,7 @@ public abstract class CollectionBinder {
|
||||||
oneToMany.setIgnoreNotFound( ignoreNotFound );
|
oneToMany.setIgnoreNotFound( ignoreNotFound );
|
||||||
|
|
||||||
String assocClass = oneToMany.getReferencedEntityName();
|
String assocClass = oneToMany.getReferencedEntityName();
|
||||||
PersistentClass associatedClass = (PersistentClass) persistentClasses.get( assocClass );
|
PersistentClass associatedClass = persistentClasses.get( assocClass );
|
||||||
if ( jpaOrderBy != null ) {
|
if ( jpaOrderBy != null ) {
|
||||||
final String orderByFragment = buildOrderByClauseFromHql(
|
final String orderByFragment = buildOrderByClauseFromHql(
|
||||||
jpaOrderBy.value(),
|
jpaOrderBy.value(),
|
||||||
|
@ -1215,8 +1222,8 @@ public abstract class CollectionBinder {
|
||||||
key.setForeignKeyName( StringHelper.nullIfEmpty( collectionTableAnn.foreignKey().name() ) );
|
key.setForeignKeyName( StringHelper.nullIfEmpty( collectionTableAnn.foreignKey().name() ) );
|
||||||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( collectionTableAnn.foreignKey().foreignKeyDefinition() ) );
|
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( collectionTableAnn.foreignKey().foreignKeyDefinition() ) );
|
||||||
if ( key.getForeignKeyName() == null &&
|
if ( key.getForeignKeyName() == null &&
|
||||||
key.getForeignKeyDefinition() == null &&
|
key.getForeignKeyDefinition() == null &&
|
||||||
collectionTableAnn.joinColumns().length == 1 ) {
|
collectionTableAnn.joinColumns().length == 1 ) {
|
||||||
JoinColumn joinColumn = collectionTableAnn.joinColumns()[0];
|
JoinColumn joinColumn = collectionTableAnn.joinColumns()[0];
|
||||||
key.setForeignKeyName( StringHelper.nullIfEmpty( joinColumn.foreignKey().name() ) );
|
key.setForeignKeyName( StringHelper.nullIfEmpty( joinColumn.foreignKey().name() ) );
|
||||||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumn.foreignKey().foreignKeyDefinition() ) );
|
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumn.foreignKey().foreignKeyDefinition() ) );
|
||||||
|
@ -1261,15 +1268,25 @@ public abstract class CollectionBinder {
|
||||||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( fkOverride.foreignKeyDefinition() ) );
|
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( fkOverride.foreignKeyDefinition() ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final JoinColumn joinColumnAnn = property.getAnnotation( JoinColumn.class );
|
final OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class );
|
||||||
if ( joinColumnAnn != null ) {
|
final OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
|
||||||
if ( joinColumnAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT
|
if ( oneToManyAnn != null && !oneToManyAnn.mappedBy().isEmpty()
|
||||||
|| joinColumnAnn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) {
|
&& ( onDeleteAnn == null || onDeleteAnn.action() != OnDeleteAction.CASCADE ) ) {
|
||||||
key.setForeignKeyName( "none" );
|
// foreign key should be up to @ManyToOne side
|
||||||
}
|
// @OnDelete generate "on delete cascade" foreign key
|
||||||
else {
|
key.setForeignKeyName( "none" );
|
||||||
key.setForeignKeyName( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().name() ) );
|
}
|
||||||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().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() ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1283,7 +1300,7 @@ public abstract class CollectionBinder {
|
||||||
|
|
||||||
private void bindManyToManySecondPass(
|
private void bindManyToManySecondPass(
|
||||||
Collection collValue,
|
Collection collValue,
|
||||||
Map persistentClasses,
|
Map<String, PersistentClass> persistentClasses,
|
||||||
Ejb3JoinColumn[] joinColumns,
|
Ejb3JoinColumn[] joinColumns,
|
||||||
Ejb3JoinColumn[] inverseJoinColumns,
|
Ejb3JoinColumn[] inverseJoinColumns,
|
||||||
Ejb3Column[] elementColumns,
|
Ejb3Column[] elementColumns,
|
||||||
|
@ -1299,7 +1316,7 @@ public abstract class CollectionBinder {
|
||||||
throw new IllegalArgumentException( "null was passed for argument property" );
|
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 );
|
final String hqlOrderBy = extractHqlOrderBy( jpaOrderBy );
|
||||||
|
|
||||||
boolean isCollectionOfEntities = collectionEntity != null;
|
boolean isCollectionOfEntities = collectionEntity != null;
|
||||||
|
@ -1732,13 +1749,13 @@ public abstract class CollectionBinder {
|
||||||
final String mappedBy = columns[0].getMappedBy();
|
final String mappedBy = columns[0].getMappedBy();
|
||||||
if ( StringHelper.isNotEmpty( mappedBy ) ) {
|
if ( StringHelper.isNotEmpty( mappedBy ) ) {
|
||||||
final Property property = referencedEntity.getRecursiveProperty( mappedBy );
|
final Property property = referencedEntity.getRecursiveProperty( mappedBy );
|
||||||
Iterator mappedByColumns;
|
Iterator<Selectable> mappedByColumns;
|
||||||
if ( property.getValue() instanceof Collection ) {
|
if ( property.getValue() instanceof Collection ) {
|
||||||
mappedByColumns = ( (Collection) property.getValue() ).getKey().getColumnIterator();
|
mappedByColumns = ( (Collection) property.getValue() ).getKey().getColumnIterator();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//find the appropriate reference key, can be in a join
|
//find the appropriate reference key, can be in a join
|
||||||
Iterator joinsIt = referencedEntity.getJoinIterator();
|
Iterator<Join> joinsIt = referencedEntity.getJoinIterator();
|
||||||
KeyValue key = null;
|
KeyValue key = null;
|
||||||
while ( joinsIt.hasNext() ) {
|
while ( joinsIt.hasNext() ) {
|
||||||
Join join = (Join) joinsIt.next();
|
Join join = (Join) joinsIt.next();
|
||||||
|
@ -1747,7 +1764,9 @@ public abstract class CollectionBinder {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( key == null ) key = property.getPersistentClass().getIdentifier();
|
if ( key == null ) {
|
||||||
|
key = property.getPersistentClass().getIdentifier();
|
||||||
|
}
|
||||||
mappedByColumns = key.getColumnIterator();
|
mappedByColumns = key.getColumnIterator();
|
||||||
}
|
}
|
||||||
while ( mappedByColumns.hasNext() ) {
|
while ( mappedByColumns.hasNext() ) {
|
||||||
|
|
|
@ -788,6 +788,13 @@ public class PostgreSQLDialect extends Dialect {
|
||||||
super.augmentRecognizedTableTypes( tableTypesList );
|
super.augmentRecognizedTableTypes( tableTypesList );
|
||||||
if ( getVersion() >= 930 ) {
|
if ( getVersion() >= 930 ) {
|
||||||
tableTypesList.add( "MATERIALIZED VIEW" );
|
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 -> {
|
mutablePropertiesIndexes.stream().forEach( i -> {
|
||||||
// This is kindly borrowed from org.hibernate.type.TypeHelper.findDirty
|
// This is kindly borrowed from org.hibernate.type.TypeHelper.findDirty
|
||||||
final boolean dirty = currentState[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY &&
|
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]
|
( propertyCheckability[i]
|
||||||
&& propertyTypes[i].isDirty(
|
&& propertyTypes[i].isDirty(
|
||||||
previousState[i],
|
previousState[i],
|
||||||
|
|
|
@ -142,9 +142,8 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||||
|
|
||||||
// first, instantiate the entity instance to use as the proxy
|
// first, instantiate the entity instance to use as the proxy
|
||||||
final EntityTuplizer entityTuplizer = persister.getEntityTuplizer();
|
final PersistentAttributeInterceptable entity = (PersistentAttributeInterceptable) persister.getRepresentationStrategy().getInstantiator().instantiate(
|
||||||
final PersistentAttributeInterceptable entity = (PersistentAttributeInterceptable) entityTuplizer
|
session.getFactory() );
|
||||||
.instantiate( identifier, session );
|
|
||||||
|
|
||||||
// clear the fields that are marked as dirty in the dirtiness tracker
|
// clear the fields that are marked as dirty in the dirtiness tracker
|
||||||
if ( entity instanceof SelfDirtinessTracker ) {
|
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();
|
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
|
@Test
|
||||||
@TestForIssue( jiraKey = "HHH-10476")
|
@TestForIssue( jiraKey = "HHH-10476")
|
||||||
public void testInsertFooAndBarWithDerivedIdPC() {
|
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.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
@ -280,6 +281,7 @@ public class UpdateDetachedTest extends BaseCoreFunctionalTestCase{
|
||||||
|
|
||||||
@Embeddable
|
@Embeddable
|
||||||
public static class Comment {
|
public static class Comment {
|
||||||
|
@Column(name = "bar_comment")
|
||||||
private String comment;
|
private String comment;
|
||||||
private String author;
|
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;
|
String name;
|
||||||
|
|
||||||
@OneToMany(targetEntity = RoleEntity.class, mappedBy = "key", fetch = FetchType.LAZY)
|
@OneToMany(targetEntity = RoleEntity.class, mappedBy = "key", fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("R")
|
@LazyGroup("R")
|
||||||
protected Set<RoleEntity> roles = new LinkedHashSet<>();
|
protected Set<RoleEntity> roles = new LinkedHashSet<>();
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("PR")
|
@LazyGroup("PR")
|
||||||
@JoinColumn
|
@JoinColumn
|
||||||
protected AbstractKey register;
|
protected AbstractKey register;
|
||||||
|
|
||||||
@OneToMany(targetEntity = AbstractKey.class, mappedBy = "register", fetch = FetchType.LAZY)
|
@OneToMany(targetEntity = AbstractKey.class, mappedBy = "register", fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("RK")
|
@LazyGroup("RK")
|
||||||
protected Set<AbstractKey> keys = new LinkedHashSet();
|
protected Set<AbstractKey> keys = new LinkedHashSet();
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("PP")
|
@LazyGroup("PP")
|
||||||
@JoinColumn
|
@JoinColumn
|
||||||
protected AbstractKey parent;
|
protected AbstractKey parent;
|
||||||
|
|
||||||
@OneToMany(targetEntity = AbstractKey.class, mappedBy = "parent", fetch = FetchType.LAZY)
|
@OneToMany(targetEntity = AbstractKey.class, mappedBy = "parent", fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("PK")
|
@LazyGroup("PK")
|
||||||
protected Set<AbstractKey> otherKeys = new LinkedHashSet();
|
protected Set<AbstractKey> otherKeys = new LinkedHashSet();
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,6 @@ public class Activity extends BaseEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("Instruction")
|
@LazyGroup("Instruction")
|
||||||
@JoinColumn(name = "Instruction_Id")
|
@JoinColumn(name = "Instruction_Id")
|
||||||
public Instruction getInstruction() {
|
public Instruction getInstruction() {
|
||||||
|
@ -66,7 +65,6 @@ public class Activity extends BaseEntity {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@ManyToOne(fetch=FetchType.LAZY)
|
@ManyToOne(fetch=FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("webApplication")
|
@LazyGroup("webApplication")
|
||||||
@JoinColumn(name="web_app_oid")
|
@JoinColumn(name="web_app_oid")
|
||||||
public WebApplication getWebApplication() {
|
public WebApplication getWebApplication() {
|
||||||
|
|
|
@ -246,7 +246,6 @@ public class BatchFetchProxyTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Employer employer;
|
private Employer employer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,6 @@ public class BidirectionalProxyTest extends BaseNonConfigCoreFunctionalTestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
@ManyToOne(fetch= FetchType.LAZY)
|
@ManyToOne(fetch= FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("aEntity")
|
@LazyGroup("aEntity")
|
||||||
@JoinColumn(name="aEntity")
|
@JoinColumn(name="aEntity")
|
||||||
protected AEntity aChildEntity = null;
|
protected AEntity aChildEntity = null;
|
||||||
|
@ -249,7 +248,6 @@ public class BidirectionalProxyTest extends BaseNonConfigCoreFunctionalTestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
@ManyToOne(fetch= FetchType.LAZY)
|
@ManyToOne(fetch= FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("aEntity")
|
@LazyGroup("aEntity")
|
||||||
@JoinColumn(name="aEntity")
|
@JoinColumn(name="aEntity")
|
||||||
protected AChildEntity aChildEntity = null;
|
protected AChildEntity aChildEntity = null;
|
||||||
|
|
|
@ -212,7 +212,6 @@ public class EntitySharedInCollectionAndToOneTest extends BaseNonConfigCoreFunct
|
||||||
private CodeTable codeTable;
|
private CodeTable codeTable;
|
||||||
|
|
||||||
@OneToOne( mappedBy = "defaultItem", fetch=FetchType.LAZY )
|
@OneToOne( mappedBy = "defaultItem", fetch=FetchType.LAZY )
|
||||||
@LazyToOne( LazyToOneOption.NO_PROXY )
|
|
||||||
@LazyGroup( "defaultItemInverse" )
|
@LazyGroup( "defaultItemInverse" )
|
||||||
protected CodeTable defaultItemInverse;
|
protected CodeTable defaultItemInverse;
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.testing.FailureExpected;
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||||
|
@ -199,6 +200,7 @@ public class FetchGraphTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@FailureExpected( jiraKey = "HHH-13658")
|
||||||
public void testRandomAccess() {
|
public void testRandomAccess() {
|
||||||
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
||||||
stats.clear();
|
stats.clear();
|
||||||
|
@ -787,14 +789,10 @@ public class FetchGraphTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
// ****** Relations *****************
|
// ****** Relations *****************
|
||||||
@OneToOne(fetch = FetchType.LAZY)
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
// @LazyToOne(LazyToOneOption.PROXY)
|
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("a")
|
@LazyGroup("a")
|
||||||
public AEntity a;
|
public AEntity a;
|
||||||
|
|
||||||
@OneToOne(fetch = FetchType.LAZY)
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
// @LazyToOne(LazyToOneOption.PROXY)
|
|
||||||
@LazyGroup("c")
|
@LazyGroup("c")
|
||||||
public CEntity c;
|
public CEntity c;
|
||||||
|
|
||||||
|
@ -802,7 +800,6 @@ public class FetchGraphTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
public Set<BEntity> bs;
|
public Set<BEntity> bs;
|
||||||
|
|
||||||
@OneToOne(mappedBy = "d", fetch = FetchType.LAZY)
|
@OneToOne(mappedBy = "d", fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("e")
|
@LazyGroup("e")
|
||||||
private EEntity e;
|
private EEntity e;
|
||||||
|
|
||||||
|
|
|
@ -264,19 +264,15 @@ public class LazyToOnesNoProxyFactoryWithSubclassesStatefulTest extends BaseNonC
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Animal animal = null;
|
private Animal animal = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Primate primate = null;
|
private Primate primate = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Human human = null;
|
private Human human = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Human otherHuman = null;
|
private Human otherHuman = null;
|
||||||
|
|
||||||
protected OtherEntity() {
|
protected OtherEntity() {
|
||||||
|
|
|
@ -264,19 +264,15 @@ public class LazyToOnesNoProxyFactoryWithSubclassesStatelessTest extends BaseNon
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Animal animal = null;
|
private Animal animal = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Primate primate = null;
|
private Primate primate = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Human human = null;
|
private Human human = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Human otherHuman = null;
|
private Human otherHuman = null;
|
||||||
|
|
||||||
protected OtherEntity() {
|
protected OtherEntity() {
|
||||||
|
|
|
@ -831,15 +831,12 @@ public class LazyToOnesProxyMergeWithSubclassesTest extends BaseNonConfigCoreFun
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Animal animal = null;
|
private Animal animal = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Primate primate = null;
|
private Primate primate = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Human human = null;
|
private Human human = null;
|
||||||
|
|
||||||
protected OtherEntity() {
|
protected OtherEntity() {
|
||||||
|
|
|
@ -298,15 +298,12 @@ public class LazyToOnesProxyWithSubclassesStatelessTest extends BaseNonConfigCor
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Animal animal = null;
|
private Animal animal = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Primate primate = null;
|
private Primate primate = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Human human = null;
|
private Human human = null;
|
||||||
|
|
||||||
protected OtherEntity() {
|
protected OtherEntity() {
|
||||||
|
|
|
@ -366,15 +366,12 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Animal animal = null;
|
private Animal animal = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Primate primate = null;
|
private Primate primate = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Human human = null;
|
private Human human = null;
|
||||||
|
|
||||||
protected OtherEntity() {
|
protected OtherEntity() {
|
||||||
|
|
|
@ -180,7 +180,6 @@ public class LoadANonExistingEntityTest extends BaseNonConfigCoreFunctionalTestC
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Employer employer;
|
private Employer employer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,6 @@ public class LoadANonExistingNotFoundBatchEntityTest extends BaseNonConfigCoreFu
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
@JoinColumn(foreignKey = @ForeignKey(value= ConstraintMode.NO_CONSTRAINT))
|
@JoinColumn(foreignKey = @ForeignKey(value= ConstraintMode.NO_CONSTRAINT))
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@NotFound(action=NotFoundAction.IGNORE)
|
@NotFound(action=NotFoundAction.IGNORE)
|
||||||
private Employer employer;
|
private Employer employer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,7 +183,6 @@ public class LoadANonExistingNotFoundEntityTest extends BaseNonConfigCoreFunctio
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
@JoinColumn(foreignKey = @ForeignKey(value= ConstraintMode.NO_CONSTRAINT))
|
@JoinColumn(foreignKey = @ForeignKey(value= ConstraintMode.NO_CONSTRAINT))
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@NotFound(action=NotFoundAction.IGNORE)
|
@NotFound(action=NotFoundAction.IGNORE)
|
||||||
private Employer employer;
|
private Employer employer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,6 @@ public class MapsIdProxyBidirectionalTest extends BaseNonConfigCoreFunctionalTes
|
||||||
|
|
||||||
@MapsId
|
@MapsId
|
||||||
@OneToOne(optional = false, fetch = FetchType.LAZY)
|
@OneToOne(optional = false, fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Employer employer;
|
private Employer employer;
|
||||||
|
|
||||||
private String info;
|
private String info;
|
||||||
|
@ -165,7 +164,6 @@ public class MapsIdProxyBidirectionalTest extends BaseNonConfigCoreFunctionalTes
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
@OneToOne(optional = false, fetch = FetchType.LAZY, mappedBy = "employer", cascade = CascadeType.ALL)
|
@OneToOne(optional = false, fetch = FetchType.LAZY, mappedBy = "employer", cascade = CascadeType.ALL)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private EmployerInfo employerInfo;
|
private EmployerInfo employerInfo;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
|
@ -122,7 +122,6 @@ public class MapsIdProxyUnidirectionalTest extends BaseNonConfigCoreFunctionalTe
|
||||||
|
|
||||||
@MapsId
|
@MapsId
|
||||||
@OneToOne(optional = false, fetch = FetchType.LAZY)
|
@OneToOne(optional = false, fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private Employer employer;
|
private Employer employer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,6 @@ public class MergeDetachedToProxyTest extends BaseNonConfigCoreFunctionalTestCas
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
private BEntity bEntity;
|
private BEntity bEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -302,7 +302,6 @@ public class QueryScrollingWithInheritanceProxyEagerManyToOneTest extends BaseNo
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@JoinColumn(name = "Employee_Id")
|
@JoinColumn(name = "Employee_Id")
|
||||||
protected Employee employee = null;
|
protected Employee employee = null;
|
||||||
|
|
||||||
|
|
|
@ -302,12 +302,10 @@ public class QueryScrollingWithInheritanceProxyTest extends BaseNonConfigCoreFun
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@JoinColumn(name = "Employee_Id")
|
@JoinColumn(name = "Employee_Id")
|
||||||
protected Employee employee = null;
|
protected Employee employee = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@JoinColumn(name = "EmployeeParent_Id")
|
@JoinColumn(name = "EmployeeParent_Id")
|
||||||
protected EmployeeParent employeeParent = null;
|
protected EmployeeParent employeeParent = null;
|
||||||
|
|
||||||
|
|
|
@ -283,7 +283,6 @@ public class SimpleUpdateTestWithLazyLoading extends BaseNonConfigCoreFunctional
|
||||||
Long id;
|
Long id;
|
||||||
|
|
||||||
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
Parent parent;
|
Parent parent;
|
||||||
|
|
||||||
@OneToMany
|
@OneToMany
|
||||||
|
|
|
@ -235,7 +235,6 @@ public class SimpleUpdateTestWithLazyLoadingAndInlineDirtyTracking extends BaseN
|
||||||
Long id;
|
Long id;
|
||||||
|
|
||||||
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
Parent parent;
|
Parent parent;
|
||||||
|
|
||||||
@OneToMany
|
@OneToMany
|
||||||
|
|
|
@ -59,7 +59,6 @@ public class WebApplication extends BaseEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@OneToMany(mappedBy="webApplication", fetch= FetchType.LAZY)
|
@OneToMany(mappedBy="webApplication", fetch= FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
|
||||||
@LazyGroup("app_activity_group")
|
@LazyGroup("app_activity_group")
|
||||||
// @CollectionType(type="baseutil.technology.hibernate.IskvLinkedSetCollectionType")
|
// @CollectionType(type="baseutil.technology.hibernate.IskvLinkedSetCollectionType")
|
||||||
public Set<Activity> getActivities() {
|
public Set<Activity> getActivities() {
|
||||||
|
|
|
@ -23,6 +23,7 @@ public class TestEntity {
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
@Column(name = "t_date")
|
||||||
private Date date;
|
private Date date;
|
||||||
|
|
||||||
@Basic
|
@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.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
import org.hibernate.boot.spi.MetadataImplementor;
|
import org.hibernate.boot.spi.MetadataImplementor;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
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.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.configuration.internal.EntitiesConfigurator;
|
import org.hibernate.envers.configuration.internal.EntitiesConfigurator;
|
||||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||||
|
@ -36,6 +39,8 @@ import org.hibernate.service.spi.Stoppable;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import static org.hibernate.cfg.AvailableSettings.XML_MAPPING_ENABLED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides central access to Envers' configuration.
|
* 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 );
|
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 );
|
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 )
|
compile( libraries.proxool )
|
||||||
testCompile project( ':hibernate-testing' )
|
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-jcache'
|
||||||
include 'hibernate-ehcache'
|
include 'hibernate-ehcache'
|
||||||
include 'hibernate-infinispan'
|
include 'hibernate-infinispan'
|
||||||
|
include 'hibernate-micrometer'
|
||||||
include 'hibernate-graalvm'
|
include 'hibernate-graalvm'
|
||||||
|
|
||||||
// The plugin used to generate Java modules was compiled using JDK11.
|
// 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." )
|
" 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