Browse Source

Merge branch '6.0.x'

pull/30772/merge
Juergen Hoeller 1 year ago
parent
commit
3a481a7d7f
  1. 12
      spring-context/src/main/java/org/springframework/context/annotation/LoadTimeWeavingConfigurer.java
  2. 3
      spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
  3. 36
      spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java
  4. 8
      spring-context/src/test/java/org/springframework/context/annotation/EnableLoadTimeWeavingTests.java
  5. 8
      spring-context/src/test/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaverTests.java
  6. 18
      spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java
  7. 16
      spring-core/src/main/java/org/springframework/util/ReflectionUtils.java
  8. 18
      spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java
  9. 4
      spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java

12
spring-context/src/main/java/org/springframework/context/annotation/LoadTimeWeavingConfigurer.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,8 +21,8 @@ import org.springframework.instrument.classloading.LoadTimeWeaver; @@ -21,8 +21,8 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
/**
* Interface to be implemented by
* {@link org.springframework.context.annotation.Configuration @Configuration}
* classes annotated with {@link EnableLoadTimeWeaving @EnableLoadTimeWeaving} that wish to
* customize the {@link LoadTimeWeaver} instance to be used.
* classes annotated with {@link EnableLoadTimeWeaving @EnableLoadTimeWeaving}
* that wish to customize the {@link LoadTimeWeaver} instance to be used.
*
* <p>See {@link org.springframework.scheduling.annotation.EnableAsync @EnableAsync}
* for usage examples and information on how a default {@code LoadTimeWeaver}
@ -36,9 +36,9 @@ import org.springframework.instrument.classloading.LoadTimeWeaver; @@ -36,9 +36,9 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
public interface LoadTimeWeavingConfigurer {
/**
* Create, configure and return the {@code LoadTimeWeaver} instance to be used. Note
* that it is unnecessary to annotate this method with {@code @Bean}, because the
* object returned will automatically be registered as a bean by
* Create, configure and return the {@code LoadTimeWeaver} instance to be used.
* Note that it is unnecessary to annotate this method with {@code @Bean}
* because the object returned will automatically be registered as a bean by
* {@link LoadTimeWeavingConfiguration#loadTimeWeaver()}
*/
LoadTimeWeaver getLoadTimeWeaver();

3
spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java

@ -769,7 +769,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @@ -769,7 +769,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null &&
beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

36
spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,6 +21,8 @@ import java.security.ProtectionDomain; @@ -21,6 +21,8 @@ import java.security.ProtectionDomain;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.DecoratingClassLoader;
import org.springframework.core.OverridingClassLoader;
import org.springframework.core.SmartClassLoader;
@ -45,15 +47,26 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart @@ -45,15 +47,26 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
}
private static Method findLoadedClassMethod;
@Nullable
private static final Method findLoadedClassMethod;
static {
// Try to enable findLoadedClass optimization which allows us to selectively
// override classes that have not been loaded yet. If not accessible, we will
// always override requested classes, even when the classes have been loaded
// by the parent ClassLoader already and cannot be transformed anymore anyway.
Method method = null;
try {
findLoadedClassMethod = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
ReflectionUtils.makeAccessible(method);
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Invalid [java.lang.ClassLoader] class: no 'findLoadedClass' method defined!");
catch (Throwable ex) {
// Typically a JDK 9+ InaccessibleObjectException...
// Avoid through JVM startup with --add-opens=java.base/java.lang=ALL-UNNAMED
LogFactory.getLog(ContextTypeMatchClassLoader.class).debug(
"ClassLoader.findLoadedClass not accessible -> will always override requested class", ex);
}
findLoadedClassMethod = method;
}
@ -96,13 +109,14 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart @@ -96,13 +109,14 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
if (isExcluded(className) || ContextTypeMatchClassLoader.this.isExcluded(className)) {
return false;
}
ReflectionUtils.makeAccessible(findLoadedClassMethod);
ClassLoader parent = getParent();
while (parent != null) {
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
return false;
if (findLoadedClassMethod != null) {
ClassLoader parent = getParent();
while (parent != null) {
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
return false;
}
parent = parent.getParent();
}
parent = parent.getParent();
}
return true;
}

