Skip to content

Commit a5cb879

Browse files
committed
Merge branch '5.1.x'
2 parents 944b943 + 7a7d410 commit a5cb879

11 files changed

Lines changed: 207 additions & 115 deletions

File tree

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -571,8 +571,8 @@ protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
571571
bean.destroy();
572572
}
573573
catch (Throwable ex) {
574-
if (logger.isInfoEnabled()) {
575-
logger.info("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
574+
if (logger.isWarnEnabled()) {
575+
logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
576576
}
577577
}
578578
}

spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,10 @@ public void destroy() {
261261
catch (Throwable ex) {
262262
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
263263
if (logger.isDebugEnabled()) {
264-
logger.info(msg, ex);
264+
logger.warn(msg, ex);
265265
}
266266
else {
267-
logger.info(msg + ": " + ex);
267+
logger.warn(msg + ": " + ex);
268268
}
269269
}
270270
}
@@ -343,14 +343,14 @@ private void invokeCustomDestroyMethod(final Method destroyMethod) {
343343
String msg = "Destroy method '" + this.destroyMethodName + "' on bean with name '" +
344344
this.beanName + "' threw an exception";
345345
if (logger.isDebugEnabled()) {
346-
logger.info(msg, ex.getTargetException());
346+
logger.warn(msg, ex.getTargetException());
347347
}
348348
else {
349-
logger.info(msg + ": " + ex.getTargetException());
349+
logger.warn(msg + ": " + ex.getTargetException());
350350
}
351351
}
352352
catch (Throwable ex) {
353-
logger.info("Failed to invoke destroy method '" + this.destroyMethodName +
353+
logger.warn("Failed to invoke destroy method '" + this.destroyMethodName +
354354
"' on bean with name '" + this.beanName + "'", ex);
355355
}
356356
}

spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/SpringValidatorAdapterTests.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
package org.springframework.validation.beanvalidation2;
1818

1919
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
2021
import java.lang.annotation.Inherited;
2122
import java.lang.annotation.Repeatable;
2223
import java.lang.annotation.Retention;
24+
import java.lang.annotation.RetentionPolicy;
2325
import java.lang.annotation.Target;
2426
import java.lang.reflect.Field;
2527
import java.util.ArrayList;
@@ -50,13 +52,11 @@
5052
import org.springframework.beans.BeanWrapperImpl;
5153
import org.springframework.context.support.StaticMessageSource;
5254
import org.springframework.util.ObjectUtils;
55+
import org.springframework.util.SerializationTestUtils;
5356
import org.springframework.validation.BeanPropertyBindingResult;
5457
import org.springframework.validation.FieldError;
5558
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
5659

57-
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
58-
import static java.lang.annotation.ElementType.TYPE;
59-
import static java.lang.annotation.RetentionPolicy.RUNTIME;
6060
import static org.assertj.core.api.Assertions.assertThat;
6161

6262
/**
@@ -88,7 +88,7 @@ public void testUnwrap() {
8888
}
8989

9090
@Test // SPR-13406
91-
public void testNoStringArgumentValue() {
91+
public void testNoStringArgumentValue() throws Exception {
9292
TestBean testBean = new TestBean();
9393
testBean.setPassword("pass");
9494
testBean.setConfirmPassword("pass");
@@ -103,10 +103,11 @@ public void testNoStringArgumentValue() {
103103
assertThat(messageSource.getMessage(error, Locale.ENGLISH)).isEqualTo("Size of Password must be between 8 and 128");
104104
assertThat(error.contains(ConstraintViolation.class)).isTrue();
105105
assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("password");
106+
assertThat(SerializationTestUtils.serializeAndDeserialize(error.toString())).isEqualTo(error.toString());
106107
}
107108

108109
@Test // SPR-13406
109-
public void testApplyMessageSourceResolvableToStringArgumentValueWithResolvedLogicalFieldName() {
110+
public void testApplyMessageSourceResolvableToStringArgumentValueWithResolvedLogicalFieldName() throws Exception {
110111
TestBean testBean = new TestBean();
111112
testBean.setPassword("password");
112113
testBean.setConfirmPassword("PASSWORD");
@@ -121,6 +122,7 @@ public void testApplyMessageSourceResolvableToStringArgumentValueWithResolvedLog
121122
assertThat(messageSource.getMessage(error, Locale.ENGLISH)).isEqualTo("Password must be same value as Password(Confirm)");
122123
assertThat(error.contains(ConstraintViolation.class)).isTrue();
123124
assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("password");
125+
assertThat(SerializationTestUtils.serializeAndDeserialize(error.toString())).isEqualTo(error.toString());
124126
}
125127

126128
@Test // SPR-13406
@@ -323,8 +325,8 @@ public void setConfirmEmail(String confirmEmail) {
323325

324326
@Documented
325327
@Constraint(validatedBy = {SameValidator.class})
326-
@Target({TYPE, ANNOTATION_TYPE})
327-
@Retention(RUNTIME)
328+
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
329+
@Retention(RetentionPolicy.RUNTIME)
328330
@Repeatable(SameGroup.class)
329331
@interface Same {
330332

@@ -338,8 +340,8 @@ public void setConfirmEmail(String confirmEmail) {
338340

339341
String comparingField();
340342

341-
@Target({TYPE, ANNOTATION_TYPE})
342-
@Retention(RUNTIME)
343+
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
344+
@Retention(RetentionPolicy.RUNTIME)
343345
@Documented
344346
@interface List {
345347
Same[] value();
@@ -349,8 +351,8 @@ public void setConfirmEmail(String confirmEmail) {
349351

350352
@Documented
351353
@Inherited
352-
@Retention(RUNTIME)
353-
@Target({TYPE, ANNOTATION_TYPE})
354+
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
355+
@Retention(RetentionPolicy.RUNTIME)
354356
@interface SameGroup {
355357

356358
Same[] value();
@@ -486,7 +488,7 @@ public void setParent(Parent parent) {
486488

487489

488490
@Constraint(validatedBy = AnythingValidator.class)
489-
@Retention(RUNTIME)
491+
@Retention(RetentionPolicy.RUNTIME)
490492
public @interface AnythingValid {
491493

492494
String message() default "{AnythingValid.message}";
@@ -507,23 +509,22 @@ public void initialize(AnythingValid constraintAnnotation) {
507509

508510
@Override
509511
public boolean isValid(Object value, ConstraintValidatorContext context) {
510-
List<Field> fieldsErros = new ArrayList<>();
511-
Arrays.asList(value.getClass().getDeclaredFields()).forEach(f -> {
512-
f.setAccessible(true);
512+
List<Field> fieldsErrors = new ArrayList<>();
513+
Arrays.asList(value.getClass().getDeclaredFields()).forEach(field -> {
514+
field.setAccessible(true);
513515
try {
514-
if (!f.getName().equals(ID) && f.get(value) == null) {
515-
fieldsErros.add(f);
516+
if (!field.getName().equals(ID) && field.get(value) == null) {
517+
fieldsErrors.add(field);
516518
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
517-
.addPropertyNode(f.getName())
519+
.addPropertyNode(field.getName())
518520
.addConstraintViolation();
519521
}
520522
}
521523
catch (IllegalAccessException ex) {
522524
throw new IllegalStateException(ex);
523525
}
524-
525526
});
526-
return fieldsErros.isEmpty();
527+
return fieldsErrors.isEmpty();
527528
}
528529
}
529530

spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -165,27 +165,15 @@ protected void processConstraintViolations(Set<ConstraintViolation<Object>> viol
165165
String nestedField = bindingResult.getNestedPath() + field;
166166
if (nestedField.isEmpty()) {
167167
String[] errorCodes = bindingResult.resolveMessageCodes(errorCode);
168-
ObjectError error = new ObjectError(
169-
errors.getObjectName(), errorCodes, errorArgs, violation.getMessage()) {
170-
@Override
171-
public boolean shouldRenderDefaultMessage() {
172-
return requiresMessageFormat(violation);
173-
}
174-
};
175-
error.wrap(violation);
168+
ObjectError error = new ViolationObjectError(
169+
errors.getObjectName(), errorCodes, errorArgs, violation, this);
176170
bindingResult.addError(error);
177171
}
178172
else {
179173
Object rejectedValue = getRejectedValue(field, violation, bindingResult);
180174
String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field);
181-
FieldError error = new FieldError(errors.getObjectName(), nestedField,
182-
rejectedValue, false, errorCodes, errorArgs, violation.getMessage()) {
183-
@Override
184-
public boolean shouldRenderDefaultMessage() {
185-
return requiresMessageFormat(violation);
186-
}
187-
};
188-
error.wrap(violation);
175+
FieldError error = new ViolationFieldError(errors.getObjectName(), nestedField,
176+
rejectedValue, errorCodes, errorArgs, violation, this);
189177
bindingResult.addError(error);
190178
}
191179
}
@@ -307,29 +295,6 @@ protected MessageSourceResolvable getResolvableField(String objectName, String f
307295
return new DefaultMessageSourceResolvable(codes, field);
308296
}
309297

310-
/**
311-
* Indicate whether this violation's interpolated message has remaining
312-
* placeholders and therefore requires {@link java.text.MessageFormat}
313-
* to be applied to it. Called for a Bean Validation defined message
314-
* (coming out {@code ValidationMessages.properties}) when rendered
315-
* as the default message in Spring's MessageSource.
316-
* <p>The default implementation considers a Spring-style "{0}" placeholder
317-
* for the field name as an indication for {@link java.text.MessageFormat}.
318-
* Any other placeholder or escape syntax occurrences are typically a
319-
* mismatch, coming out of regex pattern values or the like. Note that
320-
* standard Bean Validation does not support "{0}" style placeholders at all;
321-
* this is a feature typically used in Spring MessageSource resource bundles.
322-
* @param violation the Bean Validation constraint violation, including
323-
* BV-defined interpolation of named attribute references in its message
324-
* @return {@code true} if {@code java.text.MessageFormat} is to be applied,
325-
* or {@code false} if the violation's message should be used as-is
326-
* @since 5.1.8
327-
* @see #getArgumentsForConstraint
328-
*/
329-
protected boolean requiresMessageFormat(ConstraintViolation<?> violation) {
330-
return violation.getMessage().contains("{0}");
331-
}
332-
333298
/**
334299
* Extract the rejected value behind the given constraint violation,
335300
* for exposure through the Spring errors representation.
@@ -354,6 +319,33 @@ protected Object getRejectedValue(String field, ConstraintViolation<Object> viol
354319
return invalidValue;
355320
}
356321

322+
/**
323+
* Indicate whether this violation's interpolated message has remaining
324+
* placeholders and therefore requires {@link java.text.MessageFormat}
325+
* to be applied to it. Called for a Bean Validation defined message
326+
* (coming out {@code ValidationMessages.properties}) when rendered
327+
* as the default message in Spring's MessageSource.
328+
* <p>The default implementation considers a Spring-style "{0}" placeholder
329+
* for the field name as an indication for {@link java.text.MessageFormat}.
330+
* Any other placeholder or escape syntax occurrences are typically a
331+
* mismatch, coming out of regex pattern values or the like. Note that
332+
* standard Bean Validation does not support "{0}" style placeholders at all;
333+
* this is a feature typically used in Spring MessageSource resource bundles.
334+
* @param violation the Bean Validation constraint violation, including
335+
* BV-defined interpolation of named attribute references in its message
336+
* @return {@code true} if {@code java.text.MessageFormat} is to be applied,
337+
* or {@code false} if the violation's message should be used as-is
338+
* @since 5.1.8
339+
* @see #getArgumentsForConstraint
340+
*/
341+
protected boolean requiresMessageFormat(ConstraintViolation<?> violation) {
342+
return containsSpringStylePlaceholder(violation.getMessage());
343+
}
344+
345+
private static boolean containsSpringStylePlaceholder(@Nullable String message) {
346+
return (message != null && message.contains("{0}"));
347+
}
348+
357349

358350
//---------------------------------------------------------------------
359351
// Implementation of JSR-303 Validator interface
@@ -436,6 +428,71 @@ public Object[] getArguments() {
436428
public String getDefaultMessage() {
437429
return this.resolvableString;
438430
}
431+
432+
@Override
433+
public String toString() {
434+
return this.resolvableString;
435+
}
436+
}
437+
438+
439+
/**
440+
* Subclass of {@code ObjectError} with Spring-style default message rendering.
441+
*/
442+
@SuppressWarnings("serial")
443+
private static class ViolationObjectError extends ObjectError implements Serializable {
444+
445+
@Nullable
446+
private transient SpringValidatorAdapter adapter;
447+
448+
@Nullable
449+
private transient ConstraintViolation<?> violation;
450+
451+
public ViolationObjectError(String objectName, String[] codes, Object[] arguments,
452+
ConstraintViolation<?> violation, SpringValidatorAdapter adapter) {
453+
454+
super(objectName, codes, arguments, violation.getMessage());
455+
this.adapter = adapter;
456+
this.violation = violation;
457+
wrap(violation);
458+
}
459+
460+
@Override
461+
public boolean shouldRenderDefaultMessage() {
462+
return (this.adapter != null && this.violation != null ?
463+
this.adapter.requiresMessageFormat(this.violation) :
464+
containsSpringStylePlaceholder(getDefaultMessage()));
465+
}
466+
}
467+
468+
469+
/**
470+
* Subclass of {@code FieldError} with Spring-style default message rendering.
471+
*/
472+
@SuppressWarnings("serial")
473+
private static class ViolationFieldError extends FieldError implements Serializable {
474+
475+
@Nullable
476+
private transient SpringValidatorAdapter adapter;
477+
478+
@Nullable
479+
private transient ConstraintViolation<?> violation;
480+
481+
public ViolationFieldError(String objectName, String field, @Nullable Object rejectedValue, String[] codes,
482+
Object[] arguments, ConstraintViolation<?> violation, SpringValidatorAdapter adapter) {
483+
484+
super(objectName, field, rejectedValue, false, codes, arguments, violation.getMessage());
485+
this.adapter = adapter;
486+
this.violation = violation;
487+
wrap(violation);
488+
}
489+
490+
@Override
491+
public boolean shouldRenderDefaultMessage() {
492+
return (this.adapter != null && this.violation != null ?
493+
this.adapter.requiresMessageFormat(this.violation) :
494+
containsSpringStylePlaceholder(getDefaultMessage()));
495+
}
439496
}
440497

441498
}

0 commit comments

Comments
 (0)