Polishing

This commit is contained in:
Juergen Hoeller 2018-03-07 15:49:58 +01:00
parent 6f4d25a6e6
commit f57fcdee3c
4 changed files with 55 additions and 74 deletions

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -91,7 +91,7 @@ public abstract class PropertyMatches {
private final String propertyName; private final String propertyName;
private String[] possibleMatches; private final String[] possibleMatches;
/** /**
@ -155,8 +155,8 @@ public abstract class PropertyMatches {
if (s2.isEmpty()) { if (s2.isEmpty()) {
return s1.length(); return s1.length();
} }
int[][] d = new int[s1.length() + 1][s2.length() + 1];
int[][] d = new int[s1.length() + 1][s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) { for (int i = 0; i <= s1.length(); i++) {
d[i][0] = i; d[i][0] = i;
} }
@ -165,18 +165,17 @@ public abstract class PropertyMatches {
} }
for (int i = 1; i <= s1.length(); i++) { for (int i = 1; i <= s1.length(); i++) {
char s_i = s1.charAt(i - 1); char c1 = s1.charAt(i - 1);
for (int j = 1; j <= s2.length(); j++) { for (int j = 1; j <= s2.length(); j++) {
int cost; int cost;
char t_j = s2.charAt(j - 1); char c2 = s2.charAt(j - 1);
if (s_i == t_j) { if (c1 == c2) {
cost = 0; cost = 0;
} }
else { else {
cost = 1; cost = 1;
} }
d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + cost);
d[i - 1][j - 1] + cost);
} }
} }
@ -189,24 +188,23 @@ public abstract class PropertyMatches {
private static class BeanPropertyMatches extends PropertyMatches { private static class BeanPropertyMatches extends PropertyMatches {
public BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) { public BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
super(propertyName, calculateMatches(propertyName, super(propertyName,
BeanUtils.getPropertyDescriptors(beanClass), maxDistance)); calculateMatches(propertyName, BeanUtils.getPropertyDescriptors(beanClass), maxDistance));
} }
/** /**
* Generate possible property alternatives for the given property and * Generate possible property alternatives for the given property and class.
* class. Internally uses the {@code getStringDistance} method, which * Internally uses the {@code getStringDistance} method, which in turn uses
* in turn uses the Levenshtein algorithm to determine the distance between * the Levenshtein algorithm to determine the distance between two Strings.
* two Strings. * @param descriptors the JavaBeans property descriptors to search
* @param propertyDescriptors the JavaBeans property descriptors to search
* @param maxDistance the maximum distance to accept * @param maxDistance the maximum distance to accept
*/ */
private static String[] calculateMatches(String propertyName, PropertyDescriptor[] propertyDescriptors, int maxDistance) { private static String[] calculateMatches(String name, PropertyDescriptor[] descriptors, int maxDistance) {
List<String> candidates = new ArrayList<>(); List<String> candidates = new ArrayList<>();
for (PropertyDescriptor pd : propertyDescriptors) { for (PropertyDescriptor pd : descriptors) {
if (pd.getWriteMethod() != null) { if (pd.getWriteMethod() != null) {
String possibleAlternative = pd.getName(); String possibleAlternative = pd.getName();
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) { if (calculateStringDistance(name, possibleAlternative) <= maxDistance) {
candidates.add(possibleAlternative); candidates.add(possibleAlternative);
} }
} }
@ -215,21 +213,16 @@ public abstract class PropertyMatches {
return StringUtils.toStringArray(candidates); return StringUtils.toStringArray(candidates);
} }
@Override @Override
public String buildErrorMessage() { public String buildErrorMessage() {
String propertyName = getPropertyName(); StringBuilder msg = new StringBuilder(160);
String[] possibleMatches = getPossibleMatches(); msg.append("Bean property '").append(getPropertyName()).append(
StringBuilder msg = new StringBuilder(); "' is not writable or has an invalid setter method. ");
msg.append("Bean property '"); if (!ObjectUtils.isEmpty(getPossibleMatches())) {
msg.append(propertyName); appendHintMessage(msg);
msg.append("' is not writable or has an invalid setter method. ");
if (ObjectUtils.isEmpty(possibleMatches)) {
msg.append("Does the parameter type of the setter match the return type of the getter?");
} }
else { else {
appendHintMessage(msg); msg.append("Does the parameter type of the setter match the return type of the getter?");
} }
return msg.toString(); return msg.toString();
} }
@ -242,11 +235,11 @@ public abstract class PropertyMatches {
super(propertyName, calculateMatches(propertyName, beanClass, maxDistance)); super(propertyName, calculateMatches(propertyName, beanClass, maxDistance));
} }
private static String[] calculateMatches(final String propertyName, Class<?> beanClass, final int maxDistance) { private static String[] calculateMatches(final String name, Class<?> clazz, final int maxDistance) {
final List<String> candidates = new ArrayList<>(); final List<String> candidates = new ArrayList<>();
ReflectionUtils.doWithFields(beanClass, field -> { ReflectionUtils.doWithFields(clazz, field -> {
String possibleAlternative = field.getName(); String possibleAlternative = field.getName();
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) { if (calculateStringDistance(name, possibleAlternative) <= maxDistance) {
candidates.add(possibleAlternative); candidates.add(possibleAlternative);
} }
}); });
@ -256,14 +249,10 @@ public abstract class PropertyMatches {
@Override @Override
public String buildErrorMessage() { public String buildErrorMessage() {
String propertyName = getPropertyName(); StringBuilder msg = new StringBuilder(80);
String[] possibleMatches = getPossibleMatches(); msg.append("Bean property '").append(getPropertyName()).append("' has no matching field.");
StringBuilder msg = new StringBuilder(); if (!ObjectUtils.isEmpty(getPossibleMatches())) {
msg.append("Bean property '"); msg.append(' ');
msg.append(propertyName);
msg.append("' has no matching field. ");
if (!ObjectUtils.isEmpty(possibleMatches)) {
appendHintMessage(msg); appendHintMessage(msg);
} }
return msg.toString(); return msg.toString();

View File

@ -22,17 +22,16 @@
<xsd:complexType> <xsd:complexType>
<xsd:annotation> <xsd:annotation>
<xsd:documentation source="java:org.springframework.cache.annotation.AnnotationCacheOperationDefinitionSource"><![CDATA[ <xsd:documentation source="java:org.springframework.cache.annotation.AnnotationCacheOperationDefinitionSource"><![CDATA[
Indicates that cache configuration is defined by Java 5 Indicates that cache configuration is defined by annotations on bean classes,
annotations on bean classes, and that proxies are automatically and that proxies are automatically to be created for the relevant annotated beans.
to be created for the relevant annotated beans.
The default annotations supported are Spring's @Cacheable, @CachePut and @CacheEvict. If The default annotations supported are Spring's @Cacheable, @CachePut and @CacheEvict.
spring-context-support and the JSR-107 API are on the classpath, additional proxies are If spring-context-support and the JSR-107 API are on the classpath, additional proxies
automatically created for JSR-107 annotated beans, that is @CacheResult, @CachePut, are automatically created for JSR-107 annotated beans, that is @CacheResult, @CachePut,
@CacheRemove and @CacheRemoveAll. @CacheRemove and @CacheRemoveAll.
See org.springframework.cache.annotation.EnableCaching Javadoc See org.springframework.cache.annotation.EnableCaching javadoc for information on
for information on code-based alternatives to this XML element. code-based alternatives to this XML element.
]]></xsd:documentation> ]]></xsd:documentation>
</xsd:annotation> </xsd:annotation>
<xsd:attribute name="cache-manager" type="xsd:string" default="cacheManager"> <xsd:attribute name="cache-manager" type="xsd:string" default="cacheManager">
@ -148,8 +147,7 @@
<xsd:complexType> <xsd:complexType>
<xsd:annotation> <xsd:annotation>
<xsd:documentation source="java:org.springframework.cache.interceptor.CacheInterceptor"><![CDATA[ <xsd:documentation source="java:org.springframework.cache.interceptor.CacheInterceptor"><![CDATA[
Defines the cache semantics of the AOP advice that is to be Defines the cache semantics of the AOP advice that is to be executed.
executed.
That is, this advice element is where the cacheable semantics of That is, this advice element is where the cacheable semantics of
any number of methods are defined (where cacheable semantics any number of methods are defined (where cacheable semantics
@ -243,7 +241,6 @@
example, 'get*', 'handle*', '*Order', 'on*Event', etc.]]></xsd:documentation> example, 'get*', 'handle*', '*Order', 'on*Event', etc.]]></xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
</xsd:complexType> </xsd:complexType>
<xsd:complexType name="definitionsType"> <xsd:complexType name="definitionsType">
@ -303,7 +300,6 @@
invoked (default) or before.]]></xsd:documentation> invoked (default) or before.]]></xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
</xsd:extension> </xsd:extension>
</xsd:complexContent> </xsd:complexContent>
</xsd:complexType> </xsd:complexType>

View File

@ -20,12 +20,12 @@
<xsd:element name="annotation-driven"> <xsd:element name="annotation-driven">
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[
Enables the detection of @JmsListener annotation on any Spring-managed object. If Enables the detection of @JmsListener annotation on any Spring-managed object.
present, a message listener container will be created to receive the relevant If present, a message listener container will be created to receive the relevant
messages and invoke the annotated method accordingly. messages and invoke the annotated method accordingly.
See Javadoc for the org.springframework.jms.annotation.EnableJms annotation for See org.springframework.jms.annotation.EnableJms javadoc for information on
information on code-based alternatives to this XML element. code-based alternatives to this XML element.
]]></xsd:documentation> ]]></xsd:documentation>
</xsd:annotation> </xsd:annotation>
<xsd:complexType> <xsd:complexType>
@ -68,7 +68,7 @@
processor. By default, DefaultMessageHandlerMethodFactory is used and it can be configured processor. By default, DefaultMessageHandlerMethodFactory is used and it can be configured
further to support additional method arguments or to customize conversion and validation further to support additional method arguments or to customize conversion and validation
support. See org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory support. See org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory
Javadoc for more details. javadoc for more details.
]]></xsd:documentation> ]]></xsd:documentation>
<xsd:appinfo> <xsd:appinfo>
<tool:annotation kind="ref"> <tool:annotation kind="ref">
@ -77,8 +77,6 @@
</xsd:appinfo> </xsd:appinfo>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
@ -378,14 +376,13 @@
<xsd:element name="jca-listener-container"> <xsd:element name="jca-listener-container">
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[
Each listener child element will be hosted by a container whose configuration Each listener child element will be hosted by a container whose configuration is
is determined by this parent element. This variant builds standard JCA-based determined by this parent element. This variant builds standard JCA-based listener
listener containers, operating against a specified JCA ResourceAdapter containers, operating against a specified JCA ResourceAdapter (which needs to be
(which needs to be provided by the JMS message broker, e.g. ActiveMQ). When provided by the JMS message broker, e.g. ActiveMQ). When a factory-id attribute is
a factory-id attribute is present, the configuration defined by this element is present, the configuration defined by this element is exposed as a bean of type
exposed as a org.springframework.jms.config.JmsListenerContainerFactory. It is org.springframework.jms.config.JmsListenerContainerFactory. It is therefore possible
therefore possible to only define this element without any child to just expose to only define this element without any child to just expose a container factory.
a container factory.
]]></xsd:documentation> ]]></xsd:documentation>
<xsd:appinfo> <xsd:appinfo>
<tool:annotation> <tool:annotation>
@ -400,7 +397,8 @@
<xsd:attribute name="factory-id" type="xsd:string"> <xsd:attribute name="factory-id" type="xsd:string">
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[
Expose the settings defined by this element as a org.springframework.jms.config.JmsListenerContainerFactory Expose the settings defined by this element as a bean of type
org.springframework.jms.config.JmsListenerContainerFactory
so that they can be reused with other endpoints. so that they can be reused with other endpoints.
]]></xsd:documentation> ]]></xsd:documentation>
</xsd:annotation> </xsd:annotation>
@ -478,8 +476,8 @@
<xsd:attribute name="response-destination-type" default="queue"> <xsd:attribute name="response-destination-type" default="queue">
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[
The JMS destination type for responses: "queue", "topic". Default The JMS destination type for responses: "queue", "topic".
is the value of the "destination-type" attribute. Default is the value of the "destination-type" attribute.
]]></xsd:documentation> ]]></xsd:documentation>
</xsd:annotation> </xsd:annotation>
<xsd:simpleType> <xsd:simpleType>

View File

@ -24,7 +24,6 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -182,11 +181,10 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
* but not by consumable/producible media types * but not by consumable/producible media types
*/ */
@Override @Override
protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> infos, String lookupPath, protected HandlerMethod handleNoMatch(
HttpServletRequest request) throws ServletException { Set<RequestMappingInfo> infos, String lookupPath, HttpServletRequest request) throws ServletException {
PartialMatchHelper helper = new PartialMatchHelper(infos, request); PartialMatchHelper helper = new PartialMatchHelper(infos, request);
if (helper.isEmpty()) { if (helper.isEmpty()) {
return null; return null;
} }