From bc80d25b490a540c36ce4265d1ebaad11b679138 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 25 Jan 2013 16:38:30 -0800 Subject: [PATCH 01/12] Restore compile dependencies in generated POMs Ensure that merge projects do not downgrade the compile time dependencies of the projects that they are merged into. This commit restores the scope of the following dependencies which were inadvertently changed between Spring 3.2.0 and 3.2.1: spring-orm -> spring-tx -> spring-jdbc spring-webmvc -> spring-context -> spring-web spring-test -> spring-webmvc Issue: SPR-10218 --- build.gradle | 2 +- .../org/springframework/build/gradle/MergePlugin.groovy | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 19fe164e4dc..9ac71e790ab 100644 --- a/build.gradle +++ b/build.gradle @@ -689,7 +689,7 @@ project("spring-test-mvc") { description = "Spring Test MVC Framework" merge.into = project(":spring-test") dependencies { - provided(project(":spring-context")) + optional(project(":spring-context")) provided(project(":spring-webmvc")) provided("javax.servlet:javax.servlet-api:3.0.1") optional("org.hamcrest:hamcrest-core:1.3") diff --git a/buildSrc/src/main/groovy/org/springframework/build/gradle/MergePlugin.groovy b/buildSrc/src/main/groovy/org/springframework/build/gradle/MergePlugin.groovy index 097e65ab93c..510a2698c6a 100644 --- a/buildSrc/src/main/groovy/org/springframework/build/gradle/MergePlugin.groovy +++ b/buildSrc/src/main/groovy/org/springframework/build/gradle/MergePlugin.groovy @@ -128,7 +128,13 @@ class MergePlugin implements Plugin { (ExcludeRule.GROUP_KEY) : it.group, (ExcludeRule.MODULE_KEY) : it.module]) } - intoConfiguration.dependencies.addAll(configuration.dependencies) + configuration.dependencies.each { + def intoCompile = project.merge.into.configurations.getByName("compile") + // Protect against changing a compile scope dependency (SPR-10218) + if(!intoCompile.dependencies.contains(it)) { + intoConfiguration.dependencies.add(it) + } + } project.merge.into.install.repositories.mavenInstaller.pom.scopeMappings.addMapping( mapping.priority + 100, intoConfiguration, mapping.scope) } From b8e7314c433123be0e7b9eadcdc64be841116c82 Mon Sep 17 00:00:00 2001 From: Ken Dombeck Date: Fri, 25 Jan 2013 14:13:25 -0600 Subject: [PATCH 02/12] Fix typo in new-in-3.2.xml document This commit fixes a typo in the "New Features and Enhancements in Spring Framework 3.2" chapter of the reference manual. Specifically, ContentNegotiationStrategy is now spelled correctly. --- src/reference/docbook/new-in-3.2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reference/docbook/new-in-3.2.xml b/src/reference/docbook/new-in-3.2.xml index 1f3d04e3ba4..4ffd3cf6cdf 100644 --- a/src/reference/docbook/new-in-3.2.xml +++ b/src/reference/docbook/new-in-3.2.xml @@ -57,7 +57,7 @@
Content negotiation improvements - A ContentNeogtiationStrategy is now + A ContentNegotiationStrategy is now available for resolving the requested media types from an incoming request. The available implementations are based on the file extension, query parameter, the 'Accept' header, or a fixed content type. From ac881066767bd7c1e840198f51ab0e3e7aedbe99 Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Mon, 28 Jan 2013 10:28:14 -0600 Subject: [PATCH 03/12] Sort maven dependencies in generated pom files Previously the maven dependencies were specified in an arbitrary order which made comparing the poms against other versions difficult. This commit sorts the dependencies by scope, group id, and then artifact id. --- gradle/publish-maven.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gradle/publish-maven.gradle b/gradle/publish-maven.gradle index 528e78c15d5..d47098b4f12 100644 --- a/gradle/publish-maven.gradle +++ b/gradle/publish-maven.gradle @@ -13,6 +13,11 @@ def customizePom(pom, gradleProject) { dep.scope == "test" } + // sort to make pom dependencies order consistent to ease comparison of older poms + generatedPom.dependencies = generatedPom.dependencies.sort { dep -> + "$dep.scope:$dep.groupId:$dep.artifactId" + } + // add all items necessary for maven central publication generatedPom.project { name = gradleProject.description From 321004143b0941a10be10edd665c843ec1ab7967 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 29 Jan 2013 17:48:14 +0100 Subject: [PATCH 04/12] Improve Javadoc for ContextLoaderUtils - class-level Javadoc now mentions application context initializers. - avoided and suppressed warnings in method-level Javadoc. Issue: SPR-10232 --- .../test/context/ContextLoaderUtils.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java b/spring-test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java index 47ee0c78cf0..8016c5d7c77 100644 --- a/spring-test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -41,7 +41,8 @@ import org.springframework.util.StringUtils; /** * Utility methods for working with {@link ContextLoader ContextLoaders} and * {@link SmartContextLoader SmartContextLoaders} and resolving resource locations, - * annotated classes, and active bean definition profiles. + * annotated classes, active bean definition profiles, and application context + * initializers. * * @author Sam Brannen * @since 3.1 @@ -50,6 +51,7 @@ import org.springframework.util.StringUtils; * @see ContextConfiguration * @see ContextConfigurationAttributes * @see ActiveProfiles + * @see ApplicationContextInitializer * @see MergedContextConfiguration */ abstract class ContextLoaderUtils { @@ -78,7 +80,7 @@ abstract class ContextLoaderUtils { * either {@value #DEFAULT_CONTEXT_LOADER_CLASS_NAME} * or {@value #DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME} will be used as the * default context loader class name. For details on the class resolution - * process, see {@link #resolveContextLoaderClass()}. + * process, see {@link #resolveContextLoaderClass}. * * @param testClass the test class for which the {@code ContextLoader} * should be resolved; must not be {@code null} @@ -89,8 +91,9 @@ abstract class ContextLoaderUtils { * {@code ContextLoader} class to use; may be {@code null} or empty * @return the resolved {@code ContextLoader} for the supplied * {@code testClass} (never {@code null}) - * @see #resolveContextLoaderClass() + * @see #resolveContextLoaderClass */ + @SuppressWarnings("javadoc") static ContextLoader resolveContextLoader(Class testClass, List configAttributesList, String defaultContextLoaderClassName) { Assert.notNull(testClass, "Class must not be null"); @@ -348,11 +351,11 @@ abstract class ContextLoaderUtils { * @param defaultContextLoaderClassName the name of the default * {@code ContextLoader} class to use (may be {@code null}) * @return the merged context configuration - * @see #resolveContextLoader() - * @see #resolveContextConfigurationAttributes() - * @see SmartContextLoader#processContextConfiguration() - * @see ContextLoader#processLocations() - * @see #resolveActiveProfiles() + * @see #resolveContextLoader + * @see #resolveContextConfigurationAttributes + * @see SmartContextLoader#processContextConfiguration + * @see ContextLoader#processLocations + * @see #resolveActiveProfiles * @see MergedContextConfiguration */ static MergedContextConfiguration buildMergedContextConfiguration(Class testClass, From 94a88069ac57a4a8cc69ca2d72c1a0de69efa9e6 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 29 Jan 2013 15:39:37 -0800 Subject: [PATCH 05/12] Update example years to 2013 in CONTRIBUTING.md --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 65db556fabd..02d0bc12e2e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,7 +87,7 @@ present in the framework. ```java /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -108,16 +108,16 @@ package ...; ## Update Apache license header to modified files as necessary Always check the date range in the license header. For example, if you've -modified a file in 2012 whose header still reads +modified a file in 2013 whose header still reads ```java * Copyright 2002-2011 the original author or authors. ``` -then be sure to update it to 2012 appropriately +then be sure to update it to 2013 appropriately ```java - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 the original author or authors. ``` ## Use @since tags for newly-added public API types and methods From 6a98b40e1c76a285dd2c364fc189a960f6598615 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 30 Jan 2013 14:57:36 +0100 Subject: [PATCH 06/12] Consistent use of LinkedHashMaps and independent getAttributeNames Enumeration in Servlet/Portlet mocks Issue: SPR-10224 --- .../mock/web/MockHttpServletRequest.java | 3 ++- .../mock/web/MockHttpSession.java | 6 ++++-- .../mock/web/MockPageContext.java | 5 +++-- .../mock/web/MockServletContext.java | 5 ++--- .../mock/web/portlet/MockPortletContext.java | 5 ++--- .../mock/web/portlet/MockPortletRequest.java | 7 +++---- .../mock/web/portlet/MockPortletSession.java | 16 ++++++++-------- 7 files changed, 24 insertions(+), 23 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java index d609f39e8fc..0d29289c77e 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -30,6 +30,7 @@ import java.util.Date; import java.util.Enumeration; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -294,7 +295,7 @@ public class MockHttpServletRequest implements HttpServletRequest { public Enumeration getAttributeNames() { checkActive(); - return Collections.enumeration(this.attributes.keySet()); + return Collections.enumeration(new LinkedHashSet(this.attributes.keySet())); } public String getCharacterEncoding() { diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java index 1855230d2c5..548c2016d15 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -22,6 +22,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; @@ -50,6 +51,7 @@ public class MockHttpSession implements HttpSession { public static final String SESSION_COOKIE_NAME = "JSESSION"; + private static int nextId = 1; private final String id; @@ -141,7 +143,7 @@ public class MockHttpSession implements HttpSession { } public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); + return Collections.enumeration(new LinkedHashSet(this.attributes.keySet())); } public String[] getValueNames() { diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java b/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java index b492c1fa980..2c5d07e8e3c 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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.io.UnsupportedEncodingException; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; import javax.el.ELContext; import javax.servlet.Servlet; @@ -249,7 +250,7 @@ public class MockPageContext extends PageContext { } public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); + return Collections.enumeration(new LinkedHashSet(this.attributes.keySet())); } @SuppressWarnings("unchecked") diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java b/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java index 562179ceac8..40fbabd1a17 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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,7 +29,6 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; - import javax.activation.FileTypeMap; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; @@ -434,7 +433,7 @@ public class MockServletContext implements ServletContext { } public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); + return Collections.enumeration(new LinkedHashSet(this.attributes.keySet())); } public void setAttribute(String name, Object value) { diff --git a/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletContext.java b/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletContext.java index b1193ff5e1e..39dc9f5b294 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletContext.java +++ b/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -28,7 +28,6 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; -import java.util.Vector; import javax.activation.FileTypeMap; import javax.portlet.PortletContext; import javax.portlet.PortletRequestDispatcher; @@ -210,7 +209,7 @@ public class MockPortletContext implements PortletContext { } public Enumeration getAttributeNames() { - return new Vector(this.attributes.keySet()).elements(); + return Collections.enumeration(new LinkedHashSet(this.attributes.keySet())); } public void setAttribute(String name, Object value) { diff --git a/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletRequest.java b/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletRequest.java index 70e90567b0c..38b517351a7 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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,13 +21,12 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.Vector; - import javax.portlet.PortalContext; import javax.portlet.PortletContext; import javax.portlet.PortletMode; @@ -332,7 +331,7 @@ public class MockPortletRequest implements PortletRequest { public Enumeration getAttributeNames() { checkActive(); - return new Vector(this.attributes.keySet()).elements(); + return Collections.enumeration(new LinkedHashSet(this.attributes.keySet())); } public void setParameters(Map parameters) { diff --git a/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletSession.java b/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletSession.java index 93800340b85..5eaec799063 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletSession.java +++ b/spring-test/src/main/java/org/springframework/mock/web/portlet/MockPortletSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -18,10 +18,10 @@ package org.springframework.mock.web.portlet; import java.util.Collections; import java.util.Enumeration; -import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; -import java.util.Vector; import javax.portlet.PortletContext; import javax.portlet.PortletSession; import javax.servlet.http.HttpSessionBindingEvent; @@ -51,9 +51,9 @@ public class MockPortletSession implements PortletSession { private final PortletContext portletContext; - private final Map portletAttributes = new HashMap(); + private final Map portletAttributes = new LinkedHashMap(); - private final Map applicationAttributes = new HashMap(); + private final Map applicationAttributes = new LinkedHashMap(); private boolean invalid = false; @@ -92,15 +92,15 @@ public class MockPortletSession implements PortletSession { } public Enumeration getAttributeNames() { - return new Vector(this.portletAttributes.keySet()).elements(); + return Collections.enumeration(new LinkedHashSet(this.portletAttributes.keySet())); } public Enumeration getAttributeNames(int scope) { if (scope == PortletSession.PORTLET_SCOPE) { - return new Vector(this.portletAttributes.keySet()).elements(); + return Collections.enumeration(new LinkedHashSet(this.portletAttributes.keySet())); } else if (scope == PortletSession.APPLICATION_SCOPE) { - return new Vector(this.applicationAttributes.keySet()).elements(); + return Collections.enumeration(new LinkedHashSet(this.applicationAttributes.keySet())); } return null; } From 58f59d6851e40d872225952791741b2b50b43b06 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 30 Jan 2013 14:58:36 +0100 Subject: [PATCH 07/12] MediaType throws dedicated InvalidMediaTypeException instead of generic IllegalArgumentException Issue: SPR-10226 --- .../http/InvalidMediaTypeException.java | 51 +++++++++++++++++++ .../org/springframework/http/MediaType.java | 33 +++++++----- .../springframework/http/MediaTypeTests.java | 30 +++++------ 3 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 spring-web/src/main/java/org/springframework/http/InvalidMediaTypeException.java diff --git a/spring-web/src/main/java/org/springframework/http/InvalidMediaTypeException.java b/spring-web/src/main/java/org/springframework/http/InvalidMediaTypeException.java new file mode 100644 index 00000000000..358c9c8226a --- /dev/null +++ b/spring-web/src/main/java/org/springframework/http/InvalidMediaTypeException.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2013 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.http; + +/** + * Exception thrown from {@link MediaType#parseMediaType(String)} in case of + * encountering an invalid media type specification String. + * + * @author Juergen Hoeller + * @since 3.2.2 + */ +@SuppressWarnings("serial") +public class InvalidMediaTypeException extends IllegalArgumentException { + + private String mediaType; + + + /** + * Create a new InvalidMediaTypeException for the given media type. + * @param mediaType the offending media type + * @param msg a detail message indicating the invalid part + */ + public InvalidMediaTypeException(String mediaType, String msg) { + super("Invalid media type \"" + mediaType + "\": " + msg); + this.mediaType = mediaType; + + } + + + /** + * Return the offending media type. + */ + public String getMediaType() { + return this.mediaType; + } + +} diff --git a/spring-web/src/main/java/org/springframework/http/MediaType.java b/spring-web/src/main/java/org/springframework/http/MediaType.java index 99e1b2d1249..9f527c7c8ce 100644 --- a/spring-web/src/main/java/org/springframework/http/MediaType.java +++ b/spring-web/src/main/java/org/springframework/http/MediaType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -17,6 +17,7 @@ package org.springframework.http; import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; @@ -321,8 +322,8 @@ public class MediaType implements Comparable { * @throws IllegalArgumentException if any of the parameters contain illegal characters */ public MediaType(String type, String subtype, Map parameters) { - Assert.hasLength(type, "'type' must not be empty"); - Assert.hasLength(subtype, "'subtype' must not be empty"); + Assert.hasLength(type, "type must not be empty"); + Assert.hasLength(subtype, "subtype must not be empty"); checkToken(type); checkToken(subtype); this.type = type.toLowerCase(Locale.ENGLISH); @@ -347,11 +348,11 @@ public class MediaType implements Comparable { * @throws IllegalArgumentException in case of illegal characters * @see HTTP 1.1, section 2.2 */ - private void checkToken(String s) { - for (int i=0; i < s.length(); i++ ) { - char ch = s.charAt(i); + private void checkToken(String token) { + for (int i=0; i < token.length(); i++ ) { + char ch = token.charAt(i); if (!TOKEN.get(ch)) { - throw new IllegalArgumentException("Invalid token character '" + ch + "' in token \"" + s + "\""); + throw new IllegalArgumentException("Invalid token character '" + ch + "' in token \"" + token + "\""); } } } @@ -681,7 +682,7 @@ public class MediaType implements Comparable { * Parse the given String into a single {@code MediaType}. * @param mediaType the string to parse * @return the media type - * @throws IllegalArgumentException if the string cannot be parsed + * @throws InvalidMediaTypeException if the string cannot be parsed */ public static MediaType parseMediaType(String mediaType) { Assert.hasLength(mediaType, "'mediaType' must not be empty"); @@ -694,15 +695,15 @@ public class MediaType implements Comparable { } int subIndex = fullType.indexOf('/'); if (subIndex == -1) { - throw new IllegalArgumentException("\"" + mediaType + "\" does not contain '/'"); + throw new InvalidMediaTypeException(mediaType, "does not contain '/'"); } if (subIndex == fullType.length() - 1) { - throw new IllegalArgumentException("\"" + mediaType + "\" does not contain subtype after '/'"); + throw new InvalidMediaTypeException(mediaType, "does not contain subtype after '/'"); } String type = fullType.substring(0, subIndex); String subtype = fullType.substring(subIndex + 1, fullType.length()); if (WILDCARD_TYPE.equals(type) && !WILDCARD_TYPE.equals(subtype)) { - throw new IllegalArgumentException("A wildcard type is legal only in '*/*' (all media types)."); + throw new InvalidMediaTypeException(mediaType, "wildcard type is legal only in '*/*' (all media types)"); } Map parameters = null; @@ -719,7 +720,15 @@ public class MediaType implements Comparable { } } - return new MediaType(type, subtype, parameters); + try { + return new MediaType(type, subtype, parameters); + } + catch (UnsupportedCharsetException ex) { + throw new InvalidMediaTypeException(mediaType, "unsupported charset '" + ex.getCharsetName() + "'"); + } + catch (IllegalArgumentException ex) { + throw new InvalidMediaTypeException(mediaType, ex.getMessage()); + } } diff --git a/spring-web/src/test/java/org/springframework/http/MediaTypeTests.java b/spring-web/src/test/java/org/springframework/http/MediaTypeTests.java index 906c8dec588..d5657d199e7 100644 --- a/spring-web/src/test/java/org/springframework/http/MediaTypeTests.java +++ b/spring-web/src/test/java/org/springframework/http/MediaTypeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -97,12 +97,12 @@ public class MediaTypeTests { assertEquals("Invalid toString() returned", "text/plain;q=0.7", result); } - @Test(expected= IllegalArgumentException.class) + @Test(expected = IllegalArgumentException.class) public void slashInType() { new MediaType("text/plain"); } - @Test(expected= IllegalArgumentException.class) + @Test(expected = IllegalArgumentException.class) public void slashInSubtype() { new MediaType("text", "/"); } @@ -122,57 +122,57 @@ public class MediaTypeTests { assertEquals("Invalid quality factor", 0.2D, mediaType.getQualityValue(), 0D); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeNoSubtype() { MediaType.parseMediaType("audio"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeNoSubtypeSlash() { MediaType.parseMediaType("audio/"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeTypeRange() { MediaType.parseMediaType("*/json"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeIllegalType() { MediaType.parseMediaType("audio(/basic"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeIllegalSubtype() { MediaType.parseMediaType("audio/basic)"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeEmptyParameterAttribute() { MediaType.parseMediaType("audio/*;=value"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeEmptyParameterValue() { MediaType.parseMediaType("audio/*;attr="); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeIllegalParameterAttribute() { MediaType.parseMediaType("audio/*;attr<=value"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeIllegalParameterValue() { MediaType.parseMediaType("audio/*;attr=v>alue"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeIllegalQualityFactor() { MediaType.parseMediaType("audio/basic;q=1.1"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeIllegalCharset() { MediaType.parseMediaType("text/html; charset=foo-bar"); } @@ -193,7 +193,7 @@ public class MediaTypeTests { assertEquals("'v>alue'", mediaType.getParameter("attr")); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = InvalidMediaTypeException.class) public void parseMediaTypeIllegalQuotedParameterValue() { MediaType.parseMediaType("audio/*;attr=\""); } From 6d77f1cf3b3f060ead70d49079bc87d75e0b105c Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 31 Jan 2013 16:51:56 +0100 Subject: [PATCH 08/12] ConfigurationClassPostProcessor consistently uses ClassLoader, not loading core JDK annotations via ASM Issue: SPR-10249 --- .../annotation/ConfigurationClassParser.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index 2901e5cea0d..c03aca61ddf 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -54,6 +54,7 @@ import org.springframework.core.type.StandardAnnotationMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.AssignableTypeFilter; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import static org.springframework.context.annotation.MetadataUtils.*; @@ -228,7 +229,7 @@ class ConfigurationClassParser { // process any @Import annotations Set imports = getImports(metadata.getClassName(), null, new HashSet()); - if (imports != null && !imports.isEmpty()) { + if (!CollectionUtils.isEmpty(imports)) { processImport(configClass, imports.toArray(new String[imports.size()]), true); } @@ -292,9 +293,8 @@ class ConfigurationClassParser { * @return a set of all {@link Import#value() import values} or {@code null} * @throws IOException if there is any problem reading metadata from the named class */ - private Set getImports(String className, Set imports, - Set visited) throws IOException { - if (visited.add(className)) { + private Set getImports(String className, Set imports, Set visited) throws IOException { + if (visited.add(className) && !className.startsWith("java")) { AnnotationMetadata metadata = metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata(); for (String annotationType : metadata.getAnnotationTypes()) { imports = getImports(annotationType, imports, visited); @@ -331,7 +331,7 @@ class ConfigurationClassParser { throw new IllegalStateException(ex); } } - else if (new AssignableTypeFilter(ImportBeanDefinitionRegistrar.class).match(reader, metadataReaderFactory)) { + else if (new AssignableTypeFilter(ImportBeanDefinitionRegistrar.class).match(reader, this.metadataReaderFactory)) { // the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions try { ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass( @@ -360,17 +360,16 @@ class ConfigurationClassParser { private void invokeAwareMethods(ImportBeanDefinitionRegistrar registrar) { if (registrar instanceof Aware) { if (registrar instanceof ResourceLoaderAware) { - ((ResourceLoaderAware) registrar).setResourceLoader(resourceLoader); + ((ResourceLoaderAware) registrar).setResourceLoader(this.resourceLoader); } if (registrar instanceof BeanClassLoaderAware) { - ClassLoader classLoader = - registry instanceof ConfigurableBeanFactory ? - ((ConfigurableBeanFactory) registry).getBeanClassLoader() : - resourceLoader.getClassLoader(); + ClassLoader classLoader = (this.registry instanceof ConfigurableBeanFactory ? + ((ConfigurableBeanFactory) this.registry).getBeanClassLoader() : + this.resourceLoader.getClassLoader()); ((BeanClassLoaderAware) registrar).setBeanClassLoader(classLoader); } - if (registrar instanceof BeanFactoryAware && registry instanceof BeanFactory) { - ((BeanFactoryAware) registrar).setBeanFactory((BeanFactory) registry); + if (registrar instanceof BeanFactoryAware && this.registry instanceof BeanFactory) { + ((BeanFactoryAware) registrar).setBeanFactory((BeanFactory) this.registry); } } } @@ -398,6 +397,7 @@ class ConfigurationClassParser { return this.importStack; } + interface ImportRegistry { String getImportingClassFor(String importedClass); @@ -470,4 +470,5 @@ class ConfigurationClassParser { new Location(importStack.peek().getResource(), metadata)); } } + } From b3af29b8f655176244f42cdf086f69ea25cd6038 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 31 Jan 2013 16:53:04 +0100 Subject: [PATCH 09/12] DefaultMessageListenerContainer invokes specified ExceptionListener for recovery exceptions as well Also, DefaultMessageListenerContainer logs recovery failures at error level and exposes an "isRecovering()" method now. Issue: SPR-10230 --- .../DefaultMessageListenerContainer.java | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java index 91b15c319df..de0132dae16 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -183,6 +183,8 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe private int registeredWithDestination = 0; + private volatile boolean recovering = false; + private Runnable stopCallback; private Object currentRecoveryMarker = new Object(); @@ -758,6 +760,9 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe super.establishSharedConnection(); } catch (Exception ex) { + if (ex instanceof JMSException) { + invokeExceptionListener((JMSException) ex); + } logger.debug("Could not establish shared JMS Connection - " + "leaving it up to asynchronous invokers to establish a Connection as soon as possible", ex); } @@ -796,7 +801,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe /** * Handle the given exception that arose during setup of a listener. * Called for every such exception in every concurrent listener. - *

The default implementation logs the exception at info level + *

The default implementation logs the exception at warn level * if not recovered yet, and at debug level if already recovered. * Can be overridden in subclasses. * @param ex the exception to handle @@ -837,7 +842,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe /** * Recover this listener container after a listener failed to set itself up, - * for example reestablishing the underlying Connection. + * for example re-establishing the underlying Connection. *

The default implementation delegates to DefaultMessageListenerContainer's * recovery-capable {@link #refreshConnectionUntilSuccessful()} method, which will * try to re-establish a Connection to the JMS provider both for the shared @@ -846,8 +851,14 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe * @see #refreshDestination() */ protected void recoverAfterListenerSetupFailure() { - refreshConnectionUntilSuccessful(); - refreshDestination(); + this.recovering = true; + try { + refreshConnectionUntilSuccessful(); + refreshDestination(); + } + finally { + this.recovering = false; + } } /** @@ -856,9 +867,11 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe * Connection, so either needs to operate on the shared Connection or on a * temporary Connection that just gets established for validation purposes. *

The default implementation retries until it successfully established a - * Connection, for as long as this message listener container is active. + * Connection, for as long as this message listener container is running. * Applies the specified recovery interval between retries. * @see #setRecoveryInterval + * @see #start() + * @see #stop() */ protected void refreshConnectionUntilSuccessful() { while (isRunning()) { @@ -874,16 +887,19 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe break; } catch (Exception ex) { + if (ex instanceof JMSException) { + invokeExceptionListener((JMSException) ex); + } StringBuilder msg = new StringBuilder(); msg.append("Could not refresh JMS Connection for destination '"); msg.append(getDestinationDescription()).append("' - retrying in "); msg.append(this.recoveryInterval).append(" ms. Cause: "); msg.append(ex instanceof JMSException ? JmsUtils.buildExceptionMessage((JMSException) ex) : ex.getMessage()); if (logger.isDebugEnabled()) { - logger.warn(msg, ex); + logger.error(msg, ex); } else { - logger.warn(msg); + logger.error(msg); } } sleepInbetweenRecoveryAttempts(); @@ -925,6 +941,17 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe } } + /** + * Return whether this listener container is currently in a recovery attempt. + *

May be used to detect recovery phases but also the end of a recovery phase, + * with {@code isRecovering()} switching to {@code false} after having been found + * to return {@code true} before. + * @see #recoverAfterListenerSetupFailure() + */ + public final boolean isRecovering() { + return this.recovering; + } + //------------------------------------------------------------------------- // Inner classes used as internal adapters From bd72fcd4690c6e49e07f84dba264ca943a8a393d Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 31 Jan 2013 16:53:58 +0100 Subject: [PATCH 10/12] Initial preparations for 3.2.2 --- src/dist/changelog.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dist/changelog.txt b/src/dist/changelog.txt index 25b90985b9b..70defd90ddc 100644 --- a/src/dist/changelog.txt +++ b/src/dist/changelog.txt @@ -3,6 +3,16 @@ SPRING FRAMEWORK CHANGELOG http://www.springsource.org +Changes in version 3.2.2 (2013-03-07) +-------------------------------------- + +* ConfigurationClassPostProcessor consistently uses ClassLoader, not loading core JDK annotations via ASM (SPR-10249) +* DefaultMessageListenerContainer invokes specified ExceptionListener for recovery exceptions as well (SPR-10230) +* DefaultMessageListenerContainer logs recovery failures at error level and exposes "isRecovering()" method (SPR-10230) +* MediaType throws dedicated InvalidMediaTypeException instead of generic IllegalArgumentException (SPR-10226) +* consistent use of LinkedHashMaps and independent getAttributeNames Enumeration in Servlet/Portlet mocks (SPR-10224) + + Changes in version 3.2.1 (2013-01-24) -------------------------------------- From 7d798acd35984b4cedf0e1035305698a618407d8 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 31 Jan 2013 17:50:37 +0100 Subject: [PATCH 11/12] Added getOriginalValue() accessor to (Real)Literal Issue: SPR-10248 --- .../expression/spel/ast/Literal.java | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Literal.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Literal.java index 19ddf7caacb..9b35a78a403 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Literal.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Literal.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -17,23 +17,32 @@ package org.springframework.expression.spel.ast; import org.springframework.expression.TypedValue; -import org.springframework.expression.spel.*; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.InternalParseException; +import org.springframework.expression.spel.SpelEvaluationException; +import org.springframework.expression.spel.SpelMessage; +import org.springframework.expression.spel.SpelParseException; /** * Common superclass for nodes representing literals (boolean, string, number, etc). * * @author Andy Clement + * @author Juergen Hoeller */ public abstract class Literal extends SpelNodeImpl { - protected String literalValue; + private final String originalValue; - public Literal(String payload, int pos) { + + public Literal(String originalValue, int pos) { super(pos); - this.literalValue = payload; + this.originalValue = originalValue; } - public abstract TypedValue getLiteralValue(); + + public final String getOriginalValue() { + return this.originalValue; + } @Override public final TypedValue getValueInternal(ExpressionState state) throws SpelEvaluationException { @@ -50,10 +59,13 @@ public abstract class Literal extends SpelNodeImpl { return toString(); } + + public abstract TypedValue getLiteralValue(); + + /** * Process the string form of a number, using the specified base if supplied and return an appropriate literal to * hold it. Any suffix to indicate a long will be taken into account (either 'l' or 'L' is supported). - * * @param numberToken the token holding the number as its payload (eg. 1234 or 0xCAFE) * @param radix the base of number * @return a subtype of Literal that can represent it @@ -62,7 +74,8 @@ public abstract class Literal extends SpelNodeImpl { try { int value = Integer.parseInt(numberToken, radix); return new IntLiteral(numberToken, pos, value); - } catch (NumberFormatException nfe) { + } + catch (NumberFormatException nfe) { throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessage.NOT_AN_INTEGER, numberToken)); } } @@ -71,25 +84,26 @@ public abstract class Literal extends SpelNodeImpl { try { long value = Long.parseLong(numberToken, radix); return new LongLiteral(numberToken, pos, value); - } catch (NumberFormatException nfe) { + } + catch (NumberFormatException nfe) { throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessage.NOT_A_LONG, numberToken)); } } - public static Literal getRealLiteral(String numberToken, int pos, boolean isFloat) { try { if (isFloat) { float value = Float.parseFloat(numberToken); return new FloatLiteral(numberToken, pos, value); - } else { + } + else { double value = Double.parseDouble(numberToken); return new RealLiteral(numberToken, pos, value); } - } catch (NumberFormatException nfe) { + } + catch (NumberFormatException nfe) { throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessage.NOT_A_REAL, numberToken)); } } } - From a694db2933b9f86455e2cb53c9933d3fd79b1904 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 31 Jan 2013 18:01:01 +0100 Subject: [PATCH 12/12] Removed logging from GenericTypeResolver's resolveReturnTypeForGenericMethod GenericTypeResolver is very low-level and quite a hotspot, so let's not do any logging there and rather use the debugger instead. --- .../core/GenericTypeResolver.java | 66 ++++--------------- 1 file changed, 13 insertions(+), 53 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java index cb9e8fba331..3842a741c74 100644 --- a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java +++ b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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,11 +26,7 @@ import java.lang.reflect.WildcardType; import java.util.HashMap; import java.util.Map; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; import org.springframework.util.ConcurrentReferenceHashMap; /** @@ -47,12 +43,11 @@ import org.springframework.util.ConcurrentReferenceHashMap; */ public abstract class GenericTypeResolver { - private static final Log logger = LogFactory.getLog(GenericTypeResolver.class); - /** Cache from Class to TypeVariable Map */ private static final Map> typeVariableCache = new ConcurrentReferenceHashMap>(); + /** * Determine the target type for the given parameter specification. * @param methodParam the method parameter specification @@ -93,7 +88,6 @@ public abstract class GenericTypeResolver { /** * Determine the target type for the generic return type of the given method, * where formal type variables are declared on the given class. - * * @param method the method to introspect * @param clazz the class to resolve type variables against * @return the corresponding generic parameter or return type @@ -112,15 +106,12 @@ public abstract class GenericTypeResolver { * Determine the target type for the generic return type of the given * generic method, where formal type variables are declared on * the given method itself. - * *

