From dc080cb1be4c35398d1d995c3bb8025ccfde6dea Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 28 Oct 2016 23:39:05 +0200 Subject: [PATCH] Revised NoSuchBeanDefinitionException message and ResolvableType handling Includes consistent quoting of qualified type names in related classes. Issue: SPR-14831 --- .../beans/TypeConverterDelegate.java | 8 +-- .../beans/TypeMismatchException.java | 12 ++-- .../BeanNotOfRequiredTypeException.java | 5 +- .../NoSuchBeanDefinitionException.java | 66 +++++++------------ ...xtAnnotationAutowireCandidateResolver.java | 2 +- ...tionContextDynamicBeanPropertyTests.groovy | 3 +- ...notationConfigApplicationContextTests.java | 4 +- .../jdbc/core/BeanPropertyRowMapper.java | 6 +- .../MessageMethodArgumentResolver.java | 22 +++---- .../MessageMethodArgumentResolverTests.java | 4 +- 10 files changed, 56 insertions(+), 76 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java b/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java index 4d02d8d2a9..9080d93f74 100644 --- a/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java +++ b/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java @@ -278,15 +278,15 @@ class TypeConverterDelegate { // Definitely doesn't match: throw IllegalArgumentException/IllegalStateException StringBuilder msg = new StringBuilder(); - msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue)); - msg.append("] to required type [").append(ClassUtils.getQualifiedName(requiredType)).append("]"); + msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue)); + msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'"); if (propertyName != null) { msg.append(" for property '").append(propertyName).append("'"); } if (editor != null) { msg.append(": PropertyEditor [").append(editor.getClass().getName()).append( - "] returned inappropriate value of type [").append( - ClassUtils.getDescriptiveType(convertedValue)).append("]"); + "] returned inappropriate value of type '").append( + ClassUtils.getDescriptiveType(convertedValue)).append("'"); throw new IllegalArgumentException(msg.toString()); } else { diff --git a/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java b/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java index c2cffe10b5..2f81b70a41 100644 --- a/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java +++ b/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -57,10 +57,10 @@ public class TypeMismatchException extends PropertyAccessException { */ public TypeMismatchException(PropertyChangeEvent propertyChangeEvent, Class requiredType, Throwable cause) { super(propertyChangeEvent, - "Failed to convert property value of type [" + - ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "]" + + "Failed to convert property value of type '" + + ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "'" + (requiredType != null ? - " to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : "") + + " to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : "") + (propertyChangeEvent.getPropertyName() != null ? " for property '" + propertyChangeEvent.getPropertyName() + "'" : ""), cause); @@ -84,8 +84,8 @@ public class TypeMismatchException extends PropertyAccessException { * @param cause the root cause (may be {@code null}) */ public TypeMismatchException(Object value, Class requiredType, Throwable cause) { - super("Failed to convert value of type [" + ClassUtils.getDescriptiveType(value) + "]" + - (requiredType != null ? " to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : ""), + super("Failed to convert value of type '" + ClassUtils.getDescriptiveType(value) + "'" + + (requiredType != null ? " to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : ""), cause); this.value = value; this.requiredType = requiredType; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanNotOfRequiredTypeException.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanNotOfRequiredTypeException.java index 6f98f43539..1cb0b75830 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanNotOfRequiredTypeException.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanNotOfRequiredTypeException.java @@ -17,6 +17,7 @@ package org.springframework.beans.factory; import org.springframework.beans.BeansException; +import org.springframework.util.ClassUtils; /** * Thrown when a bean doesn't match the expected type. @@ -45,8 +46,8 @@ public class BeanNotOfRequiredTypeException extends BeansException { * the expected type */ public BeanNotOfRequiredTypeException(String beanName, Class requiredType, Class actualType) { - super("Bean named '" + beanName + "' is expected to be of type [" + requiredType.getName() + - "] but was actually of type [" + actualType.getName() + "]"); + super("Bean named '" + beanName + "' is expected to be of type '" + ClassUtils.getQualifiedName(requiredType) + + "' but was actually of type '" + ClassUtils.getQualifiedName(actualType) + "'"); this.beanName = beanName; this.requiredType = requiredType; this.actualType = actualType; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java b/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java index 1f347023a9..413282f7e8 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java @@ -18,8 +18,6 @@ package org.springframework.beans.factory; import org.springframework.beans.BeansException; import org.springframework.core.ResolvableType; -import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; /** * Exception thrown when a {@code BeanFactory} is asked for a bean instance for which it @@ -36,11 +34,9 @@ import org.springframework.util.StringUtils; @SuppressWarnings("serial") public class NoSuchBeanDefinitionException extends BeansException { - /** Name of the missing bean */ private String beanName; - /** Required type of the missing bean */ - private ResolvableType beanResolvableType; + private ResolvableType resolvableType; /** @@ -48,7 +44,7 @@ public class NoSuchBeanDefinitionException extends BeansException { * @param name the name of the missing bean */ public NoSuchBeanDefinitionException(String name) { - super("No bean named '" + name + "' is defined"); + super("No bean named '" + name + "' available"); this.beanName = name; } @@ -58,7 +54,7 @@ public class NoSuchBeanDefinitionException extends BeansException { * @param message detailed message describing the problem */ public NoSuchBeanDefinitionException(String name, String message) { - super("No bean named '" + name + "' is defined: " + message); + super("No bean named '" + name + "' available: " + message); this.beanName = name; } @@ -67,8 +63,7 @@ public class NoSuchBeanDefinitionException extends BeansException { * @param type required type of the missing bean */ public NoSuchBeanDefinitionException(Class type) { - super("No qualifying bean of type [" + type.getName() + "] is defined"); - this.beanResolvableType = ResolvableType.forClass(type); + this(ResolvableType.forClass(type)); } /** @@ -77,43 +72,28 @@ public class NoSuchBeanDefinitionException extends BeansException { * @param message detailed message describing the problem */ public NoSuchBeanDefinitionException(Class type, String message) { - super("No qualifying bean of type [" + ClassUtils.getQualifiedName(type) + "] is defined: " + message); - this.beanResolvableType = ResolvableType.forClass(type); + this(ResolvableType.forClass(type), message); } /** * Create a new {@code NoSuchBeanDefinitionException}. - * @param type required type of the missing bean - * @param dependencyDescription a description of the originating dependency - * @param message detailed message describing the problem - * @deprecated as of Spring 5.0, in favor of {@link #NoSuchBeanDefinitionException(ResolvableType, String)} - */ - @Deprecated - public NoSuchBeanDefinitionException(Class type, String dependencyDescription, String message) { - this(ResolvableType.forClass(type), dependencyDescription, message); - } - - /** - * Create a new {@code NoSuchBeanDefinitionException}. - * @param resolvableType required type of the missing bean - * @param message detailed message describing the problem + * @param type full type declaration of the missing bean + * @since 4.3.4 */ - public NoSuchBeanDefinitionException(ResolvableType resolvableType, String message) { - this(resolvableType, resolvableType.toString(), message); + public NoSuchBeanDefinitionException(ResolvableType type) { + super("No qualifying bean of type '" + type + "' available"); + this.resolvableType = type; } /** * Create a new {@code NoSuchBeanDefinitionException}. - * @param resolvableType required type of the missing bean - * @param dependencyDescription a description of the originating dependency + * @param type full type declaration of the missing bean * @param message detailed message describing the problem + * @since 4.3.4 */ - private NoSuchBeanDefinitionException(ResolvableType resolvableType, String dependencyDescription, String message) { - super("No qualifying bean" + (!StringUtils.hasLength(dependencyDescription) ? - " of type [" + ClassUtils.getQualifiedName(resolvableType.getRawClass()) + "]" : "") + - " found for dependency" + (StringUtils.hasLength(dependencyDescription) ? " [" + - dependencyDescription + "]" : "") + ": " + message); - this.beanResolvableType = resolvableType; + public NoSuchBeanDefinitionException(ResolvableType type, String message) { + super("No qualifying bean of type '" + type + "' available: " + message); + this.resolvableType = type; } @@ -125,18 +105,20 @@ public class NoSuchBeanDefinitionException extends BeansException { } /** - * Return the required {@link ResolvableType} of the missing bean, if it was a lookup - * by type that failed. + * Return the required type of the missing bean, if it was a lookup by type + * that failed. */ - public ResolvableType getBeanResolvableType() { - return this.beanResolvableType; + public Class getBeanType() { + return (this.resolvableType != null ? this.resolvableType.getRawClass() : null); } /** - * Return the required type of the missing bean, if it was a lookup by type that failed. + * Return the required {@link ResolvableType} of the missing bean, if it was a lookup + * by type that failed. + * @since 4.3.4 */ - public Class getBeanType() { - return (this.beanResolvableType != null ? this.beanResolvableType.getRawClass() : null); + public ResolvableType getResolvableType() { + return this.resolvableType; } /** diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java b/spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java index 56ba95b68e..785ada6c5e 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java @@ -82,7 +82,7 @@ public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotat public Object getTarget() { Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null); if (target == null) { - throw new NoSuchBeanDefinitionException(descriptor.getDependencyType(), + throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(), "Optional dependency not present for lazy injection point"); } return target; diff --git a/spring-context/src/test/groovy/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.groovy b/spring-context/src/test/groovy/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.groovy index 3bd5fe33c4..ad10b927d7 100644 --- a/spring-context/src/test/groovy/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.groovy +++ b/spring-context/src/test/groovy/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.groovy @@ -48,6 +48,7 @@ class GroovyApplicationContextDynamicBeanPropertyTests { def err = shouldFail NoSuchBeanDefinitionException, { ctx.someNonExistentBean } - assertEquals "No bean named 'someNonExistentBean' is defined", err.message + assertEquals "No bean named 'someNonExistentBean' available", err.message } + } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java b/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java index a718338e63..f485eeb3d5 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java @@ -128,7 +128,7 @@ public class AnnotationConfigApplicationContextTests { } catch (NoSuchBeanDefinitionException ex) { assertThat(ex.getMessage(), containsString( - format("No qualifying bean of type [%s] is defined", targetType.getName()))); + format("No qualifying bean of type '%s'", targetType.getName()))); } } @@ -142,7 +142,7 @@ public class AnnotationConfigApplicationContextTests { catch (NoSuchBeanDefinitionException ex) { assertThat(ex.getMessage(), allOf( - containsString("No qualifying bean of type [" + TestBean.class.getName() + "] is defined"), + containsString("No qualifying bean of type '" + TestBean.class.getName() + "'"), containsString("tb1"), containsString("tb2") ) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java index 7d4afa09c9..05986bb533 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java @@ -291,7 +291,7 @@ public class BeanPropertyRowMapper implements RowMapper { Object value = getColumnValue(rs, index, pd); if (rowNumber == 0 && logger.isDebugEnabled()) { logger.debug("Mapping column '" + column + "' to property '" + pd.getName() + - "' of type [" + ClassUtils.getQualifiedName(pd.getPropertyType()) + "]"); + "' of type '" + ClassUtils.getQualifiedName(pd.getPropertyType()) + "'"); } try { bw.setPropertyValue(pd.getName(), value); @@ -301,9 +301,9 @@ public class BeanPropertyRowMapper implements RowMapper { if (logger.isDebugEnabled()) { logger.debug("Intercepted TypeMismatchException for row " + rowNumber + " and column '" + column + "' with null value when setting property '" + - pd.getName() + "' of type [" + + pd.getName() + "' of type '" + ClassUtils.getQualifiedName(pd.getPropertyType()) + - "] on object: " + mappedObject, ex); + "' on object: " + mappedObject, ex); } } else { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolver.java index a388946ffb..e247cd9bd1 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolver.java @@ -73,10 +73,9 @@ public class MessageMethodArgumentResolver implements HandlerMethodArgumentResol Class targetPayloadType = getPayloadType(parameter); if (!targetMessageType.isAssignableFrom(message.getClass())) { - String actual = ClassUtils.getQualifiedName(message.getClass()); - String expected = ClassUtils.getQualifiedName(targetMessageType); - throw new MethodArgumentTypeMismatchException(message, parameter, "The actual message type " + - "[" + actual + "] does not match the expected type [" + expected + "]"); + throw new MethodArgumentTypeMismatchException(message, parameter, "Actual message type '" + + ClassUtils.getDescriptiveType(message) + "' does not match expected type '" + + ClassUtils.getQualifiedName(targetMessageType) + "'"); } Object payload = message.getPayload(); @@ -85,11 +84,9 @@ public class MessageMethodArgumentResolver implements HandlerMethodArgumentResol } if (isEmptyPayload(payload)) { - String actual = ClassUtils.getQualifiedName(payload.getClass()); - String expected = ClassUtils.getQualifiedName(targetPayloadType); - throw new MessageConversionException(message, "Cannot convert from the " + - "expected payload type [" + expected + "] to the " + - "actual payload type [" + actual + "] when the payload is empty."); + throw new MessageConversionException(message, "Cannot convert from actual payload type '" + + ClassUtils.getDescriptiveType(payload) + "' to expected payload type '" + + ClassUtils.getQualifiedName(targetPayloadType) + "' when payload is empty"); } payload = convertPayload(message, parameter, targetPayloadType); @@ -132,10 +129,9 @@ public class MessageMethodArgumentResolver implements HandlerMethodArgumentResol } if (result == null) { - String actual = ClassUtils.getQualifiedName(targetPayloadType); - String expected = ClassUtils.getQualifiedName(message.getPayload().getClass()); - throw new MessageConversionException(message, "No converter found to convert payload type [" + - actual + "] to expected payload type [" + expected + "]"); + throw new MessageConversionException(message, "No converter found from actual payload type '" + + ClassUtils.getDescriptiveType(message.getPayload()) + "' to expected payload type '" + + ClassUtils.getQualifiedName(targetPayloadType) + "'"); } return result; } diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolverTests.java index 792910f7b4..a7cb5507cc 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolverTests.java @@ -124,7 +124,7 @@ public class MessageMethodArgumentResolverTests { assertTrue(this.resolver.supportsParameter(parameter)); thrown.expect(MessageConversionException.class); - thrown.expectMessage("the payload is empty"); + thrown.expectMessage("payload is empty"); thrown.expectMessage(Integer.class.getName()); thrown.expectMessage(String.class.getName()); this.resolver.resolveArgument(parameter, message); @@ -216,7 +216,7 @@ public class MessageMethodArgumentResolverTests { assertTrue(this.resolver.supportsParameter(parameter)); thrown.expect(MessageConversionException.class); - thrown.expectMessage("the payload is empty"); + thrown.expectMessage("payload is empty"); thrown.expectMessage(Integer.class.getName()); thrown.expectMessage(String.class.getName()); this.resolver.resolveArgument(parameter, message);