Browse Source

Merge branch '5.3.x'

# Conflicts:
#	spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java
#	spring-core/src/main/java/org/springframework/core/task/SimpleAsyncTaskExecutor.java
#	spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java
#	spring-tx/src/main/java/org/springframework/jca/work/SimpleTaskWorkManager.java
#	spring-tx/src/main/java/org/springframework/jca/work/WorkManagerTaskExecutor.java
pull/28011/head
Juergen Hoeller 4 years ago
parent
commit
3eb9886724
  1. 4
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
  2. 10
      spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java
  3. 3
      spring-context-support/src/main/java/org/springframework/scheduling/quartz/SimpleThreadPoolTaskExecutor.java
  4. 3
      spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java
  5. 3
      spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.java
  6. 3
      spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java
  7. 1
      spring-core/spring-core.gradle
  8. 330
      spring-core/src/main/java/org/springframework/cglib/beans/BeanMap.java
  9. 10
      spring-core/src/main/java/org/springframework/cglib/beans/package-info.java
  10. 20
      spring-core/src/main/java/org/springframework/core/task/AsyncTaskExecutor.java
  11. 8
      spring-core/src/main/java/org/springframework/core/task/SimpleAsyncTaskExecutor.java
  12. 3
      spring-core/src/main/java/org/springframework/core/task/TaskRejectedException.java
  13. 5
      spring-core/src/main/java/org/springframework/core/task/TaskTimeoutException.java
  14. 3
      spring-core/src/main/java/org/springframework/core/task/support/TaskExecutorAdapter.java
  15. 60
      spring-core/src/main/java/org/springframework/util/ClassUtils.java
  16. 14
      spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java
  17. 8
      spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java
  18. 12
      spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java

4
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -1832,7 +1832,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'"); logger.trace("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
} }
Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod); Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod, bean.getClass());
try { try {
ReflectionUtils.makeAccessible(methodToInvoke); ReflectionUtils.makeAccessible(methodToInvoke);

10
spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -130,7 +130,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
beanName + "' has a non-boolean parameter - not supported as destroy method"); beanName + "' has a non-boolean parameter - not supported as destroy method");
} }
} }
destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod); destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod, bean.getClass());
} }
this.destroyMethod = destroyMethod; this.destroyMethod = destroyMethod;
} }
@ -223,9 +223,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
invokeCustomDestroyMethod(this.destroyMethod); invokeCustomDestroyMethod(this.destroyMethod);
} }
else if (this.destroyMethodName != null) { else if (this.destroyMethodName != null) {
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName); Method destroyMethod = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) { if (destroyMethod != null) {
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke)); invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(destroyMethod, this.bean.getClass()));
} }
} }
} }

