Merge remote-tracking branch 'upstream/master' into wip/6.0_merge_24
This commit is contained in:
commit
2660007df9
|
@ -3,6 +3,76 @@ Hibernate 5 Changelog
|
|||
|
||||
Note: Please refer to JIRA to learn more about each issue.
|
||||
|
||||
hanges in 5.4.12.Final (February 13, 2020)
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
https://hibernate.atlassian.net/projects/HHH/versions/31827/tab/release-report-done
|
||||
|
||||
** Bug
|
||||
* [HHH-13858] - Fix Oracle failing tests
|
||||
* [HHH-13859] - NPE on scanning for entities in a project having module-info.class resources
|
||||
|
||||
** New Feature
|
||||
* [HHH-13861] - Expose the doWork() and doReturningWork() APIs on StatelessSession as well
|
||||
* [HHH-13863] - Introduce a module to distribute some helpers useful to compile Hibernate ORM to GraalVM native images
|
||||
|
||||
** Improvement
|
||||
* [HHH-13864] - Cosmetic change of format when reporting version number
|
||||
|
||||
|
||||
Changes in 5.4.11.Final (February 07, 2020)
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
https://hibernate.atlassian.net/projects/HHH/versions/31818/tab/release-report-done
|
||||
|
||||
** Bug
|
||||
* [HHH-6615] - int type in Revision number
|
||||
* [HHH-6686] - JPQL operator "is empty" failes for @ElementCollection
|
||||
* [HHH-10844] - Resolve columnDefinition to appropriate sql-type for audit mappings
|
||||
* [HHH-13373] - Hibernate report query hibernate_sequence table error in spring-boot application starting on a multi-database mariadb server
|
||||
* [HHH-13456] - ForeignGenerator Throws ClassCastException When Using StatelessSession
|
||||
* [HHH-13472] - Error creating hibernate_sequence in MariaDB 10.3
|
||||
* [HHH-13644] - NullPointerException when calling StoredProcedureQuery.getResultStream() instead of StoredProcedureQuery.getResultList()
|
||||
* [HHH-13677] - org.hibernate.flushMode property not applied
|
||||
* [HHH-13704] - Make sure javassist is really an optional dependency
|
||||
* [HHH-13752] - Delete doesn't work when many-to-many uses non-primary key for join table
|
||||
* [HHH-13759] - Bytecode enhancement fails for an embedded field in a MappedSuperclass
|
||||
* [HHH-13760] - Envers tries to use relationship's entity as value for column instead of numeric identifier (cast class exception happens) for LAZY @ManyToOne
|
||||
* [HHH-13770] - Envers - modified flag column value set to null from 5.4.7 onwards
|
||||
* [HHH-13780] - Allow NamedQuery to set hint QueryHints.PASS_DISTINCT_THROUGH
|
||||
* [HHH-13783] - org.hibernate.MappingException: The increment size of the sequence is set to [10] in the entity mapping while … size is [1]
|
||||
* [HHH-13792] - L2 entity cache is evicted prior to committing transaction for HQL/native updates
|
||||
* [HHH-13796] - Missing from clause in query from BinaryLogicOperatorNode row value constructor translation
|
||||
* [HHH-13804] - HibernateProxy might need to be instantiated even with build-time enhancement
|
||||
* [HHH-13806] - CoreMessageLogger#unableToLoadCommand is not printing the cause of the error
|
||||
* [HHH-13808] - Incorrect String format in log
|
||||
* [HHH-13831] - Replaced listener is not called when EventListenerGroup#fireEventOnEachListener is called
|
||||
|
||||
** Task
|
||||
* [HHH-13726] - Extract org.hibernate.internal.SessionFactoryImpl#prepareEventListeners from SessionFactoryImpl
|
||||
* [HHH-13767] - Remove mention of Oracle and DB2 not being in MC
|
||||
* [HHH-13821] - Update to Byte Buddy 1.10.7
|
||||
* [HHH-13822] - OSGi integration tests need to be able to download dependencies from Maven Central using HTTPS
|
||||
* [HHH-13823] - Various visibility changes to help prototyping of Hibernate RX
|
||||
* [HHH-13833] - Byte Buddy enhancer should use ASM7 opcodes to improve compatibility with code compiled for Java 11
|
||||
* [HHH-13837] - Initialize the Hibernate VERSION as a real constant
|
||||
* [HHH-13838] - Allow extension of PersistenceXmlParser
|
||||
* [HHH-13849] - Convert ProxyFactoryFactory and BytecodeProvider into a Service
|
||||
|
||||
** Improvement
|
||||
* [HHH-8776] - Ability for JPA entity-graphs to handle non-lazy attributes as lazy
|
||||
* [HHH-11958] - Apply QueryHints.HINT_READONLY to load operations
|
||||
* [HHH-12856] - Upgrade DB2400 dialect to use the DB2 for i improvements
|
||||
* [HHH-13390] - Upgrade JPA MetaModel Generator (jpamodelgen) to support Gradle Incremental Compile
|
||||
* [HHH-13800] - Correct some typos in the javadocs of hibernate-core module
|
||||
* [HHH-13802] - fix javadoc warnings in 'hibernate-core'
|
||||
* [HHH-13809] - Various improvements in the user guides
|
||||
* [HHH-13830] - Fixing typo on the build task description
|
||||
* [HHH-13832] - Optimise setting of default Flush Mode on a newly created Session
|
||||
* [HHH-13850] - Clear the BytecodeProvider caches both after SessionFactory creation and stop
|
||||
* [HHH-13851] - Rework initialization of ProxyFactoryFactory to move responsibility out of PojoEntityTuplizer
|
||||
* [HHH-13854] - Allow extensions of StandardServiceRegistryBuilder to ignore Environment variables
|
||||
|
||||
|
||||
Changes in 6.0.0.Alpha4 (December 20, 2019)
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -22,8 +92,6 @@ https://hibernate.atlassian.net/projects/HHH/versions/31817
|
|||
* [HHH-13769] - Avoid unnecessary joins
|
||||
|
||||
|
||||
|
||||
|
||||
Changes in 5.4.10.Final (December 05, 2019)
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -48,6 +48,9 @@ ext {
|
|||
jaxbApiVersionOsgiRange = "[2.2,3)"
|
||||
jaxbRuntimeVersion = '2.3.1'
|
||||
|
||||
//GraalVM
|
||||
graalvmVersion = '19.3.1'
|
||||
|
||||
libraries = [
|
||||
// Ant
|
||||
ant: 'org.apache.ant:ant:1.8.2',
|
||||
|
@ -143,7 +146,7 @@ ext {
|
|||
// EL required by Hibernate Validator at test runtime
|
||||
expression_language: "org.glassfish:javax.el:${elVersion}",
|
||||
|
||||
c3p0: "com.mchange:c3p0:0.9.5.2",
|
||||
c3p0: "com.mchange:c3p0:0.9.5.3",
|
||||
ehcache: "net.sf.ehcache:ehcache:2.10.6",
|
||||
ehcache3: "org.ehcache:ehcache:3.6.1",
|
||||
jcache: "javax.cache:cache-api:1.0.0",
|
||||
|
@ -179,9 +182,10 @@ ext {
|
|||
jboss_ejb_spec_jar : 'org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final',
|
||||
jboss_annotation_spec_jar : 'org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec:1.0.0.Final',
|
||||
|
||||
asciidoclet : 'org.asciidoctor:asciidoclet:1.+'
|
||||
asciidoclet : 'org.asciidoctor:asciidoclet:1.+',
|
||||
//asciidoclet : 'org.asciidoctor:asciidoclet:1.5.7-SNAPSHOT'
|
||||
|
||||
graalvm_nativeimage : "org.graalvm.nativeimage:svm:${graalvmVersion}"
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@ import javax.persistence.criteria.CriteriaQuery;
|
|||
import javax.persistence.criteria.CriteriaUpdate;
|
||||
|
||||
import org.hibernate.graph.RootGraph;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.hibernate.stat.SessionStatistics;
|
||||
|
||||
/**
|
||||
|
@ -940,27 +938,6 @@ public interface Session extends SharedSessionContract, EntityManager, AutoClose
|
|||
*/
|
||||
void setReadOnly(Object entityOrProxy, boolean readOnly);
|
||||
|
||||
/**
|
||||
* Controller for allowing users to perform JDBC related work using the Connection managed by this Session.
|
||||
*
|
||||
* @param work The work to be performed.
|
||||
* @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
|
||||
*/
|
||||
void doWork(Work work) throws HibernateException;
|
||||
|
||||
/**
|
||||
* Controller for allowing users to perform JDBC related work using the Connection managed by this Session. After
|
||||
* execution returns the result of the {@link ReturningWork#execute} call.
|
||||
*
|
||||
* @param work The work to be performed.
|
||||
* @param <T> The type of the result returned from the work
|
||||
*
|
||||
* @return the result from calling {@link ReturningWork#execute}.
|
||||
*
|
||||
* @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
|
||||
*/
|
||||
<T> T doReturningWork(ReturningWork<T> work) throws HibernateException;
|
||||
|
||||
@Override
|
||||
<T> RootGraph<T> createEntityGraph(Class<T> rootType);
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import javax.persistence.criteria.CriteriaDelete;
|
|||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.CriteriaUpdate;
|
||||
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.query.QueryProducer;
|
||||
|
||||
|
@ -163,4 +165,30 @@ public interface SharedSessionContract extends QueryProducer, Serializable {
|
|||
org.hibernate.query.Query createQuery(CriteriaDelete deleteQuery);
|
||||
|
||||
<T> org.hibernate.query.Query<T> createNamedQuery(String name, Class<T> resultType);
|
||||
|
||||
/**
|
||||
* Controller for allowing users to perform JDBC related work using the Connection managed by this Session.
|
||||
*
|
||||
* @param work The work to be performed.
|
||||
* @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
|
||||
*/
|
||||
default void doWork(Work work) throws HibernateException {
|
||||
throw new UnsupportedOperationException( "The doWork method has not been implemented in this implementation of org.hibernate.engine.spi.SharedSessionContractImplemento" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller for allowing users to perform JDBC related work using the Connection managed by this Session. After
|
||||
* execution returns the result of the {@link ReturningWork#execute} call.
|
||||
*
|
||||
* @param work The work to be performed.
|
||||
* @param <T> The type of the result returned from the work
|
||||
*
|
||||
* @return the result from calling {@link ReturningWork#execute}.
|
||||
*
|
||||
* @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
|
||||
*/
|
||||
default <T> T doReturningWork(ReturningWork<T> work) throws HibernateException {
|
||||
throw new UnsupportedOperationException( "The doReturningWork method has not been implemented in this implementation of org.hibernate.engine.spi.SharedSessionContractImplemento" );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,6 +52,6 @@ public final class Version {
|
|||
*/
|
||||
@AllowSysOut
|
||||
public static void main(String[] args) {
|
||||
System.out.println( "Hibernate Core {" + getVersionString() + "}" );
|
||||
System.out.println( "Hibernate ORM core version " + getVersionString() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.boot.archive.scan.internal;
|
||||
|
||||
import org.hibernate.boot.archive.spi.ArchiveContext;
|
||||
import org.hibernate.boot.archive.spi.ArchiveEntry;
|
||||
import org.hibernate.boot.archive.spi.ArchiveEntryHandler;
|
||||
|
||||
public final class NoopEntryHandler implements ArchiveEntryHandler {
|
||||
|
||||
public static final ArchiveEntryHandler NOOP_INSTANCE = new NoopEntryHandler();
|
||||
|
||||
private NoopEntryHandler() {
|
||||
//Use the singleton.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import java.net.URL;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.boot.archive.scan.internal.NoopEntryHandler;
|
||||
import org.hibernate.boot.archive.scan.internal.ScanResultCollector;
|
||||
import org.hibernate.boot.archive.spi.ArchiveContext;
|
||||
import org.hibernate.boot.archive.spi.ArchiveDescriptor;
|
||||
|
@ -132,6 +133,12 @@ public abstract class AbstractScannerImpl implements Scanner {
|
|||
if ( nameWithinArchive.endsWith( "package-info.class" ) ) {
|
||||
return packageEntryHandler;
|
||||
}
|
||||
else if ( nameWithinArchive.endsWith( "module-info.class" ) ) {
|
||||
//There's two reasons to skip this: the most important one is that Jandex
|
||||
//is unable to analyze them, so we need to dodge it.
|
||||
//Secondarily, we have no use for these so let's save the effort.
|
||||
return NoopEntryHandler.NOOP_INSTANCE;
|
||||
}
|
||||
else if ( nameWithinArchive.endsWith( ".class" ) ) {
|
||||
return classEntryHandler;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.boot.archive.scan.spi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import javax.persistence.Converter;
|
||||
|
|
|
@ -20,10 +20,13 @@ import org.hibernate.SessionFactory;
|
|||
import org.hibernate.SessionFactoryObserver;
|
||||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.spi.BootstrapContext;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.SessionFactoryBuilderImplementor;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.bytecode.internal.SessionFactoryObserverForBytecodeEnhancer;
|
||||
import org.hibernate.bytecode.spi.BytecodeProvider;
|
||||
import org.hibernate.cache.spi.TimestampsCacheFactory;
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.internal.SessionFactoryImpl;
|
||||
|
@ -450,6 +453,9 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
@Override
|
||||
public SessionFactory build() {
|
||||
metadata.validate();
|
||||
final StandardServiceRegistry serviceRegistry = metadata.getMetadataBuildingOptions().getServiceRegistry();
|
||||
BytecodeProvider bytecodeProvider = serviceRegistry.getService( BytecodeProvider.class );
|
||||
addSessionFactoryObservers( new SessionFactoryObserverForBytecodeEnhancer( bytecodeProvider ) );
|
||||
return new SessionFactoryImpl( metadata, buildSessionFactoryOptions() );
|
||||
}
|
||||
|
||||
|
|
|
@ -97,11 +97,12 @@ public class StandardServiceRegistryBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Intended for use exclusively from JPA boot-strapping.
|
||||
* Intended for use exclusively from JPA boot-strapping, or extensions of
|
||||
* this class. Consider this an SPI.
|
||||
*
|
||||
* @see #forJpa
|
||||
*/
|
||||
private StandardServiceRegistryBuilder(
|
||||
protected StandardServiceRegistryBuilder(
|
||||
BootstrapServiceRegistry bootstrapServiceRegistry,
|
||||
Map settings,
|
||||
LoadedConfig loadedConfig) {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.bytecode.internal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.boot.registry.StandardServiceInitiator;
|
||||
import org.hibernate.bytecode.spi.BytecodeProvider;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
public final class BytecodeProviderInitiator implements StandardServiceInitiator<BytecodeProvider> {
|
||||
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final StandardServiceInitiator<BytecodeProvider> INSTANCE = new BytecodeProviderInitiator();
|
||||
|
||||
@Override
|
||||
public BytecodeProvider initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
|
||||
// TODO in 6 this will no longer use Environment, which is configured via global environment variables,
|
||||
// but move to a component which can be reconfigured differently in each registry.
|
||||
return Environment.getBytecodeProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<BytecodeProvider> getServiceInitiated() {
|
||||
return BytecodeProvider.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.bytecode.internal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.boot.registry.StandardServiceInitiator;
|
||||
import org.hibernate.bytecode.spi.BytecodeProvider;
|
||||
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
/**
|
||||
* Most commonly the {@link ProxyFactoryFactory} will depend directly on the chosen {@link BytecodeProvider},
|
||||
* however by registering them as two separate services we can allow to override either one
|
||||
* or both of them.
|
||||
* @author Sanne Grinovero
|
||||
*/
|
||||
public final class ProxyFactoryFactoryInitiator implements StandardServiceInitiator<ProxyFactoryFactory> {
|
||||
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final StandardServiceInitiator<ProxyFactoryFactory> INSTANCE = new ProxyFactoryFactoryInitiator();
|
||||
|
||||
@Override
|
||||
public ProxyFactoryFactory initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
|
||||
final BytecodeProvider bytecodeProvider = registry.getService( BytecodeProvider.class );
|
||||
return bytecodeProvider.getProxyFactoryFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ProxyFactoryFactory> getServiceInitiated() {
|
||||
return ProxyFactoryFactory.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.bytecode.internal;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.SessionFactoryObserver;
|
||||
import org.hibernate.bytecode.spi.BytecodeProvider;
|
||||
|
||||
public final class SessionFactoryObserverForBytecodeEnhancer implements SessionFactoryObserver {
|
||||
|
||||
private final BytecodeProvider bytecodeProvider;
|
||||
|
||||
public SessionFactoryObserverForBytecodeEnhancer(BytecodeProvider bytecodeProvider) {
|
||||
this.bytecodeProvider = bytecodeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionFactoryCreated(final SessionFactory factory) {
|
||||
this.bytecodeProvider.resetCaches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionFactoryClosing(final SessionFactory factory) {
|
||||
this.bytecodeProvider.resetCaches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionFactoryClosed(final SessionFactory factory) {
|
||||
this.bytecodeProvider.resetCaches();
|
||||
}
|
||||
}
|
|
@ -159,7 +159,7 @@ public final class ByteBuddyState {
|
|||
|
||||
/**
|
||||
* Wipes out all known caches used by ByteBuddy. This implies it might trigger the need
|
||||
* to re-create some helpers if used at runtime, especially as this state is shared by
|
||||
* to re-create some helpers if used at runtime, especially as this state might be shared by
|
||||
* multiple SessionFactory instances, but at least ensures we cleanup anything which is no
|
||||
* longer needed after a SessionFactory close.
|
||||
* The assumption is that closing SessionFactories is a rare event; in this perspective the cost
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.bytecode.spi;
|
|||
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
||||
import org.hibernate.service.Service;
|
||||
|
||||
/**
|
||||
* Contract for providers of bytecode services to Hibernate.
|
||||
|
@ -19,7 +20,7 @@ import org.hibernate.bytecode.enhance.spi.Enhancer;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface BytecodeProvider {
|
||||
public interface BytecodeProvider extends Service {
|
||||
/**
|
||||
* Retrieve the specific factory for this provider capable of
|
||||
* generating run-time proxies for lazy-loading purposes.
|
||||
|
|
|
@ -6,11 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.bytecode.spi;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.SessionFactoryImpl;
|
||||
import org.hibernate.proxy.ProxyFactory;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.Service;
|
||||
|
||||
/**
|
||||
* An interface for factories of {@link ProxyFactory proxy factory} instances.
|
||||
|
@ -20,7 +18,7 @@ import org.hibernate.service.ServiceRegistry;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ProxyFactoryFactory {
|
||||
public interface ProxyFactoryFactory extends Service {
|
||||
/**
|
||||
* Build a proxy factory specifically for handling runtime
|
||||
* lazy loading.
|
||||
|
|
|
@ -198,13 +198,18 @@ public abstract class AbstractReadWriteAccess extends AbstractCachedDomainDataAc
|
|||
public void remove(SharedSessionContractImplementor session, Object key) {
|
||||
if ( getStorageAccess().getFromCache( key, session ) instanceof SoftLock ) {
|
||||
log.debugf( "Skipping #remove call in read-write access to maintain SoftLock : %s", key );
|
||||
// don'tm do anything... we want the SoftLock to remain in place
|
||||
// don't do anything... we want the SoftLock to remain in place
|
||||
}
|
||||
else {
|
||||
super.remove( session, key );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll(SharedSessionContractImplementor session) {
|
||||
// A no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface type implemented by all wrapper objects in the cache.
|
||||
*/
|
||||
|
|
|
@ -151,9 +151,4 @@ public class EntityReadWriteAccess extends AbstractReadWriteAccess implements En
|
|||
public SoftLock lockRegion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockRegion(SoftLock lock) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -351,8 +351,15 @@ public final class Environment implements AvailableSettings {
|
|||
|
||||
LOG.bytecodeProvider( providerName );
|
||||
|
||||
// todo : allow a custom class name - just check if the config is a FQN
|
||||
// currently we assume it is only ever the Strings "javassist" or "bytebuddy"...
|
||||
// there is no need to support plugging in a custom BytecodeProvider via FQCN:
|
||||
// - the static helper methods on this class are deprecated
|
||||
// - it's possible to plug a custom BytecodeProvider directly into the ServiceRegistry
|
||||
//
|
||||
// This also allows integrators to inject a BytecodeProvider instance which has some
|
||||
// state; particularly useful to inject proxy definitions which have been prepared in
|
||||
// advance.
|
||||
// See also https://hibernate.atlassian.net/browse/HHH-13804 and how this was solved in
|
||||
// Quarkus.
|
||||
|
||||
LOG.unknownBytecodeProvider( providerName, BYTECODE_PROVIDER_NAME_DEFAULT );
|
||||
return new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl();
|
||||
|
|
|
@ -51,6 +51,9 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|||
import org.hibernate.engine.transaction.internal.TransactionImpl;
|
||||
import org.hibernate.engine.transaction.spi.TransactionImplementor;
|
||||
import org.hibernate.id.uuid.StandardRandomStrategy;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.hibernate.jdbc.WorkExecutorVisitable;
|
||||
import org.hibernate.jpa.QueryHints;
|
||||
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
@ -728,6 +731,28 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
return buildNamedQuery( name, resultClass );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWork(final Work work) throws HibernateException {
|
||||
WorkExecutorVisitable<Void> realWork = (workExecutor, connection) -> {
|
||||
workExecutor.executeWork( work, connection );
|
||||
return null;
|
||||
};
|
||||
doWork( realWork );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doReturningWork(final ReturningWork<T> work) throws HibernateException {
|
||||
WorkExecutorVisitable<T> realWork = (workExecutor, connection) -> workExecutor.executeReturningWork(
|
||||
work,
|
||||
connection
|
||||
);
|
||||
return doWork( realWork );
|
||||
}
|
||||
|
||||
private <T> T doWork(WorkExecutorVisitable<T> work) throws HibernateException {
|
||||
return getJdbcCoordinator().coordinateWork( work );
|
||||
}
|
||||
|
||||
protected <T> QueryImplementor<T> buildNamedQuery(String queryName, Class<T> resultType) {
|
||||
checkOpen();
|
||||
pulseTransactionCoordinator();
|
||||
|
@ -794,7 +819,6 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
throw getExceptionConverter().convert( new IllegalArgumentException( "No query defined for that name [" + queryName + "]" ) );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
public ProcedureCall getNamedProcedureCall(String name) {
|
||||
|
|
|
@ -1439,7 +1439,7 @@ public interface CoreMessageLogger extends BasicLogger {
|
|||
void validatorNotFound();
|
||||
|
||||
@LogMessage(level = INFO)
|
||||
@Message(value = "Hibernate Core {%s}", id = 412)
|
||||
@Message(value = "Hibernate ORM core version %s", id = 412)
|
||||
void version(String versionString);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
|
|
|
@ -770,8 +770,6 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
|
|||
* @throws HibernateException
|
||||
*/
|
||||
public void close() throws HibernateException {
|
||||
//This is an idempotent operation so we can do it even before the checks (it won't hurt):
|
||||
Environment.getBytecodeProvider().resetCaches();
|
||||
synchronized (this) {
|
||||
if ( isClosed ) {
|
||||
if ( getSessionFactoryOptions().getJpaCompliance().isJpaClosedComplianceEnabled() ) {
|
||||
|
|
|
@ -115,10 +115,6 @@ import org.hibernate.graph.RootGraph;
|
|||
import org.hibernate.graph.internal.RootGraphImpl;
|
||||
import org.hibernate.graph.spi.GraphImplementor;
|
||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.hibernate.jdbc.WorkExecutor;
|
||||
import org.hibernate.jdbc.WorkExecutorVisitable;
|
||||
import org.hibernate.jpa.AvailableSettings;
|
||||
import org.hibernate.jpa.QueryHints;
|
||||
import org.hibernate.jpa.internal.util.CacheModeHelper;
|
||||
|
@ -1745,33 +1741,6 @@ public class SessionImpl
|
|||
persistenceContext.setReadOnly( entity, readOnly );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWork(final Work work) throws HibernateException {
|
||||
WorkExecutorVisitable<Void> realWork = new WorkExecutorVisitable<Void>() {
|
||||
@Override
|
||||
public Void accept(WorkExecutor<Void> workExecutor, Connection connection) throws SQLException {
|
||||
workExecutor.executeWork( work, connection );
|
||||
return null;
|
||||
}
|
||||
};
|
||||
doWork( realWork );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doReturningWork(final ReturningWork<T> work) throws HibernateException {
|
||||
WorkExecutorVisitable<T> realWork = new WorkExecutorVisitable<T>() {
|
||||
@Override
|
||||
public T accept(WorkExecutor<T> workExecutor, Connection connection) throws SQLException {
|
||||
return workExecutor.executeReturningWork( work, connection );
|
||||
}
|
||||
};
|
||||
return doWork( realWork );
|
||||
}
|
||||
|
||||
private <T> T doWork(WorkExecutorVisitable<T> work) throws HibernateException {
|
||||
return getJdbcCoordinator().coordinateWork( work );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterScrollOperation() {
|
||||
// nothing to do in a stateful session
|
||||
|
|
|
@ -3921,7 +3921,7 @@ public abstract class AbstractEntityPersister
|
|||
final String[] deleteStrings;
|
||||
if ( isImpliedOptimisticLocking && loadedState != null ) {
|
||||
// we need to utilize dynamic delete statements
|
||||
deleteStrings = generateSQLDeletStrings( loadedState );
|
||||
deleteStrings = generateSQLDeleteStrings( loadedState );
|
||||
}
|
||||
else {
|
||||
// otherwise, utilize the static delete statements
|
||||
|
@ -3939,7 +3939,7 @@ public abstract class AbstractEntityPersister
|
|||
|| entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.ALL;
|
||||
}
|
||||
|
||||
private String[] generateSQLDeletStrings(Object[] loadedState) {
|
||||
private String[] generateSQLDeleteStrings(Object[] loadedState) {
|
||||
int span = getTableSpan();
|
||||
String[] deleteStrings = new String[span];
|
||||
for ( int j = span - 1; j >= 0; j-- ) {
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.proxy.pojo;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Subclass;
|
||||
import org.hibernate.property.access.spi.Getter;
|
||||
import org.hibernate.property.access.spi.Setter;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.tuple.entity.PojoEntityTuplizer;
|
||||
|
||||
/**
|
||||
* Most of this code was originally an internal detail of {@link PojoEntityTuplizer},
|
||||
* then extracted to make it easier for integrators to initialize a custom
|
||||
* {@link org.hibernate.proxy.ProxyFactory}.
|
||||
*/
|
||||
public final class ProxyFactoryHelper {
|
||||
|
||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ProxyFactoryHelper.class );
|
||||
|
||||
private ProxyFactoryHelper() {
|
||||
//not meant to be instantiated
|
||||
}
|
||||
|
||||
public static Set<Class> extractProxyInterfaces(final PersistentClass persistentClass, final String entityName) {
|
||||
/*
|
||||
* We need to preserve the order of the interfaces they were put into the set, since javassist will choose the
|
||||
* first one's class-loader to construct the proxy class with. This is also the reason why HibernateProxy.class
|
||||
* should be the last one in the order (on JBossAS7 its class-loader will be org.hibernate module's class-
|
||||
* loader, which will not see the classes inside deployed apps. See HHH-3078
|
||||
*/
|
||||
final Set<Class> proxyInterfaces = new java.util.LinkedHashSet<Class>();
|
||||
final Class mappedClass = persistentClass.getMappedClass();
|
||||
final Class proxyInterface = persistentClass.getProxyInterface();
|
||||
|
||||
if ( proxyInterface != null && !mappedClass.equals( proxyInterface ) ) {
|
||||
if ( !proxyInterface.isInterface() ) {
|
||||
throw new MappingException(
|
||||
"proxy must be either an interface, or the class itself: " + entityName
|
||||
);
|
||||
}
|
||||
proxyInterfaces.add( proxyInterface );
|
||||
}
|
||||
|
||||
if ( mappedClass.isInterface() ) {
|
||||
proxyInterfaces.add( mappedClass );
|
||||
}
|
||||
|
||||
Iterator<Subclass> subclasses = persistentClass.getSubclassIterator();
|
||||
while ( subclasses.hasNext() ) {
|
||||
final Subclass subclass = subclasses.next();
|
||||
final Class subclassProxy = subclass.getProxyInterface();
|
||||
final Class subclassClass = subclass.getMappedClass();
|
||||
if ( subclassProxy != null && !subclassClass.equals( subclassProxy ) ) {
|
||||
if ( !subclassProxy.isInterface() ) {
|
||||
throw new MappingException(
|
||||
"proxy must be either an interface, or the class itself: " + subclass.getEntityName()
|
||||
);
|
||||
}
|
||||
proxyInterfaces.add( subclassProxy );
|
||||
}
|
||||
}
|
||||
|
||||
proxyInterfaces.add( HibernateProxy.class );
|
||||
return proxyInterfaces;
|
||||
}
|
||||
|
||||
public static void validateProxyability(final PersistentClass persistentClass) {
|
||||
Iterator properties = persistentClass.getPropertyIterator();
|
||||
Class clazz = persistentClass.getMappedClass();
|
||||
while ( properties.hasNext() ) {
|
||||
Property property = (Property) properties.next();
|
||||
Method method = property.getGetter( clazz ).getMethod();
|
||||
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
|
||||
LOG.gettersOfLazyClassesCannotBeFinal( persistentClass.getEntityName(), property.getName() );
|
||||
}
|
||||
method = property.getSetter( clazz ).getMethod();
|
||||
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
|
||||
LOG.settersOfLazyClassesCannotBeFinal( persistentClass.getEntityName(), property.getName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Method extractProxySetIdentifierMethod(final Setter idSetter, final Class proxyInterface) {
|
||||
Method idSetterMethod = idSetter == null ? null : idSetter.getMethod();
|
||||
|
||||
Method proxySetIdentifierMethod = idSetterMethod == null || proxyInterface == null ?
|
||||
null :
|
||||
ReflectHelper.getMethod( proxyInterface, idSetterMethod );
|
||||
return proxySetIdentifierMethod;
|
||||
}
|
||||
|
||||
public static Method extractProxyGetIdentifierMethod(final Getter idGetter, final Class proxyInterface) {
|
||||
Method idGetterMethod = idGetter == null ? null : idGetter.getMethod();
|
||||
|
||||
Method proxyGetIdentifierMethod = idGetterMethod == null || proxyInterface == null ?
|
||||
null :
|
||||
ReflectHelper.getMethod( proxyInterface, idGetterMethod );
|
||||
return proxyGetIdentifierMethod;
|
||||
}
|
||||
}
|
|
@ -12,6 +12,8 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.boot.cfgxml.internal.CfgXmlAccessServiceInitiator;
|
||||
import org.hibernate.boot.registry.StandardServiceInitiator;
|
||||
import org.hibernate.bytecode.internal.BytecodeProviderInitiator;
|
||||
import org.hibernate.bytecode.internal.ProxyFactoryFactoryInitiator;
|
||||
import org.hibernate.cache.internal.RegionFactoryInitiator;
|
||||
import org.hibernate.engine.config.internal.ConfigurationServiceInitiator;
|
||||
import org.hibernate.engine.jdbc.batch.internal.BatchBuilderInitiator;
|
||||
|
@ -51,6 +53,9 @@ public final class StandardServiceInitiators {
|
|||
private static List<StandardServiceInitiator> buildStandardServiceInitiatorList() {
|
||||
final ArrayList<StandardServiceInitiator> serviceInitiators = new ArrayList<StandardServiceInitiator>();
|
||||
|
||||
serviceInitiators.add( BytecodeProviderInitiator.INSTANCE );
|
||||
serviceInitiators.add( ProxyFactoryFactoryInitiator.INSTANCE );
|
||||
|
||||
serviceInitiators.add( CfgXmlAccessServiceInitiator.INSTANCE );
|
||||
serviceInitiators.add( ConfigurationServiceInitiator.INSTANCE );
|
||||
serviceInitiators.add( PropertyAccessStrategyResolverInitiator.INSTANCE );
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.tuple.component;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.spi.BasicProxyFactory;
|
||||
import org.hibernate.bytecode.spi.BytecodeProvider;
|
||||
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
|
||||
import org.hibernate.bytecode.spi.ReflectionOptimizer;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -67,9 +70,8 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer {
|
|||
optimizer = null;
|
||||
}
|
||||
else {
|
||||
// TODO: here is why we need to make bytecode provider global :(
|
||||
// TODO : again, fix this after HHH-1907 is complete
|
||||
optimizer = Environment.getBytecodeProvider().getReflectionOptimizer(
|
||||
final BytecodeProvider bytecodeProvider = component.getServiceRegistry().getService( BytecodeProvider.class );
|
||||
optimizer = bytecodeProvider.getReflectionOptimizer(
|
||||
componentClass, getterNames, setterNames, propTypes
|
||||
);
|
||||
}
|
||||
|
@ -124,7 +126,8 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer {
|
|||
|
||||
protected Instantiator buildInstantiator(Component component) {
|
||||
if ( component.isEmbedded() && ReflectHelper.isAbstractClass( this.componentClass ) ) {
|
||||
return new ProxiedInstantiator( this.componentClass );
|
||||
ProxyFactoryFactory proxyFactoryFactory = component.getServiceRegistry().getService( ProxyFactoryFactory.class );
|
||||
return new ProxiedInstantiator( this.componentClass, proxyFactoryFactory );
|
||||
}
|
||||
if ( optimizer == null ) {
|
||||
return new PojoInstantiator( this.componentClass, null );
|
||||
|
@ -151,16 +154,14 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer {
|
|||
private final Class proxiedClass;
|
||||
private final BasicProxyFactory factory;
|
||||
|
||||
public ProxiedInstantiator(Class componentClass) {
|
||||
public ProxiedInstantiator(Class componentClass, ProxyFactoryFactory proxyFactoryFactory) {
|
||||
proxiedClass = componentClass;
|
||||
if ( proxiedClass.isInterface() ) {
|
||||
factory = Environment.getBytecodeProvider()
|
||||
.getProxyFactoryFactory()
|
||||
factory = proxyFactoryFactory
|
||||
.buildBasicProxyFactory( null, new Class[] { proxiedClass } );
|
||||
}
|
||||
else {
|
||||
factory = Environment.getBytecodeProvider()
|
||||
.getProxyFactoryFactory()
|
||||
factory = proxyFactoryFactory
|
||||
.buildBasicProxyFactory( proxiedClass, null );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,17 +7,16 @@
|
|||
package org.hibernate.tuple.entity;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.EntityNameResolver;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeProvider;
|
||||
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
|
||||
import org.hibernate.bytecode.spi.ReflectionOptimizer;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.classic.Lifecycle;
|
||||
|
@ -27,14 +26,12 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Subclass;
|
||||
import org.hibernate.property.access.spi.Getter;
|
||||
import org.hibernate.property.access.spi.Setter;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.ProxyFactory;
|
||||
import org.hibernate.proxy.pojo.ProxyFactoryHelper;
|
||||
import org.hibernate.tuple.Instantiator;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
|
@ -52,15 +49,11 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
private final boolean lifecycleImplementor;
|
||||
private final ReflectionOptimizer optimizer;
|
||||
|
||||
private final boolean isBytecodeEnhanced;
|
||||
|
||||
|
||||
public PojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
|
||||
super( entityMetamodel, mappedEntity );
|
||||
this.mappedClass = mappedEntity.getMappedClass();
|
||||
this.proxyInterface = mappedEntity.getProxyInterface();
|
||||
this.lifecycleImplementor = Lifecycle.class.isAssignableFrom( mappedClass );
|
||||
this.isBytecodeEnhanced = entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
|
||||
|
||||
String[] getterNames = new String[propertySpan];
|
||||
String[] setterNames = new String[propertySpan];
|
||||
|
@ -75,16 +68,13 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
optimizer = null;
|
||||
}
|
||||
else {
|
||||
// todo : YUCK!!!
|
||||
optimizer = Environment.getBytecodeProvider().getReflectionOptimizer(
|
||||
final BytecodeProvider bytecodeProvider = entityMetamodel.getSessionFactory().getServiceRegistry().getService( BytecodeProvider.class );
|
||||
optimizer = bytecodeProvider.getReflectionOptimizer(
|
||||
mappedClass,
|
||||
getterNames,
|
||||
setterNames,
|
||||
propTypes
|
||||
);
|
||||
// optimizer = getFactory().getSettings().getBytecodeProvider().getReflectionOptimizer(
|
||||
// mappedClass, getterNames, setterNames, propTypes
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,76 +82,21 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
|
||||
// determine the id getter and setter methods from the proxy interface (if any)
|
||||
// determine all interfaces needed by the resulting proxy
|
||||
final String entityName = getEntityName();
|
||||
final Class mappedClass = persistentClass.getMappedClass();
|
||||
final Class proxyInterface = persistentClass.getProxyInterface();
|
||||
|
||||
/*
|
||||
* We need to preserve the order of the interfaces they were put into the set, since javassist will choose the
|
||||
* first one's class-loader to construct the proxy class with. This is also the reason why HibernateProxy.class
|
||||
* should be the last one in the order (on JBossAS7 its class-loader will be org.hibernate module's class-
|
||||
* loader, which will not see the classes inside deployed apps. See HHH-3078
|
||||
*/
|
||||
Set<Class> proxyInterfaces = new java.util.LinkedHashSet<Class>();
|
||||
final Set<Class> proxyInterfaces = ProxyFactoryHelper.extractProxyInterfaces( persistentClass, entityName );
|
||||
|
||||
Class mappedClass = persistentClass.getMappedClass();
|
||||
Class proxyInterface = persistentClass.getProxyInterface();
|
||||
ProxyFactoryHelper.validateProxyability( persistentClass );
|
||||
|
||||
if ( proxyInterface != null && !mappedClass.equals( proxyInterface ) ) {
|
||||
if ( !proxyInterface.isInterface() ) {
|
||||
throw new MappingException(
|
||||
"proxy must be either an interface, or the class itself: " + getEntityName()
|
||||
);
|
||||
}
|
||||
proxyInterfaces.add( proxyInterface );
|
||||
}
|
||||
|
||||
if ( mappedClass.isInterface() ) {
|
||||
proxyInterfaces.add( mappedClass );
|
||||
}
|
||||
|
||||
Iterator<Subclass> subclasses = persistentClass.getSubclassIterator();
|
||||
while ( subclasses.hasNext() ) {
|
||||
final Subclass subclass = subclasses.next();
|
||||
final Class subclassProxy = subclass.getProxyInterface();
|
||||
final Class subclassClass = subclass.getMappedClass();
|
||||
if ( subclassProxy != null && !subclassClass.equals( subclassProxy ) ) {
|
||||
if ( !subclassProxy.isInterface() ) {
|
||||
throw new MappingException(
|
||||
"proxy must be either an interface, or the class itself: " + subclass.getEntityName()
|
||||
);
|
||||
}
|
||||
proxyInterfaces.add( subclassProxy );
|
||||
}
|
||||
}
|
||||
|
||||
proxyInterfaces.add( HibernateProxy.class );
|
||||
|
||||
Iterator properties = persistentClass.getPropertyIterator();
|
||||
Class clazz = persistentClass.getMappedClass();
|
||||
while ( properties.hasNext() ) {
|
||||
Property property = (Property) properties.next();
|
||||
Method method = property.getGetter( clazz ).getMethod();
|
||||
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
|
||||
LOG.gettersOfLazyClassesCannotBeFinal( persistentClass.getEntityName(), property.getName() );
|
||||
}
|
||||
method = property.getSetter( clazz ).getMethod();
|
||||
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
|
||||
LOG.settersOfLazyClassesCannotBeFinal( persistentClass.getEntityName(), property.getName() );
|
||||
}
|
||||
}
|
||||
|
||||
Method idGetterMethod = idGetter == null ? null : idGetter.getMethod();
|
||||
Method idSetterMethod = idSetter == null ? null : idSetter.getMethod();
|
||||
|
||||
Method proxyGetIdentifierMethod = idGetterMethod == null || proxyInterface == null ?
|
||||
null :
|
||||
ReflectHelper.getMethod( proxyInterface, idGetterMethod );
|
||||
Method proxySetIdentifierMethod = idSetterMethod == null || proxyInterface == null ?
|
||||
null :
|
||||
ReflectHelper.getMethod( proxyInterface, idSetterMethod );
|
||||
Method proxyGetIdentifierMethod = ProxyFactoryHelper.extractProxyGetIdentifierMethod( idGetter, proxyInterface );
|
||||
Method proxySetIdentifierMethod = ProxyFactoryHelper.extractProxySetIdentifierMethod( idSetter, proxyInterface );
|
||||
|
||||
ProxyFactory pf = buildProxyFactoryInternal( persistentClass, idGetter, idSetter );
|
||||
try {
|
||||
pf.postInstantiate(
|
||||
getEntityName(),
|
||||
entityName,
|
||||
mappedClass,
|
||||
proxyInterfaces,
|
||||
proxyGetIdentifierMethod,
|
||||
|
@ -172,7 +107,7 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
);
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
LOG.unableToCreateProxyFactory( getEntityName(), he );
|
||||
LOG.unableToCreateProxyFactory( entityName, he );
|
||||
pf = null;
|
||||
}
|
||||
return pf;
|
||||
|
@ -182,9 +117,8 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
PersistentClass persistentClass,
|
||||
Getter idGetter,
|
||||
Setter idSetter) {
|
||||
// TODO : YUCK!!! fix after HHH-1907 is complete
|
||||
return Environment.getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory( getFactory() );
|
||||
// return getFactory().getSettings().getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory();
|
||||
ProxyFactoryFactory proxyFactory = getFactory().getServiceRegistry().getService( ProxyFactoryFactory.class );
|
||||
return proxyFactory.buildProxyFactory( getFactory() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
310
hibernate-core/src/test/java/org/hibernate/cache/spi/ReadWriteCacheTest.java
vendored
Normal file
310
hibernate-core/src/test/java/org/hibernate/cache/spi/ReadWriteCacheTest.java
vendored
Normal file
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* 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.cache.spi;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.EmptyInterceptor;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
* @author Frank Doherty
|
||||
*/
|
||||
public class ReadWriteCacheTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private static final String ORIGINAL_TITLE = "Original Title";
|
||||
private static final String UPDATED_TITLE = "Updated Title";
|
||||
|
||||
private long bookId;
|
||||
private CountDownLatch endLatch;
|
||||
private AtomicBoolean interceptTransaction;
|
||||
|
||||
@Override
|
||||
public void buildSessionFactory() {
|
||||
buildSessionFactory( getCacheConfig() );
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
endLatch = new CountDownLatch( 1 );
|
||||
interceptTransaction = new AtomicBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rebuildSessionFactory() {
|
||||
rebuildSessionFactory( getCacheConfig() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelete() throws InterruptedException {
|
||||
bookId = 1L;
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
createBook( bookId, session );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
log.info( "Delete Book" );
|
||||
Book book = session.get( Book.class, bookId );
|
||||
session.delete( book );
|
||||
interceptTransaction.set( true );
|
||||
} );
|
||||
|
||||
endLatch.await();
|
||||
interceptTransaction.set( false );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
assertBookNotFound( bookId, session );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13792")
|
||||
public void testDeleteHQL() throws InterruptedException {
|
||||
bookId = 2L;
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
createBook( bookId, session );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
log.info( "Delete Book using HQL" );
|
||||
int numRows = session.createQuery( "delete from Book where id = :id" )
|
||||
.setParameter( "id", bookId )
|
||||
.executeUpdate();
|
||||
assertEquals( 1, numRows );
|
||||
interceptTransaction.set( true );
|
||||
} );
|
||||
|
||||
endLatch.await();
|
||||
interceptTransaction.set( false );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
assertBookNotFound( bookId, session );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13792")
|
||||
public void testDeleteNativeQuery() throws InterruptedException {
|
||||
bookId = 3L;
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
createBook( bookId, session );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
log.info( "Delete Book using NativeQuery" );
|
||||
int numRows = session.createNativeQuery( "delete from Book where id = :id" )
|
||||
.setParameter( "id", bookId )
|
||||
.addSynchronizedEntityClass( Book.class )
|
||||
.executeUpdate();
|
||||
assertEquals( 1, numRows );
|
||||
interceptTransaction.set( true );
|
||||
} );
|
||||
|
||||
endLatch.await();
|
||||
interceptTransaction.set( false );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
assertBookNotFound( bookId, session );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() throws InterruptedException {
|
||||
bookId = 4L;
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
createBook( bookId, session );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
log.info( "Update Book" );
|
||||
Book book = session.get( Book.class, bookId );
|
||||
book.setTitle( UPDATED_TITLE );
|
||||
session.save( book );
|
||||
interceptTransaction.set( true );
|
||||
} );
|
||||
|
||||
endLatch.await();
|
||||
interceptTransaction.set( false );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
loadBook( bookId, session );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13792")
|
||||
public void testUpdateHQL() throws InterruptedException {
|
||||
bookId = 5L;
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
createBook( bookId, session );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
log.info( "Update Book using HQL" );
|
||||
int numRows = session.createQuery( "update Book set title = :title where id = :id" )
|
||||
.setParameter( "title", UPDATED_TITLE )
|
||||
.setParameter( "id", bookId )
|
||||
.executeUpdate();
|
||||
assertEquals( 1, numRows );
|
||||
interceptTransaction.set( true );
|
||||
} );
|
||||
|
||||
endLatch.await();
|
||||
interceptTransaction.set( false );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
loadBook( bookId, session );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13792")
|
||||
public void testUpdateNativeQuery() throws InterruptedException {
|
||||
bookId = 6L;
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
createBook( bookId, session );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
log.info( "Update Book using NativeQuery" );
|
||||
int numRows = session.createNativeQuery( "update Book set title = :title where id = :id" )
|
||||
.setParameter( "title", UPDATED_TITLE )
|
||||
.setParameter( "id", bookId )
|
||||
.addSynchronizedEntityClass( Book.class )
|
||||
.executeUpdate();
|
||||
assertEquals( 1, numRows );
|
||||
interceptTransaction.set( true );
|
||||
} );
|
||||
|
||||
endLatch.await();
|
||||
interceptTransaction.set( false );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
loadBook( bookId, session );
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Book.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCacheConcurrencyStrategy() {
|
||||
return "read-write";
|
||||
}
|
||||
|
||||
private void assertBookNotFound(long bookId, Session session) {
|
||||
log.info( "Load Book" );
|
||||
Book book = session.get( Book.class, bookId );
|
||||
assertNull( book );
|
||||
}
|
||||
|
||||
private void createBook(long bookId, Session session) {
|
||||
log.info( "Create Book" );
|
||||
Book book = new Book();
|
||||
book.setId( bookId );
|
||||
book.setTitle( ORIGINAL_TITLE );
|
||||
session.save( book );
|
||||
}
|
||||
|
||||
private Consumer<Configuration> getCacheConfig() {
|
||||
return configuration -> configuration.setInterceptor( new TransactionInterceptor() );
|
||||
}
|
||||
|
||||
private void loadBook(long bookId, Session session) {
|
||||
log.info( "Load Book" );
|
||||
Book book = session.get( Book.class, bookId );
|
||||
assertNotNull( book );
|
||||
assertEquals( "Found old value", UPDATED_TITLE, book.getTitle() );
|
||||
}
|
||||
|
||||
@Entity(name = "Book")
|
||||
@Cacheable
|
||||
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||
private static final class Book {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Book[id=" + id + ",title=" + title + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private final class TransactionInterceptor extends EmptyInterceptor {
|
||||
@Override
|
||||
public void beforeTransactionCompletion(Transaction tx) {
|
||||
if ( interceptTransaction.get() ) {
|
||||
try {
|
||||
log.info( "Fetch Book" );
|
||||
|
||||
executeSync( () -> {
|
||||
Session session = sessionFactory()
|
||||
.openSession();
|
||||
Book book = session.get( Book.class, bookId );
|
||||
assertNotNull( book );
|
||||
log.infof( "Fetched %s", book );
|
||||
session.close();
|
||||
} );
|
||||
|
||||
assertTrue( sessionFactory().getCache()
|
||||
.containsEntity( Book.class, bookId ) );
|
||||
}
|
||||
finally {
|
||||
endLatch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,13 +22,13 @@ import java.util.Set;
|
|||
name = "company.location",
|
||||
fetchOverrides = {
|
||||
@FetchProfile.FetchOverride(
|
||||
entity = CompanyWithFetchProfile.class,
|
||||
entity = CompanyFetchProfile.class,
|
||||
association = "location",
|
||||
mode = FetchMode.JOIN
|
||||
)
|
||||
}
|
||||
)
|
||||
public class CompanyWithFetchProfile {
|
||||
public class CompanyFetchProfile {
|
||||
@Id @GeneratedValue
|
||||
public long id;
|
||||
|
||||
|
@ -42,6 +42,7 @@ public class CompanyWithFetchProfile {
|
|||
public Set<Market> markets = new HashSet<Market>();
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@JoinTable(name= "companyfp_phonenos")
|
||||
public Set<String> phoneNumbers = new HashSet<String>();
|
||||
|
||||
public Location getLocation() {
|
|
@ -1,4 +1,4 @@
|
|||
package org.hibernate.jpa.test.graphs.mapped_by_id;
|
||||
package org.hibernate.jpa.test.graphs.mappedbyid;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
|
@ -99,12 +99,12 @@ public class FetchGraphFindByIdTest extends BaseEntityManagerFunctionalTestCase
|
|||
|
||||
entityManager.unwrap( Session.class ).enableFetchProfile("company.location");
|
||||
|
||||
EntityGraph<CompanyWithFetchProfile> entityGraph = entityManager.createEntityGraph( CompanyWithFetchProfile.class );
|
||||
EntityGraph<CompanyFetchProfile> entityGraph = entityManager.createEntityGraph( CompanyFetchProfile.class );
|
||||
entityGraph.addAttributeNodes( "markets" );
|
||||
|
||||
Map<String, Object> properties = Collections.singletonMap( "javax.persistence.fetchgraph", entityGraph );
|
||||
|
||||
CompanyWithFetchProfile company = entityManager.find( CompanyWithFetchProfile.class, companyWithFetchProfileId, properties );
|
||||
CompanyFetchProfile company = entityManager.find( CompanyFetchProfile.class, companyWithFetchProfileId, properties );
|
||||
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
|
@ -126,7 +126,7 @@ public class FetchGraphFindByIdTest extends BaseEntityManagerFunctionalTestCase
|
|||
subSubgraph.addAttributeNodes( "managers" );
|
||||
subSubgraph.addAttributeNodes( "friends" );
|
||||
|
||||
company = entityManager.find( CompanyWithFetchProfile.class, companyWithFetchProfileId, properties );
|
||||
company = entityManager.find( CompanyFetchProfile.class, companyWithFetchProfileId, properties );
|
||||
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
|
@ -189,17 +189,17 @@ public class FetchGraphFindByIdTest extends BaseEntityManagerFunctionalTestCase
|
|||
entityManager.persist( company );
|
||||
companyId = company.id;
|
||||
|
||||
CompanyWithFetchProfile companyWithFetchProfile = new CompanyWithFetchProfile();
|
||||
companyWithFetchProfile.employees.add( employee );
|
||||
companyWithFetchProfile.employees.add( manager1 );
|
||||
companyWithFetchProfile.employees.add( manager2 );
|
||||
companyWithFetchProfile.location = location;
|
||||
companyWithFetchProfile.markets.add( Market.SERVICES );
|
||||
companyWithFetchProfile.markets.add( Market.TECHNOLOGY );
|
||||
companyWithFetchProfile.phoneNumbers.add( "012-345-6789" );
|
||||
companyWithFetchProfile.phoneNumbers.add( "987-654-3210" );
|
||||
entityManager.persist( companyWithFetchProfile );
|
||||
companyWithFetchProfileId = companyWithFetchProfile.id;
|
||||
CompanyFetchProfile companyFetchProfile = new CompanyFetchProfile();
|
||||
companyFetchProfile.employees.add( employee );
|
||||
companyFetchProfile.employees.add( manager1 );
|
||||
companyFetchProfile.employees.add( manager2 );
|
||||
companyFetchProfile.location = location;
|
||||
companyFetchProfile.markets.add( Market.SERVICES );
|
||||
companyFetchProfile.markets.add( Market.TECHNOLOGY );
|
||||
companyFetchProfile.phoneNumbers.add( "012-345-6789" );
|
||||
companyFetchProfile.phoneNumbers.add( "987-654-3210" );
|
||||
entityManager.persist( companyFetchProfile );
|
||||
companyWithFetchProfileId = companyFetchProfile.id;
|
||||
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
|
@ -207,7 +207,7 @@ public class FetchGraphFindByIdTest extends BaseEntityManagerFunctionalTestCase
|
|||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { Company.class, CompanyWithFetchProfile.class, Employee.class, Manager.class, Location.class, Course.class, Student.class };
|
||||
return new Class<?>[] { Company.class, CompanyFetchProfile.class, Employee.class, Manager.class, Location.class, Course.class, Student.class };
|
||||
}
|
||||
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.graphs.mapped_by_id;
|
||||
package org.hibernate.jpa.test.graphs.mappedbyid;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
|
@ -175,11 +175,11 @@ public class QueryHintEntityGraphTest extends BaseEntityManagerFunctionalTestCas
|
|||
|
||||
entityManager.unwrap( Session.class ).enableFetchProfile( "company.location" );
|
||||
|
||||
EntityGraph<CompanyWithFetchProfile> entityGraph = entityManager.createEntityGraph( CompanyWithFetchProfile.class );
|
||||
EntityGraph<CompanyFetchProfile> entityGraph = entityManager.createEntityGraph( CompanyFetchProfile.class );
|
||||
entityGraph.addAttributeNodes( "markets" );
|
||||
Query query = entityManager.createQuery( "from " + CompanyWithFetchProfile.class.getName() );
|
||||
Query query = entityManager.createQuery( "from " + CompanyFetchProfile.class.getName() );
|
||||
query.setHint( QueryHints.HINT_FETCHGRAPH, entityGraph );
|
||||
CompanyWithFetchProfile company = (CompanyWithFetchProfile) query.getSingleResult();
|
||||
CompanyFetchProfile company = (CompanyFetchProfile) query.getSingleResult();
|
||||
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
|
@ -201,9 +201,9 @@ public class QueryHintEntityGraphTest extends BaseEntityManagerFunctionalTestCas
|
|||
subSubgraph.addAttributeNodes( "managers" );
|
||||
subSubgraph.addAttributeNodes( "friends" );
|
||||
|
||||
query = entityManager.createQuery( "from " + CompanyWithFetchProfile.class.getName() );
|
||||
query = entityManager.createQuery( "from " + CompanyFetchProfile.class.getName() );
|
||||
query.setHint( QueryHints.HINT_FETCHGRAPH, entityGraph );
|
||||
company = (CompanyWithFetchProfile) query.getSingleResult();
|
||||
company = (CompanyFetchProfile) query.getSingleResult();
|
||||
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
|
@ -508,16 +508,16 @@ public class QueryHintEntityGraphTest extends BaseEntityManagerFunctionalTestCas
|
|||
company.phoneNumbers.add( "987-654-3210" );
|
||||
entityManager.persist( company );
|
||||
|
||||
CompanyWithFetchProfile companyWithFetchProfile = new CompanyWithFetchProfile();
|
||||
companyWithFetchProfile.employees.add( employee );
|
||||
companyWithFetchProfile.employees.add( manager1 );
|
||||
companyWithFetchProfile.employees.add( manager2 );
|
||||
companyWithFetchProfile.location = location;
|
||||
companyWithFetchProfile.markets.add( Market.SERVICES );
|
||||
companyWithFetchProfile.markets.add( Market.TECHNOLOGY );
|
||||
companyWithFetchProfile.phoneNumbers.add( "012-345-6789" );
|
||||
companyWithFetchProfile.phoneNumbers.add( "987-654-3210" );
|
||||
entityManager.persist( companyWithFetchProfile );
|
||||
CompanyFetchProfile companyFetchProfile = new CompanyFetchProfile();
|
||||
companyFetchProfile.employees.add( employee );
|
||||
companyFetchProfile.employees.add( manager1 );
|
||||
companyFetchProfile.employees.add( manager2 );
|
||||
companyFetchProfile.location = location;
|
||||
companyFetchProfile.markets.add( Market.SERVICES );
|
||||
companyFetchProfile.markets.add( Market.TECHNOLOGY );
|
||||
companyFetchProfile.phoneNumbers.add( "012-345-6789" );
|
||||
companyFetchProfile.phoneNumbers.add( "987-654-3210" );
|
||||
entityManager.persist( companyFetchProfile );
|
||||
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
|
@ -525,6 +525,6 @@ public class QueryHintEntityGraphTest extends BaseEntityManagerFunctionalTestCas
|
|||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { Company.class, CompanyWithFetchProfile.class, Employee.class, Manager.class, Location.class, Course.class, Student.class };
|
||||
return new Class<?>[] { Company.class, CompanyFetchProfile.class, Employee.class, Manager.class, Location.class, Course.class, Student.class };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.stateless;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.StatelessSession;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
public class StatelessDoWorkTest extends BaseCoreFunctionalTestCase {
|
||||
public static final String EXPECTED_ENTITY_NAME = "test";
|
||||
public static final Integer PERSISTED_TEST_ENTITY_ID = 1;
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { TestEntity.class };
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
inTransaction(
|
||||
session -> {
|
||||
TestEntity entity = new TestEntity( PERSISTED_TEST_ENTITY_ID, EXPECTED_ENTITY_NAME );
|
||||
session.save( entity );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from TestEntity" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoReturningWork() {
|
||||
String retrievedEntityName;
|
||||
try (StatelessSession statelessSession = sessionFactory().openStatelessSession()) {
|
||||
retrievedEntityName = statelessSession.doReturningWork(
|
||||
(connection) -> {
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(
|
||||
"SELECT NAME FROM TEST_ENTITY WHERE ID = ?" )) {
|
||||
preparedStatement.setInt( 1, PERSISTED_TEST_ENTITY_ID );
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
String name = null;
|
||||
if ( resultSet.next() ) {
|
||||
name = resultSet.getString( 1 );
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
assertThat( retrievedEntityName, is( EXPECTED_ENTITY_NAME ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoWork() {
|
||||
try (StatelessSession statelessSession = sessionFactory().openStatelessSession()) {
|
||||
statelessSession.doWork(
|
||||
(connection) -> {
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(
|
||||
"DELETE FROM TEST_ENTITY " )) {
|
||||
preparedStatement.execute();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
assertThatAllTestEntitiesHaveBeenDeleted();
|
||||
}
|
||||
|
||||
private void assertThatAllTestEntitiesHaveBeenDeleted() {
|
||||
inTransaction( session -> {
|
||||
List results = session.createQuery( "from TestEntity" ).list();
|
||||
assertThat( results.size(), is( 0 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity")
|
||||
@Table(name = "TEST_ENTITY")
|
||||
public static class TestEntity {
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "NAME")
|
||||
private String name;
|
||||
|
||||
public TestEntity() {
|
||||
}
|
||||
|
||||
public TestEntity(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
apply from: rootProject.file( 'gradle/published-java-module.gradle' )
|
||||
|
||||
description = "Experimental extension to make it easier to compile applications into a GraalVM native image"
|
||||
|
||||
dependencies {
|
||||
//No need for transitive dependencies: this is all just metadata to be used as companion jar.
|
||||
compileOnly project( ':hibernate-core' )
|
||||
compileOnly( libraries.graalvm_nativeimage )
|
||||
testCompile( project( ':hibernate-core' ) )
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.graalvm.internal;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
|
||||
import com.oracle.svm.core.annotate.AutomaticFeature;
|
||||
import org.graalvm.nativeimage.hosted.Feature;
|
||||
import org.graalvm.nativeimage.hosted.RuntimeReflection;
|
||||
|
||||
/**
|
||||
* This is a best effort, untested experimental GraalVM feature to help people getting Hibernate ORM
|
||||
* to work with GraalVM native images.
|
||||
* There are multiple reasons for this to be untested. One is that for tests to be effective they would
|
||||
* need very extensive coverage of all functionality: the point of this class being a list of all things
|
||||
* being initialized reflectively, it's not possible to ensure that the list is comprehensive without the
|
||||
* tests being comprehensive as well.
|
||||
* The other problem is that this is listing just that "static needs" of Hibernate ORM: it will very likely
|
||||
* also need to access reflectively the user's domain model and the various extension points, depending on
|
||||
* configurations. Such configuration - and especially the domain model - is dynamic by its very own nature,
|
||||
* and therefore this list is merely provided as a useful starting point, but it needs to be extended;
|
||||
* such extensions could be automated, or will need to be explicitly passed to the native-image arguments.
|
||||
* <p>
|
||||
* In conclusion, it's not possible to provide a fully comprehensive list: take this as a hopefully
|
||||
* useful building block.
|
||||
* </p>
|
||||
* @author Sanne Grinovero
|
||||
*/
|
||||
@AutomaticFeature
|
||||
public class GraalVMStaticAutofeature implements Feature {
|
||||
|
||||
public void beforeAnalysis(Feature.BeforeAnalysisAccess before) {
|
||||
final Class<?>[] needsHavingSimpleConstructors = StaticClassLists.typesNeedingDefaultConstructorAccessible();
|
||||
final Class[] neddingAllConstructorsAccessible = StaticClassLists.typesNeedingAllConstructorsAccessible();
|
||||
//Size formula is just a reasonable guess:
|
||||
ArrayList<Executable> executables = new ArrayList<>( needsHavingSimpleConstructors.length + neddingAllConstructorsAccessible.length * 3 );
|
||||
for ( Class c : needsHavingSimpleConstructors ) {
|
||||
executables.add( ReflectHelper.getDefaultConstructor( c ) );
|
||||
}
|
||||
for ( Class c : neddingAllConstructorsAccessible ) {
|
||||
for ( Constructor declaredConstructor : c.getDeclaredConstructors() ) {
|
||||
executables.add( declaredConstructor );
|
||||
}
|
||||
}
|
||||
RuntimeReflection.register( needsHavingSimpleConstructors );
|
||||
RuntimeReflection.register( neddingAllConstructorsAccessible );
|
||||
RuntimeReflection.register( StaticClassLists.typesNeedingArrayCopy() );
|
||||
RuntimeReflection.register( executables.toArray(new Executable[0]) );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* 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.graalvm.internal;
|
||||
|
||||
import org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor;
|
||||
import org.hibernate.type.EnumType;
|
||||
|
||||
/**
|
||||
* The place to list all "static" types we know of that need to be possible to
|
||||
* construct at runtime via reflection.
|
||||
* This is useful for GraalVM native images - but is not intenteded to be an
|
||||
* exhaustive list: take these as an helpful starting point.
|
||||
*/
|
||||
final class StaticClassLists {
|
||||
|
||||
public static Class[] typesNeedingAllConstructorsAccessible() {
|
||||
return new Class[] {
|
||||
//The CoreMessageLogger is sometimes looked up without it necessarily being a field, so we're
|
||||
//not processing it the same way as other Logger lookups.
|
||||
org.hibernate.internal.CoreMessageLogger_$logger.class,
|
||||
org.hibernate.tuple.component.PojoComponentTuplizer.class,
|
||||
org.hibernate.tuple.component.DynamicMapComponentTuplizer.class,
|
||||
org.hibernate.tuple.entity.DynamicMapEntityTuplizer.class,
|
||||
org.hibernate.persister.collection.OneToManyPersister.class,
|
||||
org.hibernate.persister.collection.BasicCollectionPersister.class,
|
||||
org.hibernate.persister.entity.JoinedSubclassEntityPersister.class,
|
||||
org.hibernate.persister.entity.UnionSubclassEntityPersister.class,
|
||||
org.hibernate.persister.entity.SingleTableEntityPersister.class,
|
||||
org.hibernate.tuple.entity.PojoEntityTuplizer.class,
|
||||
//ANTLR special ones:
|
||||
org.hibernate.hql.internal.ast.tree.EntityJoinFromElement.class,
|
||||
org.hibernate.hql.internal.ast.tree.MapKeyEntityFromElement.class,
|
||||
org.hibernate.hql.internal.ast.tree.ComponentJoin.class,
|
||||
};
|
||||
}
|
||||
|
||||
public static Class[] typesNeedingDefaultConstructorAccessible() {
|
||||
return new Class[] {
|
||||
//Support for @OrderBy
|
||||
org.hibernate.sql.ordering.antlr.NodeSupport.class,
|
||||
org.hibernate.sql.ordering.antlr.OrderByFragment.class,
|
||||
org.hibernate.sql.ordering.antlr.SortSpecification.class,
|
||||
org.hibernate.sql.ordering.antlr.OrderingSpecification.class,
|
||||
org.hibernate.sql.ordering.antlr.CollationSpecification.class,
|
||||
org.hibernate.sql.ordering.antlr.SortKey.class,
|
||||
|
||||
//ANTLR tokens:
|
||||
org.hibernate.hql.internal.ast.tree.SelectClause.class,
|
||||
org.hibernate.hql.internal.ast.tree.HqlSqlWalkerNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.MethodNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.UnaryLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.NullNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.IntoClause.class,
|
||||
org.hibernate.hql.internal.ast.tree.UpdateStatement.class,
|
||||
org.hibernate.hql.internal.ast.tree.SelectExpressionImpl.class,
|
||||
org.hibernate.hql.internal.ast.tree.CastFunctionNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.DeleteStatement.class,
|
||||
org.hibernate.hql.internal.ast.tree.SqlNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.SearchedCaseNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.FromElement.class,
|
||||
org.hibernate.hql.internal.ast.tree.JavaConstantNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.SqlFragment.class,
|
||||
org.hibernate.hql.internal.ast.tree.MapKeyNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.ImpliedFromElement.class,
|
||||
org.hibernate.hql.internal.ast.tree.IsNotNullLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.InsertStatement.class,
|
||||
org.hibernate.hql.internal.ast.tree.UnaryArithmeticNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.CollectionFunction.class,
|
||||
org.hibernate.hql.internal.ast.tree.BinaryLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.CountNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.IsNullLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.IdentNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.ParameterNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.MapEntryNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.MapValueNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.InLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.IndexNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.DotNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.ResultVariableRefNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.BetweenOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.AggregateNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.QueryNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.BooleanLiteralNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.SimpleCaseNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.OrderByClause.class,
|
||||
org.hibernate.hql.internal.ast.tree.FromClause.class,
|
||||
org.hibernate.hql.internal.ast.tree.ConstructorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.LiteralNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.BinaryArithmeticOperatorNode.class,
|
||||
|
||||
//Various well known needs:
|
||||
|
||||
org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl.class,
|
||||
org.hibernate.id.enhanced.SequenceStyleGenerator.class,
|
||||
org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl.class,
|
||||
org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl.class,
|
||||
EnumType.class,
|
||||
MultipleLinesSqlCommandExtractor.class,
|
||||
org.hibernate.hql.internal.ast.HqlToken.class,
|
||||
org.hibernate.hql.internal.ast.tree.Node.class,
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static Class[] typesNeedingArrayCopy() {
|
||||
return new Class[] {
|
||||
//Eventlisteners need to be registered for reflection to allow creation via Array#newInstance ;
|
||||
// types need to be in synch with those declared in org.hibernate.event.spi.EventType
|
||||
org.hibernate.event.spi.LoadEventListener[].class,
|
||||
org.hibernate.event.spi.ResolveNaturalIdEventListener[].class,
|
||||
org.hibernate.event.spi.InitializeCollectionEventListener[].class,
|
||||
org.hibernate.event.spi.SaveOrUpdateEventListener[].class,
|
||||
org.hibernate.event.spi.PersistEventListener[].class,
|
||||
org.hibernate.event.spi.MergeEventListener[].class,
|
||||
org.hibernate.event.spi.DeleteEventListener[].class,
|
||||
org.hibernate.event.spi.ReplicateEventListener[].class,
|
||||
org.hibernate.event.spi.FlushEventListener[].class,
|
||||
org.hibernate.event.spi.AutoFlushEventListener[].class,
|
||||
org.hibernate.event.spi.DirtyCheckEventListener[].class,
|
||||
org.hibernate.event.spi.FlushEntityEventListener[].class,
|
||||
org.hibernate.event.spi.ClearEventListener[].class,
|
||||
org.hibernate.event.spi.EvictEventListener[].class,
|
||||
org.hibernate.event.spi.LockEventListener[].class,
|
||||
org.hibernate.event.spi.RefreshEventListener[].class,
|
||||
org.hibernate.event.spi.PreLoadEventListener[].class,
|
||||
org.hibernate.event.spi.PreDeleteEventListener[].class,
|
||||
org.hibernate.event.spi.PreUpdateEventListener[].class,
|
||||
org.hibernate.event.spi.PreInsertEventListener[].class,
|
||||
org.hibernate.event.spi.PostLoadEventListener[].class,
|
||||
org.hibernate.event.spi.PostDeleteEventListener[].class,
|
||||
org.hibernate.event.spi.PostUpdateEventListener[].class,
|
||||
org.hibernate.event.spi.PostInsertEventListener[].class,
|
||||
org.hibernate.event.spi.PreCollectionRecreateEventListener[].class,
|
||||
org.hibernate.event.spi.PreCollectionRemoveEventListener[].class,
|
||||
org.hibernate.event.spi.PreCollectionUpdateEventListener[].class,
|
||||
org.hibernate.event.spi.PostCollectionRecreateEventListener[].class,
|
||||
org.hibernate.event.spi.PostCollectionRemoveEventListener[].class,
|
||||
org.hibernate.event.spi.PostCollectionUpdateEventListener[].class
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.graalvm.internal;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class BasicConstructorsAvailableTest {
|
||||
|
||||
@Test
|
||||
public void checkNonDefaultConstructorsCanBeLoaded() {
|
||||
Class[] classes = StaticClassLists.typesNeedingAllConstructorsAccessible();
|
||||
for ( Class c : classes ) {
|
||||
Constructor[] declaredConstructors = c.getDeclaredConstructors();
|
||||
Assert.assertTrue( declaredConstructors.length > 0 );
|
||||
if ( declaredConstructors.length == 1 ) {
|
||||
//If there's only one, let's check that this class wasn't placed in the wrong cathegory:
|
||||
Assert.assertTrue( declaredConstructors[0].getParameterCount() > 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDefaultConstructorsAreAvailable() {
|
||||
Class[] classes = StaticClassLists.typesNeedingDefaultConstructorAccessible();
|
||||
for ( Class c : classes ) {
|
||||
Constructor constructor = ReflectHelper.getDefaultConstructor( c );
|
||||
Assert.assertNotNull( "Failed for class: " + c.getName(), constructor );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkArraysAreArrays() {
|
||||
Class[] classes = StaticClassLists.typesNeedingArrayCopy();
|
||||
for ( Class c : classes ) {
|
||||
Assert.assertTrue( "Wrong category for type: " + c.getName(), c.isArray() );
|
||||
Constructor[] constructors = c.getConstructors();
|
||||
Assert.assertEquals( 0, constructors.length );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.integrationtest.java.module.test;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.boot.archive.internal.StandardArchiveDescriptorFactory;
|
||||
import org.hibernate.boot.archive.scan.internal.StandardScanOptions;
|
||||
import org.hibernate.boot.archive.scan.internal.StandardScanParameters;
|
||||
import org.hibernate.boot.archive.scan.internal.StandardScanner;
|
||||
import org.hibernate.boot.archive.scan.spi.ClassDescriptor;
|
||||
import org.hibernate.boot.archive.scan.spi.ScanResult;
|
||||
import org.hibernate.orm.integrationtest.java.module.entity.Author;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* We need to test that the scanner works, including when there is a module-info.class
|
||||
* resource in the project. See also HHH-13859.
|
||||
*/
|
||||
public class ScannerTest {
|
||||
|
||||
@Test
|
||||
public void verifyModuleInfoScanner() {
|
||||
URL urlToThis = Author.class.getProtectionDomain().getCodeSource().getLocation();
|
||||
StandardScanner standardScanner = new StandardScanner( StandardArchiveDescriptorFactory.INSTANCE );
|
||||
ScanResult scan = standardScanner.scan(
|
||||
new TestScanEnvironment( urlToThis ),
|
||||
new StandardScanOptions(),
|
||||
StandardScanParameters.INSTANCE
|
||||
);
|
||||
Set<ClassDescriptor> locatedClasses = scan.getLocatedClasses();
|
||||
Assert.assertEquals( 1, locatedClasses.size() );
|
||||
ClassDescriptor classDescriptor = locatedClasses.iterator().next();
|
||||
Assert.assertNotNull( classDescriptor );
|
||||
Assert.assertEquals( Author.class.getName(), classDescriptor.getName() );
|
||||
Assert.assertEquals( ClassDescriptor.Categorization.MODEL, classDescriptor.getCategorization() );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.orm.integrationtest.java.module.test;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
|
||||
|
||||
final class TestScanEnvironment implements ScanEnvironment {
|
||||
|
||||
private final URL root;
|
||||
|
||||
TestScanEnvironment(URL root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getRootUrl() {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> getNonRootUrls() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getExplicitlyListedClassNames() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getExplicitlyListedMappingFiles() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ include 'hibernate-infinispan'
|
|||
include 'hibernate-jipijapa'
|
||||
|
||||
include 'hibernate-orm-modules'
|
||||
include 'hibernate-graalvm'
|
||||
|
||||
if ( JavaVersion.current().isJava11Compatible() ) {
|
||||
include 'hibernate-integrationtest-java-modules'
|
||||
|
|
Loading…
Reference in New Issue