From 88049e9b5cf9bf77d2712bb090e12a2b96887aee Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 13 Mar 2019 15:32:14 +0100 Subject: [PATCH 1/3] EventListenerMethodProcessor skips annotation search on java classes Closes gh-22564 --- .../context/event/EventListenerMethodProcessor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java b/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java index 191f08925b..703b96f3c9 100644 --- a/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -142,7 +142,10 @@ public class EventListenerMethodProcessor } private void processBean(final String beanName, final Class targetType) { - if (!this.nonAnnotatedClasses.contains(targetType) && !isSpringContainerClass(targetType)) { + if (!this.nonAnnotatedClasses.contains(targetType) && + !targetType.getName().startsWith("java") && + !isSpringContainerClass(targetType)) { + Map annotatedMethods = null; try { annotatedMethods = MethodIntrospector.selectMethods(targetType, @@ -155,6 +158,7 @@ public class EventListenerMethodProcessor logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex); } } + if (CollectionUtils.isEmpty(annotatedMethods)) { this.nonAnnotatedClasses.add(targetType); if (logger.isTraceEnabled()) { From fe56aa6fa47933509c3c5c8300d3e9a06c802dcc Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 13 Mar 2019 15:32:24 +0100 Subject: [PATCH 2/3] Polishing --- .../cache/interceptor/CacheAspectSupport.java | 12 +- .../interceptor/CacheOperationSource.java | 7 +- .../CompositeCacheOperationSource.java | 9 +- .../support/StandardScriptFactory.java | 5 +- .../org/springframework/lang/NonNull.java | 7 +- .../springframework/lang/NonNullFields.java | 4 +- .../org/springframework/lang/Nullable.java | 8 +- .../springframework/util/ReflectionUtils.java | 584 +++++++++--------- .../CompositeTransactionAttributeSource.java | 12 +- .../TransactionAttributeSource.java | 6 +- .../http/server/ServerHttpRequest.java | 8 +- 11 files changed, 341 insertions(+), 321 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java index f8156ab095..3c7d5fe999 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -313,9 +313,9 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker * @param expectedType type for the bean * @return the bean matching that name * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException if such bean does not exist - * @see CacheOperation#keyGenerator - * @see CacheOperation#cacheManager - * @see CacheOperation#cacheResolver + * @see CacheOperation#getKeyGenerator() + * @see CacheOperation#getCacheManager() + * @see CacheOperation#getCacheResolver() */ protected T getBean(String beanName, Class expectedType) { if (this.beanFactory == null) { @@ -353,8 +353,8 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker /** * Execute the underlying operation (typically in case of cache miss) and return - * the result of the invocation. If an exception occurs it will be wrapped in - * a {@link CacheOperationInvoker.ThrowableWrapper}: the exception can be handled + * the result of the invocation. If an exception occurs it will be wrapped in a + * {@link CacheOperationInvoker.ThrowableWrapper}: the exception can be handled * or modified but it must be wrapped in a * {@link CacheOperationInvoker.ThrowableWrapper} as well. * @param invoker the invoker handling the operation being cached diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSource.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSource.java index 0ab1059325..47c8def776 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSource.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2019 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. @@ -27,13 +27,14 @@ import org.springframework.lang.Nullable; * source level, or elsewhere. * * @author Costin Leau + * @author Juergen Hoeller * @since 3.1 */ public interface CacheOperationSource { /** - * Return the collection of cache operations for this method, or {@code null} - * if the method contains no cacheable annotations. + * Return the collection of cache operations for this method, + * or {@code null} if the method contains no cacheable annotations. * @param method the method to introspect * @param targetClass the target class (may be {@code null}, in which case * the declaring class of the method must be used) diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CompositeCacheOperationSource.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CompositeCacheOperationSource.java index a5baa2cc43..a342234927 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CompositeCacheOperationSource.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CompositeCacheOperationSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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. @@ -29,6 +29,7 @@ import org.springframework.util.Assert; * over a given array of {@code CacheOperationSource} instances. * * @author Costin Leau + * @author Juergen Hoeller * @since 3.1 */ @SuppressWarnings("serial") @@ -42,7 +43,7 @@ public class CompositeCacheOperationSource implements CacheOperationSource, Seri * @param cacheOperationSources the CacheOperationSource instances to combine */ public CompositeCacheOperationSource(CacheOperationSource... cacheOperationSources) { - Assert.notEmpty(cacheOperationSources, "cacheOperationSources array must not be empty"); + Assert.notEmpty(cacheOperationSources, "CacheOperationSource array must not be empty"); this.cacheOperationSources = cacheOperationSources; } @@ -54,21 +55,21 @@ public class CompositeCacheOperationSource implements CacheOperationSource, Seri return this.cacheOperationSources; } + @Override @Nullable public Collection getCacheOperations(Method method, @Nullable Class targetClass) { Collection ops = null; - for (CacheOperationSource source : this.cacheOperationSources) { Collection cacheOperations = source.getCacheOperations(method, targetClass); if (cacheOperations != null) { if (ops == null) { ops = new ArrayList<>(); } - ops.addAll(cacheOperations); } } return ops; } + } diff --git a/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java b/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java index 4c684b35b6..5420312ec1 100644 --- a/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java +++ b/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 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. @@ -36,7 +36,7 @@ import org.springframework.util.StringUtils; /** * {@link org.springframework.scripting.ScriptFactory} implementation based * on the JSR-223 script engine abstraction (as included in Java 6+). - * Supports JavaScript, Groovy, JRuby and other JSR-223 compliant engines. + * Supports JavaScript, Groovy, JRuby, and other JSR-223 compliant engines. * *

Typically used in combination with a * {@link org.springframework.scripting.support.ScriptFactoryPostProcessor}; @@ -151,6 +151,7 @@ public class StandardScriptFactory implements ScriptFactory, BeanClassLoaderAwar if (script instanceof Class ? !requestedIfc.isAssignableFrom((Class) script) : !requestedIfc.isInstance(script)) { adaptationRequired = true; + break; } } if (adaptationRequired) { diff --git a/spring-core/src/main/java/org/springframework/lang/NonNull.java b/spring-core/src/main/java/org/springframework/lang/NonNull.java index 264cb11e8c..20fdcfb80c 100644 --- a/spring-core/src/main/java/org/springframework/lang/NonNull.java +++ b/spring-core/src/main/java/org/springframework/lang/NonNull.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -26,8 +26,9 @@ import javax.annotation.meta.TypeQualifierNickname; /** * A common Spring annotation to declare that annotated elements cannot be {@code null}. - * Leverages JSR 305 meta-annotations to indicate nullability in Java to common tools with - * JSR 305 support and used by Kotlin to infer nullability of Spring API. + * + *

Leverages JSR-305 meta-annotations to indicate nullability in Java to common + * tools with JSR-305 support and used by Kotlin to infer nullability of Spring API. * *

Should be used at parameter, return value, and field level. Method overrides should * repeat parent {@code @NonNull} annotations unless they behave differently. diff --git a/spring-core/src/main/java/org/springframework/lang/NonNullFields.java b/spring-core/src/main/java/org/springframework/lang/NonNullFields.java index 3c9d39ddc2..ac431e5f16 100644 --- a/spring-core/src/main/java/org/springframework/lang/NonNullFields.java +++ b/spring-core/src/main/java/org/springframework/lang/NonNullFields.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 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. @@ -36,7 +36,7 @@ import javax.annotation.meta.TypeQualifierDefault; * * @author Sebastien Deleuze * @since 5.0 - * @see NonNullFields + * @see NonNullApi * @see Nullable * @see NonNull */ diff --git a/spring-core/src/main/java/org/springframework/lang/Nullable.java b/spring-core/src/main/java/org/springframework/lang/Nullable.java index 1c343cd4d2..6b5ca26ff8 100644 --- a/spring-core/src/main/java/org/springframework/lang/Nullable.java +++ b/spring-core/src/main/java/org/springframework/lang/Nullable.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -27,8 +27,10 @@ import javax.annotation.meta.When; /** * A common Spring annotation to declare that annotated elements can be {@code null} under - * some circumstance. Leverages JSR 305 meta-annotations to indicate nullability in Java - * to common tools with JSR 305 support and used by Kotlin to infer nullability of Spring API. + * some circumstance. + * + *

Leverages JSR-305 meta-annotations to indicate nullability in Java to common + * tools with JSR-305 support and used by Kotlin to infer nullability of Spring API. * *

Should be used at parameter, return value, and field level. Methods override should * repeat parent {@code @Nullable} annotations unless they behave differently. diff --git a/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java b/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java index e329fecfc1..83e10dc9d0 100644 --- a/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -61,13 +61,13 @@ public abstract class ReflectionUtils { * @since 3.0.5 */ public static final MethodFilter USER_DECLARED_METHODS = - (method -> (!method.isBridge() && !method.isSynthetic() && method.getDeclaringClass() != Object.class)); + (method -> !method.isBridge() && !method.isSynthetic() && method.getDeclaringClass() != Object.class); /** * Pre-built FieldFilter that matches all non-static, non-final fields. */ public static final FieldFilter COPYABLE_FIELDS = - field -> !(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())); + (field -> !(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()))); /** @@ -76,9 +76,9 @@ public abstract class ReflectionUtils { */ private static final String CGLIB_RENAMED_METHOD_PREFIX = "CGLIB$"; - private static final Method[] NO_METHODS = {}; + private static final Method[] EMPTY_METHOD_ARRAY = new Method[0]; - private static final Field[] NO_FIELDS = {}; + private static final Field[] EMPTY_FIELD_ARRAY = new Field[0]; /** @@ -93,88 +93,124 @@ public abstract class ReflectionUtils { private static final Map, Field[]> declaredFieldsCache = new ConcurrentReferenceHashMap<>(256); + // Exception handling + /** - * Attempt to find a {@link Field field} on the supplied {@link Class} with the - * supplied {@code name}. Searches all superclasses up to {@link Object}. - * @param clazz the class to introspect - * @param name the name of the field - * @return the corresponding Field object, or {@code null} if not found + * Handle the given reflection exception. Should only be called if no + * checked exception is expected to be thrown by the target method. + *

Throws the underlying RuntimeException or Error in case of an + * InvocationTargetException with such a root cause. Throws an + * IllegalStateException with an appropriate message or + * UndeclaredThrowableException otherwise. + * @param ex the reflection exception to handle */ - @Nullable - public static Field findField(Class clazz, String name) { - return findField(clazz, name, null); + public static void handleReflectionException(Exception ex) { + if (ex instanceof NoSuchMethodException) { + throw new IllegalStateException("Method not found: " + ex.getMessage()); + } + if (ex instanceof IllegalAccessException) { + throw new IllegalStateException("Could not access method: " + ex.getMessage()); + } + if (ex instanceof InvocationTargetException) { + handleInvocationTargetException((InvocationTargetException) ex); + } + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + throw new UndeclaredThrowableException(ex); } /** - * Attempt to find a {@link Field field} on the supplied {@link Class} with the - * supplied {@code name} and/or {@link Class type}. Searches all superclasses - * up to {@link Object}. - * @param clazz the class to introspect - * @param name the name of the field (may be {@code null} if type is specified) - * @param type the type of the field (may be {@code null} if name is specified) - * @return the corresponding Field object, or {@code null} if not found + * Handle the given invocation target exception. Should only be called if no + * checked exception is expected to be thrown by the target method. + *

Throws the underlying RuntimeException or Error in case of such a root + * cause. Throws an UndeclaredThrowableException otherwise. + * @param ex the invocation target exception to handle */ - @Nullable - public static Field findField(Class clazz, @Nullable String name, @Nullable Class type) { - Assert.notNull(clazz, "Class must not be null"); - Assert.isTrue(name != null || type != null, "Either name or type of the field must be specified"); - Class searchType = clazz; - while (Object.class != searchType && searchType != null) { - Field[] fields = getDeclaredFields(searchType); - for (Field field : fields) { - if ((name == null || name.equals(field.getName())) && - (type == null || type.equals(field.getType()))) { - return field; - } - } - searchType = searchType.getSuperclass(); - } - return null; + public static void handleInvocationTargetException(InvocationTargetException ex) { + rethrowRuntimeException(ex.getTargetException()); } /** - * Set the field represented by the supplied {@link Field field object} on the - * specified {@link Object target object} to the specified {@code value}. - * In accordance with {@link Field#set(Object, Object)} semantics, the new value - * is automatically unwrapped if the underlying field has a primitive type. - *

Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}. - * @param field the field to set - * @param target the target object on which to set the field - * @param value the value to set (may be {@code null}) + * Rethrow the given {@link Throwable exception}, which is presumably the + * target exception of an {@link InvocationTargetException}. + * Should only be called if no checked exception is expected to be thrown + * by the target method. + *

Rethrows the underlying exception cast to a {@link RuntimeException} or + * {@link Error} if appropriate; otherwise, throws an + * {@link UndeclaredThrowableException}. + * @param ex the exception to rethrow + * @throws RuntimeException the rethrown exception */ - public static void setField(Field field, @Nullable Object target, @Nullable Object value) { - try { - field.set(target, value); + public static void rethrowRuntimeException(Throwable ex) { + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; } - catch (IllegalAccessException ex) { - handleReflectionException(ex); - throw new IllegalStateException( - "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage()); + if (ex instanceof Error) { + throw (Error) ex; } + throw new UndeclaredThrowableException(ex); } /** - * Get the field represented by the supplied {@link Field field object} on the - * specified {@link Object target object}. In accordance with {@link Field#get(Object)} - * semantics, the returned value is automatically wrapped if the underlying field - * has a primitive type. - *

Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}. - * @param field the field to get - * @param target the target object from which to get the field - * @return the field's current value + * Rethrow the given {@link Throwable exception}, which is presumably the + * target exception of an {@link InvocationTargetException}. + * Should only be called if no checked exception is expected to be thrown + * by the target method. + *

Rethrows the underlying exception cast to an {@link Exception} or + * {@link Error} if appropriate; otherwise, throws an + * {@link UndeclaredThrowableException}. + * @param ex the exception to rethrow + * @throws Exception the rethrown exception (in case of a checked exception) */ - @Nullable - public static Object getField(Field field, @Nullable Object target) { - try { - return field.get(target); + public static void rethrowException(Throwable ex) throws Exception { + if (ex instanceof Exception) { + throw (Exception) ex; } - catch (IllegalAccessException ex) { - handleReflectionException(ex); - throw new IllegalStateException( - "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage()); + if (ex instanceof Error) { + throw (Error) ex; + } + throw new UndeclaredThrowableException(ex); + } + + + // Constructor handling + + /** + * Obtain an accessible constructor for the given class and parameters. + * @param clazz the clazz to check + * @param parameterTypes the parameter types of the desired constructor + * @return the constructor reference + * @throws NoSuchMethodException if no such constructor exists + * @since 5.0 + */ + public static Constructor accessibleConstructor(Class clazz, Class... parameterTypes) + throws NoSuchMethodException { + + Constructor ctor = clazz.getDeclaredConstructor(parameterTypes); + makeAccessible(ctor); + return ctor; + } + + /** + * Make the given constructor accessible, explicitly setting it accessible + * if necessary. The {@code setAccessible(true)} method is only called + * when actually necessary, to avoid unnecessary conflicts with a JVM + * SecurityManager (if active). + * @param ctor the constructor to make accessible + * @see java.lang.reflect.Constructor#setAccessible + */ + @SuppressWarnings("deprecation") // on JDK 9 + public static void makeAccessible(Constructor ctor) { + if ((!Modifier.isPublic(ctor.getModifiers()) || + !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) && !ctor.isAccessible()) { + ctor.setAccessible(true); } } + + // Method handling + /** * Attempt to find a {@link Method} on the supplied class with the supplied name * and no parameters. Searches all superclasses up to {@code Object}. @@ -297,84 +333,6 @@ public abstract class ReflectionUtils { throw new IllegalStateException("Should never get here"); } - /** - * Handle the given reflection exception. Should only be called if no - * checked exception is expected to be thrown by the target method. - *

Throws the underlying RuntimeException or Error in case of an - * InvocationTargetException with such a root cause. Throws an - * IllegalStateException with an appropriate message or - * UndeclaredThrowableException otherwise. - * @param ex the reflection exception to handle - */ - public static void handleReflectionException(Exception ex) { - if (ex instanceof NoSuchMethodException) { - throw new IllegalStateException("Method not found: " + ex.getMessage()); - } - if (ex instanceof IllegalAccessException) { - throw new IllegalStateException("Could not access method: " + ex.getMessage()); - } - if (ex instanceof InvocationTargetException) { - handleInvocationTargetException((InvocationTargetException) ex); - } - if (ex instanceof RuntimeException) { - throw (RuntimeException) ex; - } - throw new UndeclaredThrowableException(ex); - } - - /** - * Handle the given invocation target exception. Should only be called if no - * checked exception is expected to be thrown by the target method. - *

Throws the underlying RuntimeException or Error in case of such a root - * cause. Throws an UndeclaredThrowableException otherwise. - * @param ex the invocation target exception to handle - */ - public static void handleInvocationTargetException(InvocationTargetException ex) { - rethrowRuntimeException(ex.getTargetException()); - } - - /** - * Rethrow the given {@link Throwable exception}, which is presumably the - * target exception of an {@link InvocationTargetException}. - * Should only be called if no checked exception is expected to be thrown - * by the target method. - *

Rethrows the underlying exception cast to a {@link RuntimeException} or - * {@link Error} if appropriate; otherwise, throws an - * {@link UndeclaredThrowableException}. - * @param ex the exception to rethrow - * @throws RuntimeException the rethrown exception - */ - public static void rethrowRuntimeException(Throwable ex) { - if (ex instanceof RuntimeException) { - throw (RuntimeException) ex; - } - if (ex instanceof Error) { - throw (Error) ex; - } - throw new UndeclaredThrowableException(ex); - } - - /** - * Rethrow the given {@link Throwable exception}, which is presumably the - * target exception of an {@link InvocationTargetException}. - * Should only be called if no checked exception is expected to be thrown - * by the target method. - *

Rethrows the underlying exception cast to an {@link Exception} or - * {@link Error} if appropriate; otherwise, throws an - * {@link UndeclaredThrowableException}. - * @param ex the exception to rethrow - * @throws Exception the rethrown exception (in case of a checked exception) - */ - public static void rethrowException(Throwable ex) throws Exception { - if (ex instanceof Exception) { - throw (Exception) ex; - } - if (ex instanceof Error) { - throw (Error) ex; - } - throw new UndeclaredThrowableException(ex); - } - /** * Determine whether the given method explicitly declares the given * exception or one of its superclasses, which means that an exception @@ -395,143 +353,6 @@ public abstract class ReflectionUtils { return false; } - /** - * Determine whether the given field is a "public static final" constant. - * @param field the field to check - */ - public static boolean isPublicStaticFinal(Field field) { - int modifiers = field.getModifiers(); - return (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)); - } - - /** - * Determine whether the given method is an "equals" method. - * @see java.lang.Object#equals(Object) - */ - public static boolean isEqualsMethod(@Nullable Method method) { - if (method == null || !method.getName().equals("equals")) { - return false; - } - Class[] paramTypes = method.getParameterTypes(); - return (paramTypes.length == 1 && paramTypes[0] == Object.class); - } - - /** - * Determine whether the given method is a "hashCode" method. - * @see java.lang.Object#hashCode() - */ - public static boolean isHashCodeMethod(@Nullable Method method) { - return (method != null && method.getName().equals("hashCode") && method.getParameterCount() == 0); - } - - /** - * Determine whether the given method is a "toString" method. - * @see java.lang.Object#toString() - */ - public static boolean isToStringMethod(@Nullable Method method) { - return (method != null && method.getName().equals("toString") && method.getParameterCount() == 0); - } - - /** - * Determine whether the given method is originally declared by {@link java.lang.Object}. - */ - public static boolean isObjectMethod(@Nullable Method method) { - if (method == null) { - return false; - } - try { - Object.class.getDeclaredMethod(method.getName(), method.getParameterTypes()); - return true; - } - catch (Exception ex) { - return false; - } - } - - /** - * Determine whether the given method is a CGLIB 'renamed' method, - * following the pattern "CGLIB$methodName$0". - * @param renamedMethod the method to check - * @see org.springframework.cglib.proxy.Enhancer#rename - */ - public static boolean isCglibRenamedMethod(Method renamedMethod) { - String name = renamedMethod.getName(); - if (name.startsWith(CGLIB_RENAMED_METHOD_PREFIX)) { - int i = name.length() - 1; - while (i >= 0 && Character.isDigit(name.charAt(i))) { - i--; - } - return ((i > CGLIB_RENAMED_METHOD_PREFIX.length()) && - (i < name.length() - 1) && name.charAt(i) == '$'); - } - return false; - } - - /** - * Make the given field accessible, explicitly setting it accessible if - * necessary. The {@code setAccessible(true)} method is only called - * when actually necessary, to avoid unnecessary conflicts with a JVM - * SecurityManager (if active). - * @param field the field to make accessible - * @see java.lang.reflect.Field#setAccessible - */ - @SuppressWarnings("deprecation") // on JDK 9 - public static void makeAccessible(Field field) { - if ((!Modifier.isPublic(field.getModifiers()) || - !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || - Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) { - field.setAccessible(true); - } - } - - /** - * Make the given method accessible, explicitly setting it accessible if - * necessary. The {@code setAccessible(true)} method is only called - * when actually necessary, to avoid unnecessary conflicts with a JVM - * SecurityManager (if active). - * @param method the method to make accessible - * @see java.lang.reflect.Method#setAccessible - */ - @SuppressWarnings("deprecation") // on JDK 9 - public static void makeAccessible(Method method) { - if ((!Modifier.isPublic(method.getModifiers()) || - !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) { - method.setAccessible(true); - } - } - - /** - * Make the given constructor accessible, explicitly setting it accessible - * if necessary. The {@code setAccessible(true)} method is only called - * when actually necessary, to avoid unnecessary conflicts with a JVM - * SecurityManager (if active). - * @param ctor the constructor to make accessible - * @see java.lang.reflect.Constructor#setAccessible - */ - @SuppressWarnings("deprecation") // on JDK 9 - public static void makeAccessible(Constructor ctor) { - if ((!Modifier.isPublic(ctor.getModifiers()) || - !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) && !ctor.isAccessible()) { - ctor.setAccessible(true); - } - } - - /** - * Obtain an accessible constructor for the given class and parameters. - * @param clazz the clazz to check - * @param parameterTypes the parameter types of the desired constructor - * @return the constructor reference - * @throws NoSuchMethodException if no such constructor exists - * @since 5.0 - */ - public static Constructor accessibleConstructor(Class clazz, Class... parameterTypes) - throws NoSuchMethodException { - - Constructor ctor = clazz.getDeclaredConstructor(parameterTypes); - makeAccessible(ctor); - return ctor; - } - /** * Perform the given callback operation on all matching methods of the given * class, as locally declared or equivalent thereof (such as default methods @@ -611,7 +432,7 @@ public abstract class ReflectionUtils { public static Method[] getAllDeclaredMethods(Class leafClass) { final List methods = new ArrayList<>(32); doWithMethods(leafClass, methods::add); - return methods.toArray(new Method[0]); + return methods.toArray(EMPTY_METHOD_ARRAY); } /** @@ -647,7 +468,7 @@ public abstract class ReflectionUtils { methods.add(method); } }); - return methods.toArray(new Method[0]); + return methods.toArray(EMPTY_METHOD_ARRAY); } /** @@ -679,7 +500,7 @@ public abstract class ReflectionUtils { else { result = declaredMethods; } - declaredMethodsCache.put(clazz, (result.length == 0 ? NO_METHODS : result)); + declaredMethodsCache.put(clazz, (result.length == 0 ? EMPTY_METHOD_ARRAY : result)); } catch (Throwable ex) { throw new IllegalStateException("Failed to introspect Class [" + clazz.getName() + @@ -705,6 +526,168 @@ public abstract class ReflectionUtils { return result; } + /** + * Determine whether the given method is an "equals" method. + * @see java.lang.Object#equals(Object) + */ + public static boolean isEqualsMethod(@Nullable Method method) { + if (method == null || !method.getName().equals("equals")) { + return false; + } + Class[] paramTypes = method.getParameterTypes(); + return (paramTypes.length == 1 && paramTypes[0] == Object.class); + } + + /** + * Determine whether the given method is a "hashCode" method. + * @see java.lang.Object#hashCode() + */ + public static boolean isHashCodeMethod(@Nullable Method method) { + return (method != null && method.getName().equals("hashCode") && method.getParameterCount() == 0); + } + + /** + * Determine whether the given method is a "toString" method. + * @see java.lang.Object#toString() + */ + public static boolean isToStringMethod(@Nullable Method method) { + return (method != null && method.getName().equals("toString") && method.getParameterCount() == 0); + } + + /** + * Determine whether the given method is originally declared by {@link java.lang.Object}. + */ + public static boolean isObjectMethod(@Nullable Method method) { + if (method == null) { + return false; + } + try { + Object.class.getDeclaredMethod(method.getName(), method.getParameterTypes()); + return true; + } + catch (Exception ex) { + return false; + } + } + + /** + * Determine whether the given method is a CGLIB 'renamed' method, + * following the pattern "CGLIB$methodName$0". + * @param renamedMethod the method to check + */ + public static boolean isCglibRenamedMethod(Method renamedMethod) { + String name = renamedMethod.getName(); + if (name.startsWith(CGLIB_RENAMED_METHOD_PREFIX)) { + int i = name.length() - 1; + while (i >= 0 && Character.isDigit(name.charAt(i))) { + i--; + } + return (i > CGLIB_RENAMED_METHOD_PREFIX.length() && (i < name.length() - 1) && name.charAt(i) == '$'); + } + return false; + } + + /** + * Make the given method accessible, explicitly setting it accessible if + * necessary. The {@code setAccessible(true)} method is only called + * when actually necessary, to avoid unnecessary conflicts with a JVM + * SecurityManager (if active). + * @param method the method to make accessible + * @see java.lang.reflect.Method#setAccessible + */ + @SuppressWarnings("deprecation") // on JDK 9 + public static void makeAccessible(Method method) { + if ((!Modifier.isPublic(method.getModifiers()) || + !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) { + method.setAccessible(true); + } + } + + + // Field handling + + /** + * Attempt to find a {@link Field field} on the supplied {@link Class} with the + * supplied {@code name}. Searches all superclasses up to {@link Object}. + * @param clazz the class to introspect + * @param name the name of the field + * @return the corresponding Field object, or {@code null} if not found + */ + @Nullable + public static Field findField(Class clazz, String name) { + return findField(clazz, name, null); + } + + /** + * Attempt to find a {@link Field field} on the supplied {@link Class} with the + * supplied {@code name} and/or {@link Class type}. Searches all superclasses + * up to {@link Object}. + * @param clazz the class to introspect + * @param name the name of the field (may be {@code null} if type is specified) + * @param type the type of the field (may be {@code null} if name is specified) + * @return the corresponding Field object, or {@code null} if not found + */ + @Nullable + public static Field findField(Class clazz, @Nullable String name, @Nullable Class type) { + Assert.notNull(clazz, "Class must not be null"); + Assert.isTrue(name != null || type != null, "Either name or type of the field must be specified"); + Class searchType = clazz; + while (Object.class != searchType && searchType != null) { + Field[] fields = getDeclaredFields(searchType); + for (Field field : fields) { + if ((name == null || name.equals(field.getName())) && + (type == null || type.equals(field.getType()))) { + return field; + } + } + searchType = searchType.getSuperclass(); + } + return null; + } + + /** + * Set the field represented by the supplied {@link Field field object} on the + * specified {@link Object target object} to the specified {@code value}. + * In accordance with {@link Field#set(Object, Object)} semantics, the new value + * is automatically unwrapped if the underlying field has a primitive type. + *

Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}. + * @param field the field to set + * @param target the target object on which to set the field + * @param value the value to set (may be {@code null}) + */ + public static void setField(Field field, @Nullable Object target, @Nullable Object value) { + try { + field.set(target, value); + } + catch (IllegalAccessException ex) { + handleReflectionException(ex); + throw new IllegalStateException( + "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage()); + } + } + + /** + * Get the field represented by the supplied {@link Field field object} on the + * specified {@link Object target object}. In accordance with {@link Field#get(Object)} + * semantics, the returned value is automatically wrapped if the underlying field + * has a primitive type. + *

Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}. + * @param field the field to get + * @param target the target object from which to get the field + * @return the field's current value + */ + @Nullable + public static Object getField(Field field, @Nullable Object target) { + try { + return field.get(target); + } + catch (IllegalAccessException ex) { + handleReflectionException(ex); + throw new IllegalStateException( + "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage()); + } + } + /** * Invoke the given callback on all locally declared fields in the given class. * @param clazz the target class to analyze @@ -778,7 +761,7 @@ public abstract class ReflectionUtils { if (result == null) { try { result = clazz.getDeclaredFields(); - declaredFieldsCache.put(clazz, (result.length == 0 ? NO_FIELDS : result)); + declaredFieldsCache.put(clazz, (result.length == 0 ? EMPTY_FIELD_ARRAY : result)); } catch (Throwable ex) { throw new IllegalStateException("Failed to introspect Class [" + clazz.getName() + @@ -808,6 +791,35 @@ public abstract class ReflectionUtils { }, COPYABLE_FIELDS); } + /** + * Determine whether the given field is a "public static final" constant. + * @param field the field to check + */ + public static boolean isPublicStaticFinal(Field field) { + int modifiers = field.getModifiers(); + return (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)); + } + + /** + * Make the given field accessible, explicitly setting it accessible if + * necessary. The {@code setAccessible(true)} method is only called + * when actually necessary, to avoid unnecessary conflicts with a JVM + * SecurityManager (if active). + * @param field the field to make accessible + * @see java.lang.reflect.Field#setAccessible + */ + @SuppressWarnings("deprecation") // on JDK 9 + public static void makeAccessible(Field field) { + if ((!Modifier.isPublic(field.getModifiers()) || + !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || + Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) { + field.setAccessible(true); + } + } + + + // Cache handling + /** * Clear the internal method/field cache. * @since 4.2.4 diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/CompositeTransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/CompositeTransactionAttributeSource.java index 521b2eca00..84f1fe04c6 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/CompositeTransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/CompositeTransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2019 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. @@ -39,7 +39,7 @@ public class CompositeTransactionAttributeSource implements TransactionAttribute * Create a new CompositeTransactionAttributeSource for the given sources. * @param transactionAttributeSources the TransactionAttributeSource instances to combine */ - public CompositeTransactionAttributeSource(TransactionAttributeSource[] transactionAttributeSources) { + public CompositeTransactionAttributeSource(TransactionAttributeSource... transactionAttributeSources) { Assert.notNull(transactionAttributeSources, "TransactionAttributeSource array must not be null"); this.transactionAttributeSources = transactionAttributeSources; } @@ -56,10 +56,10 @@ public class CompositeTransactionAttributeSource implements TransactionAttribute @Override @Nullable public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class targetClass) { - for (TransactionAttributeSource tas : this.transactionAttributeSources) { - TransactionAttribute ta = tas.getTransactionAttribute(method, targetClass); - if (ta != null) { - return ta; + for (TransactionAttributeSource source : this.transactionAttributeSources) { + TransactionAttribute attr = source.getTransactionAttribute(method, targetClass); + if (attr != null) { + return attr; } } return null; diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSource.java index 3b384ab6e3..1660223989 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -27,6 +27,7 @@ import org.springframework.lang.Nullable; * metadata attributes at source level (such as Java 5 annotations), or anywhere else. * * @author Rod Johnson + * @author Juergen Hoeller * @since 15.04.2003 * @see TransactionInterceptor#setTransactionAttributeSource * @see TransactionProxyFactoryBean#setTransactionAttributeSource @@ -40,8 +41,7 @@ public interface TransactionAttributeSource { * @param method the method to introspect * @param targetClass the target class (may be {@code null}, * in which case the declaring class of the method must be used) - * @return the TransactionAttribute the matching transaction attribute, - * or {@code null} if none found + * @return the matching transaction attribute, or {@code null} if none found */ @Nullable TransactionAttribute getTransactionAttribute(Method method, @Nullable Class targetClass); diff --git a/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java index 8856452613..3c4dbac78c 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2019 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,7 @@ import java.security.Principal; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpRequest; +import org.springframework.lang.Nullable; /** * Represents a server-side HTTP request. @@ -33,9 +34,10 @@ public interface ServerHttpRequest extends HttpRequest, HttpInputMessage { /** * Return a {@link java.security.Principal} instance containing the name of the - * authenticated user. If the user has not been authenticated, the method returns - * null. + * authenticated user. + *

If the user has not been authenticated, the method returns null. */ + @Nullable Principal getPrincipal(); /** From fcb3957884779053225429c02d52aa8f2c186f8e Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 13 Mar 2019 15:32:37 +0100 Subject: [PATCH 3/3] Upgrade to Netty 4.1.34 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 029b26fe50..436f7b0507 100644 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,7 @@ ext { junit5Version = "5.3.2" kotlinVersion = "1.2.71" log4jVersion = "2.11.2" - nettyVersion = "4.1.33.Final" + nettyVersion = "4.1.34.Final" reactorVersion = "Californium-SR5" rxjavaVersion = "1.3.8" rxjavaAdapterVersion = "1.2.1"