3
spring-context-support/src/main/java/org/springframework/scheduling/quartz/SimpleThreadPoolTaskExecutor.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -76,6 +76,7 @@ public class SimpleThreadPoolTaskExecutor extends SimpleThreadPool
} }
} }
@Deprecated
@Override @Override
public void execute(Runnable task, long startTimeout) { public void execute(Runnable task, long startTimeout) {
execute(task); execute(task);

3
spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -147,6 +147,7 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
this.adaptedExecutor.execute(task); this.adaptedExecutor.execute(task);
} }
@Deprecated
@Override @Override
public void execute(Runnable task, long startTimeout) { public void execute(Runnable task, long startTimeout) {
this.adaptedExecutor.execute(task, startTimeout); this.adaptedExecutor.execute(task, startTimeout);

3
spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -340,6 +340,7 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
} }
} }
@Deprecated
@Override @Override
public void execute(Runnable task, long startTimeout) { public void execute(Runnable task, long startTimeout) {
execute(task); execute(task);

3
spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -281,6 +281,7 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
} }
} }
@Deprecated
@Override @Override
public void execute(Runnable task, long startTimeout) { public void execute(Runnable task, long startTimeout) {
execute(task); execute(task);

1
spring-core/spring-core.gradle

@ -73,6 +73,7 @@ jar {
dependsOn cglibRepackJar dependsOn cglibRepackJar
from(zipTree(cglibRepackJar.archivePath)) { from(zipTree(cglibRepackJar.archivePath)) {
include "org/springframework/cglib/**" include "org/springframework/cglib/**"
exclude "org/springframework/cglib/beans/BeanMap*.class"
exclude "org/springframework/cglib/core/AbstractClassGenerator*.class" exclude "org/springframework/cglib/core/AbstractClassGenerator*.class"
exclude "org/springframework/cglib/core/AsmApi*.class" exclude "org/springframework/cglib/core/AsmApi*.class"
exclude "org/springframework/cglib/core/KeyFactory.class" exclude "org/springframework/cglib/core/KeyFactory.class"

330
spring-core/src/main/java/org/springframework/cglib/beans/BeanMap.java

@ -0,0 +1,330 @@
/*
* Copyright 2003,2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cglib.beans;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.asm.ClassVisitor;
import org.springframework.cglib.core.AbstractClassGenerator;
import org.springframework.cglib.core.KeyFactory;
import org.springframework.cglib.core.ReflectUtils;
/**
* A <code>Map</code>-based view of a JavaBean. The default set of keys is the
* union of all property names (getters or setters). An attempt to set
* a read-only property will be ignored, and write-only properties will
* be returned as <code>null</code>. Removal of objects is not a
* supported (the key set is fixed).
* @author Chris Nokleberg
*/
@SuppressWarnings({"rawtypes", "unchecked"})
abstract public class BeanMap implements Map {
/**
* Limit the properties reflected in the key set of the map
* to readable properties.
* @see BeanMap.Generator#setRequire
*/
public static final int REQUIRE_GETTER = 1;
/**
* Limit the properties reflected in the key set of the map
* to writable properties.
* @see BeanMap.Generator#setRequire
*/
public static final int REQUIRE_SETTER = 2;
/**
* Helper method to create a new <code>BeanMap</code>. For finer
* control over the generated instance, use a new instance of
* <code>BeanMap.Generator</code> instead of this static method.
* @param bean the JavaBean underlying the map
* @return a new <code>BeanMap</code> instance
*/
public static BeanMap create(Object bean) {
Generator gen = new Generator();
gen.setBean(bean);
return gen.create();
}
public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(BeanMap.class.getName());
private static final BeanMapKey KEY_FACTORY =
(BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME);
interface BeanMapKey {
public Object newInstance(Class type, int require);
}
private Object bean;
private Class beanClass;
private int require;
public Generator() {
super(SOURCE);
}
/**
* Set the bean that the generated map should reflect. The bean may be swapped
* out for another bean of the same type using {@link #setBean}.
* Calling this method overrides any value previously set using {@link #setBeanClass}.
* You must call either this method or {@link #setBeanClass} before {@link #create}.
* @param bean the initial bean
*/
public void setBean(Object bean) {
this.bean = bean;
if (bean != null) {
beanClass = bean.getClass();
setContextClass(beanClass);
}
}
/**
* Set the class of the bean that the generated map should support.
* You must call either this method or {@link #setBeanClass} before {@link #create}.
* @param beanClass the class of the bean
*/
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
/**
* Limit the properties reflected by the generated map.
* @param require any combination of {@link #REQUIRE_GETTER} and
* {@link #REQUIRE_SETTER}; default is zero (any property allowed)
*/
public void setRequire(int require) {
this.require = require;
}
protected ClassLoader getDefaultClassLoader() {
return beanClass.getClassLoader();
}
protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(beanClass);
}
/**
* Create a new instance of the <code>BeanMap</code>. An existing
* generated class will be reused if possible.
*/
public BeanMap create() {
if (beanClass == null)
throw new IllegalArgumentException("Class of bean unknown");
setNamePrefix(beanClass.getName());
return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require));
}
public void generateClass(ClassVisitor v) throws Exception {
new BeanMapEmitter(v, getClassName(), beanClass, require);
}
protected Object firstInstance(Class type) {
return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
}
protected Object nextInstance(Object instance) {
return ((BeanMap)instance).newInstance(bean);
}
}
/**
* Create a new <code>BeanMap</code> instance using the specified bean.
* This is faster than using the {@link #create} static method.
* @param bean the JavaBean underlying the map
* @return a new <code>BeanMap</code> instance
*/
abstract public BeanMap newInstance(Object bean);
/**
* Get the type of a property.
* @param name the name of the JavaBean property
* @return the type of the property, or null if the property does not exist
*/
abstract public Class getPropertyType(String name);
protected Object bean;
protected BeanMap() {
}
protected BeanMap(Object bean) {
setBean(bean);
}
public Object get(Object key) {
return get(bean, key);
}
public Object put(Object key, Object value) {
return put(bean, key, value);
}
/**
* Get the property of a bean. This allows a <code>BeanMap</code>
* to be used statically for multiple beans--the bean instance tied to the
* map is ignored and the bean passed to this method is used instead.
* @param bean the bean to query; must be compatible with the type of
* this <code>BeanMap</code>
* @param key must be a String
* @return the current value, or null if there is no matching property
*/
abstract public Object get(Object bean, Object key);
/**
* Set the property of a bean. This allows a <code>BeanMap</code>
* to be used statically for multiple beans--the bean instance tied to the
* map is ignored and the bean passed to this method is used instead.
* @param key must be a String
* @return the old value, if there was one, or null
*/
abstract public Object put(Object bean, Object key, Object value);
/**
* Change the underlying bean this map should use.
* @param bean the new JavaBean
* @see #getBean
*/
public void setBean(Object bean) {
this.bean = bean;
}
/**
* Return the bean currently in use by this map.
* @return the current JavaBean
* @see #setBean
*/
public Object getBean() {
return bean;
}
public void clear() {
throw new UnsupportedOperationException();
}
public boolean containsKey(Object key) {
return keySet().contains(key);
}
public boolean containsValue(Object value) {
for (Iterator it = keySet().iterator(); it.hasNext();) {
Object v = get(it.next());
if (((value == null) && (v == null)) || (value != null && value.equals(v)))
return true;
}
return false;
}
public int size() {
return keySet().size();
}
public boolean isEmpty() {
return size() == 0;
}
public Object remove(Object key) {
throw new UnsupportedOperationException();
}
public void putAll(Map t) {
for (Iterator it = t.keySet().iterator(); it.hasNext();) {
Object key = it.next();
put(key, t.get(key));
}
}
public boolean equals(Object o) {
if (o == null || !(o instanceof Map)) {
return false;
}
Map other = (Map)o;
if (size() != other.size()) {
return false;
}
for (Iterator it = keySet().iterator(); it.hasNext();) {
Object key = it.next();
if (!other.containsKey(key)) {
return false;
}
Object v1 = get(key);
Object v2 = other.get(key);
if (!((v1 == null) ? v2 == null : v1.equals(v2))) {
return false;
}
}
return true;
}
public int hashCode() {
int code = 0;
for (Iterator it = keySet().iterator(); it.hasNext();) {
Object key = it.next();
Object value = get(key);
code += ((key == null) ? 0 : key.hashCode()) ^
((value == null) ? 0 : value.hashCode());
}
return code;
}
// TODO: optimize
public Set entrySet() {
HashMap copy = new HashMap();
for (Iterator it = keySet().iterator(); it.hasNext();) {
Object key = it.next();
copy.put(key, get(key));
}
return Collections.unmodifiableMap(copy).entrySet();
}
public Collection values() {
Set keys = keySet();
List values = new ArrayList(keys.size());
for (Iterator it = keys.iterator(); it.hasNext();) {
values.add(get(it.next()));
}
return Collections.unmodifiableCollection(values);
}
/*
* @see java.util.AbstractMap#toString
*/
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append('{');
for (Iterator it = keySet().iterator(); it.hasNext();) {
Object key = it.next();
sb.append(key);
sb.append('=');
sb.append(get(key));
if (it.hasNext()) {
sb.append(", ");
}
}
sb.append('}');
return sb.toString();
}
}

