Polishing
This commit is contained in:
@@ -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.
|
||||
@@ -227,7 +227,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <b>declaration order</b> of this advice within the aspect
|
||||
* Set the declaration order of this advice within the aspect.
|
||||
*/
|
||||
public void setDeclarationOrder(int order) {
|
||||
this.declarationOrder = order;
|
||||
@@ -366,7 +366,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
* to which argument name. There are multiple strategies for determining
|
||||
* this binding, which are arranged in a ChainOfResponsibility.
|
||||
*/
|
||||
public synchronized final void calculateArgumentBindings() {
|
||||
public final synchronized void calculateArgumentBindings() {
|
||||
// The simple case... nothing to bind.
|
||||
if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
|
||||
return;
|
||||
@@ -374,10 +374,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
|
||||
int numUnboundArgs = this.parameterTypes.length;
|
||||
Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
|
||||
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) {
|
||||
numUnboundArgs--;
|
||||
}
|
||||
else if (maybeBindJoinPointStaticPart(parameterTypes[0])) {
|
||||
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0]) ||
|
||||
maybeBindJoinPointStaticPart(parameterTypes[0])) {
|
||||
numUnboundArgs--;
|
||||
}
|
||||
|
||||
|
||||
@@ -381,10 +381,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
refName = args[0].toString();
|
||||
}
|
||||
boolean parentRef = false;
|
||||
if (args.length > 1) {
|
||||
if (args[1] instanceof Boolean) {
|
||||
parentRef = (Boolean) args[1];
|
||||
}
|
||||
if (args.length > 1 && args[1] instanceof Boolean) {
|
||||
parentRef = (Boolean) args[1];
|
||||
}
|
||||
return new RuntimeBeanReference(refName, parentRef);
|
||||
}
|
||||
@@ -411,12 +409,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
private boolean addDeferredProperty(String property, Object newValue) {
|
||||
if (newValue instanceof List) {
|
||||
this.deferredProperties.put(this.currentBeanDefinition.getBeanName() + '.' + property,
|
||||
new DeferredProperty(this.currentBeanDefinition, property, newValue));
|
||||
return true;
|
||||
}
|
||||
else if (newValue instanceof Map) {
|
||||
if (newValue instanceof List || newValue instanceof Map) {
|
||||
this.deferredProperties.put(this.currentBeanDefinition.getBeanName() + '.' + property,
|
||||
new DeferredProperty(this.currentBeanDefinition, property, newValue));
|
||||
return true;
|
||||
|
||||
@@ -311,23 +311,23 @@ public abstract class BeanUtils {
|
||||
public static Method resolveSignature(String signature, Class<?> clazz) {
|
||||
Assert.hasText(signature, "'signature' must not be empty");
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
int firstParen = signature.indexOf('(');
|
||||
int lastParen = signature.indexOf(')');
|
||||
if (firstParen > -1 && lastParen == -1) {
|
||||
int startParen = signature.indexOf('(');
|
||||
int endParen = signature.indexOf(')');
|
||||
if (startParen > -1 && endParen == -1) {
|
||||
throw new IllegalArgumentException("Invalid method signature '" + signature +
|
||||
"': expected closing ')' for args list");
|
||||
}
|
||||
else if (lastParen > -1 && firstParen == -1) {
|
||||
else if (startParen == -1 && endParen > -1) {
|
||||
throw new IllegalArgumentException("Invalid method signature '" + signature +
|
||||
"': expected opening '(' for args list");
|
||||
}
|
||||
else if (firstParen == -1 && lastParen == -1) {
|
||||
else if (startParen == -1 && endParen == -1) {
|
||||
return findMethodWithMinimalParameters(clazz, signature);
|
||||
}
|
||||
else {
|
||||
String methodName = signature.substring(0, firstParen);
|
||||
String methodName = signature.substring(0, startParen);
|
||||
String[] parameterTypeNames =
|
||||
StringUtils.commaDelimitedListToStringArray(signature.substring(firstParen + 1, lastParen));
|
||||
StringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen));
|
||||
Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
|
||||
for (int i = 0; i < parameterTypeNames.length; i++) {
|
||||
String parameterTypeName = parameterTypeNames[i].trim();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -262,7 +262,7 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
|
||||
/**
|
||||
* Get the raw property value, if any.
|
||||
* @param propertyName the name to search for
|
||||
* @return the raw property value, or {@code null}
|
||||
* @return the raw property value, or {@code null} if none found
|
||||
* @since 4.0
|
||||
* @see #getPropertyValue(String)
|
||||
* @see PropertyValue#getValue()
|
||||
@@ -283,11 +283,7 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
|
||||
for (PropertyValue newPv : this.propertyValueList) {
|
||||
// if there wasn't an old one, add it
|
||||
PropertyValue pvOld = old.getPropertyValue(newPv.getName());
|
||||
if (pvOld == null) {
|
||||
changes.addPropertyValue(newPv);
|
||||
}
|
||||
else if (!pvOld.equals(newPv)) {
|
||||
// it's changed
|
||||
if (pvOld == null || !pvOld.equals(newPv)) {
|
||||
changes.addPropertyValue(newPv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,7 +561,7 @@ class ConfigurationClassParser {
|
||||
}
|
||||
|
||||
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
|
||||
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
|
||||
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
|
||||
|
||||
if (importCandidates.isEmpty()) {
|
||||
return;
|
||||
@@ -702,7 +702,8 @@ class ConfigurationClassParser {
|
||||
@SuppressWarnings("serial")
|
||||
private static class ImportStack extends ArrayDeque<ConfigurationClass> implements ImportRegistry {
|
||||
|
||||
private final MultiValueMap<String, AnnotationMetadata> imports = new LinkedMultiValueMap<String, AnnotationMetadata>();
|
||||
private final MultiValueMap<String, AnnotationMetadata> imports =
|
||||
new LinkedMultiValueMap<String, AnnotationMetadata>();
|
||||
|
||||
public void registerImport(AnnotationMetadata importingClass, String importedClass) {
|
||||
this.imports.add(importedClass, importingClass);
|
||||
@@ -948,9 +949,9 @@ class ConfigurationClassParser {
|
||||
public CircularImportProblem(ConfigurationClass attemptedImport, Deque<ConfigurationClass> importStack) {
|
||||
super(String.format("A circular @Import has been detected: " +
|
||||
"Illegal attempt by @Configuration class '%s' to import class '%s' as '%s' is " +
|
||||
"already present in the current import stack %s", importStack.peek().getSimpleName(),
|
||||
"already present in the current import stack %s", importStack.element().getSimpleName(),
|
||||
attemptedImport.getSimpleName(), attemptedImport.getSimpleName(), importStack),
|
||||
new Location(importStack.peek().getResource(), attemptedImport.getMetadata()));
|
||||
new Location(importStack.element().getResource(), attemptedImport.getMetadata()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -134,8 +134,9 @@ public class ListenableFutureCallbackRegistry<T> {
|
||||
synchronized (this.mutex) {
|
||||
this.state = State.SUCCESS;
|
||||
this.result = result;
|
||||
while (!this.successCallbacks.isEmpty()) {
|
||||
notifySuccess(this.successCallbacks.poll());
|
||||
SuccessCallback<? super T> callback;
|
||||
while ((callback = this.successCallbacks.poll()) != null) {
|
||||
notifySuccess(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,8 +150,9 @@ public class ListenableFutureCallbackRegistry<T> {
|
||||
synchronized (this.mutex) {
|
||||
this.state = State.FAILURE;
|
||||
this.result = ex;
|
||||
while (!this.failureCallbacks.isEmpty()) {
|
||||
notifyFailure(this.failureCallbacks.poll());
|
||||
FailureCallback callback;
|
||||
while ((callback = this.failureCallbacks.poll()) != null) {
|
||||
notifyFailure(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,7 +57,7 @@ public interface ValueRef {
|
||||
/**
|
||||
* A ValueRef for the null value.
|
||||
*/
|
||||
static class NullValueRef implements ValueRef {
|
||||
class NullValueRef implements ValueRef {
|
||||
|
||||
static final NullValueRef INSTANCE = new NullValueRef();
|
||||
|
||||
@@ -84,13 +84,13 @@ public interface ValueRef {
|
||||
/**
|
||||
* A ValueRef holder for a single value, which cannot be set.
|
||||
*/
|
||||
static class TypedValueHolderValueRef implements ValueRef {
|
||||
class TypedValueHolderValueRef implements ValueRef {
|
||||
|
||||
private final TypedValue typedValue;
|
||||
|
||||
private final SpelNodeImpl node; // used only for error reporting
|
||||
|
||||
public TypedValueHolderValueRef(TypedValue typedValue,SpelNodeImpl node) {
|
||||
public TypedValueHolderValueRef(TypedValue typedValue, SpelNodeImpl node) {
|
||||
this.typedValue = typedValue;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@@ -349,10 +349,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||
if (typeDescriptor == null) {
|
||||
// Attempt to populate the cache entry
|
||||
try {
|
||||
if (canRead(context, target, name)) {
|
||||
typeDescriptor = this.typeDescriptorCache.get(cacheKey);
|
||||
}
|
||||
else if (canWrite(context, target, name)) {
|
||||
if (canRead(context, target, name) || canWrite(context, target, name)) {
|
||||
typeDescriptor = this.typeDescriptorCache.get(cacheKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -263,16 +263,13 @@ abstract class AbstractListenerContainerParser implements BeanDefinitionParser {
|
||||
|
||||
boolean replyPubSubDomain = false;
|
||||
String replyDestinationType = containerEle.getAttribute(RESPONSE_DESTINATION_TYPE_ATTRIBUTE);
|
||||
if (DESTINATION_TYPE_TOPIC.equals(replyDestinationType)) {
|
||||
if (!StringUtils.hasText(replyDestinationType)) {
|
||||
replyPubSubDomain = pubSubDomain; // the default: same value as pubSubDomain
|
||||
}
|
||||
else if (DESTINATION_TYPE_TOPIC.equals(replyDestinationType)) {
|
||||
replyPubSubDomain = true;
|
||||
}
|
||||
else if (DESTINATION_TYPE_QUEUE.equals(replyDestinationType)) {
|
||||
replyPubSubDomain = false;
|
||||
}
|
||||
else if (!StringUtils.hasText(replyDestinationType)) {
|
||||
replyPubSubDomain = pubSubDomain; // the default: same value as pubSubDomain
|
||||
}
|
||||
else if (StringUtils.hasText(replyDestinationType)) {
|
||||
else if (!DESTINATION_TYPE_QUEUE.equals(replyDestinationType)) {
|
||||
parserContext.getReaderContext().error("Invalid listener container 'response-destination-type': only " +
|
||||
"\"queue\", \"topic\" supported.", containerEle);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -90,6 +90,7 @@ public final class MockMvc {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A default request builder merged into every performed request.
|
||||
* @see org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder#defaultRequest(RequestBuilder)
|
||||
@@ -103,7 +104,7 @@ public final class MockMvc {
|
||||
* @see org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder#alwaysExpect(ResultMatcher)
|
||||
*/
|
||||
void setGlobalResultMatchers(List<ResultMatcher> resultMatchers) {
|
||||
Assert.notNull(resultMatchers, "resultMatchers is required");
|
||||
Assert.notNull(resultMatchers, "ResultMatcher List is required");
|
||||
this.defaultResultMatchers = resultMatchers;
|
||||
}
|
||||
|
||||
@@ -112,20 +113,17 @@ public final class MockMvc {
|
||||
* @see org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder#alwaysDo(ResultHandler)
|
||||
*/
|
||||
void setGlobalResultHandlers(List<ResultHandler> resultHandlers) {
|
||||
Assert.notNull(resultHandlers, "resultHandlers is required");
|
||||
Assert.notNull(resultHandlers, "ResultHandler List is required");
|
||||
this.defaultResultHandlers = resultHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a request and return a type that allows chaining further
|
||||
* actions, such as asserting expectations, on the result.
|
||||
*
|
||||
* @param requestBuilder used to prepare the request to execute;
|
||||
* see static factory methods in
|
||||
* {@link org.springframework.test.web.servlet.request.MockMvcRequestBuilders}
|
||||
*
|
||||
* @return an instance of {@link ResultActions}; never {@code null}
|
||||
*
|
||||
* @return an instance of {@link ResultActions} (never {@code null})
|
||||
* @see org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
* @see org.springframework.test.web.servlet.result.MockMvcResultMatchers
|
||||
*/
|
||||
@@ -153,29 +151,24 @@ public final class MockMvc {
|
||||
filterChain.doFilter(request, response);
|
||||
|
||||
if (DispatcherType.ASYNC.equals(request.getDispatcherType()) &&
|
||||
request.getAsyncContext() != null & !request.isAsyncStarted()) {
|
||||
|
||||
request.getAsyncContext() != null && !request.isAsyncStarted()) {
|
||||
request.getAsyncContext().complete();
|
||||
}
|
||||
|
||||
applyDefaultResultActions(mvcResult);
|
||||
|
||||
RequestContextHolder.setRequestAttributes(previousAttributes);
|
||||
|
||||
return new ResultActions() {
|
||||
|
||||
@Override
|
||||
public ResultActions andExpect(ResultMatcher matcher) throws Exception {
|
||||
matcher.match(mvcResult);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultActions andDo(ResultHandler handler) throws Exception {
|
||||
handler.handle(mvcResult);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcResult andReturn() {
|
||||
return mvcResult;
|
||||
@@ -184,7 +177,6 @@ public final class MockMvc {
|
||||
}
|
||||
|
||||
private void applyDefaultResultActions(MvcResult mvcResult) throws Exception {
|
||||
|
||||
for (ResultMatcher matcher : this.defaultResultMatchers) {
|
||||
matcher.match(mvcResult);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -128,10 +128,8 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
|
||||
String responseETag = generateETagHeaderValue(responseWrapper.getContentInputStream(), this.writeWeakETag);
|
||||
rawResponse.setHeader(HEADER_ETAG, responseETag);
|
||||
String requestETag = request.getHeader(HEADER_IF_NONE_MATCH);
|
||||
if (requestETag != null
|
||||
&& (responseETag.equals(requestETag)
|
||||
|| responseETag.replaceFirst("^W/", "").equals(requestETag.replaceFirst("^W/", ""))
|
||||
|| "*".equals(requestETag))) {
|
||||
if (requestETag != null && ("*".equals(requestETag) || responseETag.equals(requestETag) ||
|
||||
responseETag.replaceFirst("^W/", "").equals(requestETag.replaceFirst("^W/", "")))) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("ETag [" + responseETag + "] equal to If-None-Match, sending 304");
|
||||
}
|
||||
@@ -165,15 +163,13 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
|
||||
* @param response the HTTP response
|
||||
* @param responseStatusCode the HTTP response status code
|
||||
* @param inputStream the response body
|
||||
* @return {@code true} if eligible for ETag generation; {@code false} otherwise
|
||||
* @return {@code true} if eligible for ETag generation, {@code false} otherwise
|
||||
*/
|
||||
protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response,
|
||||
int responseStatusCode, InputStream inputStream) {
|
||||
|
||||
String method = request.getMethod();
|
||||
if (responseStatusCode >= 200 && responseStatusCode < 300
|
||||
&& HttpMethod.GET.matches(method)) {
|
||||
|
||||
if (responseStatusCode >= 200 && responseStatusCode < 300 && HttpMethod.GET.matches(method)) {
|
||||
String cacheControl = null;
|
||||
if (servlet3Present) {
|
||||
cacheControl = response.getHeader(HEADER_CACHE_CONTROL);
|
||||
@@ -194,7 +190,7 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
|
||||
* @see org.springframework.util.DigestUtils
|
||||
*/
|
||||
protected String generateETagHeaderValue(InputStream inputStream, boolean isWeak) throws IOException {
|
||||
// length of W/ + 0 + " + 32bits md5 hash + "
|
||||
// length of W/ + " + 0 + 32bits md5 hash + "
|
||||
StringBuilder builder = new StringBuilder(37);
|
||||
if (isWeak) {
|
||||
builder.append("W/");
|
||||
|
||||
@@ -259,10 +259,7 @@ public class UrlPathHelper {
|
||||
}
|
||||
c1 = requestUri.charAt(index1);
|
||||
}
|
||||
if (c1 == c2) {
|
||||
continue;
|
||||
}
|
||||
else if (ignoreCase && (Character.toLowerCase(c1) == Character.toLowerCase(c2))) {
|
||||
if (c1 == c2 || (ignoreCase && (Character.toLowerCase(c1) == Character.toLowerCase(c2)))) {
|
||||
continue;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1095,7 +1095,7 @@ The `number` package provides a `NumberFormatter`, `CurrencyFormatter`, and
|
||||
`PercentFormatter` to format `java.lang.Number` objects using a `java.text.NumberFormat`.
|
||||
The `datetime` package provides a `DateFormatter` to format `java.util.Date` objects with
|
||||
a `java.text.DateFormat`. The `datetime.joda` package provides comprehensive datetime
|
||||
formatting support based on the http://joda-time.sourceforge.net[Joda Time library].
|
||||
formatting support based on the http://joda-time.sourceforge.net[Joda-Time library].
|
||||
|
||||
Consider `DateFormatter` as an example `Formatter` implementation:
|
||||
|
||||
@@ -1227,7 +1227,7 @@ To trigger formatting, simply annotate fields with @NumberFormat:
|
||||
==== Format Annotation API
|
||||
A portable format annotation API exists in the `org.springframework.format.annotation`
|
||||
package. Use @NumberFormat to format java.lang.Number fields. Use @DateTimeFormat to
|
||||
format java.util.Date, java.util.Calendar, java.util.Long, or Joda Time fields.
|
||||
format java.util.Date, java.util.Calendar, java.util.Long, or Joda-Time fields.
|
||||
|
||||
The example below uses @DateTimeFormat to format a java.util.Date as a ISO Date
|
||||
(yyyy-MM-dd):
|
||||
@@ -1328,10 +1328,10 @@ You will need to ensure that Spring does not register default formatters, and in
|
||||
you should register all formatters manually. Use the
|
||||
`org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar` or
|
||||
`org.springframework.format.datetime.DateFormatterRegistrar` class depending on whether
|
||||
you use the Joda Time library.
|
||||
you use the Joda-Time library.
|
||||
|
||||
For example, the following Java configuration will register a global ' `yyyyMMdd`'
|
||||
format. This example does not depend on the Joda Time library:
|
||||
format. This example does not depend on the Joda-Time library:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -1396,7 +1396,7 @@ Time:
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Joda Time provides separate distinct types to represent `date`, `time` and `date-time`
|
||||
Joda-Time provides separate distinct types to represent `date`, `time` and `date-time`
|
||||
values. The `dateFormatter`, `timeFormatter` and `dateTimeFormatter` properties of the
|
||||
`JodaTimeFormatterRegistrar` should be used to configure the different formats for each
|
||||
type. The `DateTimeFormatterFactoryBean` provides a convenient way to create formatters.
|
||||
|
||||
@@ -4841,7 +4841,7 @@ It also enables the following:
|
||||
in addition to the JavaBeans PropertyEditors used for Data Binding.
|
||||
. Support for <<format,formatting>> Number fields using the `@NumberFormat` annotation
|
||||
through the `ConversionService`.
|
||||
. Support for <<format,formatting>> `Date`, `Calendar`, `Long`, and Joda Time fields using the
|
||||
. Support for <<format,formatting>> `Date`, `Calendar`, `Long`, and Joda-Time fields using the
|
||||
`@DateTimeFormat` annotation.
|
||||
. Support for <<mvc-config-validation,validating>> `@Controller` inputs with `@Valid`, if
|
||||
a JSR-303 Provider is present on the classpath.
|
||||
@@ -4925,8 +4925,8 @@ available.
|
||||
=== Conversion and Formatting
|
||||
|
||||
By default formatters for `Number` and `Date` types are installed, including support for
|
||||
the `@NumberFormat` and `@DateTimeFormat` annotations. Full support for the Joda Time
|
||||
formatting library is also installed if Joda Time is present on the classpath. To
|
||||
the `@NumberFormat` and `@DateTimeFormat` annotations. Full support for the Joda-Time
|
||||
formatting library is also installed if Joda-Time is present on the classpath. To
|
||||
register custom formatters and converters, override the `addFormatters` method:
|
||||
|
||||
[source,java,indent=0]
|
||||
|
||||
Reference in New Issue
Block a user