Merge branch 'andrea-merge' into wip/6.0
This commit is contained in:
commit
0f5107ca11
|
@ -3,6 +3,90 @@ Hibernate 5 Changelog
|
|||
|
||||
Note: Please refer to JIRA to learn more about each issue.
|
||||
|
||||
Changes in 5.4.5.Final (September 17, 2019)
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
https://hibernate.atlassian.net/projects/HHH/versions/31779/tab/release-report-done
|
||||
|
||||
** Bug
|
||||
* [HHH-13259] - StackOverflowError from StringHelper
|
||||
* [HHH-13466] - ClassCastException when changing a Collection association to a Set if @PreUpdate listener exists
|
||||
* [HHH-13544] - Restore logged warning on jdbc code mapping issue in NationalizedTypeMappings
|
||||
* [HHH-13550] - Fix Oracle failure for test added by HHH-13424
|
||||
* [HHH-13551] - StrategyRegistrationProvider does not properly handle implementations from different classloader
|
||||
* [HHH-13554] - QueryAndSQLTest.testNativeQueryWithFormulaAttributeWithoutAlias() fails on Oracle, MSSQL, Sybase, DB2, MariaDB
|
||||
* [HHH-13555] - FetchGraphTest, MergeProxyTest and ProxyDeletionTest fail due to ConstraintViolationException
|
||||
* [HHH-13556] - Tests doing dynamic fetch scrolling a collection fail on DB2
|
||||
* [HHH-13557] - LocalTimeTest#writeThenNativeRead and OffsetTimeTest#writeThenNativeRead tests are failing on SQL Server
|
||||
* [HHH-13558] - InstantTest, LocalDateTimeTest, OffsetDateTimeTest, ZonedDateTimeTest failing on Sybase for year 1600
|
||||
* [HHH-13564] - Envers - Getting NPE while reading revisions of entity with @EmbeddedId composite key located in parent @MappedSuperclass
|
||||
* [HHH-13569] - org.hibernate.test.annotations.embedded.EmbeddedTest failures on Sybase
|
||||
* [HHH-13570] - Test failures due to Sybase not supporting UPDATE statement with WITH(NOWAIT)
|
||||
* [HHH-13571] - Test failures due to cross joined table out of scope of a subsequent JOIN on Sybase
|
||||
* [HHH-13573] - Test failure due to Sybase not supporting cascade delete on foreign key definitions
|
||||
* [HHH-13574] - SybaseASE does not support PARTITION BY
|
||||
* [HHH-13577] - LockTest.testContendedPessimisticLock and StatementIsClosedAfterALockExceptionTest.testStatementIsClosed tests fail on Sybase
|
||||
* [HHH-13580] - LocalTimeTest#writeThenNativeRead* and OffsetTimeTest#writeThenNativeRead* failing on MySQL
|
||||
* [HHH-13581] - LocalTimeTest#writeThenRead* and OffsetTimeTest#writeThenRead* failing on MariaDB
|
||||
* [HHH-13582] - LocalDateTest failures on MySQL
|
||||
* [HHH-13586] - ClassCastException when using a single region name for both entity and query results
|
||||
* [HHH-13590] - TransientObjectException merging a non-proxy association to a HibernateProxy
|
||||
* [HHH-13592] - AutoFlushEvent#isFlushRequired is always false
|
||||
* [HHH-13607] - Exception thrown while flushing uninitialized enhanced proxy with immutable natural ID
|
||||
* [HHH-13611] - Restore EntityMetamodel constructor to take SessionFactoryImplementor argument instead of PersisterCreationContext.
|
||||
* [HHH-13616] - Enable the hibernate-orm-modules test for JDK 11
|
||||
* [HHH-13621] - Exception if spaces after value of javax.persistence.schema-generation.scripts.action in hibernate.properties
|
||||
|
||||
** New Feature
|
||||
* [HHH-13249] - Introduce an option to Log slow queries instead of all queries
|
||||
|
||||
** Task
|
||||
* [HHH-13525] - Make test SessionDelegatorBaseImplTest more resilient to previously existing alias definition
|
||||
* [HHH-13526] - Optimise ResourceRegistryStandardImpl#release
|
||||
* [HHH-13527] - Performance regression in org.hibernate.stat.internal.StatisticsImpl
|
||||
* [HHH-13528] - Invoke afterStatements only at the end of releasing all statements for a batch
|
||||
* [HHH-13529] - Performance regression in org.hibernate.engine.spi.SessionFactoryImplementor#getDialect
|
||||
* [HHH-13531] - Some more opportunities to reuse the constants pool in AliasConstantsHelper
|
||||
* [HHH-13534] - AbstractLoadPlanBasedLoader never needs a List of AfterLoadAction
|
||||
* [HHH-13546] - Make the sessionFactory field in StatisticsImpl required
|
||||
* [HHH-13549] - Cleanup dead code in StringHelper
|
||||
* [HHH-13552] - CollectionType needs a direct reference to its Persister
|
||||
* [HHH-13553] - Fix test failures on SAP HANA
|
||||
* [HHH-13561] - Do not retrieve the same ActionQueue multiple times
|
||||
* [HHH-13562] - List of TransactionObserver for JdbcResourceLocalTransactionCoordinatorImpl should be lazily initialized
|
||||
* [HHH-13563] - ResultSetReturnImpl is looking up JdbcServices on each construction
|
||||
* [HHH-13565] - Improve Session opening efficiency
|
||||
* [HHH-13568] - Instances of NaturalIdXrefDelegate should be lazily initialized if possible
|
||||
* [HHH-13605] - InstantTest, OffsetDateTimeTest, ZonedDateTimeTest fail for MariaDB on CI
|
||||
* [HHH-13606] - LocalDateTimeTest fails for HANA on CI
|
||||
* [HHH-13622] - Upgrade the WildFly Transaction Client to 1.1.7.Final
|
||||
|
||||
** Improvement
|
||||
* [HHH-13133] - Print message about 'successfully enhanced class' as debug in Maven enhancement plugin
|
||||
* [HHH-13412] - Move hibernate.connection description out of c3p0 section
|
||||
* [HHH-13512] - Avoid allocating an array in org.hibernate.internal.util.StringHelper#unquote(String[], Dialect) if there are no changes to be applied
|
||||
* [HHH-13521] - Avoid excessive validation of enabled filters
|
||||
* [HHH-13522] - Optimise LoadQueryInfluencers by making maps lazily initialized
|
||||
* [HHH-13523] - StatementPreparerImpl should not need to retrieve the JDBCService as often
|
||||
* [HHH-13524] - Remove unused fields xref,unassociatedResultSets from JdbcCoordinatorImpl
|
||||
* [HHH-13541] - ExceptionConverter instance in AbstractSharedSessionContract should be lazily initialized
|
||||
* [HHH-13548] - Since SessionOwner is deprecated several fields in SessionImpl can be removed
|
||||
* [HHH-13576] - Invoking tracef() or debugf() w/o an array of parameters actually allocates an empty Object[]
|
||||
* [HHH-13579] - Cleanup of resources in ResourceRegistryStandardImpl allocates many Iterators
|
||||
* [HHH-13584] - Reduce ServiceRegistry lookups in LocalConnectionAccess in SessionFactory
|
||||
* [HHH-13585] - Duplicate resource release in PessimisticReadSelectLockingStrategy
|
||||
* [HHH-13587] - Initialize selected collections of StatefulPersistenceContext lazily
|
||||
* [HHH-13588] - MySQL Dialect: missed functions: weight_string, to_base64, from_base64, regexp_replace, regexp_instr, regexp_substr
|
||||
* [HHH-13589] - Minor memory allocation improvements in ActionQueue
|
||||
* [HHH-13591] - Replaces simple uses of array iteration with a corresponding for-each loop
|
||||
* [HHH-13594] - ResourceRegistryStandardImpl#release could avoid allocating a capturing lambda
|
||||
* [HHH-13599] - Avoid ArrayList allocation in JtaTransactionCoordinatorImp in common scenario
|
||||
* [HHH-13600] - Avoid allocation of capturing lambdas in ParameterTranslationsImpl and AbstractDomainDataRegion
|
||||
|
||||
** Deprecation
|
||||
* [HHH-13595] - Deprecate ConnectionObserver
|
||||
|
||||
|
||||
Changes in 5.4.4.Final (July 29, 2019)
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
jdbcDependency 'com.sap.cloud.db.jdbc:ngdbc:2.2.16'
|
||||
jdbcDependency 'com.sap.cloud.db.jdbc:ngdbc:2.4.59'
|
|
@ -0,0 +1,23 @@
|
|||
[[enhancement]]
|
||||
== Enhancement
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/userguide/bytecode
|
||||
:extrasdir: extras
|
||||
|
||||
Hibernate offers a number of services that can be added into an application's domain model classes
|
||||
through bytecode enhancement...
|
||||
|
||||
|
||||
[[enhancement-laziness]]
|
||||
=== Laziness
|
||||
|
||||
|
||||
[[enhancement-bidir]]
|
||||
=== Bi-directionality
|
||||
|
||||
|
||||
[[enhancement-dirty]]
|
||||
=== In-line dirty checking
|
||||
|
||||
|
||||
[[enhancement-extended]]
|
||||
=== Extended enhancement
|
|
@ -168,7 +168,7 @@ ext {
|
|||
wildfly_arquillian_container_managed: "org.wildfly.arquillian:wildfly-arquillian-container-managed:${wildflyArquillianContainerVersion}",
|
||||
jboss_vfs: "org.jboss:jboss-vfs:3.2.11.Final",
|
||||
jipijapa_spi: "org.wildfly:jipijapa-spi:${wildflyVersion}",
|
||||
wildfly_transaction_client : 'org.wildfly.transaction:wildfly-transaction-client:1.0.3.Final',
|
||||
wildfly_transaction_client : 'org.wildfly.transaction:wildfly-transaction-client:1.1.7.Final',
|
||||
|
||||
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',
|
||||
|
|
|
@ -74,7 +74,7 @@ public final class Settings {
|
|||
LOG.debugf( "Check Nullability in Core (should be disabled when Bean Validation is on): %s", enabledDisabled( sessionFactoryOptions.isCheckNullability() ) );
|
||||
LOG.debugf( "Allow initialization of lazy state outside session : %s", enabledDisabled( sessionFactoryOptions.isInitializeLazyStateOutsideTransactionsEnabled() ) );
|
||||
|
||||
LOG.debugf( "Using BatchFetchStyle : %", sessionFactoryOptions.getBatchFetchStyle().name() );
|
||||
LOG.debugf( "Using BatchFetchStyle : %s", sessionFactoryOptions.getBatchFetchStyle().name() );
|
||||
LOG.debugf( "Default batch fetch size: %s", sessionFactoryOptions.getDefaultBatchFetchSize() );
|
||||
LOG.debugf( "Maximum outer join fetch depth: %s", sessionFactoryOptions.getMaximumFetchDepth() );
|
||||
LOG.debugf( "Default null ordering: %s", sessionFactoryOptions.getDefaultNullPrecedence() );
|
||||
|
|
|
@ -109,7 +109,7 @@ public enum Action {
|
|||
return (Action) value;
|
||||
}
|
||||
|
||||
final String name = value.toString();
|
||||
final String name = value.toString().trim();
|
||||
if ( name.isEmpty() || NONE.externalJpaName.equals( name ) ) {
|
||||
// default is NONE
|
||||
return NONE;
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.tool.schema;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.boot.registry.BootstrapServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-13621")
|
||||
public class SchemaGenetationSciptsActionPropertyValueEndingWithSpaceTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private File dropOutput;
|
||||
private File createOutput;
|
||||
|
||||
@Override
|
||||
protected StandardServiceRegistryImpl buildServiceRegistry(
|
||||
BootstrapServiceRegistry bootRegistry,
|
||||
Configuration configuration) {
|
||||
try {
|
||||
dropOutput = File.createTempFile( "drop_script", ".sql" );
|
||||
createOutput = File.createTempFile( "create_script", ".sql" );
|
||||
dropOutput.deleteOnExit();
|
||||
createOutput.deleteOnExit();
|
||||
}
|
||||
catch (IOException e) {
|
||||
fail( "unable to create temp file" + e );
|
||||
}
|
||||
Properties properties = new Properties();
|
||||
properties.putAll( configuration.getProperties() );
|
||||
// the value of the property ends with a space
|
||||
properties.setProperty( "javax.persistence.schema-generation.scripts.action", "drop-and-create " );
|
||||
properties.setProperty(
|
||||
"javax.persistence.schema-generation.scripts.create-target",
|
||||
createOutput.getAbsolutePath()
|
||||
);
|
||||
properties.setProperty(
|
||||
"javax.persistence.schema-generation.scripts.drop-target",
|
||||
dropOutput.getAbsolutePath()
|
||||
);
|
||||
ConfigurationHelper.resolvePlaceHolders( properties );
|
||||
|
||||
StandardServiceRegistryBuilder cfgRegistryBuilder = configuration.getStandardServiceRegistryBuilder();
|
||||
|
||||
StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder(
|
||||
bootRegistry,
|
||||
cfgRegistryBuilder.getAggregatedCfgXml()
|
||||
).applySettings( properties );
|
||||
|
||||
prepareBasicRegistryBuilder( registryBuilder );
|
||||
return (StandardServiceRegistryImpl) registryBuilder.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueEndingWithSpaceDoesNotCauseExceptionDuringBootstrap() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.tooling.gradle
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.util.ConfigureUtil
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
class EnhanceTask extends DefaultTask {
|
||||
EnhanceExtension options
|
||||
SourceSet[] sourceSets
|
||||
|
||||
@TaskAction
|
||||
void enhance() {
|
||||
for ( SourceSet sourceSet: sourceSets ) {
|
||||
EnhancementHelper.enhance( sourceSet, options, project )
|
||||
}
|
||||
}
|
||||
|
||||
void options(Closure closure) {
|
||||
options = new EnhanceExtension()
|
||||
ConfigureUtil.configure( closure, options )
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.tooling.gradle;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.file.FileTree;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedField;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EnhancementHelper {
|
||||
static void enhance(SourceSet sourceSet, EnhanceExtension options, Project project) {
|
||||
final ClassLoader classLoader = toClassLoader( sourceSet.getRuntimeClasspath() );
|
||||
|
||||
final EnhancementContext enhancementContext = new DefaultEnhancementContext() {
|
||||
@Override
|
||||
public ClassLoader getLoadingClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doBiDirectionalAssociationManagement(UnloadedField field) {
|
||||
return options.getEnableAssociationManagement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
|
||||
return options.getEnableDirtyTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLazyLoadableAttributes(UnloadedClass classDescriptor) {
|
||||
return options.getEnableLazyInitialization();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLazyLoadable(UnloadedField field) {
|
||||
return options.getEnableLazyInitialization();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doExtendedEnhancement(UnloadedClass classDescriptor) {
|
||||
return options.getEnableExtendedEnhancement();
|
||||
}
|
||||
};
|
||||
|
||||
final Enhancer enhancer = Environment.getBytecodeProvider().getEnhancer( enhancementContext );
|
||||
|
||||
for ( File classesDir: sourceSet.getOutput().getClassesDirs() ) {
|
||||
final FileTree fileTree = project.fileTree( classesDir );
|
||||
for ( File file : fileTree ) {
|
||||
if ( !file.getName().endsWith( ".class" ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final byte[] enhancedBytecode = doEnhancement( classesDir, file, enhancer );
|
||||
if ( enhancedBytecode != null ) {
|
||||
writeOutEnhancedClass( enhancedBytecode, file, project.getLogger() );
|
||||
project.getLogger().info( "Successfully enhanced class [" + file + "]" );
|
||||
}
|
||||
else {
|
||||
project.getLogger().info( "Skipping class [" + file.getAbsolutePath() + "], not an entity nor embeddable" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ClassLoader toClassLoader(FileCollection runtimeClasspath) {
|
||||
List<URL> urls = new ArrayList<>();
|
||||
for ( File file : runtimeClasspath ) {
|
||||
try {
|
||||
urls.add( file.toURI().toURL() );
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new GradleException( "Unable to resolve classpath entry to URL : " + file.getAbsolutePath(), e );
|
||||
}
|
||||
}
|
||||
return new URLClassLoader( urls.toArray( new URL[0] ), Enhancer.class.getClassLoader() );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
static byte[] doEnhancement(File root, File javaClassFile, Enhancer enhancer) {
|
||||
try {
|
||||
final String className = determineClassName( root, javaClassFile );
|
||||
final ByteArrayOutputStream originalBytes = new ByteArrayOutputStream();
|
||||
try (final FileInputStream fileInputStream = new FileInputStream( javaClassFile )) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ( ( length = fileInputStream.read( buffer ) ) != -1 ) {
|
||||
originalBytes.write( buffer, 0, length );
|
||||
}
|
||||
}
|
||||
return enhancer.enhance( className, originalBytes.toByteArray() );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new GradleException( "Unable to enhance class : " + javaClassFile, e );
|
||||
}
|
||||
}
|
||||
|
||||
private static String determineClassName(File root, File javaClassFile) {
|
||||
return javaClassFile.getAbsolutePath().substring(
|
||||
root.getAbsolutePath().length() + 1,
|
||||
javaClassFile.getAbsolutePath().length() - ".class".length()
|
||||
).replace( File.separatorChar, '.' );
|
||||
}
|
||||
|
||||
private static void writeOutEnhancedClass(byte[] enhancedBytecode, File file, Logger logger) {
|
||||
try {
|
||||
if ( file.delete() ) {
|
||||
if ( !file.createNewFile() ) {
|
||||
logger.error( "Unable to recreate class file [" + file.getName() + "]" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.error( "Unable to delete class file [" + file.getName() + "]" );
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.warn( "Problem preparing class file for writing out enhancements [" + file.getName() + "]" );
|
||||
}
|
||||
|
||||
try {
|
||||
FileOutputStream outputStream = new FileOutputStream( file, false );
|
||||
try {
|
||||
outputStream.write( enhancedBytecode );
|
||||
outputStream.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GradleException( "Error writing to enhanced class [" + file.getName() + "] to file [" + file.getAbsolutePath() + "]", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
outputStream.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw new GradleException( "Error opening class file for writing : " + file.getAbsolutePath(), e );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private EnhancementHelper() {
|
||||
}
|
||||
}
|
|
@ -55,12 +55,9 @@ public class HibernatePlugin implements Plugin<Project> {
|
|||
project.getExtensions().add( "hibernate", hibernateExtension );
|
||||
|
||||
project.afterEvaluate(
|
||||
new Action<Project>() {
|
||||
@Override
|
||||
public void execute(Project project) {
|
||||
if ( hibernateExtension.enhance != null ) {
|
||||
applyEnhancement( project, hibernateExtension );
|
||||
}
|
||||
project1 -> {
|
||||
if ( hibernateExtension.enhance != null ) {
|
||||
applyEnhancement( project1, hibernateExtension );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -76,150 +73,11 @@ public class HibernatePlugin implements Plugin<Project> {
|
|||
project.getLogger().debug( "Applying Hibernate enhancement action to SourceSet.{}", sourceSet.getName() );
|
||||
|
||||
final Task compileTask = project.getTasks().findByName( sourceSet.getCompileJavaTaskName() );
|
||||
assert compileTask != null;
|
||||
compileTask.doLast(
|
||||
new Action<Task>() {
|
||||
@Override
|
||||
public void execute(Task task) {
|
||||
project.getLogger().debug( "Starting Hibernate enhancement on SourceSet.{}", sourceSet.getName() );
|
||||
|
||||
final ClassLoader classLoader = toClassLoader( sourceSet.getRuntimeClasspath() );
|
||||
|
||||
EnhancementContext enhancementContext = new DefaultEnhancementContext() {
|
||||
@Override
|
||||
public ClassLoader getLoadingClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doBiDirectionalAssociationManagement(UnloadedField field) {
|
||||
return hibernateExtension.enhance.getEnableAssociationManagement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
|
||||
return hibernateExtension.enhance.getEnableDirtyTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLazyLoadableAttributes(UnloadedClass classDescriptor) {
|
||||
return hibernateExtension.enhance.getEnableLazyInitialization();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLazyLoadable(UnloadedField field) {
|
||||
return hibernateExtension.enhance.getEnableLazyInitialization();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doExtendedEnhancement(UnloadedClass classDescriptor) {
|
||||
return hibernateExtension.enhance.getEnableExtendedEnhancement();
|
||||
}
|
||||
};
|
||||
|
||||
if ( hibernateExtension.enhance.getEnableExtendedEnhancement() ) {
|
||||
logger.warn("Extended enhancement is enabled. Classes other than entities may be modified. You should consider access the entities using getter/setter methods and disable this property. Use at your own risk." );
|
||||
}
|
||||
|
||||
final Enhancer enhancer = Environment.getBytecodeProvider().getEnhancer( enhancementContext );
|
||||
|
||||
for ( File classesDir: sourceSet.getOutput().getClassesDirs() ) {
|
||||
final FileTree fileTree = project.fileTree( classesDir );
|
||||
for ( File file : fileTree ) {
|
||||
if ( !file.getName().endsWith( ".class" ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final byte[] enhancedBytecode = doEnhancement( classesDir, file, enhancer );
|
||||
if ( enhancedBytecode != null ) {
|
||||
writeOutEnhancedClass( enhancedBytecode, file );
|
||||
logger.info( "Successfully enhanced class [" + file + "]" );
|
||||
}
|
||||
else {
|
||||
logger.info( "Skipping class [" + file.getAbsolutePath() + "], not an entity nor embeddable" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
task -> EnhancementHelper.enhance( sourceSet, hibernateExtension.enhance, project )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader toClassLoader(FileCollection runtimeClasspath) {
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
for ( File file : runtimeClasspath ) {
|
||||
try {
|
||||
urls.add( file.toURI().toURL() );
|
||||
logger.debug( "Adding classpath entry for " + file.getAbsolutePath() );
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new GradleException( "Unable to resolve classpath entry to URL : " + file.getAbsolutePath(), e );
|
||||
}
|
||||
}
|
||||
return new URLClassLoader( urls.toArray( new URL[urls.size()] ), Enhancer.class.getClassLoader() );
|
||||
}
|
||||
|
||||
private byte[] doEnhancement(File root, File javaClassFile, Enhancer enhancer) {
|
||||
try {
|
||||
String className = javaClassFile.getAbsolutePath().substring(
|
||||
root.getAbsolutePath().length() + 1,
|
||||
javaClassFile.getAbsolutePath().length() - ".class".length()
|
||||
).replace( File.separatorChar, '.' );
|
||||
ByteArrayOutputStream originalBytes = new ByteArrayOutputStream();
|
||||
FileInputStream fileInputStream = new FileInputStream( javaClassFile );
|
||||
try {
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ( ( length = fileInputStream.read( buffer ) ) != -1 ) {
|
||||
originalBytes.write( buffer, 0, length );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
fileInputStream.close();
|
||||
}
|
||||
return enhancer.enhance( className, originalBytes.toByteArray() );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new GradleException( "Unable to enhance class : " + javaClassFile, e );
|
||||
}
|
||||
}
|
||||
|
||||
private void writeOutEnhancedClass(byte[] enhancedBytecode, File file) {
|
||||
try {
|
||||
if ( file.delete() ) {
|
||||
if ( !file.createNewFile() ) {
|
||||
logger.error( "Unable to recreate class file [" + file.getName() + "]" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.error( "Unable to delete class file [" + file.getName() + "]" );
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.warn( "Problem preparing class file for writing out enhancements [" + file.getName() + "]" );
|
||||
}
|
||||
|
||||
try {
|
||||
FileOutputStream outputStream = new FileOutputStream( file, false );
|
||||
try {
|
||||
outputStream.write( enhancedBytecode );
|
||||
outputStream.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GradleException( "Error writing to enhanced class [" + file.getName() + "] to file [" + file.getAbsolutePath() + "]", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
outputStream.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw new GradleException( "Error opening class file for writing : " + file.getAbsolutePath(), e );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
*/
|
||||
package org.hibernate.orm.tooling.gradle
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
|
||||
import org.junit.Test
|
||||
|
@ -38,4 +42,46 @@ class HibernatePluginTest {
|
|||
enableExtendedEnhancement = false
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnhanceTask() {
|
||||
Project project = ProjectBuilder.builder().build()
|
||||
project.plugins.apply 'org.hibernate.orm'
|
||||
|
||||
def task = project.tasks.create( "finishHim", EnhanceTask )
|
||||
|
||||
task.options {
|
||||
enableLazyInitialization = true
|
||||
enableDirtyTracking = true
|
||||
enableAssociationManagement = false
|
||||
enableExtendedEnhancement = false
|
||||
}
|
||||
|
||||
task.sourceSets = project.getConvention().getPlugin( JavaPluginConvention ).sourceSets.main
|
||||
|
||||
task.enhance()
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskAction() {
|
||||
Project project = ProjectBuilder.builder().build()
|
||||
project.plugins.apply 'org.hibernate.orm'
|
||||
|
||||
// the test sourceSet
|
||||
def sourceSet = project.getConvention().getPlugin( JavaPluginConvention ).sourceSets.test;
|
||||
|
||||
// The compile task for the test sourceSet
|
||||
final JavaCompile compileTestTask = project.getTasks().findByName( sourceSet.getCompileJavaTaskName() );
|
||||
|
||||
// Lets add our enhancer to enhance the test classes after the test are compiled
|
||||
compileTestTask.doLast {
|
||||
EnhancementHelper.enhance(
|
||||
sourceSet,
|
||||
project.extensions.findByType( HibernateExtension.class ).enhance,
|
||||
project
|
||||
)
|
||||
}
|
||||
|
||||
compileTestTask.execute()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue