From 4a57e26d76bf6263098785bcc050e4bf7c29212c Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sun, 7 Jan 2018 23:33:35 +0100 Subject: [PATCH] Polishing --- .../AutowiredAnnotationBeanPostProcessor.java | 4 +- ...wiredAnnotationBeanPostProcessorTests.java | 48 ++++++++++++++-- .../xml/XmlBeanDefinitionReaderTests.java | 11 ++-- .../spel/ast/ConstructorReference.java | 6 +- .../expression/spel/ast/SpelNodeImpl.java | 11 ++-- .../spel/SpelCompilationCoverageTests.java | 7 ++- ...tenerAnnotationBeanPostProcessorTests.java | 56 ++++++++++++++++--- .../web/reactive/server/HeaderAssertions.java | 11 ++-- .../web/server/ServerWebExchange.java | 4 +- .../adapter/DefaultServerWebExchange.java | 4 +- src/docs/asciidoc/testing.adoc | 19 ++----- 11 files changed, 124 insertions(+), 57 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index d3810f4e8b..92fc4f2b20 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.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. @@ -280,7 +280,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean "Resolution of declared constructors on bean Class [" + beanClass.getName() + "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex); } - List> candidates = new ArrayList>(rawCandidates.length); + List> candidates = new ArrayList<>(rawCandidates.length); Constructor requiredConstructor = null; Constructor defaultConstructor = null; Constructor primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java index a374b1e65f..463dba2ed0 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.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. @@ -43,6 +43,7 @@ import org.mockito.Mockito; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; @@ -152,6 +153,35 @@ public class AutowiredAnnotationBeanPostProcessorTests { assertEquals("nestedTestBean", depBeans[1]); } + @Test + public void testExtendedResourceInjectionWithDestruction() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerResolvableDependency(BeanFactory.class, bf); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(TypedExtendedResourceInjectionBean.class)); + bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class)); + NestedTestBean ntb = new NestedTestBean(); + bf.registerSingleton("nestedTestBean", ntb); + + TestBean tb = bf.getBean("testBean", TestBean.class); + TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean"); + assertSame(tb, bean.getTestBean()); + assertSame(tb, bean.getTestBean2()); + assertSame(tb, bean.getTestBean3()); + assertSame(tb, bean.getTestBean4()); + assertSame(ntb, bean.getNestedTestBean()); + assertSame(bf, bean.getBeanFactory()); + + assertArrayEquals(new String[] {"testBean", "nestedTestBean"}, bf.getDependenciesForBean("annotatedBean")); + bf.destroySingleton("testBean"); + assertFalse(bf.containsSingleton("testBean")); + assertFalse(bf.containsSingleton("annotatedBean")); + assertTrue(bean.destroyed); + assertSame(0, bf.getDependenciesForBean("annotatedBean").length); + } + @Test public void testExtendedResourceInjectionWithOverriding() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -1286,9 +1316,6 @@ public class AutowiredAnnotationBeanPostProcessorTests { bf.destroySingletons(); } - @Qualifier("testBean") - private void testBeanQualifierProvider() {} - @Test public void testObjectFactorySerialization() throws Exception { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -2494,6 +2521,9 @@ public class AutowiredAnnotationBeanPostProcessorTests { } + @Qualifier("testBean") + private void testBeanQualifierProvider() {} + @Qualifier("integerRepo") private Repository integerRepositoryQualifierProvider; @@ -2579,7 +2609,15 @@ public class AutowiredAnnotationBeanPostProcessorTests { } - public static class TypedExtendedResourceInjectionBean extends NonPublicResourceInjectionBean { + public static class TypedExtendedResourceInjectionBean extends NonPublicResourceInjectionBean + implements DisposableBean { + + public boolean destroyed = false; + + @Override + public void destroy() { + this.destroyed = true; + } } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java index f2fda4c2b0..213b566290 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.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. @@ -49,8 +49,7 @@ public class XmlBeanDefinitionReaderTests { @Test(expected = BeanDefinitionStoreException.class) public void withOpenInputStream() { SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry(); - Resource resource = new InputStreamResource(getClass().getResourceAsStream( - "test.xml")); + Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml")); new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource); } @@ -122,16 +121,16 @@ public class XmlBeanDefinitionReaderTests { } @Test - public void dtdValidationAutodetect() throws Exception { + public void dtdValidationAutodetect() { doTestValidation("validateWithDtd.xml"); } @Test - public void xsdValidationAutodetect() throws Exception { + public void xsdValidationAutodetect() { doTestValidation("validateWithXsd.xml"); } - private void doTestValidation(String resourceName) throws Exception { + private void doTestValidation(String resourceName) { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); Resource resource = new ClassPathResource(resourceName, getClass()); new XmlBeanDefinitionReader(factory).loadBeanDefinitions(resource); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java index bcc3bc901e..76762beeac 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.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. @@ -458,8 +458,8 @@ public class ConstructorReference extends SpelNodeImpl { mv.visitInsn(DUP); // children[0] is the type of the constructor, don't want to include that in argument processing - SpelNodeImpl[] arguments = new SpelNodeImpl[children.length - 1]; - System.arraycopy(children, 1, arguments, 0, children.length - 1); + SpelNodeImpl[] arguments = new SpelNodeImpl[this.children.length - 1]; + System.arraycopy(this.children, 1, arguments, 0, this.children.length - 1); generateCodeForArguments(mv, cf, constructor, arguments); mv.visitMethodInsn(INVOKESPECIAL, classDesc, "", CodeFlow.createSignatureDescriptor(constructor), false); cf.pushDescriptor(this.exitTypeDescriptor); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java index 21719576b6..06a843f483 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.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. @@ -39,6 +39,7 @@ import org.springframework.util.ObjectUtils; * format expression. * * @author Andy Clement + * @author Juergen Hoeller * @since 3.0 */ public abstract class SpelNodeImpl implements SpelNode, Opcodes { @@ -46,7 +47,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { private static SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0]; - protected int pos; // start = top 16bits, end = bottom 16bits + protected int pos; // start = top 16bits, end = bottom 16bits protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN; @@ -81,7 +82,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { /** - * @return true if the next child is one of the specified classes + * Return {@code true} if the next child is one of the specified classes. */ protected boolean nextChildIs(Class... clazzes) { if (this.parent != null) { @@ -123,8 +124,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { @Override public void setValue(ExpressionState expressionState, @Nullable Object newValue) throws EvaluationException { - throw new SpelEvaluationException(getStartPosition(), - SpelMessage.SETVALUE_NOT_SUPPORTED, getClass()); + throw new SpelEvaluationException(getStartPosition(), SpelMessage.SETVALUE_NOT_SUPPORTED, getClass()); } @Override @@ -281,4 +281,5 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { } cf.exitCompilationScope(); } + } diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java index c558ed4151..6e0addf839 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.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. @@ -4988,7 +4988,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { } @Override - public void generateCode(String propertyName, MethodVisitor mv,CodeFlow cf) { + public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) { if (method == null) { try { method = Payload2.class.getDeclaredMethod("getField", String.class); @@ -5005,7 +5005,8 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor); } mv.visitLdcInsn(propertyName); - mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(),CodeFlow.createSignatureDescriptor(method),false); + mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(), + CodeFlow.createSignatureDescriptor(method), false); } } diff --git a/spring-jms/src/test/java/org/springframework/jms/annotation/JmsListenerAnnotationBeanPostProcessorTests.java b/spring-jms/src/test/java/org/springframework/jms/annotation/JmsListenerAnnotationBeanPostProcessorTests.java index 46a8f9fedc..90ff30d307 100644 --- a/spring-jms/src/test/java/org/springframework/jms/annotation/JmsListenerAnnotationBeanPostProcessorTests.java +++ b/spring-jms/src/test/java/org/springframework/jms/annotation/JmsListenerAnnotationBeanPostProcessorTests.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. @@ -39,6 +39,7 @@ import org.springframework.jms.config.JmsListenerEndpointRegistry; import org.springframework.jms.config.MessageListenerTestContainer; import org.springframework.jms.config.MethodJmsListenerEndpoint; import org.springframework.jms.listener.SimpleMessageListenerContainer; +import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; @@ -108,9 +109,9 @@ public class JmsListenerAnnotationBeanPostProcessorTests { } @Test - public void sendToAnnotationFoundOnProxy() throws Exception { + public void sendToAnnotationFoundOnInterfaceProxy() throws Exception { ConfigurableApplicationContext context = new AnnotationConfigApplicationContext( - Config.class, ProxyConfig.class, ProxyTestBean.class); + Config.class, ProxyConfig.class, InterfaceProxyTestBean.class); try { JmsListenerContainerTestFactory factory = context.getBean(JmsListenerContainerTestFactory.class); assertEquals("one container should have been registered", 1, factory.getListenerContainers().size()); @@ -120,8 +121,34 @@ public class JmsListenerAnnotationBeanPostProcessorTests { MethodJmsListenerEndpoint methodEndpoint = (MethodJmsListenerEndpoint) endpoint; assertTrue(AopUtils.isJdkDynamicProxy(methodEndpoint.getBean())); assertTrue(methodEndpoint.getBean() instanceof SimpleService); - assertEquals(SimpleService.class.getMethod("handleIt", String.class), methodEndpoint.getMethod()); - assertEquals(ProxyTestBean.class.getMethod("handleIt", String.class), methodEndpoint.getMostSpecificMethod()); + assertEquals(SimpleService.class.getMethod("handleIt", String.class, String.class), methodEndpoint.getMethod()); + assertEquals(InterfaceProxyTestBean.class.getMethod("handleIt", String.class, String.class), methodEndpoint.getMostSpecificMethod()); + + Method m = ReflectionUtils.findMethod(endpoint.getClass(), "getDefaultResponseDestination"); + ReflectionUtils.makeAccessible(m); + Object destination = ReflectionUtils.invokeMethod(m, endpoint); + assertEquals("SendTo annotation not found on proxy", "foobar", destination); + } + finally { + context.close(); + } + } + + @Test + public void sendToAnnotationFoundOnCglibProxy() throws Exception { + ConfigurableApplicationContext context = new AnnotationConfigApplicationContext( + Config.class, ProxyConfig.class, ClassProxyTestBean.class); + try { + JmsListenerContainerTestFactory factory = context.getBean(JmsListenerContainerTestFactory.class); + assertEquals("one container should have been registered", 1, factory.getListenerContainers().size()); + + JmsListenerEndpoint endpoint = factory.getListenerContainers().get(0).getEndpoint(); + assertEquals("Wrong endpoint type", MethodJmsListenerEndpoint.class, endpoint.getClass()); + MethodJmsListenerEndpoint methodEndpoint = (MethodJmsListenerEndpoint) endpoint; + assertTrue(AopUtils.isCglibProxy(methodEndpoint.getBean())); + assertTrue(methodEndpoint.getBean() instanceof ClassProxyTestBean); + assertEquals(ClassProxyTestBean.class.getMethod("handleIt", String.class, String.class), methodEndpoint.getMethod()); + assertEquals(ClassProxyTestBean.class.getMethod("handleIt", String.class, String.class), methodEndpoint.getMostSpecificMethod()); Method m = ReflectionUtils.findMethod(endpoint.getClass(), "getDefaultResponseDestination"); ReflectionUtils.makeAccessible(m); @@ -204,18 +231,29 @@ public class JmsListenerAnnotationBeanPostProcessorTests { interface SimpleService { - void handleIt(String body); + void handleIt(String value, String body); } @Component - static class ProxyTestBean implements SimpleService { + static class InterfaceProxyTestBean implements SimpleService { @Override @Transactional @JmsListener(destination = "testQueue") @SendTo("foobar") - public void handleIt(String body) { + public void handleIt(@Header String value, String body) { + } + } + + + @Component + static class ClassProxyTestBean { + + @Transactional + @JmsListener(destination = "testQueue") + @SendTo("foobar") + public void handleIt(@Header String value, String body) { } } @@ -224,7 +262,7 @@ public class JmsListenerAnnotationBeanPostProcessorTests { static class InvalidProxyTestBean implements SimpleService { @Override - public void handleIt(String body) { + public void handleIt(String value, String body) { } @Transactional diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java index 6c726e3f93..08617d179c 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.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. @@ -25,9 +25,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.lang.Nullable; -import static org.springframework.test.util.AssertionErrors.assertEquals; -import static org.springframework.test.util.AssertionErrors.assertTrue; -import static org.springframework.test.util.AssertionErrors.fail; +import static org.springframework.test.util.AssertionErrors.*; /** * Assertions on headers of the response. @@ -125,10 +123,9 @@ public class HeaderAssertions { */ public WebTestClient.ResponseSpec contentTypeCompatibleWith(MediaType mediaType) { MediaType actual = getHeaders().getContentType(); - String message = getMessage("Content-Type") + "=[" + actual.toString() + "]" - + " is not compatible with [" + mediaType.toString() + "]"; + String message = getMessage("Content-Type") + "=[" + actual + "] is not compatible with [" + mediaType + "]"; this.exchangeResult.assertWithDiagnostics(() -> - assertTrue(message, actual.isCompatibleWith(mediaType))); + assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType)))); return this.responseSpec; } diff --git a/spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java b/spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java index 7acd1f4b51..905e21d378 100644 --- a/spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java +++ b/spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.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. @@ -142,8 +142,8 @@ public interface ServerWebExchange { * if it was initialized with one via * {@link org.springframework.web.server.adapter.WebHttpHandlerBuilder#applicationContext * WebHttpHandlerBuilder#applicationContext}. - * @see org.springframework.web.server.adapter.WebHttpHandlerBuilder#applicationContext(ApplicationContext) * @since 5.0.3 + * @see org.springframework.web.server.adapter.WebHttpHandlerBuilder#applicationContext(ApplicationContext) */ @Nullable ApplicationContext getApplicationContext(); diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java b/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java index 74bf53b338..c4a136ed28 100644 --- a/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java +++ b/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.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. @@ -219,6 +219,7 @@ public class DefaultServerWebExchange implements ServerWebExchange { } @Override + @Nullable public ApplicationContext getApplicationContext() { return this.applicationContext; } @@ -354,5 +355,4 @@ public class DefaultServerWebExchange implements ServerWebExchange { this.urlTransformer = this.urlTransformer.andThen(transformer); } - } diff --git a/src/docs/asciidoc/testing.adoc b/src/docs/asciidoc/testing.adoc index e24f1c61e2..09a523bab8 100644 --- a/src/docs/asciidoc/testing.adoc +++ b/src/docs/asciidoc/testing.adoc @@ -3142,15 +3142,14 @@ framework. ---- - + - + @@ -3179,12 +3178,10 @@ inputs for the username and password. @Test public void requestScope() { - request.setParameter("user", "enigma"); request.setParameter("pswd", "$pr!ng"); LoginResults results = userService.loginUser(); - // assert results } } @@ -3203,15 +3200,13 @@ framework. ---- - - - + @@ -3239,11 +3234,9 @@ configured theme. @Test public void sessionScope() throws Exception { - session.setAttribute("theme", "blue"); Results results = userService.processUserPreferences(); - // assert results } }