diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java index 70b928ab2fb..9e5136b152e 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -123,15 +123,15 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac /** * Find and return the first AspectJ annotation on the given method - * (there should only be one anyway...) + * (there should only be one anyway...). */ @SuppressWarnings("unchecked") @Nullable protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) { Class[] classesToLookFor = new Class[] { Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class}; - for (Class c : classesToLookFor) { - AspectJAnnotation foundAnnotation = findAnnotation(method, (Class) c); + for (Class clazz : classesToLookFor) { + AspectJAnnotation foundAnnotation = findAnnotation(method, (Class) clazz); if (foundAnnotation != null) { return foundAnnotation; } @@ -151,6 +151,9 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac } + /** + * AspectJ annotation types. + */ protected enum AspectJAnnotationType { AtPointcut, diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java b/spring-context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java index f611eab5807..e2f8681e181 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java @@ -131,9 +131,14 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati Collection annOps = provider.getCacheOperations(annotationParser); if (annOps != null) { if (ops == null) { - ops = new ArrayList<>(); + ops = annOps; + } + else { + Collection combined = new ArrayList<>(ops.size() + annOps.size()); + combined.addAll(ops); + combined.addAll(annOps); + ops = combined; } - ops.addAll(annOps); } } return ops; diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java index 4bf5532c79e..ba029f45ae2 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java @@ -155,7 +155,7 @@ public class AnnotationConfigUtils { } } - Set beanDefs = new LinkedHashSet<>(4); + Set beanDefs = new LinkedHashSet<>(8); if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); @@ -202,6 +202,7 @@ public class AnnotationConfigUtils { def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME)); } + if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); diff --git a/spring-context/src/main/java/org/springframework/context/event/DefaultEventListenerFactory.java b/spring-context/src/main/java/org/springframework/context/event/DefaultEventListenerFactory.java index 8d6cd686445..b0ffe7516a1 100644 --- a/spring-context/src/main/java/org/springframework/context/event/DefaultEventListenerFactory.java +++ b/spring-context/src/main/java/org/springframework/context/event/DefaultEventListenerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -24,6 +24,7 @@ import org.springframework.core.Ordered; /** * Default {@link EventListenerFactory} implementation that supports the * regular {@link EventListener} annotation. + * *

Used as "catch-all" implementation by default. * * @author Stephane Nicoll @@ -33,15 +34,17 @@ public class DefaultEventListenerFactory implements EventListenerFactory, Ordere private int order = LOWEST_PRECEDENCE; - @Override - public int getOrder() { - return order; - } public void setOrder(int order) { this.order = order; } + @Override + public int getOrder() { + return this.order; + } + + public boolean supportsMethod(Method method) { return true; } 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 d914df5ff41..8105d2465de 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-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -45,8 +45,7 @@ import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; /** - * Register {@link EventListener} annotated method as individual {@link ApplicationListener} - * instances. + * Registers {@link EventListener} methods as individual {@link ApplicationListener} instances. * * @author Stephane Nicoll * @author Juergen Hoeller diff --git a/spring-core/src/main/java/org/springframework/util/Base64Utils.java b/spring-core/src/main/java/org/springframework/util/Base64Utils.java index 9806852017d..a127fc5fe3d 100644 --- a/spring-core/src/main/java/org/springframework/util/Base64Utils.java +++ b/spring-core/src/main/java/org/springframework/util/Base64Utils.java @@ -39,8 +39,6 @@ public abstract class Base64Utils { * Base64-encode the given byte array. * @param src the original byte array * @return the encoded byte array - * @throws IllegalStateException if Base64 encoding between byte arrays is not - * supported, i.e. neither Java 8 nor Apache Commons Codec is present at runtime */ public static byte[] encode(byte[] src) { if (src.length == 0) { @@ -53,8 +51,6 @@ public abstract class Base64Utils { * Base64-decode the given byte array. * @param src the encoded byte array * @return the original byte array - * @throws IllegalStateException if Base64 encoding between byte arrays is not - * supported, i.e. neither Java 8 nor Apache Commons Codec is present at runtime */ public static byte[] decode(byte[] src) { if (src.length == 0) { @@ -68,8 +64,6 @@ public abstract class Base64Utils { * "URL and Filename Safe Alphabet". * @param src the original byte array * @return the encoded byte array - * @throws IllegalStateException if Base64 encoding between byte arrays is not - * supported, i.e. neither Java 8 nor Apache Commons Codec is present at runtime * @since 4.2.4 */ public static byte[] encodeUrlSafe(byte[] src) { @@ -84,8 +78,6 @@ public abstract class Base64Utils { * "URL and Filename Safe Alphabet". * @param src the encoded byte array * @return the original byte array - * @throws IllegalStateException if Base64 encoding between byte arrays is not - * supported, i.e. neither Java 8 nor Apache Commons Codec is present at runtime * @since 4.2.4 */ public static byte[] decodeUrlSafe(byte[] src) { @@ -124,8 +116,6 @@ public abstract class Base64Utils { * "URL and Filename Safe Alphabet". * @param src the original byte array * @return the encoded byte array as a UTF-8 String - * @throws IllegalStateException if Base64 encoding between byte arrays is not - * supported, i.e. neither Java 8 nor Apache Commons Codec is present at runtime */ public static String encodeToUrlSafeString(byte[] src) { return new String(encodeUrlSafe(src), DEFAULT_CHARSET); @@ -136,8 +126,6 @@ public abstract class Base64Utils { * "URL and Filename Safe Alphabet". * @param src the encoded UTF-8 String * @return the original byte array - * @throws IllegalStateException if Base64 encoding between byte arrays is not - * supported, i.e. neither Java 8 nor Apache Commons Codec is present at runtime */ public static byte[] decodeFromUrlSafeString(String src) { return decodeUrlSafe(src.getBytes(DEFAULT_CHARSET)); diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java index b4d886ca174..c3e6fb1f0c4 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java @@ -176,13 +176,15 @@ public class JdbcTemplateTests { @Test public void testStringsWithEmptyPreparedStatementArgs() throws Exception { - doTestStrings(null, null, null, null, (template, sql, rch) -> template.query(sql, (Object[]) null, rch)); + doTestStrings(null, null, null, null, + (template, sql, rch) -> template.query(sql, (Object[]) null, rch)); } @Test public void testStringsWithPreparedStatementArgs() throws Exception { final Integer argument = 99; - doTestStrings(null, null, null, argument, (template, sql, rch) -> template.query(sql, new Object[] { argument }, rch)); + doTestStrings(null, null, null, argument, + (template, sql, rch) -> template.query(sql, new Object[] {argument}, rch)); } private void doTestStrings(Integer fetchSize, Integer maxRows, Integer queryTimeout, @@ -362,10 +364,10 @@ public class JdbcTemplateTests { given(this.preparedStatement.executeUpdate()).willReturn(rowsAffected); int actualRowsAffected = this.template.update(sql, - new Object[] {4, new SqlParameterValue(Types.NUMERIC, 2, new Float(1.4142))}); + 4, new SqlParameterValue(Types.NUMERIC, 2, Float.valueOf(1.4142f))); assertTrue("Actual rows affected is correct", actualRowsAffected == rowsAffected); verify(this.preparedStatement).setObject(1, 4); - verify(this.preparedStatement).setObject(2, new Float(1.4142), Types.NUMERIC, 2); + verify(this.preparedStatement).setObject(2, Float.valueOf(1.4142f), Types.NUMERIC, 2); verify(this.preparedStatement).close(); verify(this.connection).close(); } @@ -427,8 +429,7 @@ public class JdbcTemplateTests { public void testBatchUpdateWithBatchFailure() throws Exception { final String[] sql = {"A", "B", "C", "D"}; given(this.statement.executeBatch()).willThrow( - new BatchUpdateException(new int[] { 1, Statement.EXECUTE_FAILED, 1, - Statement.EXECUTE_FAILED })); + new BatchUpdateException(new int[] {1, Statement.EXECUTE_FAILED, 1, Statement.EXECUTE_FAILED})); mockDatabaseMetaData(true); given(this.connection.createStatement()).willReturn(this.statement); @@ -495,18 +496,16 @@ public class JdbcTemplateTests { given(this.preparedStatement.executeBatch()).willReturn(rowsAffected); mockDatabaseMetaData(true); - BatchPreparedStatementSetter setter = - new BatchPreparedStatementSetter() { - @Override - public void setValues(PreparedStatement ps, int i) - throws SQLException { - ps.setInt(1, ids[i]); - } - @Override - public int getBatchSize() { - return ids.length; - } - }; + BatchPreparedStatementSetter setter = new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(1, ids[i]); + } + @Override + public int getBatchSize() { + return ids.length; + } + }; JdbcTemplate template = new JdbcTemplate(this.dataSource, false); @@ -1049,10 +1048,9 @@ public class JdbcTemplateTests { } try { - this.template.query(con -> con.prepareStatement("my query"), - (ResultSetExtractor) rs2 -> { - throw new InvalidDataAccessApiUsageException(""); - } ); + this.template.query(con -> con.prepareStatement("my query"), (ResultSetExtractor) rs2 -> { + throw new InvalidDataAccessApiUsageException(""); + }); fail("Should have thrown InvalidDataAccessApiUsageException"); } catch (InvalidDataAccessApiUsageException ex) { diff --git a/spring-tx/src/main/java/org/springframework/transaction/event/TransactionalEventListenerFactory.java b/spring-tx/src/main/java/org/springframework/transaction/event/TransactionalEventListenerFactory.java index 19d5ab82f86..57aae2b1340 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/event/TransactionalEventListenerFactory.java +++ b/spring-tx/src/main/java/org/springframework/transaction/event/TransactionalEventListenerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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,11 +21,11 @@ import java.lang.reflect.Method; import org.springframework.context.ApplicationListener; import org.springframework.context.event.EventListenerFactory; import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.AnnotatedElementUtils; /** * {@link EventListenerFactory} implementation that handles {@link TransactionalEventListener} - * annotated method. + * annotated methods. * * @author Stephane Nicoll * @since 4.2 @@ -47,7 +47,7 @@ public class TransactionalEventListenerFactory implements EventListenerFactory, @Override public boolean supportsMethod(Method method) { - return (AnnotationUtils.findAnnotation(method, TransactionalEventListener.class) != null); + return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class); } @Override diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java index 00bc01eb779..368cd5a83c5 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java @@ -32,13 +32,14 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.MethodIntrospector; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.http.codec.HttpMessageReader; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.ReflectionUtils; +import org.springframework.util.ReflectionUtils.MethodFilter; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; @@ -50,12 +51,11 @@ import org.springframework.web.reactive.result.method.InvocableHandlerMethod; import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; import org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod; -import static org.springframework.core.MethodIntrospector.*; - /** * Package-private class to assist {@link RequestMappingHandlerAdapter} with * resolving, initializing, and caching annotated methods declared in - * {@code @Controller} and {@code @ControllerAdvice} components: + * {@code @Controller} and {@code @ControllerAdvice} components. Assists with + * the following annotations: *
    *
  • {@code @InitBinder} *
  • {@code @ModelAttribute} @@ -68,9 +68,22 @@ import static org.springframework.core.MethodIntrospector.*; */ class ControllerMethodResolver { - private static Log logger = LogFactory.getLog(ControllerMethodResolver.class); + /** + * MethodFilter that matches {@link InitBinder @InitBinder} methods. + */ + private static final MethodFilter INIT_BINDER_METHODS = method -> + (AnnotationUtils.findAnnotation(method, InitBinder.class) != null); + + /** + * MethodFilter that matches {@link ModelAttribute @ModelAttribute} methods. + */ + private static final MethodFilter MODEL_ATTRIBUTE_METHODS = method -> + (AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) && + (AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null); + private static Log logger = LogFactory.getLog(ControllerMethodResolver.class); + private final List initBinderResolvers; private final List modelAttributeResolvers; @@ -204,7 +217,6 @@ class ControllerMethodResolver { } private void initControllerAdviceCaches(ApplicationContext applicationContext) { - if (logger.isInfoEnabled()) { logger.info("Looking for @ControllerAdvice: " + applicationContext); } @@ -215,14 +227,14 @@ class ControllerMethodResolver { for (ControllerAdviceBean bean : beans) { Class beanType = bean.getBeanType(); if (beanType != null) { - Set attrMethods = selectMethods(beanType, ATTRIBUTE_METHODS); + Set attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { this.modelAttributeAdviceCache.put(bean, attrMethods); if (logger.isInfoEnabled()) { logger.info("Detected @ModelAttribute methods in " + bean); } } - Set binderMethods = selectMethods(beanType, BINDER_METHODS); + Set binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(bean, binderMethods); if (logger.isInfoEnabled()) { @@ -269,7 +281,8 @@ class ControllerMethodResolver { }); this.initBinderMethodCache - .computeIfAbsent(handlerType, aClass -> selectMethods(handlerType, BINDER_METHODS)) + .computeIfAbsent(handlerType, + clazz -> MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS)) .forEach(method -> { Object bean = handlerMethod.getBean(); result.add(getInitBinderMethod(bean, method)); @@ -301,7 +314,8 @@ class ControllerMethodResolver { }); this.modelAttributeMethodCache - .computeIfAbsent(handlerType, aClass -> selectMethods(handlerType, ATTRIBUTE_METHODS)) + .computeIfAbsent(handlerType, + clazz -> MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS)) .forEach(method -> { Object bean = handlerMethod.getBean(); result.add(createAttributeMethod(bean, method)); @@ -372,14 +386,4 @@ class ControllerMethodResolver { return result; } - - /** Filter for {@link InitBinder @InitBinder} methods. */ - private static final ReflectionUtils.MethodFilter BINDER_METHODS = method -> - AnnotationUtils.findAnnotation(method, InitBinder.class) != null; - - /** Filter for {@link ModelAttribute @ModelAttribute} methods. */ - private static final ReflectionUtils.MethodFilter ATTRIBUTE_METHODS = method -> - (AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) && - (AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null); - } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java index 0945146f3d8..19439aea5c0 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java @@ -114,6 +114,20 @@ import org.springframework.web.util.WebUtils; public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { + /** + * MethodFilter that matches {@link InitBinder @InitBinder} methods. + */ + public static final MethodFilter INIT_BINDER_METHODS = method -> + (AnnotationUtils.findAnnotation(method, InitBinder.class) != null); + + /** + * MethodFilter that matches {@link ModelAttribute @ModelAttribute} methods. + */ + public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method -> + ((AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) && + (AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null)); + + @Nullable private List customArgumentResolvers; @@ -1002,18 +1016,4 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter return mav; } - - /** - * MethodFilter that matches {@link InitBinder @InitBinder} methods. - */ - public static final MethodFilter INIT_BINDER_METHODS = method -> - AnnotationUtils.findAnnotation(method, InitBinder.class) != null; - - /** - * MethodFilter that matches {@link ModelAttribute @ModelAttribute} methods. - */ - public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method -> - ((AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) && - (AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null)); - } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HandlerMethodAnnotationDetectionTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HandlerMethodAnnotationDetectionTests.java index f0e4e976a1b..64c9d9c1e9f 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HandlerMethodAnnotationDetectionTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HandlerMethodAnnotationDetectionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -66,31 +66,29 @@ public class HandlerMethodAnnotationDetectionTests { @Parameters(name = "controller [{0}], auto-proxy [{1}]") public static Object[][] handlerTypes() { return new Object[][] { + { SimpleController.class, true }, // CGLIB proxy + { SimpleController.class, false }, - { SimpleController.class, true }, // CGLib proxy - { SimpleController.class, false }, + { AbstractClassController.class, true }, // CGLIB proxy + { AbstractClassController.class, false }, - { AbstractClassController.class, true }, // CGLib proxy - { AbstractClassController.class, false }, + { ParameterizedAbstractClassController.class, true }, // CGLIB proxy + { ParameterizedAbstractClassController.class, false }, - { ParameterizedAbstractClassController.class, true }, // CGLib proxy - { ParameterizedAbstractClassController.class, false }, + { ParameterizedSubclassOverridesDefaultMappings.class, true }, // CGLIB proxy + { ParameterizedSubclassOverridesDefaultMappings.class, false }, - { ParameterizedSubclassOverridesDefaultMappings.class, true }, // CGLib proxy - { ParameterizedSubclassOverridesDefaultMappings.class, false }, + // TODO [SPR-9517] Enable ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass test cases + // { ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass.class, true }, // CGLIB proxy + // { ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass.class, false }, - // TODO [SPR-9517] Enable ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass test cases - // { ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass.class, true }, // CGLib proxy - // { ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass.class, false }, + { InterfaceController.class, true }, // JDK dynamic proxy + { InterfaceController.class, false }, - { InterfaceController.class, true }, // JDK dynamic proxy - { InterfaceController.class, false }, - - { ParameterizedInterfaceController.class, false }, // no AOP - - { SupportClassController.class, true }, // CGLib proxy - { SupportClassController.class, false } + { ParameterizedInterfaceController.class, false }, // no AOP + { SupportClassController.class, true }, // CGLIB proxy + { SupportClassController.class, false } }; } @@ -100,7 +98,8 @@ public class HandlerMethodAnnotationDetectionTests { private ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver(); - public HandlerMethodAnnotationDetectionTests(final Class controllerType, boolean useAutoProxy) { + + public HandlerMethodAnnotationDetectionTests(Class controllerType, boolean useAutoProxy) { GenericWebApplicationContext context = new GenericWebApplicationContext(); context.registerBeanDefinition("controller", new RootBeanDefinition(controllerType)); context.registerBeanDefinition("handlerMapping", new RootBeanDefinition(RequestMappingHandlerMapping.class)); @@ -120,12 +119,6 @@ public class HandlerMethodAnnotationDetectionTests { context.close(); } - class TestPointcut extends StaticMethodMatcherPointcut { - @Override - public boolean matches(Method method, @Nullable Class clazz) { - return method.getName().equals("hashCode"); - } - } @Test public void testRequestMappingMethod() throws Exception { @@ -203,9 +196,9 @@ public class HandlerMethodAnnotationDetectionTests { public abstract String handleException(Exception exception); } + /** * CONTROLLER WITH ABSTRACT CLASS - * *

    All annotations can be on methods in the abstract class except parameter annotations. */ static class AbstractClassController extends MappingAbstractClass { @@ -232,10 +225,10 @@ public class HandlerMethodAnnotationDetectionTests { } } - // SPR-9374 + // SPR-9374 @RequestMapping - static interface MappingInterface { + interface MappingInterface { @InitBinder void initBinder(WebDataBinder dataBinder, @RequestParam("datePattern") String thePattern); @@ -252,14 +245,11 @@ public class HandlerMethodAnnotationDetectionTests { String handleException(Exception exception); } + /** * CONTROLLER WITH INTERFACE - * - * JDK Dynamic proxy: - * All annotations must be on the interface. - * - * Without AOP: - * Annotations can be on interface methods except parameter annotations. + *

    JDK Dynamic proxy: All annotations must be on the interface. + *

    Without AOP: Annotations can be on interface methods except parameter annotations. */ static class InterfaceController implements MappingInterface { @@ -304,9 +294,9 @@ public class HandlerMethodAnnotationDetectionTests { public abstract String handleException(Exception exception); } + /** * CONTROLLER WITH PARAMETERIZED BASE CLASS - * *

    All annotations can be on methods in the abstract class except parameter annotations. */ static class ParameterizedAbstractClassController extends MappingGenericAbstractClass { @@ -333,6 +323,7 @@ public class HandlerMethodAnnotationDetectionTests { } } + @Controller static abstract class MappedGenericAbstractClassWithConcreteImplementations { @@ -353,6 +344,7 @@ public class HandlerMethodAnnotationDetectionTests { public abstract String handleException(Exception exception); } + static class ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass extends MappedGenericAbstractClassWithConcreteImplementations { @@ -375,6 +367,7 @@ public class HandlerMethodAnnotationDetectionTests { } } + @Controller static abstract class GenericAbstractClassDeclaresDefaultMappings { @@ -395,6 +388,7 @@ public class HandlerMethodAnnotationDetectionTests { public abstract String handleException(Exception exception); } + static class ParameterizedSubclassOverridesDefaultMappings extends GenericAbstractClassDeclaresDefaultMappings { @@ -425,8 +419,9 @@ public class HandlerMethodAnnotationDetectionTests { } } + @RequestMapping - static interface MappingGenericInterface { + interface MappingGenericInterface { @InitBinder void initBinder(WebDataBinder dataBinder, A thePattern); @@ -443,11 +438,10 @@ public class HandlerMethodAnnotationDetectionTests { String handleException(Exception exception); } + /** * CONTROLLER WITH PARAMETERIZED INTERFACE - * *

    All annotations can be on interface except parameter annotations. - * *

    Cannot be used as JDK dynamic proxy since parameterized interface does not contain type information. */ static class ParameterizedInterfaceController implements MappingGenericInterface { @@ -483,7 +477,6 @@ public class HandlerMethodAnnotationDetectionTests { /** * SPR-8248 - * *

    Support class contains all annotations. Subclass has type-level @{@link RequestMapping}. */ @Controller diff --git a/src/test/java/org/springframework/cache/annotation/EnableCachingIntegrationTests.java b/src/test/java/org/springframework/cache/annotation/EnableCachingIntegrationTests.java index bf16d0cdd75..d23b77d757a 100644 --- a/src/test/java/org/springframework/cache/annotation/EnableCachingIntegrationTests.java +++ b/src/test/java/org/springframework/cache/annotation/EnableCachingIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -70,6 +70,7 @@ public class EnableCachingIntegrationTests { } } + private void assertCacheProxying(AnnotationConfigApplicationContext ctx) { FooRepository repo = ctx.getBean(FooRepository.class); @@ -89,6 +90,7 @@ public class EnableCachingIntegrationTests { @Configuration @EnableCaching(proxyTargetClass=true) static class ProxyTargetClassCachingConfig { + @Bean CacheManager mgr() { return new NoOpCacheManager(); @@ -98,6 +100,7 @@ public class EnableCachingIntegrationTests { @Configuration static class Config { + @Bean FooRepository fooRepository() { return new DummyFooRepository(); @@ -108,6 +111,7 @@ public class EnableCachingIntegrationTests { @Configuration @EnableCaching(mode=AdviceMode.ASPECTJ) static class AspectJCacheConfig { + @Bean CacheManager cacheManager() { return new NoOpCacheManager(); @@ -116,6 +120,7 @@ public class EnableCachingIntegrationTests { interface FooRepository { + List findAll(); } @@ -129,4 +134,5 @@ public class EnableCachingIntegrationTests { return Collections.emptyList(); } } + } diff --git a/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementIntegrationTests.java b/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementIntegrationTests.java index fde5359d9a4..e4660945433 100644 --- a/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementIntegrationTests.java +++ b/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -16,20 +16,14 @@ package org.springframework.transaction.annotation; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - import java.util.ArrayList; import java.util.Collections; import java.util.List; - import javax.sql.DataSource; import org.junit.Ignore; import org.junit.Test; + import org.springframework.aop.Advisor; import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; @@ -50,6 +44,9 @@ import org.springframework.tests.transaction.CallCountingTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + /** * Integration tests for the @EnableTransactionManagement annotation. * @@ -169,10 +166,30 @@ public class EnableTransactionManagementIntegrationTests { } + private void assertTxProxying(AnnotationConfigApplicationContext ctx) { + FooRepository repo = ctx.getBean(FooRepository.class); + + boolean isTxProxy = false; + if (AopUtils.isAopProxy(repo)) { + for (Advisor advisor : ((Advised)repo).getAdvisors()) { + if (advisor instanceof BeanFactoryTransactionAttributeSourceAdvisor) { + isTxProxy = true; + break; + } + } + } + assertTrue("FooRepository is not a TX proxy", isTxProxy); + + // trigger a transaction + repo.findAll(); + } + + @Configuration @EnableTransactionManagement @ImportResource("org/springframework/transaction/annotation/enable-caching.xml") static class EnableTxAndCachingConfig { + @Bean public PlatformTransactionManager txManager() { return new CallCountingTransactionManager(); @@ -197,6 +214,7 @@ public class EnableTransactionManagementIntegrationTests { @Configuration @EnableTransactionManagement static class ImplicitTxManagerConfig { + @Bean public PlatformTransactionManager txManager() { return new CallCountingTransactionManager(); @@ -212,6 +230,7 @@ public class EnableTransactionManagementIntegrationTests { @Configuration @EnableTransactionManagement static class ExplicitTxManagerConfig implements TransactionManagementConfigurer { + @Bean public PlatformTransactionManager txManager1() { return new CallCountingTransactionManager(); @@ -233,28 +252,11 @@ public class EnableTransactionManagementIntegrationTests { } } - private void assertTxProxying(AnnotationConfigApplicationContext ctx) { - FooRepository repo = ctx.getBean(FooRepository.class); - - boolean isTxProxy = false; - if (AopUtils.isAopProxy(repo)) { - for (Advisor advisor : ((Advised)repo).getAdvisors()) { - if (advisor instanceof BeanFactoryTransactionAttributeSourceAdvisor) { - isTxProxy = true; - break; - } - } - } - assertTrue("FooRepository is not a TX proxy", isTxProxy); - - // trigger a transaction - repo.findAll(); - } - @Configuration @EnableTransactionManagement static class DefaultTxManagerNameConfig { + @Bean PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); @@ -265,6 +267,7 @@ public class EnableTransactionManagementIntegrationTests { @Configuration @EnableTransactionManagement static class CustomTxManagerNameConfig { + @Bean PlatformTransactionManager txManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); @@ -275,6 +278,7 @@ public class EnableTransactionManagementIntegrationTests { @Configuration @EnableTransactionManagement static class NonConventionalTxManagerNameConfig { + @Bean PlatformTransactionManager txManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); @@ -285,6 +289,7 @@ public class EnableTransactionManagementIntegrationTests { @Configuration @EnableTransactionManagement(proxyTargetClass=true) static class ProxyTargetClassTxConfig { + @Bean PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); @@ -295,6 +300,7 @@ public class EnableTransactionManagementIntegrationTests { @Configuration @EnableTransactionManagement(mode=AdviceMode.ASPECTJ) static class AspectJTxConfig { + @Bean PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); @@ -304,6 +310,7 @@ public class EnableTransactionManagementIntegrationTests { @Configuration static class Config { + @Bean FooRepository fooRepository() { JdbcFooRepository repos = new JdbcFooRepository(); @@ -321,6 +328,7 @@ public class EnableTransactionManagementIntegrationTests { interface FooRepository { + List findAll(); } @@ -338,6 +346,7 @@ public class EnableTransactionManagementIntegrationTests { } } + @Repository static class DummyFooRepository implements FooRepository { @@ -347,4 +356,5 @@ public class EnableTransactionManagementIntegrationTests { return Collections.emptyList(); } } + }