For example, given a factory method with the following signature, * if {@code resolveReturnTypeForGenericMethod()} is invoked with the reflected * method for {@code creatProxy()} and an {@code Object[]} array containing * {@code MyService.class}, {@code resolveReturnTypeForGenericMethod()} will * infer that the target return type is {@code MyService}. - * *

{@code public static  T createProxy(Class clazz)}
- * *

Possible Return Values

*
    *
  • the target return type, if it can be inferred
  • @@ -134,27 +125,20 @@ public abstract class GenericTypeResolver { * Method#getGenericParameterTypes() formal argument list} for the given * method *
- * * @param method the method to introspect, never {@code null} * @param args the arguments that will be supplied to the method when it is * invoked, never {@code null} - * @return the resolved target return type, the standard return type, or - * {@code null} + * @return the resolved target return type, the standard return type, or {@code null} * @since 3.2 * @see #resolveReturnType */ public static Class resolveReturnTypeForGenericMethod(Method method, Object[] args) { - Assert.notNull(method, "method must not be null"); - Assert.notNull(args, "args must not be null"); - - if (logger.isDebugEnabled()) { - logger.debug(String.format("Resolving return type for [%s] with concrete method arguments [%s].", - method.toGenericString(), ObjectUtils.nullSafeToString(args))); - } + Assert.notNull(method, "Method must not be null"); + Assert.notNull(args, "Argument array must not be null"); - final TypeVariable[] declaredTypeVariables = method.getTypeParameters(); - final Type genericReturnType = method.getGenericReturnType(); - final Type[] methodArgumentTypes = method.getGenericParameterTypes(); + TypeVariable[] declaredTypeVariables = method.getTypeParameters(); + Type genericReturnType = method.getGenericReturnType(); + Type[] methodArgumentTypes = method.getGenericParameterTypes(); // No declared type variables to inspect, so just return the standard return type. if (declaredTypeVariables.length == 0) { @@ -172,11 +156,6 @@ public abstract class GenericTypeResolver { boolean locallyDeclaredTypeVariableMatchesReturnType = false; for (TypeVariable currentTypeVariable : declaredTypeVariables) { if (currentTypeVariable.equals(genericReturnType)) { - if (logger.isDebugEnabled()) { - logger.debug(String.format( - "Found declared type variable [%s] that matches the target return type [%s].", - currentTypeVariable, genericReturnType)); - } locallyDeclaredTypeVariableMatchesReturnType = true; break; } @@ -184,39 +163,20 @@ public abstract class GenericTypeResolver { if (locallyDeclaredTypeVariableMatchesReturnType) { for (int i = 0; i < methodArgumentTypes.length; i++) { - final Type currentMethodArgumentType = methodArgumentTypes[i]; - + Type currentMethodArgumentType = methodArgumentTypes[i]; if (currentMethodArgumentType.equals(genericReturnType)) { - if (logger.isDebugEnabled()) { - logger.debug(String.format( - "Found method argument type at index [%s] that matches the target return type.", i)); - } return args[i].getClass(); } - if (currentMethodArgumentType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) currentMethodArgumentType; Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); - - for (int j = 0; j < actualTypeArguments.length; j++) { - final Type typeArg = actualTypeArguments[j]; - + for (Type typeArg : actualTypeArguments) { if (typeArg.equals(genericReturnType)) { - if (logger.isDebugEnabled()) { - logger.debug(String.format( - "Found method argument type at index [%s] that is parameterized with a type argument that matches the target return type.", - i)); - } - if (args[i] instanceof Class) { return (Class) args[i]; - } else { - // Consider adding logic to determine the class of the - // J'th typeArg, if possible. - logger.info(String.format( - "Could not determine the target type for type argument [%s] for method [%s].", - typeArg, method.toGenericString())); - + } + else { + // Consider adding logic to determine the class of the typeArg, if possible. // For now, just fall back... return method.getReturnType(); }