Merge remote-tracking branch 'upstream/master' into wip/6.0_merge_16
This commit is contained in:
commit
1d4bb08ef7
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() ) );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.hibernate.service.ServiceRegistry;
|
|||
/**
|
||||
* An interface for factories of {@link ProxyFactory proxy factory} instances.
|
||||
* <p/>
|
||||
* 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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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<R>
|
|||
public ProcedureCallImplementor<R> setParameter(int position, Date value, TemporalType temporalPrecision) {
|
||||
return (ProcedureCallImplementor<R>) super.setParameter( position, value, temporalPrecision );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Stream getResultStream() {
|
||||
return getResultList().stream();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
<module name="org.jboss.jandex"/>
|
||||
<module name="org.jboss.logging"/>
|
||||
<module name="org.jboss.vfs"/>
|
||||
<module name="org.javassist" export="true"/>
|
||||
<module name="org.javassist" export="true" optional="true"/>
|
||||
<module name="org.hibernate.commons-annotations"/>
|
||||
<module name="org.hibernate.orm.jipijapa-hibernate5" services="import" slot="${slot}"/>
|
||||
<module name="net.bytebuddy" slot="${bytebuddySlot}" />
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
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() );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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<SessionImplementor> action) {
|
||||
TransactionUtil2.inSession( sessionFactory(), action );
|
||||
}
|
||||
|
||||
protected void inStatelessSession(Consumer<StatelessSession> action) {
|
||||
TransactionUtil2.inStatelessSession( sessionFactory(), action );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue