diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle
index 0fe2a23e5b..48f95889fb 100644
--- a/hibernate-core/hibernate-core.gradle
+++ b/hibernate-core/hibernate-core.gradle
@@ -16,15 +16,44 @@ apply plugin: 'hibernate-matrix-testing'
description = 'Hibernate\'s core ORM functionality'
+ext {
+ jaxbTargetDir = file( "${buildDir}/generated-src/jaxb/main" )
+}
+
+sourceSets.main {
+ java.srcDir project.jaxbTargetDir
+}
+
+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
+ }
+ }
+}
+
configurations {
tests {
description = 'Configuration for the produced test jar'
}
+
+ //Configures the compile and runtime configurations for our javassist tests
+ //and includes the dependencies of the test task.
+ testJavassistCompile.extendsFrom testCompile
+ testJavassistRuntime.extendsFrom testRuntime
}
dependencies {
compile( libraries.jpa )
- // Javassist is no longer the default enhancer but still required for other purposes, e.g. Scanning
+ // This can now be made provided
compile( libraries.javassist )
compile( libraries.byteBuddy )
compile( libraries.antlr )
@@ -107,6 +136,10 @@ dependencies {
testCompile libraries.jboss_ejb_spec_jar
testCompile libraries.jboss_annotation_spec_jar
+
+ // Additional tests requiring Javassist
+ // folder in src/javassist/java
+ testJavassistCompile libraries.javassist
}
jar {
@@ -407,4 +440,18 @@ class Antlr4GenerationTask extends DefaultTask {
args sourceFile.absolutePath
}
}
-}
\ No newline at end of file
+
+}
+//Create the task that runs the integration tests found from the
+//configured source directory and uses the correct classpath.
+task testJavassist(type: Test) {
+ testClassesDirs = sourceSets.testJavassist.output.classesDirs
+ classpath = sourceSets.testJavassist.runtimeClasspath
+ //If you want to ensure that integration tests are run every time when you invoke
+ //this task, uncomment the following line.
+ //outputs.upToDateWhen { false }
+}
+
+check.dependsOn testJavassist
+testJavassist.mustRunAfter test
+
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/archive/scan/spi/ClassFileArchiveEntryHandler.java b/hibernate-core/src/main/java/org/hibernate/boot/archive/scan/spi/ClassFileArchiveEntryHandler.java
index b005eaf539..7647c0a1cf 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/archive/scan/spi/ClassFileArchiveEntryHandler.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/archive/scan/spi/ClassFileArchiveEntryHandler.java
@@ -14,9 +14,6 @@ import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
-import javassist.bytecode.AnnotationsAttribute;
-import javassist.bytecode.ClassFile;
-
import org.hibernate.boot.archive.scan.internal.ClassDescriptorImpl;
import org.hibernate.boot.archive.scan.internal.ScanResultCollector;
import org.hibernate.boot.archive.spi.ArchiveContext;
@@ -24,12 +21,26 @@ import org.hibernate.boot.archive.spi.ArchiveEntry;
import org.hibernate.boot.archive.spi.ArchiveEntryHandler;
import org.hibernate.boot.archive.spi.ArchiveException;
+import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.Index;
+import org.jboss.jandex.Indexer;
+
/**
* Defines handling and filtering for class file entries within an archive
*
* @author Steve Ebersole
*/
public class ClassFileArchiveEntryHandler implements ArchiveEntryHandler {
+
+ private final static DotName CONVERTER = DotName.createSimple( Converter.class.getName() );
+
+ private final static DotName[] MODELS = {
+ DotName.createSimple( Entity.class.getName() ),
+ DotName.createSimple( MappedSuperclass.class.getName() ),
+ DotName.createSimple( Embeddable.class.getName() )
+ };
+
private final ScanResultCollector resultCollector;
public ClassFileArchiveEntryHandler(ScanResultCollector resultCollector) {
@@ -38,14 +49,8 @@ public class ClassFileArchiveEntryHandler implements ArchiveEntryHandler {
@Override
public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
- // Ultimately we'd like to leverage Jandex here as long term we want to move to
- // using Jandex for annotation processing. But even then, Jandex atm does not have
- // any facility for passing a stream and conditionally indexing it into an Index or
- // returning existing ClassInfo objects.
- //
- // So not sure we can ever not do this unconditional input stream read :(
- final ClassFile classFile = toClassFile( entry );
- final ClassDescriptor classDescriptor = toClassDescriptor( classFile, entry );
+
+ final ClassDescriptor classDescriptor = toClassDescriptor( entry );
if ( classDescriptor.getCategorization() == ClassDescriptor.Categorization.OTHER ) {
return;
@@ -54,45 +59,41 @@ public class ClassFileArchiveEntryHandler implements ArchiveEntryHandler {
resultCollector.handleClass( classDescriptor, context.isRootUrl() );
}
- private ClassFile toClassFile(ArchiveEntry entry) {
- final InputStream inputStream = entry.getStreamAccess().accessInputStream();
- final DataInputStream dataInputStream = new DataInputStream( inputStream );
- try {
- return new ClassFile( dataInputStream );
+ private ClassDescriptor toClassDescriptor(ArchiveEntry entry) {
+ try (InputStream inputStream = entry.getStreamAccess().accessInputStream()) {
+ Indexer indexer = new Indexer();
+ ClassInfo classInfo = indexer.index( inputStream );
+ Index index = indexer.complete();
+ return toClassDescriptor( classInfo, index, entry );
}
catch (IOException e) {
- throw new ArchiveException( "Could not build ClassFile", e );
- }
- finally {
- try {
- dataInputStream.close();
- }
- catch (Exception ignore) {
- }
-
- try {
- inputStream.close();
- }
- catch (IOException ignore) {
- }
+ throw new ArchiveException( "Could not build ClassInfo", e );
}
}
- private ClassDescriptor toClassDescriptor(ClassFile classFile, ArchiveEntry entry) {
+ private ClassDescriptor toClassDescriptor(ClassInfo classInfo, Index index, ArchiveEntry entry) {
ClassDescriptor.Categorization categorization = ClassDescriptor.Categorization.OTHER;
- final AnnotationsAttribute visibleAnnotations = (AnnotationsAttribute) classFile.getAttribute( AnnotationsAttribute.visibleTag );
- if ( visibleAnnotations != null ) {
- if ( visibleAnnotations.getAnnotation( Entity.class.getName() ) != null
- || visibleAnnotations.getAnnotation( MappedSuperclass.class.getName() ) != null
- || visibleAnnotations.getAnnotation( Embeddable.class.getName() ) != null ) {
- categorization = ClassDescriptor.Categorization.MODEL;
- }
- else if ( visibleAnnotations.getAnnotation( Converter.class.getName() ) != null ) {
- categorization = ClassDescriptor.Categorization.CONVERTER;
- }
+ if ( isModel( index ) ) {
+ categorization = ClassDescriptor.Categorization.MODEL;
+ }
+ else if ( isConverter( index ) ) {
+ categorization = ClassDescriptor.Categorization.CONVERTER;
}
- return new ClassDescriptorImpl( classFile.getName(), categorization, entry.getStreamAccess() );
+ return new ClassDescriptorImpl( classInfo.name().toString(), categorization, entry.getStreamAccess() );
+ }
+
+ private boolean isConverter(Index index) {
+ return !index.getAnnotations( CONVERTER ).isEmpty();
+ }
+
+ private boolean isModel(Index index) {
+ for ( DotName model : MODELS ) {
+ if ( !index.getAnnotations( model ).isEmpty() ) {
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/CodeTemplates.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/CodeTemplates.java
index 2c870b1844..7b846dceab 100644
--- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/CodeTemplates.java
+++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/CodeTemplates.java
@@ -26,6 +26,14 @@ import org.hibernate.engine.spi.ExtendedSelfDirtinessTracker;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import net.bytebuddy.asm.Advice;
+import net.bytebuddy.description.field.FieldDescription;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.implementation.bytecode.StackManipulation;
+import net.bytebuddy.implementation.bytecode.assign.Assigner;
+import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
+import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
+import net.bytebuddy.jar.asm.Opcodes;
class CodeTemplates {
@@ -510,4 +518,26 @@ class CodeTemplates {
@interface MappedBy {
}
+
+ // mapping to get private field from superclass by calling the enhanced reader, for use when field is not visible
+ static class GetterMapping implements Advice.OffsetMapping {
+
+ private final FieldDescription persistentField;
+
+ GetterMapping(FieldDescription persistentField) {
+ this.persistentField = persistentField;
+ }
+
+ @Override public Target resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Assigner assigner, Advice.ArgumentHandler argumentHandler, Sort sort) {
+ MethodDescription.Token signature = new MethodDescription.Token( EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + persistentField.getName(), Opcodes.ACC_PUBLIC, persistentField.getType() );
+ MethodDescription method = new MethodDescription.Latent( instrumentedType.getSuperClass().asErasure(), signature );
+
+ return new Target.AbstractReadOnlyAdapter() {
+ @Override
+ public StackManipulation resolveRead() {
+ return new StackManipulation.Compound( MethodVariableAccess.loadThis(), MethodInvocation.invoke( method ).special( method.getDeclaringType().asErasure() ) );
+ }
+ };
+ }
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java
index 56dbb9d54b..11d0506e00 100644
--- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java
@@ -285,7 +285,7 @@ public class EnhancerImpl implements Enhancer {
}
}
- return createTransformer( managedCtClass ).applyTo( builder, false );
+ return createTransformer( managedCtClass ).applyTo( builder );
}
else if ( enhancementContext.isCompositeClass( managedCtClass ) ) {
log.debugf( "Enhancing [%s] as Composite", managedCtClass.getName() );
@@ -318,13 +318,13 @@ public class EnhancerImpl implements Enhancer {
.intercept( implementationClearOwner );
}
- return createTransformer( managedCtClass ).applyTo( builder, false );
+ return createTransformer( managedCtClass ).applyTo( builder );
}
else if ( enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
log.debugf( "Enhancing [%s] as MappedSuperclass", managedCtClass.getName() );
builder = builder.implement( ManagedMappedSuperclass.class );
- return createTransformer( managedCtClass ).applyTo( builder, true );
+ return createTransformer( managedCtClass ).applyTo( builder );
}
else if ( enhancementContext.doExtendedEnhancement( managedCtClass ) ) {
log.debugf( "Extended enhancement of [%s]", managedCtClass.getName() );
diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/InlineDirtyCheckingHandler.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/InlineDirtyCheckingHandler.java
index 34e2bb30cf..1c61641c29 100644
--- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/InlineDirtyCheckingHandler.java
+++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/InlineDirtyCheckingHandler.java
@@ -64,8 +64,15 @@ final class InlineDirtyCheckingHandler implements Implementation, ByteCodeAppend
if ( enhancementContext.isCompositeClass( persistentField.getType().asErasure() )
&& persistentField.hasAnnotation( Embedded.class ) ) {
- implementation = Advice.withCustomMapping()
- .bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() )
+ // HHH-13759 - Call getter on superclass if field is not visible
+ // An embedded field won't be visible if declared private in a superclass
+ // annotated with @MappedSuperclass
+ Advice.WithCustomMapping advice = Advice.withCustomMapping();
+ advice = persistentField.isVisibleTo( managedCtClass )
+ ? advice.bind( CodeTemplates.FieldValue.class, persistentField.getFieldDescription() )
+ : advice.bind( CodeTemplates.FieldValue.class, new CodeTemplates.GetterMapping( persistentField.getFieldDescription() ) );
+
+ implementation = advice
.bind( CodeTemplates.FieldName.class, persistentField.getName() )
.to( CodeTemplates.CompositeFieldDirtyCheckingHandler.class )
.wrap( implementation );
diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java
index 3b9eb4114b..e482e6f7cb 100644
--- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java
+++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java
@@ -175,7 +175,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
return false;
}
- DynamicType.Builder> applyTo(DynamicType.Builder> builder, boolean accessor) {
+ DynamicType.Builder> applyTo(DynamicType.Builder> builder) {
boolean compositeOwner = false;
builder = builder.visit( new AsmVisitorWrapper.ForDeclaredMethods().invokable( NOT_HIBERNATE_GENERATED, this ) );
@@ -186,10 +186,7 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
enhancedField.getType().asErasure(),
Visibility.PUBLIC
)
- .intercept(
- accessor
- ? FieldAccessor.ofField( enhancedField.getName() ).in( enhancedField.getDeclaringType().asErasure() )
- : fieldReader( enhancedField )
+ .intercept( fieldReader( enhancedField )
)
.defineMethod(
EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + enhancedField.getName(),
@@ -197,12 +194,10 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
Visibility.PUBLIC
)
.withParameters( enhancedField.getType().asErasure() )
- .intercept( accessor
- ? FieldAccessor.ofField( enhancedField.getName() ).in( enhancedField.getDeclaringType().asErasure() )
- : fieldWriter( enhancedField ) );
+ .intercept( fieldWriter( enhancedField ) );
if ( !compositeOwner
- && !accessor
+ && !enhancementContext.isMappedSuperclassClass( managedCtClass )
&& enhancedField.hasAnnotation( Embedded.class )
&& enhancementContext.isCompositeClass( enhancedField.getType().asErasure() )
&& enhancementContext.doDirtyCheckingInline( managedCtClass ) ) {
@@ -228,6 +223,9 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
}
private Implementation fieldReader(AnnotatedFieldDescription enhancedField) {
+ if ( enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
+ return FieldAccessor.ofField( enhancedField.getName() ).in( enhancedField.getDeclaringType().asErasure() );
+ }
if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) || !enhancementContext.isLazyLoadable( enhancedField ) ) {
if ( enhancedField.getDeclaringType().asErasure().equals( managedCtClass ) ) {
return FieldAccessor.ofField( enhancedField.getName() ).in( enhancedField.getDeclaringType().asErasure() );
@@ -242,20 +240,29 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla
}
private Implementation fieldWriter(AnnotatedFieldDescription enhancedField) {
- Implementation implementation;
+ Implementation implementation = fieldWriterImplementation( enhancedField );
+ if ( !enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
+ implementation = InlineDirtyCheckingHandler.wrap( managedCtClass, enhancementContext, enhancedField, implementation );
+ implementation = BiDirectionalAssociationHandler.wrap( managedCtClass, enhancementContext, enhancedField, implementation );
+ }
+ return implementation;
+ }
+
+ private Implementation fieldWriterImplementation(AnnotatedFieldDescription enhancedField) {
+ if ( enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
+ return FieldAccessor.ofField( enhancedField.getName() ).in( enhancedField.getDeclaringType().asErasure() );
+ }
if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) || !enhancementContext.isLazyLoadable( enhancedField ) ) {
if ( enhancedField.getDeclaringType().asErasure().equals( managedCtClass ) ) {
- implementation = FieldAccessor.ofField( enhancedField.getName() ).in( enhancedField.getDeclaringType().asErasure() );
+ return FieldAccessor.ofField( enhancedField.getName() ).in( enhancedField.getDeclaringType().asErasure() );
}
else {
- implementation = new Implementation.Simple( new FieldMethodWriter( managedCtClass, enhancedField ) );
+ return new Implementation.Simple( new FieldMethodWriter( managedCtClass, enhancedField ) );
}
}
else {
- implementation = new Implementation.Simple( FieldWriterAppender.of( managedCtClass, enhancedField ) );
+ return new Implementation.Simple( FieldWriterAppender.of( managedCtClass, enhancedField ) );
}
- implementation = InlineDirtyCheckingHandler.wrap( managedCtClass, enhancementContext, enhancedField, implementation );
- return BiDirectionalAssociationHandler.wrap( managedCtClass, enhancementContext, enhancedField, implementation );
}
DynamicType.Builder> applyExtended(DynamicType.Builder> builder) {
diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesEnhancer.java
index 990553fead..17e70f2416 100644
--- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesEnhancer.java
+++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesEnhancer.java
@@ -520,26 +520,30 @@ public class PersistentAttributesEnhancer extends EnhancerImpl {
// make sure to add the CompositeOwner interface
addCompositeOwnerInterface( managedCtClass );
+ String readFragment = persistentField.visibleFrom( managedCtClass ) ? persistentField.getName() : "super." + EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + persistentField.getName() + "()";
+
// cleanup previous owner
fieldWriter.insertBefore(
String.format(
- "if (%1$s != null) { ((%2$s) %1$s).%3$s(\"%1$s\"); }%n",
- persistentField.getName(),
+ "if (%1$s != null) { ((%2$s) %1$s).%3$s(\"%4$s\"); }%n",
+ readFragment,
CompositeTracker.class.getName(),
- EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER
+ EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER,
+ persistentField.getName()
)
);
// trigger track changes
fieldWriter.insertAfter(
String.format(
- "if (%1$s != null) { ((%2$s) %1$s).%4$s(\"%1$s\", (%3$s) this); }%n" +
- "%5$s(\"%1$s\");",
- persistentField.getName(),
+ "if (%1$s != null) { ((%2$s) %1$s).%4$s(\"%6$s\", (%3$s) this); }%n" +
+ "%5$s(\"%6$s\");",
+ readFragment,
CompositeTracker.class.getName(),
CompositeOwner.class.getName(),
EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER,
- EnhancerConstants.TRACKER_CHANGER_NAME
+ EnhancerConstants.TRACKER_CHANGER_NAME,
+ persistentField.getName()
)
);
}
diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java
index 2565bf35a4..7e624c0145 100644
--- a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java
+++ b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java
@@ -15,7 +15,7 @@ import org.hibernate.service.ServiceRegistry;
/**
* An interface for factories of {@link ProxyFactory proxy factory} instances.
*
- * Currently used to abstract from the tupizer whether we are using Byte Buddy or
+ * Currently used to abstract from the tuplizer whether we are using Byte Buddy or
* Javassist for lazy proxy generation.
*
* @author Steve Ebersole
diff --git a/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java
index 47a75e157b..b50024de9c 100644
--- a/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java
+++ b/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java
@@ -10,6 +10,7 @@ import java.util.Properties;
import org.hibernate.MappingException;
import org.hibernate.Session;
+import org.hibernate.StatelessSession;
import org.hibernate.TransientObjectException;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@@ -78,9 +79,6 @@ public class ForeignGenerator implements IdentifierGenerator, Configurable {
@Override
public Object generate(SharedSessionContractImplementor sessionImplementor, Object object) {
- // needs to be a Session for the #save and #contains calls below...
- final Session session = ( Session ) sessionImplementor;
-
final EntityPersister persister = sessionImplementor.getFactory().getMetamodel().entityPersister( entityName );
Object associatedObject = persister.getPropertyValue( object, propertyName );
if ( associatedObject == null ) {
@@ -115,10 +113,20 @@ public class ForeignGenerator implements IdentifierGenerator, Configurable {
foreignValueSourceType.getAssociatedEntityName()
);
}
- id = session.save( foreignValueSourceType.getAssociatedEntityName(), associatedObject );
+ if (sessionImplementor instanceof Session) {
+ id = ((Session) sessionImplementor)
+ .save(foreignValueSourceType.getAssociatedEntityName(), associatedObject);
+ }
+ else if (sessionImplementor instanceof StatelessSession) {
+ id = ((StatelessSession) sessionImplementor)
+ .insert(foreignValueSourceType.getAssociatedEntityName(), associatedObject);
+ }
+ else {
+ throw new IdentifierGenerationException("sessionImplementor is neither Session nor StatelessSession");
+ }
}
- if ( session.contains( entityName, object ) ) {
+ if ( sessionImplementor instanceof Session && ((Session) sessionImplementor).contains( entityName, object ) ) {
//abort the save (the object is already saved by a circular cascade)
return IdentifierGeneratorHelper.SHORT_CIRCUIT_INDICATOR;
//throw new IdentifierGenerationException("save associated object first, or disable cascade for inverse association");
diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java
index a6296f0211..233943cc57 100644
--- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java
@@ -14,6 +14,8 @@ import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
@@ -902,4 +904,11 @@ public class ProcedureCallImpl
public ProcedureCallImplementor setParameter(int position, Date value, TemporalType temporalPrecision) {
return (ProcedureCallImplementor) super.setParameter( position, value, temporalPrecision );
}
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Stream getResultStream() {
+ return getResultList().stream();
+ }
+
}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhance/internal/bytebuddy/DirtyCheckingWithEmbeddableAndMappedSuperclassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhance/internal/bytebuddy/DirtyCheckingWithEmbeddableAndMappedSuperclassTest.java
new file mode 100644
index 0000000000..cab0230a0b
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhance/internal/bytebuddy/DirtyCheckingWithEmbeddableAndMappedSuperclassTest.java
@@ -0,0 +1,210 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later
+ * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
+ */
+package org.hibernate.orm.test.bytecode.enhance.internal.bytebuddy;
+
+import java.lang.reflect.Method;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+
+import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker;
+import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
+
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
+import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_ENTRY_FIELD_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_ENTRY_GETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_FIELD_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_GETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_SETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_FIELD_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_GETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_SETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_CLEAR_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_FIELD_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_GET_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_HAS_CHANGED_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_SUSPEND_NAME;
+
+@TestForIssue(jiraKey = "HHH-13759")
+@RunWith(BytecodeEnhancerRunner.class)
+@EnhancementOptions(inlineDirtyChecking = true)
+public class DirtyCheckingWithEmbeddableAndMappedSuperclassTest {
+
+ @Test
+ public void shouldDeclareFieldsInEntityClass() {
+ assertThat( CardGame.class )
+ .hasDeclaredFields( ENTITY_ENTRY_FIELD_NAME, PREVIOUS_FIELD_NAME, NEXT_FIELD_NAME, TRACKER_FIELD_NAME );
+ }
+
+ @Test
+ public void shouldDeclareMethodsInEntityClass() {
+ assertThat( CardGame.class )
+ .hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "id", PERSISTENT_FIELD_WRITER_PREFIX + "id" )
+ .hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "name", PERSISTENT_FIELD_WRITER_PREFIX + "name" )
+ .hasDeclaredMethods( ENTITY_INSTANCE_GETTER_NAME, ENTITY_ENTRY_GETTER_NAME )
+ .hasDeclaredMethods( PREVIOUS_GETTER_NAME, PREVIOUS_SETTER_NAME, NEXT_GETTER_NAME, NEXT_SETTER_NAME )
+ .hasDeclaredMethods( TRACKER_HAS_CHANGED_NAME, TRACKER_CLEAR_NAME, TRACKER_SUSPEND_NAME, TRACKER_GET_NAME );
+ }
+
+ @Test
+ public void shouldDeclareFieldsInEmbeddedClass() {
+ assertThat( Component.class )
+ .hasDeclaredFields( TRACKER_COMPOSITE_FIELD_NAME );
+ }
+
+ @Test
+ public void shouldDeclareMethodsInEmbeddedClass() {
+ assertThat(Component.class )
+ .hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "component", PERSISTENT_FIELD_WRITER_PREFIX + "component" )
+ .hasDeclaredMethods( TRACKER_COMPOSITE_SET_OWNER, TRACKER_COMPOSITE_CLEAR_OWNER );
+ }
+
+ @Test
+ public void shouldCreateTheTracker() throws Exception {
+ CardGame entity = new CardGame( "MTG", "Magic the Gathering" );
+ assertThat( entity )
+ .extracting( NEXT_FIELD_NAME ).isNull();
+ assertThat( entity )
+ .extracting( PREVIOUS_FIELD_NAME ).isNull();
+ assertThat( entity )
+ .extracting( ENTITY_ENTRY_FIELD_NAME ).isNull();
+ assertThat( entity )
+ .extracting( TRACKER_FIELD_NAME ).isInstanceOf( SimpleFieldTracker.class );
+ assertThat( entity.getFirstPlayerToken() )
+ .extracting( TRACKER_COMPOSITE_FIELD_NAME ).isInstanceOf( CompositeOwnerTracker.class);
+
+ assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( true );
+ assertThat( entity ).extracting( TRACKER_GET_NAME )
+ .isEqualTo( new String[] { "name", "firstPlayerToken" } );
+ assertThat( entity.getFirstPlayerToken() )
+ .extracting( TRACKER_COMPOSITE_FIELD_NAME + ".names" ).isEqualTo( new String[] { "firstPlayerToken" } );
+ }
+
+ @Test
+ public void shouldResetTheTracker() throws Exception {
+ CardGame entity = new CardGame( "7WD", "7 Wonders duel" );
+
+ Method trackerClearMethod = CardGame.class.getMethod( TRACKER_CLEAR_NAME );
+ trackerClearMethod.invoke( entity );
+
+ assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( false );
+ assertThat( entity ).extracting( TRACKER_GET_NAME ).isEqualTo( new String[0] );
+ }
+
+ @Test
+ public void shouldUpdateTheTracker() throws Exception {
+ CardGame entity = new CardGame( "SPL", "Splendor" );
+
+ Method trackerClearMethod = CardGame.class.getMethod( TRACKER_CLEAR_NAME );
+ trackerClearMethod.invoke( entity );
+
+ entity.setName( "Splendor: Cities of Splendor" );
+
+ assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( true );
+ assertThat( entity ).extracting( TRACKER_GET_NAME )
+ .isEqualTo( new String[] { "name", "firstPlayerToken" } );
+
+ trackerClearMethod.invoke( entity );
+
+ entity.setFirstPlayerToken( new Component( "FIRST PLAYER!!!!!!!!" ) );
+ assertThat( entity ).extracting( TRACKER_GET_NAME )
+ .isEqualTo( new String[] { "firstPlayerToken" } );
+ assertThat( entity.getFirstPlayerToken() )
+ .extracting( TRACKER_COMPOSITE_FIELD_NAME + ".names" ).isEqualTo( new String[] { "firstPlayerToken" } );
+ }
+
+ @MappedSuperclass
+ public static abstract class TableTopGame {
+
+ @Embedded
+ private Component firstPlayerToken;
+
+ public Component getFirstPlayerToken() {
+ return firstPlayerToken;
+ }
+
+ public void setFirstPlayerToken(Component firstPlayerToken) {
+ this.firstPlayerToken = firstPlayerToken;
+ }
+ }
+
+ @Embeddable
+ public static class Component {
+
+ @Column(name = "first_player_token")
+ private String component;
+
+ public Component() {
+ }
+
+ private Component(String component) {
+ this.component = component;
+ }
+
+ public String getComponent() {
+ return component;
+ }
+
+ public void setComponent(String component) {
+ this.component = component;
+ }
+ }
+
+ @Entity(name = "CardGame")
+ public static class CardGame extends TableTopGame {
+
+ @Id
+ private String id;
+ private String name;
+
+ public CardGame() {
+ }
+
+ private CardGame(String id, String name) {
+ this.id = id;
+ this.name = name;
+ setFirstPlayerToken( createEmbeddedValue( name ) );
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ setFirstPlayerToken( createEmbeddedValue( name ) );
+ }
+
+ private Component createEmbeddedValue(String name) {
+ return new Component( name + " first player token");
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhance/internal/bytebuddy/DirtyCheckingWithMappedsuperclassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhance/internal/bytebuddy/DirtyCheckingWithMappedsuperclassTest.java
new file mode 100644
index 0000000000..3b0fea279a
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhance/internal/bytebuddy/DirtyCheckingWithMappedsuperclassTest.java
@@ -0,0 +1,162 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later
+ * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
+ */
+package org.hibernate.orm.test.bytecode.enhance.internal.bytebuddy;
+
+import java.lang.reflect.Method;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+
+import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
+
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
+import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_ENTRY_FIELD_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_ENTRY_GETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_FIELD_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_GETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.NEXT_SETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_FIELD_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_GETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.PREVIOUS_SETTER_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_CLEAR_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_FIELD_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_GET_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_HAS_CHANGED_NAME;
+import static org.hibernate.bytecode.enhance.spi.EnhancerConstants.TRACKER_SUSPEND_NAME;
+
+@TestForIssue(jiraKey = "HHH-13759")
+@RunWith(BytecodeEnhancerRunner.class)
+@EnhancementOptions(inlineDirtyChecking = true)
+public class DirtyCheckingWithMappedsuperclassTest {
+
+ @Test
+ public void shouldDeclareFieldsInEntityClass() {
+ assertThat( CardGame.class )
+ .hasDeclaredFields( ENTITY_ENTRY_FIELD_NAME, PREVIOUS_FIELD_NAME, NEXT_FIELD_NAME, TRACKER_FIELD_NAME );
+ }
+
+ @Test
+ public void shouldDeclareMethodsInEntityClass() {
+ assertThat( CardGame.class )
+ .hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "id", PERSISTENT_FIELD_WRITER_PREFIX + "id" )
+ .hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "name", PERSISTENT_FIELD_WRITER_PREFIX + "name" )
+ .hasDeclaredMethods( PERSISTENT_FIELD_READER_PREFIX + "code", PERSISTENT_FIELD_WRITER_PREFIX + "code" )
+ .hasDeclaredMethods( ENTITY_INSTANCE_GETTER_NAME, ENTITY_ENTRY_GETTER_NAME )
+ .hasDeclaredMethods( PREVIOUS_GETTER_NAME, PREVIOUS_SETTER_NAME, NEXT_GETTER_NAME, NEXT_SETTER_NAME )
+ .hasDeclaredMethods( TRACKER_HAS_CHANGED_NAME, TRACKER_CLEAR_NAME, TRACKER_SUSPEND_NAME, TRACKER_GET_NAME );
+ }
+
+ @Test
+ public void shouldCreateTheTracker() throws Exception {
+ CardGame entity = new CardGame( "MTG", "Magic the Gathering" );
+ assertThat( entity )
+ .extracting( NEXT_FIELD_NAME ).isNull();
+ assertThat( entity )
+ .extracting( PREVIOUS_FIELD_NAME ).isNull();
+ assertThat( entity )
+ .extracting( ENTITY_ENTRY_FIELD_NAME ).isNull();
+ assertThat( entity )
+ .extracting( TRACKER_FIELD_NAME ).isInstanceOf( SimpleFieldTracker.class );
+
+ assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( true );
+ assertThat( entity ).extracting( TRACKER_GET_NAME ).isEqualTo( new String[] { "name", "code" } );
+ }
+
+ @Test
+ public void shouldResetTheTracker() throws Exception {
+ CardGame entity = new CardGame( "7WD", "7 Wonders duel" );
+
+ Method trackerClearMethod = CardGame.class.getMethod( TRACKER_CLEAR_NAME );
+ trackerClearMethod.invoke( entity );
+
+ assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( false );
+ assertThat( entity ).extracting( TRACKER_GET_NAME ).isEqualTo( new String[0] );
+ }
+
+ @Test
+ public void shouldUpdateTheTracker() throws Exception {
+ CardGame entity = new CardGame( "SPL", "Splendor" );
+ assertThat( entity.getCode() ).isEqualTo( "XsplX" );
+
+ Method trackerClearMethod = CardGame.class.getMethod( TRACKER_CLEAR_NAME );
+ trackerClearMethod.invoke( entity );
+
+ entity.setName( "Splendor: Cities of Splendor" );
+
+ assertThat( entity.getCode() )
+ .as( "Field 'code' should have not change" ).isEqualTo( "XsplX" );
+ assertThat( entity ).extracting( TRACKER_HAS_CHANGED_NAME ).isEqualTo( true );
+ assertThat( entity ).extracting( TRACKER_GET_NAME ).isEqualTo( new String[] { "name" } );
+
+ entity.setName( "Cities of Splendor" );
+
+ assertThat( entity ).extracting( TRACKER_GET_NAME ).isEqualTo( new String[] { "name", "code" } );
+ }
+
+ @MappedSuperclass
+ public static abstract class TableTopGame {
+
+ private String code;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+ }
+
+ @Entity(name = "CardGame")
+ public static class CardGame extends TableTopGame {
+ @Id
+ private String id;
+
+ private String name;
+
+ public CardGame() {
+ }
+
+ private CardGame(String id, String name) {
+ this.id = id;
+ this.name = name;
+ setCode( createCode( name ) );
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ setCode( createCode( name ) );
+ }
+
+ private String createCode(String name) {
+ return "X" + name.substring( 0, 3 ).toLowerCase() + "X";
+ }
+
+ }
+
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/procedure/internal/ProcedureCallImplTest.java b/hibernate-core/src/test/java/org/hibernate/procedure/internal/ProcedureCallImplTest.java
new file mode 100644
index 0000000000..0b89867ee2
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/procedure/internal/ProcedureCallImplTest.java
@@ -0,0 +1,39 @@
+package org.hibernate.procedure.internal;
+
+import java.util.stream.Stream;
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
+import org.hibernate.testing.RequiresDialect;
+import org.hibernate.testing.TestForIssue;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Nathan Xu
+ */
+public class ProcedureCallImplTest extends BaseEntityManagerFunctionalTestCase {
+
+ @Test
+ @TestForIssue( jiraKey = "HHH-13644" )
+ @RequiresDialect( H2Dialect.class )
+ public void testNoNullPointerExceptionThrown() {
+
+ EntityManager em = getOrCreateEntityManager();
+
+ em.getTransaction().begin();
+
+ em.createNativeQuery("CREATE ALIAS GET_RANDOM_VALUE FOR \"java.lang.Math.random\";").executeUpdate();
+
+ Query query = em.createStoredProcedureQuery("GET_RANDOM_VALUE");
+
+ Stream stream = query.getResultStream();
+
+ Assert.assertEquals(1, stream.count());
+
+ em.getTransaction().commit();
+
+ em.close();
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MappedSuperclassWithEmbeddableTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MappedSuperclassWithEmbeddableTest.java
new file mode 100644
index 0000000000..4871d85819
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MappedSuperclassWithEmbeddableTest.java
@@ -0,0 +1,148 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later
+ * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
+ */
+package org.hibernate.test.bytecode.enhancement.lazy.proxy;
+
+import java.io.Serializable;
+import java.util.Objects;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.cfg.AvailableSettings;
+
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
+import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
+import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author Andrea Boriero
+ */
+@RunWith(BytecodeEnhancerRunner.class)
+@EnhancementOptions(lazyLoading = true, inlineDirtyChecking = true)
+public class MappedSuperclassWithEmbeddableTest extends BaseNonConfigCoreFunctionalTestCase {
+
+ @Override
+ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
+ super.configureStandardServiceRegistryBuilder( ssrb );
+ ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
+ ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" );
+ ssrb.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
+ ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
+ }
+
+ @Override
+ public Class>[] getAnnotatedClasses() {
+ return new Class>[] { TestEntity.class };
+ }
+
+ @Before
+ public void prepare() {
+ doInHibernate( this::sessionFactory, s -> {
+ TestEntity testEntity = new TestEntity( "2", "test" );
+ s.persist( testEntity );
+ } );
+ }
+
+ @After
+ public void tearDown() {
+ doInHibernate( this::sessionFactory, s -> {
+ s.createQuery( "delete from TestEntity" ).executeUpdate();
+ } );
+ }
+
+ @Test
+ public void testIt() {
+ doInHibernate( this::sessionFactory, s -> {
+ TestEntity testEntity = s.get( TestEntity.class, "2" );
+ assertThat( testEntity, notNullValue() );
+ } );
+ }
+
+ @MappedSuperclass
+ public static abstract class BaseEntity {
+ @Embedded
+ private EmbeddedValue superField;
+
+ public EmbeddedValue getSuperField() {
+ return superField;
+ }
+
+ public void setSuperField(EmbeddedValue superField) {
+ this.superField = superField;
+ }
+ }
+
+ @Embeddable
+ public static class EmbeddedValue implements Serializable {
+ @Column(name = "super_field")
+ private String superField;
+
+ public EmbeddedValue() {
+ }
+
+ private EmbeddedValue(String superField) {
+ this.superField = superField;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+ EmbeddedValue that = (EmbeddedValue) o;
+ return superField.equals( that.superField );
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash( superField );
+ }
+ }
+
+ @Entity(name = "TestEntity")
+ public static class TestEntity extends BaseEntity {
+ @Id
+ private String id;
+ private String name;
+
+ public TestEntity() {
+ }
+
+ private TestEntity(String id, String name) {
+ this.id = id;
+ this.name = name;
+ EmbeddedValue value = new EmbeddedValue( "SUPER " + name );
+ setSuperField( value );
+ }
+
+
+ public String id() {
+ return id;
+ }
+
+ public String name() {
+ return name;
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/id/ForeignGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/test/id/ForeignGeneratorTest.java
new file mode 100644
index 0000000000..d9d222488d
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/id/ForeignGeneratorTest.java
@@ -0,0 +1,70 @@
+package org.hibernate.test.id;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.MapsId;
+import javax.persistence.OneToOne;
+import org.hibernate.Transaction;
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
+import org.junit.Test;
+
+/**
+ * @author Nathan Xu
+ */
+public class ForeignGeneratorTest extends BaseCoreFunctionalTestCase {
+
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class>[] {
+ Product.class,
+ ProductDetails.class
+ };
+ }
+
+ @Test
+ @TestForIssue( jiraKey = "HHH-13456")
+ public void testForeignGeneratorInStatelessSession() {
+
+ inStatelessSession(statelessSession -> {
+
+ Transaction tx = statelessSession.beginTransaction();
+
+ Product product = new Product();
+
+ ProductDetails productDetails = new ProductDetails( product );
+
+ statelessSession.insert( productDetails );
+
+ tx.commit();
+ });
+ }
+
+ @Entity(name = "Product")
+ public static class Product {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+ }
+
+ @Entity(name = "ProductDetails")
+ public static class ProductDetails {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @OneToOne
+ @MapsId
+ private Product product;
+
+ public ProductDetails() {
+ }
+
+ public ProductDetails( Product product ) {
+ this.product = product;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java b/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java
similarity index 99%
rename from hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java
rename to hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java
index b3fbb0c8dc..38647d1a6f 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java
+++ b/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java
@@ -6,18 +6,20 @@
*/
package org.hibernate.test.bytecode.enhancement.javassist;
-import javassist.CtClass;
-import org.hibernate.bytecode.enhance.internal.javassist.EnhancerImpl;
-import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
-import org.hibernate.bytecode.enhance.spi.EnhancementContext;
-import org.hibernate.testing.TestForIssue;
-import org.junit.Test;
-
import java.io.FileNotFoundException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
+import javassist.CtClass;
+
+import org.hibernate.bytecode.enhance.internal.javassist.EnhancerImpl;
+import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
+import org.hibernate.bytecode.enhance.spi.EnhancementContext;
+
+import org.hibernate.testing.TestForIssue;
+import org.junit.Test;
+
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
diff --git a/hibernate-orm-modules/module-templates/hibernate-core.xml b/hibernate-orm-modules/module-templates/hibernate-core.xml
index 625dc7d61e..ec645f1fa7 100644
--- a/hibernate-orm-modules/module-templates/hibernate-core.xml
+++ b/hibernate-orm-modules/module-templates/hibernate-core.xml
@@ -26,7 +26,7 @@
-
+
diff --git a/hibernate-orm-modules/src/test/java/org/hibernate/wildfly/integrationtest/JavassistHibernateModulesOnWildflyTest.java b/hibernate-orm-modules/src/test/java/org/hibernate/wildfly/integrationtest/JavassistHibernateModulesOnWildflyTest.java
new file mode 100644
index 0000000000..3a4e396182
--- /dev/null
+++ b/hibernate-orm-modules/src/test/java/org/hibernate/wildfly/integrationtest/JavassistHibernateModulesOnWildflyTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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 .
+ */
+package org.hibernate.wildfly.integrationtest;
+
+import java.util.Properties;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.hibernate.Session;
+import org.hibernate.bytecode.internal.javassist.BytecodeProviderImpl;
+import org.hibernate.bytecode.spi.BasicProxyFactory;
+import org.hibernate.bytecode.spi.BytecodeProvider;
+import org.hibernate.bytecode.spi.ProxyFactoryFactory;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.cfg.Environment;
+import org.hibernate.wildfly.model.Kryptonite;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.Asset;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jboss.shrinkwrap.descriptor.api.Descriptors;
+import org.jboss.shrinkwrap.descriptor.api.persistence21.PersistenceDescriptor;
+import org.jboss.shrinkwrap.descriptor.api.persistence21.PersistenceUnitTransactionType;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertThat;
+
+/**
+ * The purpose of this test is to check that it's still possible to use Javassist as byte code provider with WildFly.
+ */
+@RunWith(Arquillian.class)
+public class JavassistHibernateModulesOnWildflyTest {
+
+ private static final String ORM_VERSION = Session.class.getPackage().getImplementationVersion();
+ private static final String ORM_MINOR_VERSION = ORM_VERSION.substring( 0, ORM_VERSION.indexOf( ".", ORM_VERSION.indexOf( "." ) + 1) );
+
+ @Deployment
+ public static WebArchive createDeployment() {
+ return ShrinkWrap.create( WebArchive.class )
+ .addClass( Kryptonite.class )
+ .addAsWebInfResource( EmptyAsset.INSTANCE, "beans.xml" )
+ .addAsResource( persistenceXml(), "META-INF/persistence.xml" );
+ }
+
+ private static Asset persistenceXml() {
+ PersistenceDescriptor persistenceXml = Descriptors.create( PersistenceDescriptor.class )
+ .version( "2.1" )
+ .createPersistenceUnit()
+ .name( "primary" )
+ .transactionType( PersistenceUnitTransactionType._JTA )
+ .jtaDataSource( "java:jboss/datasources/ExampleDS" )
+ .getOrCreateProperties()
+ // We want to use the ORM from this build instead of the one coming with WildFly
+ .createProperty().name( "jboss.as.jpa.providerModule" ).value( "org.hibernate:" + ORM_MINOR_VERSION ).up()
+ .createProperty().name( "hibernate.hbm2ddl.auto" ).value( "create-drop" ).up()
+ .createProperty().name( "hibernate.allow_update_outside_transaction" ).value( "true" ).up()
+ .up().up();
+ return new StringAsset( persistenceXml.exportAsString() );
+ }
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Test
+ public void shouldUseHibernateOrm52() {
+ Session session = entityManager.unwrap( Session.class );
+
+ Kryptonite kryptonite1 = new Kryptonite();
+ kryptonite1.id = 1L;
+ kryptonite1.description = "Some Kryptonite";
+ session.persist( kryptonite1 );
+
+ // EntityManager methods exposed through Session only as of 5.2
+ Kryptonite loaded = session.find( Kryptonite.class, 1L );
+
+ assertThat( loaded.description, equalTo( "Some Kryptonite" ) );
+ }
+
+ @Test
+ public void shouldBeAbleToCreateProxyWithJavassist() {
+ Properties properties = new Properties();
+ properties.setProperty( AvailableSettings.BYTECODE_PROVIDER, Environment.BYTECODE_PROVIDER_NAME_JAVASSIST );
+
+ // hibernate.bytecode.provider is a system property. I don't want to apply it
+ // to the arquillian.xml because it will change the other tests as well.
+ // I guess this is a more explicit way anyway to test that Javassist is available.
+ BytecodeProvider provider = Environment.buildBytecodeProvider( properties );
+ assertThat( provider.getClass(), equalTo( BytecodeProviderImpl.class ) );
+
+ ProxyFactoryFactory factory = provider.getProxyFactoryFactory();
+ BasicProxyFactory basicProxyFactory = factory.buildBasicProxyFactory( Kryptonite.class, null );
+ Object proxy = basicProxyFactory.getProxy();
+ assertThat( proxy, notNullValue() );
+ }
+}
diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/EnhancerTestContext.java b/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/EnhancerTestContext.java
index bc3c80aa4d..cdcb80dd6f 100644
--- a/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/EnhancerTestContext.java
+++ b/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/EnhancerTestContext.java
@@ -6,9 +6,6 @@
*/
package org.hibernate.testing.bytecode.enhancement;
-import javassist.CtClass;
-import javassist.CtField;
-
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
import org.hibernate.bytecode.enhance.spi.UnloadedField;
diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java
index 6d813712de..63853abe21 100644
--- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java
+++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java
@@ -21,6 +21,7 @@ import javax.persistence.SharedCacheMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.Session;
+import org.hibernate.StatelessSession;
import org.hibernate.Transaction;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
@@ -388,7 +389,7 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
sessionFactory.getCache().evictAllRegions();
}
}
-
+
protected boolean isCleanupTestDataRequired() {
return false;
}
@@ -518,4 +519,8 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
protected void inSession(Consumer action) {
TransactionUtil2.inSession( sessionFactory(), action );
}
+
+ protected void inStatelessSession(Consumer action) {
+ TransactionUtil2.inStatelessSession( sessionFactory(), action );
+ }
}