8
spring-context/src/test/java/org/springframework/context/annotation/EnableLoadTimeWeavingTests.java

@ -79,7 +79,7 @@ class EnableLoadTimeWeavingTests { @@ -79,7 +79,7 @@ class EnableLoadTimeWeavingTests {
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.DISABLED)
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.DISABLED)
static class EnableLTWConfig_withAjWeavingDisabled implements LoadTimeWeavingConfigurer {
@Override
@ -88,8 +88,9 @@ class EnableLoadTimeWeavingTests { @@ -88,8 +88,9 @@ class EnableLoadTimeWeavingTests {
}
}
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.AUTODETECT)
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.AUTODETECT)
static class EnableLTWConfig_withAjWeavingAutodetect implements LoadTimeWeavingConfigurer {
@Override
@ -98,8 +99,9 @@ class EnableLoadTimeWeavingTests { @@ -98,8 +99,9 @@ class EnableLoadTimeWeavingTests {
}
}
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED)
static class EnableLTWConfig_withAjWeavingEnabled implements LoadTimeWeavingConfigurer {
@Override

8
spring-context/src/test/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaverTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -85,16 +85,13 @@ public class ReflectiveLoadTimeWeaverTests { @@ -85,16 +85,13 @@ public class ReflectiveLoadTimeWeaverTests {
private int numTimesAddTransformerCalled = 0;
public int getNumTimesGetThrowawayClassLoaderCalled() {
return this.numTimesAddTransformerCalled;
}
public void addTransformer(ClassFileTransformer transformer) {
++this.numTimesAddTransformerCalled;
}
}
@ -102,18 +99,15 @@ public class ReflectiveLoadTimeWeaverTests { @@ -102,18 +99,15 @@ public class ReflectiveLoadTimeWeaverTests {
private int numTimesGetThrowawayClassLoaderCalled = 0;
@Override
public int getNumTimesGetThrowawayClassLoaderCalled() {
return this.numTimesGetThrowawayClassLoaderCalled;
}
public ClassLoader getThrowawayClassLoader() {
++this.numTimesGetThrowawayClassLoaderCalled;
return getClass().getClassLoader();
}
}
}

18
spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java

@ -22,6 +22,7 @@ import java.beans.Introspector; @@ -22,6 +22,7 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
@ -508,14 +509,14 @@ public class ReflectUtils { @@ -508,14 +509,14 @@ public class ReflectUtils {
catch (InvocationTargetException ex) {
throw new CodeGenerationException(ex.getTargetException());
}
catch (Throwable ex) {
// Fall through if setAccessible fails with InaccessibleObjectException on JDK 9+
// (on the module path and/or with a JVM bootstrapped with --illegal-access=deny)
if (!ex.getClass().getName().endsWith("InaccessibleObjectException")) {
throw new CodeGenerationException(ex);
}
catch (InaccessibleObjectException ex) {
// setAccessible failed with JDK 9+ InaccessibleObjectException -> fall through
// Avoid through JVM startup with --add-opens=java.base/java.lang=ALL-UNNAMED
t = ex;
}
catch (Throwable ex) {
throw new CodeGenerationException(ex);
}
}
}
@ -525,13 +526,14 @@ public class ReflectUtils { @@ -525,13 +526,14 @@ public class ReflectUtils {
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(contextClass, MethodHandles.lookup());
c = lookup.defineClass(b);
}
catch (IllegalAccessException ex) {
catch (LinkageError | IllegalAccessException ex) {
throw new CodeGenerationException(ex) {
@Override
public String getMessage() {
return "ClassLoader mismatch for [" + contextClass.getName() +
"]: JVM should be started with --add-opens=java.base/java.lang=ALL-UNNAMED " +
"for ClassLoader.defineClass to be accessible on " + loader.getClass().getName();
"for ClassLoader.defineClass to be accessible on " + loader.getClass().getName() +
"; consider co-locating the affected class in that target ClassLoader instead.";
}
};
}

16
spring-core/src/main/java/org/springframework/util/ReflectionUtils.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -507,16 +507,8 @@ public abstract class ReflectionUtils { @@ -507,16 +507,8 @@ public abstract class ReflectionUtils {
* @see java.lang.Object#equals(Object)
*/
public static boolean isEqualsMethod(@Nullable Method method) {
if (method == null) {
return false;
}
if (method.getParameterCount() != 1) {
return false;
}
if (!method.getName().equals("equals")) {
return false;
}
return method.getParameterTypes()[0] == Object.class;
return (method != null && method.getParameterCount() == 1 && method.getName().equals("equals") &&
method.getParameterTypes()[0] == Object.class);
}
/**
@ -524,7 +516,7 @@ public abstract class ReflectionUtils { @@ -524,7 +516,7 @@ public abstract class ReflectionUtils {
* @see java.lang.Object#hashCode()
*/
public static boolean isHashCodeMethod(@Nullable Method method) {
return method != null && method.getParameterCount() == 0 && method.getName().equals("hashCode");
return (method != null && method.getParameterCount() == 0 && method.getName().equals("hashCode"));
}
/**

18
spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java

@ -97,16 +97,18 @@ import org.springframework.util.Assert; @@ -97,16 +97,18 @@ import org.springframework.util.Assert;
* support nested transactions! Hence, do not expect Hibernate access code to
* semantically participate in a nested transaction.</i>
*
* <p><b>NOTE: Hibernate ORM 6.x is officially only supported as a JPA provider.
* Please use {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}
* with {@link org.springframework.orm.jpa.JpaTransactionManager} there instead.</b>
*
* @author Juergen Hoeller
* @since 4.2
* @see #setSessionFactory
* @see #setDataSource
* @see SessionFactory#getCurrentSession()
* @see DataSourceUtils#getConnection
* @see DataSourceUtils#releaseConnection
* @see org.springframework.jdbc.core.JdbcTemplate
* @see org.springframework.jdbc.support.JdbcTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.orm.jpa.JpaTransactionManager
* @see org.springframework.orm.jpa.vendor.HibernateJpaDialect
*/
@SuppressWarnings("serial")
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
@ -271,7 +273,11 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana @@ -271,7 +273,11 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* @see Connection#setHoldability
* @see ResultSet#HOLD_CURSORS_OVER_COMMIT
* @see #disconnectOnCompletion(Session)
* @deprecated as of 5.3.29 since Hibernate 5.x aggressively closes ResultSets on commit,
* making it impossible to rely on ResultSet holdability. Also, Spring does not provide
* an equivalent setting on {@link org.springframework.orm.jpa.JpaTransactionManager}.
*/
@Deprecated(since = "5.3.29")
public void setAllowResultAccessAfterCompletion(boolean allowResultAccessAfterCompletion) {
this.allowResultAccessAfterCompletion = allowResultAccessAfterCompletion;
}
@ -487,7 +493,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana @@ -487,7 +493,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
session = txObject.getSessionHolder().getSession().unwrap(SessionImplementor.class);
boolean holdabilityNeeded = this.allowResultAccessAfterCompletion && !txObject.isNewSession();
boolean holdabilityNeeded = (this.allowResultAccessAfterCompletion && !txObject.isNewSession());
boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
if (holdabilityNeeded || isolationLevelNeeded || definition.isReadOnly()) {
if (this.prepareConnection && ConnectionReleaseMode.ON_CLOSE.equals(
@ -500,7 +506,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana @@ -500,7 +506,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
if (holdabilityNeeded) {
int currentHoldability = con.getHoldability();
if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
txObject.setPreviousHoldability(currentHoldability);

4
spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java

@ -66,6 +66,10 @@ import org.springframework.lang.Nullable; @@ -66,6 +66,10 @@ import org.springframework.lang.Nullable;
* {@link HibernateTransactionManager}, this naturally allows for mixing JPA access code
* with native Hibernate access code within the same transaction.
*
* <p><b>NOTE: Hibernate ORM 6.x is officially only supported as a JPA provider.
* Please use {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}
* with {@link org.springframework.orm.jpa.JpaTransactionManager} there instead.</b>
*
* @author Juergen Hoeller
* @since 4.2
* @see #setDataSource

Loading…
Cancel
Save