10
spring-core/src/main/java/org/springframework/cglib/beans/package-info.java

@ -0,0 +1,10 @@
/**
* Spring's repackaging of the
* <a href="http://cglib.sourceforge.net">CGLIB</a> beans package
* (for internal use only).
*
* <p>As this repackaging happens at the class file level, sources
* and javadocs are not available here... except for a few files
* that have been patched for Spring's purposes on JDK 9-17.
*/
package org.springframework.cglib.beans;

20
spring-core/src/main/java/org/springframework/core/task/AsyncTaskExecutor.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,8 +21,7 @@ import java.util.concurrent.Future;
/** /**
* Extended interface for asynchronous {@link TaskExecutor} implementations, * Extended interface for asynchronous {@link TaskExecutor} implementations,
* offering an overloaded {@link #execute(Runnable, long)} variant with a start * offering support for {@link java.util.concurrent.Callable}.
* timeout parameter as well support for {@link java.util.concurrent.Callable}.
* *
* <p>Note: The {@link java.util.concurrent.Executors} class includes a set of * <p>Note: The {@link java.util.concurrent.Executors} class includes a set of
* methods that can convert some other common closure-like objects, for example, * methods that can convert some other common closure-like objects, for example,
@ -41,10 +40,18 @@ import java.util.concurrent.Future;
*/ */
public interface AsyncTaskExecutor extends TaskExecutor { public interface AsyncTaskExecutor extends TaskExecutor {
/** Constant that indicates immediate execution. */ /**
* Constant that indicates immediate execution.
* @deprecated as of 5.3.16 along with {@link #execute(Runnable, long)}
*/
@Deprecated
long TIMEOUT_IMMEDIATE = 0; long TIMEOUT_IMMEDIATE = 0;
/** Constant that indicates no time limit. */ /**
* Constant that indicates no time limit.
* @deprecated as of 5.3.16 along with {@link #execute(Runnable, long)}
*/
@Deprecated
long TIMEOUT_INDEFINITE = Long.MAX_VALUE; long TIMEOUT_INDEFINITE = Long.MAX_VALUE;
@ -58,7 +65,10 @@ public interface AsyncTaskExecutor extends TaskExecutor {
* @throws TaskTimeoutException in case of the task being rejected because * @throws TaskTimeoutException in case of the task being rejected because
* of the timeout (i.e. it cannot be started in time) * of the timeout (i.e. it cannot be started in time)
* @throws TaskRejectedException if the given task was not accepted * @throws TaskRejectedException if the given task was not accepted
* @see #execute(Runnable)
* @deprecated as of 5.3.16 since the common executors do not support start timeouts
*/ */
@Deprecated
void execute(Runnable task, long startTimeout); void execute(Runnable task, long startTimeout);
/** /**

8
spring-core/src/main/java/org/springframework/core/task/SimpleAsyncTaskExecutor.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -173,6 +173,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
* if configured (through the superclass's settings). * if configured (through the superclass's settings).
* @see #doExecute(Runnable) * @see #doExecute(Runnable)
*/ */
@SuppressWarnings("deprecation")
@Override @Override
public void execute(Runnable task) { public void execute(Runnable task) {
execute(task, TIMEOUT_INDEFINITE); execute(task, TIMEOUT_INDEFINITE);
@ -187,6 +188,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
* @see #TIMEOUT_IMMEDIATE * @see #TIMEOUT_IMMEDIATE
* @see #doExecute(Runnable) * @see #doExecute(Runnable)
*/ */
@Deprecated
@Override @Override
public void execute(Runnable task, long startTimeout) { public void execute(Runnable task, long startTimeout) {
Assert.notNull(task, "Runnable must not be null"); Assert.notNull(task, "Runnable must not be null");
@ -200,6 +202,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
} }
} }
@SuppressWarnings("deprecation")
@Override @Override
public Future<?> submit(Runnable task) { public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<>(task, null); FutureTask<Object> future = new FutureTask<>(task, null);
@ -207,6 +210,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
return future; return future;
} }
@SuppressWarnings("deprecation")
@Override @Override
public <T> Future<T> submit(Callable<T> task) { public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<>(task); FutureTask<T> future = new FutureTask<>(task);
@ -214,6 +218,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
return future; return future;
} }
@SuppressWarnings("deprecation")
@Override @Override
public ListenableFuture<?> submitListenable(Runnable task) { public ListenableFuture<?> submitListenable(Runnable task) {
ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null); ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
@ -221,6 +226,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
return future; return future;
} }
@SuppressWarnings("deprecation")
@Override @Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) { public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
ListenableFutureTask<T> future = new ListenableFutureTask<>(task); ListenableFutureTask<T> future = new ListenableFutureTask<>(task);

3
spring-core/src/main/java/org/springframework/core/task/TaskRejectedException.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,7 +25,6 @@ import java.util.concurrent.RejectedExecutionException;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.0.1 * @since 2.0.1
* @see TaskExecutor#execute(Runnable) * @see TaskExecutor#execute(Runnable)
* @see TaskTimeoutException
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class TaskRejectedException extends RejectedExecutionException { public class TaskRejectedException extends RejectedExecutionException {

5
spring-core/src/main/java/org/springframework/core/task/TaskTimeoutException.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,8 +23,9 @@ package org.springframework.core.task;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.0.3 * @since 2.0.3
* @see AsyncTaskExecutor#execute(Runnable, long) * @see AsyncTaskExecutor#execute(Runnable, long)
* @see TaskRejectedException * @deprecated as of 5.3.16 since the common executors do not support start timeouts
*/ */
@Deprecated
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class TaskTimeoutException extends TaskRejectedException { public class TaskTimeoutException extends TaskRejectedException {

3
spring-core/src/main/java/org/springframework/core/task/support/TaskExecutorAdapter.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -97,6 +97,7 @@ public class TaskExecutorAdapter implements AsyncListenableTaskExecutor {
} }
} }
@Deprecated
@Override @Override
public void execute(Runnable task, long startTimeout) { public void execute(Runnable task, long startTimeout) {
execute(task); execute(task);

60
spring-core/src/main/java/org/springframework/util/ClassUtils.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -1256,7 +1256,7 @@ public abstract class ClassUtils {
* (may be {@code null} or may not even implement the method) * (may be {@code null} or may not even implement the method)
* @return the specific target method, or the original method if the * @return the specific target method, or the original method if the
* {@code targetClass} does not implement it * {@code targetClass} does not implement it
* @see #getInterfaceMethodIfPossible * @see #getInterfaceMethodIfPossible(Method, Class)
*/ */
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) { public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
if (targetClass != null && targetClass != method.getDeclaringClass() && isOverridable(method, targetClass)) { if (targetClass != null && targetClass != method.getDeclaringClass() && isOverridable(method, targetClass)) {
@ -1289,28 +1289,54 @@ public abstract class ClassUtils {
* @param method the method to be invoked, potentially from an implementation class * @param method the method to be invoked, potentially from an implementation class
* @return the corresponding interface method, or the original method if none found * @return the corresponding interface method, or the original method if none found
* @since 5.1 * @since 5.1
* @see #getMostSpecificMethod * @deprecated in favor of {@link #getInterfaceMethodIfPossible(Method, Class)}
*/ */
@Deprecated
public static Method getInterfaceMethodIfPossible(Method method) { public static Method getInterfaceMethodIfPossible(Method method) {
return getInterfaceMethodIfPossible(method, null);
}
/**
* Determine a corresponding interface method for the given method handle, if possible.
* <p>This is particularly useful for arriving at a public exported type on Jigsaw
* which can be reflectively invoked without an illegal access warning.
* @param method the method to be invoked, potentially from an implementation class
* @param targetClass the target class to check for declared interfaces
* @return the corresponding interface method, or the original method if none found
* @since 5.3.16
* @see #getMostSpecificMethod
*/
public static Method getInterfaceMethodIfPossible(Method method, @Nullable Class<?> targetClass) {
if (!Modifier.isPublic(method.getModifiers()) || method.getDeclaringClass().isInterface()) { if (!Modifier.isPublic(method.getModifiers()) || method.getDeclaringClass().isInterface()) {
return method; return method;
} }
return interfaceMethodCache.computeIfAbsent(method, key -> { // Try cached version of method in its declaring class
Class<?> current = key.getDeclaringClass(); Method result = interfaceMethodCache.computeIfAbsent(method,
while (current != null && current != Object.class) { key -> findInterfaceMethodIfPossible(key, key.getDeclaringClass(), Object.class));
Class<?>[] ifcs = current.getInterfaces(); if (result == method && targetClass != null) {
for (Class<?> ifc : ifcs) { // No interface method found yet -> try given target class (possibly a subclass of the
try { // declaring class, late-binding a base class method to a subclass-declared interface:
return ifc.getMethod(key.getName(), key.getParameterTypes()); // see e.g. HashMap.HashIterator.hasNext)
} result = findInterfaceMethodIfPossible(method, targetClass, method.getDeclaringClass());
catch (NoSuchMethodException ex) { }
// ignore return result;
} }
private static Method findInterfaceMethodIfPossible(Method method, Class<?> startClass, Class<?> endClass) {
Class<?> current = startClass;
while (current != null && current != endClass) {
Class<?>[] ifcs = current.getInterfaces();
for (Class<?> ifc : ifcs) {
try {
return ifc.getMethod(method.getName(), method.getParameterTypes());
}
catch (NoSuchMethodException ex) {
// ignore
} }
current = current.getSuperclass();
} }
return key; current = current.getSuperclass();
}); }
return method;
} }
/** /**

14
spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -58,8 +58,18 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
* @param method the method to invoke * @param method the method to invoke
*/ */
public ReflectiveMethodExecutor(Method method) { public ReflectiveMethodExecutor(Method method) {
this(method, null);
}
/**
* Create a new executor for the given method.
* @param method the method to invoke
* @param targetClass the target class to invoke the method on
* @since 5.3.16
*/
public ReflectiveMethodExecutor(Method method, @Nullable Class<?> targetClass) {
this.originalMethod = method; this.originalMethod = method;
this.methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(method); this.methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(method, targetClass);
if (method.isVarArgs()) { if (method.isVarArgs()) {
this.varargsPosition = method.getParameterCount() - 1; this.varargsPosition = method.getParameterCount() - 1;
} }

8
spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -176,7 +176,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
} }
if (matchInfo != null) { if (matchInfo != null) {
if (matchInfo.isExactMatch()) { if (matchInfo.isExactMatch()) {
return new ReflectiveMethodExecutor(method); return new ReflectiveMethodExecutor(method, type);
} }
else if (matchInfo.isCloseMatch()) { else if (matchInfo.isCloseMatch()) {
if (this.useDistance) { if (this.useDistance) {
@ -204,13 +204,13 @@ public class ReflectiveMethodResolver implements MethodResolver {
} }
} }
if (closeMatch != null) { if (closeMatch != null) {
return new ReflectiveMethodExecutor(closeMatch); return new ReflectiveMethodExecutor(closeMatch, type);
} }
else if (matchRequiringConversion != null) { else if (matchRequiringConversion != null) {
if (multipleOptions) { if (multipleOptions) {
throw new SpelEvaluationException(SpelMessage.MULTIPLE_POSSIBLE_METHODS, name); throw new SpelEvaluationException(SpelMessage.MULTIPLE_POSSIBLE_METHODS, name);
} }
return new ReflectiveMethodExecutor(matchRequiringConversion); return new ReflectiveMethodExecutor(matchRequiringConversion, type);
} }
else { else {
return null; return null;

12
spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -130,7 +130,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
// The readerCache will only contain gettable properties (let's not worry about setters for now). // The readerCache will only contain gettable properties (let's not worry about setters for now).
Property property = new Property(type, method, null); Property property = new Property(type, method, null);
TypeDescriptor typeDescriptor = new TypeDescriptor(property); TypeDescriptor typeDescriptor = new TypeDescriptor(property);
method = ClassUtils.getInterfaceMethodIfPossible(method); method = ClassUtils.getInterfaceMethodIfPossible(method, type);
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor)); this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor); this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true; return true;
@ -173,7 +173,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
// The readerCache will only contain gettable properties (let's not worry about setters for now). // The readerCache will only contain gettable properties (let's not worry about setters for now).
Property property = new Property(type, method, null); Property property = new Property(type, method, null);
TypeDescriptor typeDescriptor = new TypeDescriptor(property); TypeDescriptor typeDescriptor = new TypeDescriptor(property);
method = ClassUtils.getInterfaceMethodIfPossible(method); method = ClassUtils.getInterfaceMethodIfPossible(method, type);
invoker = new InvokerPair(method, typeDescriptor); invoker = new InvokerPair(method, typeDescriptor);
this.lastReadInvokerPair = invoker; this.lastReadInvokerPair = invoker;
this.readerCache.put(cacheKey, invoker); this.readerCache.put(cacheKey, invoker);
@ -233,7 +233,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
// Treat it like a property // Treat it like a property
Property property = new Property(type, null, method); Property property = new Property(type, null, method);
TypeDescriptor typeDescriptor = new TypeDescriptor(property); TypeDescriptor typeDescriptor = new TypeDescriptor(property);
method = ClassUtils.getInterfaceMethodIfPossible(method); method = ClassUtils.getInterfaceMethodIfPossible(method, type);
this.writerCache.put(cacheKey, method); this.writerCache.put(cacheKey, method);
this.typeDescriptorCache.put(cacheKey, typeDescriptor); this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true; return true;
@ -282,7 +282,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (method == null) { if (method == null) {
method = findSetterForProperty(name, type, target); method = findSetterForProperty(name, type, target);
if (method != null) { if (method != null) {
method = ClassUtils.getInterfaceMethodIfPossible(method); method = ClassUtils.getInterfaceMethodIfPossible(method, type);
cachedMember = method; cachedMember = method;
this.writerCache.put(cacheKey, cachedMember); this.writerCache.put(cacheKey, cachedMember);
} }
@ -527,7 +527,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
method = findGetterForProperty(name, type, target); method = findGetterForProperty(name, type, target);
if (method != null) { if (method != null) {
TypeDescriptor typeDescriptor = new TypeDescriptor(new MethodParameter(method, -1)); TypeDescriptor typeDescriptor = new TypeDescriptor(new MethodParameter(method, -1));
method = ClassUtils.getInterfaceMethodIfPossible(method); method = ClassUtils.getInterfaceMethodIfPossible(method, type);
invocationTarget = new InvokerPair(method, typeDescriptor); invocationTarget = new InvokerPair(method, typeDescriptor);
ReflectionUtils.makeAccessible(method); ReflectionUtils.makeAccessible(method);
this.readerCache.put(cacheKey, invocationTarget); this.readerCache.put(cacheKey, invocationTarget);

Loading…
Cancel
Save