Browse Source
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1836 50f2f4bb-b051-0410-bef5-90022cba6387pull/1/head
72 changed files with 1801 additions and 841 deletions
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.beans; |
||||
|
||||
import java.beans.PropertyDescriptor; |
||||
import java.lang.annotation.Annotation; |
||||
import java.lang.reflect.Field; |
||||
import java.lang.reflect.Method; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.core.MethodParameter; |
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
import org.springframework.util.ReflectionUtils; |
||||
|
||||
/** |
||||
* {@link TypeDescriptor} extension that exposes additional annotations |
||||
* as conversion metadata: namely, annotations on other accessor methods |
||||
* (getter/setter) and on the underlying field, if found. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
*/ |
||||
class BeanTypeDescriptor extends TypeDescriptor { |
||||
|
||||
private final PropertyDescriptor propertyDescriptor; |
||||
|
||||
private Annotation[] cachedAnnotations; |
||||
|
||||
|
||||
/** |
||||
* Create a new BeanTypeDescriptor for the given bean property. |
||||
* @param methodParameter the target method parameter |
||||
* @param propertyDescriptor the corresponding JavaBean PropertyDescriptor |
||||
*/ |
||||
public BeanTypeDescriptor(MethodParameter methodParameter, PropertyDescriptor propertyDescriptor) { |
||||
super(methodParameter); |
||||
this.propertyDescriptor = propertyDescriptor; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Annotation[] getAnnotations() { |
||||
Annotation[] anns = this.cachedAnnotations; |
||||
if (anns == null) { |
||||
Field underlyingField = ReflectionUtils.findField( |
||||
getMethodParameter().getMethod().getDeclaringClass(), this.propertyDescriptor.getName()); |
||||
Map<Class, Annotation> annMap = new LinkedHashMap<Class, Annotation>(); |
||||
if (underlyingField != null) { |
||||
for (Annotation ann : underlyingField.getAnnotations()) { |
||||
annMap.put(ann.annotationType(), ann); |
||||
} |
||||
} |
||||
Method targetMethod = getMethodParameter().getMethod(); |
||||
Method writeMethod = this.propertyDescriptor.getWriteMethod(); |
||||
Method readMethod = this.propertyDescriptor.getReadMethod(); |
||||
if (writeMethod != null && writeMethod != targetMethod) { |
||||
for (Annotation ann : writeMethod.getAnnotations()) { |
||||
annMap.put(ann.annotationType(), ann); |
||||
} |
||||
} |
||||
if (readMethod != null && readMethod != targetMethod) { |
||||
for (Annotation ann : readMethod.getAnnotations()) { |
||||
annMap.put(ann.annotationType(), ann); |
||||
} |
||||
} |
||||
for (Annotation ann : targetMethod.getAnnotations()) { |
||||
annMap.put(ann.annotationType(), ann); |
||||
} |
||||
anns = annMap.values().toArray(new Annotation[annMap.size()]); |
||||
this.cachedAnnotations = anns; |
||||
} |
||||
return anns; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.number; |
||||
|
||||
import java.text.NumberFormat; |
||||
import java.text.ParseException; |
||||
import java.text.ParsePosition; |
||||
import java.util.Locale; |
||||
|
||||
import org.springframework.ui.format.Formatter; |
||||
|
||||
/** |
||||
* Abstract formatter for Numbers, |
||||
* providing a {@link #getNumberFormat(java.util.Locale)} template method. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
public abstract class AbstractNumberFormatter implements Formatter<Number> { |
||||
|
||||
private boolean lenient = false; |
||||
|
||||
|
||||
/** |
||||
* Specify whether or not parsing is to be lenient. Default is false. |
||||
* <p>With lenient parsing, the parser may allow inputs that do not precisely match the format. |
||||
* With strict parsing, inputs must match the format exactly. |
||||
*/ |
||||
public void setLenient(boolean lenient) { |
||||
this.lenient = lenient; |
||||
} |
||||
|
||||
|
||||
public String format(Number integer, Locale locale) { |
||||
if (integer == null) { |
||||
return ""; |
||||
} |
||||
NumberFormat format = getNumberFormat(locale); |
||||
return format.format(integer); |
||||
} |
||||
|
||||
public Number parse(String formatted, Locale locale) throws ParseException { |
||||
if (formatted.length() == 0) { |
||||
return null; |
||||
} |
||||
NumberFormat format = getNumberFormat(locale); |
||||
ParsePosition position = new ParsePosition(0); |
||||
Number number = format.parse(formatted, position); |
||||
if (position.getErrorIndex() != -1) { |
||||
throw new ParseException(formatted, position.getIndex()); |
||||
} |
||||
if (!this.lenient) { |
||||
if (formatted.length() != position.getIndex()) { |
||||
// indicates a part of the string that was not parsed
|
||||
throw new ParseException(formatted, position.getIndex()); |
||||
} |
||||
} |
||||
return number; |
||||
} |
||||
|
||||
/** |
||||
* Obtain a concrete NumberFormat for the specified locale. |
||||
* @param locale the current locale |
||||
* @return the NumberFormat instance (never <code>null</code>) |
||||
*/ |
||||
protected abstract NumberFormat getNumberFormat(Locale locale); |
||||
|
||||
} |
||||
@ -1,82 +1,103 @@
@@ -1,82 +1,103 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Copyright 2002-2009 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.ui.format.number; |
||||
|
||||
import java.math.BigDecimal; |
||||
import java.math.RoundingMode; |
||||
import java.text.DecimalFormat; |
||||
import java.text.NumberFormat; |
||||
import java.text.ParseException; |
||||
import java.text.ParsePosition; |
||||
import java.util.Currency; |
||||
import java.util.Locale; |
||||
|
||||
import org.springframework.ui.format.Formatter; |
||||
import org.springframework.util.ClassUtils; |
||||
|
||||
/** |
||||
* A BigDecimal formatter for currency values. |
||||
* Delegates to {@link NumberFormat#getCurrencyInstance(Locale)}. |
||||
* |
||||
* <p>Delegates to {@link NumberFormat#getCurrencyInstance(Locale)}. |
||||
* Configures BigDecimal parsing so there is no loss of precision. |
||||
* Sets the scale of parsed BigDecimal values to {@link NumberFormat#getMaximumFractionDigits()}. |
||||
* Applies {@link RoundingMode#DOWN} to parsed values. |
||||
* Can apply a specified {@link RoundingMode} to parsed values. |
||||
* |
||||
* @author Keith Donald |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
* @see #setLenient(boolean) |
||||
* @see #setLenient |
||||
* @see #setRoundingMode |
||||
*/ |
||||
public final class CurrencyFormatter implements Formatter<BigDecimal> { |
||||
public final class CurrencyFormatter extends AbstractNumberFormatter { |
||||
|
||||
private static final boolean roundingModeOnDecimalFormat = |
||||
ClassUtils.hasMethod(DecimalFormat.class, "setRoundingMode", RoundingMode.class); |
||||
|
||||
private int fractionDigits = 2; |
||||
|
||||
private CurrencyNumberFormatFactory currencyFormatFactory = new CurrencyNumberFormatFactory(); |
||||
private RoundingMode roundingMode; |
||||
|
||||
private Currency currency; |
||||
|
||||
private boolean lenient; |
||||
|
||||
/** |
||||
* Specify whether or not parsing is to be lenient. |
||||
* With lenient parsing, the parser may allow inputs that do not precisely match the format. |
||||
* With strict parsing, inputs must match the format exactly. |
||||
* Default is false. |
||||
* Specify the desired number of fraction digits. |
||||
* Default is 2. |
||||
*/ |
||||
public void setLenient(boolean lenient) { |
||||
this.lenient = lenient; |
||||
public void setFractionDigits(int fractionDigits) { |
||||
this.fractionDigits = fractionDigits; |
||||
} |
||||
|
||||
public String format(BigDecimal decimal, Locale locale) { |
||||
if (decimal == null) { |
||||
return ""; |
||||
} |
||||
NumberFormat format = currencyFormatFactory.getNumberFormat(locale); |
||||
return format.format(decimal); |
||||
/** |
||||
* Specify the rounding mode to use for decimal parsing. |
||||
* Default is {@link RoundingMode#UNNECESSARY}. |
||||
*/ |
||||
public void setRoundingMode(RoundingMode roundingMode) { |
||||
this.roundingMode = roundingMode; |
||||
} |
||||
|
||||
/** |
||||
* Specify the currency, if known. |
||||
*/ |
||||
public void setCurrency(Currency currency) { |
||||
this.currency = currency; |
||||
} |
||||
|
||||
public BigDecimal parse(String formatted, Locale locale) |
||||
throws ParseException { |
||||
if (formatted.length() == 0) { |
||||
return null; |
||||
} |
||||
NumberFormat format = currencyFormatFactory.getNumberFormat(locale); |
||||
ParsePosition position = new ParsePosition(0); |
||||
BigDecimal decimal = (BigDecimal) format.parse(formatted, position); |
||||
if (position.getErrorIndex() != -1) { |
||||
throw new ParseException(formatted, position.getIndex()); |
||||
|
||||
public BigDecimal parse(String formatted, Locale locale) throws ParseException { |
||||
BigDecimal decimal = (BigDecimal) super.parse(formatted, locale); |
||||
if (this.roundingMode != null) { |
||||
decimal = decimal.setScale(this.fractionDigits, this.roundingMode); |
||||
} |
||||
else { |
||||
decimal = decimal.setScale(this.fractionDigits); |
||||
} |
||||
if (!lenient) { |
||||
if (formatted.length() != position.getIndex()) { |
||||
// indicates a part of the string that was not parsed
|
||||
throw new ParseException(formatted, position.getIndex()); |
||||
} |
||||
} |
||||
decimal = decimal.setScale(format.getMaximumFractionDigits(), format.getRoundingMode()); |
||||
return decimal; |
||||
} |
||||
|
||||
} |
||||
|
||||
protected NumberFormat getNumberFormat(Locale locale) { |
||||
DecimalFormat format = (DecimalFormat) NumberFormat.getCurrencyInstance(locale); |
||||
format.setParseBigDecimal(true); |
||||
format.setMaximumFractionDigits(this.fractionDigits); |
||||
format.setMinimumFractionDigits(this.fractionDigits); |
||||
if (this.roundingMode != null && roundingModeOnDecimalFormat) { |
||||
format.setRoundingMode(this.roundingMode); |
||||
} |
||||
if (this.currency != null) { |
||||
format.setCurrency(this.currency); |
||||
} |
||||
return format; |
||||
} |
||||
|
||||
} |
||||
|
||||
@ -1,39 +0,0 @@
@@ -1,39 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 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.ui.format.number; |
||||
|
||||
import java.math.RoundingMode; |
||||
import java.text.DecimalFormat; |
||||
import java.text.NumberFormat; |
||||
import java.util.Locale; |
||||
|
||||
/** |
||||
* Produces NumberFormat instances that format currency values. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see NumberFormat |
||||
*/ |
||||
final class CurrencyNumberFormatFactory extends NumberFormatFactory { |
||||
|
||||
private RoundingMode roundingMode = RoundingMode.DOWN; |
||||
|
||||
public NumberFormat getNumberFormat(Locale locale) { |
||||
DecimalFormat format = (DecimalFormat) NumberFormat.getCurrencyInstance(locale); |
||||
format.setParseBigDecimal(true); |
||||
format.setRoundingMode(roundingMode); |
||||
return format; |
||||
} |
||||
} |
||||
@ -1,80 +0,0 @@
@@ -1,80 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 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.ui.format.number; |
||||
|
||||
import java.text.DecimalFormat; |
||||
import java.text.NumberFormat; |
||||
import java.util.Locale; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
|
||||
/** |
||||
* Works with a general purpose {@link DecimalFormat} instance returned by calling |
||||
* {@link NumberFormat#getInstance(Locale)} by default. |
||||
* @author Keith Donald |
||||
* @see NumberFormat |
||||
* @see DecimalFormat |
||||
* @since 3.0 |
||||
*/ |
||||
class DefaultNumberFormatFactory extends NumberFormatFactory { |
||||
|
||||
private static Log logger = LogFactory.getLog(DefaultNumberFormatFactory.class); |
||||
|
||||
private String pattern; |
||||
|
||||
private Boolean parseBigDecimal; |
||||
|
||||
/** |
||||
* Sets the pattern to use to format number values. |
||||
* If not specified, the default DecimalFormat pattern is used. |
||||
* @param pattern the format pattern |
||||
* @see DecimalFormat#applyPattern(String) |
||||
*/ |
||||
public void setPattern(String pattern) { |
||||
this.pattern = pattern; |
||||
} |
||||
|
||||
/** |
||||
* Sets whether the format should always parse a big decimal. |
||||
* @param parseBigDecimal the big decimal parse status |
||||
* @see DecimalFormat#setParseBigDecimal(boolean) |
||||
*/ |
||||
public void setParseBigDecimal(boolean parseBigDecimal) { |
||||
this.parseBigDecimal = parseBigDecimal; |
||||
} |
||||
|
||||
public NumberFormat getNumberFormat(Locale locale) { |
||||
NumberFormat format = NumberFormat.getInstance(locale); |
||||
if (pattern != null) { |
||||
if (format instanceof DecimalFormat) { |
||||
((DecimalFormat) format).applyPattern(pattern); |
||||
} else { |
||||
logger.warn("Unable to apply format pattern '" + pattern |
||||
+ "'; Returned NumberFormat is not a DecimalFormat"); |
||||
} |
||||
} |
||||
if (parseBigDecimal != null) { |
||||
if (format instanceof DecimalFormat) { |
||||
((DecimalFormat) format).setParseBigDecimal(parseBigDecimal); |
||||
} else { |
||||
logger.warn("Unable to call setParseBigDecimal; not a DecimalFormat"); |
||||
} |
||||
} |
||||
return format; |
||||
} |
||||
|
||||
} |
||||
@ -1,77 +1,39 @@
@@ -1,77 +1,39 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Copyright 2002-2009 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.ui.format.number; |
||||
|
||||
import java.text.NumberFormat; |
||||
import java.text.ParseException; |
||||
import java.text.ParsePosition; |
||||
import java.util.Locale; |
||||
|
||||
import org.springframework.ui.format.Formatter; |
||||
|
||||
/** |
||||
* A Number formatter for whole integer values. |
||||
* Delegates to {@link NumberFormat#getIntegerInstance(Locale)}. |
||||
* |
||||
* <p>Delegates to {@link NumberFormat#getIntegerInstance(Locale)}. |
||||
* The {@link #parse(String, Locale)} routine always returns a Long. |
||||
* |
||||
* @author Keith Donald |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
* @see #setLenient(boolean) |
||||
* @see #setLenient |
||||
*/ |
||||
public final class IntegerFormatter implements Formatter<Number> { |
||||
|
||||
private IntegerNumberFormatFactory formatFactory = new IntegerNumberFormatFactory(); |
||||
|
||||
private boolean lenient; |
||||
|
||||
/** |
||||
* Specify whether or not parsing is to be lenient. |
||||
* With lenient parsing, the parser may allow inputs that do not precisely match the format. |
||||
* With strict parsing, inputs must match the format exactly. |
||||
* Default is false. |
||||
*/ |
||||
public void setLenient(boolean lenient) { |
||||
this.lenient = lenient; |
||||
} |
||||
|
||||
public String format(Number integer, Locale locale) { |
||||
if (integer == null) { |
||||
return ""; |
||||
} |
||||
NumberFormat format = formatFactory.getNumberFormat(locale); |
||||
return format.format(integer); |
||||
} |
||||
public final class IntegerFormatter extends AbstractNumberFormatter { |
||||
|
||||
public Number parse(String formatted, Locale locale) |
||||
throws ParseException { |
||||
if (formatted.length() == 0) { |
||||
return null; |
||||
} |
||||
NumberFormat format = formatFactory.getNumberFormat(locale); |
||||
ParsePosition position = new ParsePosition(0); |
||||
Long integer = (Long) format.parse(formatted, position); |
||||
if (position.getErrorIndex() != -1) { |
||||
throw new ParseException(formatted, position.getIndex()); |
||||
} |
||||
if (!lenient) { |
||||
if (formatted.length() != position.getIndex()) { |
||||
// indicates a part of the string that was not parsed
|
||||
throw new ParseException(formatted, position.getIndex()); |
||||
} |
||||
} |
||||
return integer; |
||||
protected NumberFormat getNumberFormat(Locale locale) { |
||||
return NumberFormat.getIntegerInstance(locale); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@ -1,31 +0,0 @@
@@ -1,31 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 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.ui.format.number; |
||||
|
||||
import java.text.NumberFormat; |
||||
import java.util.Locale; |
||||
|
||||
/** |
||||
* Produces NumberFormat instances that format integer values. |
||||
* @author Keith Donald |
||||
* @see NumberFormat |
||||
* @since 3.0 |
||||
*/ |
||||
final class IntegerNumberFormatFactory extends NumberFormatFactory { |
||||
public NumberFormat getNumberFormat(Locale locale) { |
||||
return NumberFormat.getIntegerInstance(locale); |
||||
} |
||||
} |
||||
@ -1,36 +0,0 @@
@@ -1,36 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 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.ui.format.number; |
||||
|
||||
import java.text.NumberFormat; |
||||
import java.util.Locale; |
||||
|
||||
/** |
||||
* A factory for {@link NumberFormat} objects. |
||||
* Conceals the complexity associated with configuring, constructing, and/or caching number format instances. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
abstract class NumberFormatFactory { |
||||
|
||||
/** |
||||
* Factory method that returns a fully-configured {@link NumberFormat} instance to use to format an object for |
||||
* display. |
||||
* @return the number format |
||||
*/ |
||||
public abstract NumberFormat getNumberFormat(Locale locale); |
||||
|
||||
} |
||||
@ -1,79 +1,45 @@
@@ -1,79 +1,45 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Copyright 2002-2009 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.ui.format.number; |
||||
|
||||
import java.math.BigDecimal; |
||||
import java.text.DecimalFormat; |
||||
import java.text.NumberFormat; |
||||
import java.text.ParseException; |
||||
import java.text.ParsePosition; |
||||
import java.util.Locale; |
||||
|
||||
import org.springframework.ui.format.Formatter; |
||||
|
||||
/** |
||||
* A Number formatter for percent values. |
||||
* Delegates to {@link NumberFormat#getPercentInstance(Locale)}. |
||||
* |
||||
* <p>Delegates to {@link NumberFormat#getPercentInstance(Locale)}. |
||||
* Configures BigDecimal parsing so there is no loss in precision. |
||||
* The {@link #parse(String, Locale)} routine always returns a BigDecimal. |
||||
* |
||||
* @author Keith Donald |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
* @see #setLenient(boolean) |
||||
* @see #setLenient |
||||
*/ |
||||
public final class PercentFormatter implements Formatter<Number> { |
||||
|
||||
private PercentNumberFormatFactory percentFormatFactory = new PercentNumberFormatFactory(); |
||||
|
||||
private boolean lenient; |
||||
|
||||
/** |
||||
* Specify whether or not parsing is to be lenient. |
||||
* With lenient parsing, the parser may allow inputs that do not precisely match the format. |
||||
* With strict parsing, inputs must match the format exactly. |
||||
* Default is false. |
||||
*/ |
||||
public void setLenient(boolean lenient) { |
||||
this.lenient = lenient; |
||||
} |
||||
public final class PercentFormatter extends AbstractNumberFormatter { |
||||
|
||||
public String format(Number number, Locale locale) { |
||||
if (number == null) { |
||||
return ""; |
||||
} |
||||
NumberFormat format = percentFormatFactory.getNumberFormat(locale); |
||||
return format.format(number); |
||||
} |
||||
|
||||
public Number parse(String formatted, Locale locale) |
||||
throws ParseException { |
||||
if (formatted.length() == 0) { |
||||
return null; |
||||
} |
||||
NumberFormat format = percentFormatFactory.getNumberFormat(locale); |
||||
ParsePosition position = new ParsePosition(0); |
||||
BigDecimal decimal = (BigDecimal) format.parse(formatted, position); |
||||
if (position.getErrorIndex() != -1) { |
||||
throw new ParseException(formatted, position.getIndex()); |
||||
} |
||||
if (!lenient) { |
||||
if (formatted.length() != position.getIndex()) { |
||||
// indicates a part of the string that was not parsed
|
||||
throw new ParseException(formatted, position.getIndex()); |
||||
} |
||||
protected NumberFormat getNumberFormat(Locale locale) { |
||||
NumberFormat format = NumberFormat.getPercentInstance(locale); |
||||
if (format instanceof DecimalFormat) { |
||||
((DecimalFormat) format).setParseBigDecimal(true); |
||||
} |
||||
return decimal; |
||||
return format; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@ -1,34 +0,0 @@
@@ -1,34 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 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.ui.format.number; |
||||
|
||||
import java.text.DecimalFormat; |
||||
import java.text.NumberFormat; |
||||
import java.util.Locale; |
||||
|
||||
/** |
||||
* Produces NumberFormat instances that format percent values. |
||||
* @see NumberFormat |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
final class PercentNumberFormatFactory extends NumberFormatFactory { |
||||
public NumberFormat getNumberFormat(Locale locale) { |
||||
DecimalFormat format = (DecimalFormat) NumberFormat.getPercentInstance(locale); |
||||
format.setParseBigDecimal(true); |
||||
return format; |
||||
} |
||||
} |
||||
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.validation.beanvalidation; |
||||
|
||||
import java.util.Iterator; |
||||
import java.util.Set; |
||||
import javax.validation.ConstraintViolation; |
||||
import javax.validation.Validation; |
||||
import javax.validation.Validator; |
||||
import javax.validation.ValidatorFactory; |
||||
|
||||
import org.springframework.beans.BeansException; |
||||
import org.springframework.beans.factory.BeanInitializationException; |
||||
import org.springframework.beans.factory.InitializingBean; |
||||
import org.springframework.beans.factory.config.BeanPostProcessor; |
||||
|
||||
/** |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
*/ |
||||
public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean { |
||||
|
||||
private javax.validation.Validator validator; |
||||
|
||||
|
||||
public void setValidator(Validator validator) { |
||||
this.validator = validator; |
||||
} |
||||
|
||||
public void setValidatorFactory(ValidatorFactory validatorFactory) { |
||||
this.validator = validatorFactory.getValidator(); |
||||
} |
||||
|
||||
public void afterPropertiesSet() { |
||||
if (this.validator == null) { |
||||
Validation.buildDefaultValidatorFactory().getValidator(); |
||||
} |
||||
} |
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { |
||||
return bean; |
||||
} |
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { |
||||
Set<ConstraintViolation<Object>> result = this.validator.validate(bean); |
||||
if (!result.isEmpty()) { |
||||
StringBuilder sb = new StringBuilder("Bean state is invalid: "); |
||||
for (Iterator<ConstraintViolation<Object>> it = result.iterator(); it.hasNext();) { |
||||
ConstraintViolation<Object> violation = it.next(); |
||||
sb.append(violation.getPropertyPath()).append(" - ").append(violation.getMessage()); |
||||
if (it.hasNext()) { |
||||
sb.append("; "); |
||||
} |
||||
} |
||||
throw new BeanInitializationException(sb.toString()); |
||||
} |
||||
return bean; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.validation.beanvalidation; |
||||
|
||||
import javax.validation.MessageInterpolator; |
||||
import javax.validation.TraversableResolver; |
||||
import javax.validation.Validation; |
||||
import javax.validation.Validator; |
||||
import javax.validation.ValidatorContext; |
||||
import javax.validation.ValidatorFactory; |
||||
|
||||
import org.springframework.beans.factory.InitializingBean; |
||||
|
||||
/** |
||||
* Configurable bean class that exposes a specific JSR-303 Validator |
||||
* through its original interface as well as through the Spring |
||||
* {@link org.springframework.validation.Validator} interface. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
*/ |
||||
public class CustomValidatorBean extends SpringValidatorAdapter implements Validator, InitializingBean { |
||||
|
||||
private ValidatorFactory validatorFactory; |
||||
|
||||
private MessageInterpolator messageInterpolator; |
||||
|
||||
private TraversableResolver traversableResolver; |
||||
|
||||
|
||||
/** |
||||
* Set the ValidatorFactory to obtain the target Validator from. |
||||
* <p>Default is {@link javax.validation.Validation#buildDefaultValidatorFactory()}. |
||||
*/ |
||||
public void setValidatorFactory(ValidatorFactory validatorFactory) { |
||||
this.validatorFactory = validatorFactory; |
||||
} |
||||
|
||||
/** |
||||
* Specify a custom MessageInterpolator to use for this Validator. |
||||
*/ |
||||
public void setMessageInterpolator(MessageInterpolator messageInterpolator) { |
||||
this.messageInterpolator = messageInterpolator; |
||||
} |
||||
|
||||
/** |
||||
* Specify a custom TraversableResolver to use for this Validator. |
||||
*/ |
||||
public void setTraversableResolver(TraversableResolver traversableResolver) { |
||||
this.traversableResolver = traversableResolver; |
||||
} |
||||
|
||||
|
||||
public void afterPropertiesSet() { |
||||
if (this.validatorFactory == null) { |
||||
this.validatorFactory = Validation.buildDefaultValidatorFactory(); |
||||
} |
||||
|
||||
ValidatorContext validatorContext = this.validatorFactory.usingContext(); |
||||
validatorContext.messageInterpolator(new LocaleContextMessageInterpolator( |
||||
this.messageInterpolator, this.validatorFactory.getMessageInterpolator())); |
||||
if (this.traversableResolver != null) { |
||||
validatorContext.traversableResolver(this.traversableResolver); |
||||
} |
||||
|
||||
setTargetValidator(validatorContext.getValidator()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,209 @@
@@ -0,0 +1,209 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.validation.beanvalidation; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.Properties; |
||||
import javax.validation.Configuration; |
||||
import javax.validation.ConstraintValidatorFactory; |
||||
import javax.validation.MessageInterpolator; |
||||
import javax.validation.TraversableResolver; |
||||
import javax.validation.Validation; |
||||
import javax.validation.Validator; |
||||
import javax.validation.ValidatorContext; |
||||
import javax.validation.ValidatorFactory; |
||||
import javax.validation.spi.ValidationProvider; |
||||
|
||||
import org.springframework.beans.factory.InitializingBean; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.ApplicationContextAware; |
||||
import org.springframework.core.io.Resource; |
||||
import org.springframework.util.CollectionUtils; |
||||
|
||||
/** |
||||
* This is the central class for <code>javax.validation</code> (JSR-303) setup |
||||
* in a Spring application context: It bootstraps a <code>javax.validation.ValidationFactory</code> |
||||
* and exposes it through the Spring {@link org.springframework.validation.Validator} interface
|
||||
* as well as through the JSR-303 {@link javax.validation.Validator} interface and the |
||||
* {@link javax.validation.ValidatorFactory} interface itself. |
||||
* |
||||
* <p>When talking to an instance of this bean through the Spring or JSR-303 Validator interfaces, |
||||
* you'll be talking to the default Validator of the underlying ValidatorFactory. This is very |
||||
* convenient in that you don't have to perform yet another call on the factory, assuming that |
||||
* you will almost always use the default Validator anyway. This can also be injected directly |
||||
* into any target dependency of type {@link org.springframework.validation.Validator}! |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
* @see javax.validation.ValidatorFactory |
||||
* @see javax.validation.Validator |
||||
* @see javax.validation.Validation#buildDefaultValidatorFactory() |
||||
*/ |
||||
public class LocalValidatorFactoryBean extends SpringValidatorAdapter |
||||
implements ValidatorFactory, Validator, ApplicationContextAware, InitializingBean { |
||||
|
||||
private Class<? extends ValidationProvider> providerClass; |
||||
|
||||
private MessageInterpolator messageInterpolator; |
||||
|
||||
private TraversableResolver traversableResolver; |
||||
|
||||
private ConstraintValidatorFactory constraintValidatorFactory; |
||||
|
||||
private Resource[] mappingLocations; |
||||
|
||||
private final Map<String, String> validationPropertyMap = new HashMap<String, String>(); |
||||
|
||||
private ApplicationContext applicationContext; |
||||
|
||||
private ValidatorFactory validatorFactory; |
||||
|
||||
|
||||
/** |
||||
* Specify the desired provider class, if any. |
||||
* <p>If not specified, JSR-303's default search mechanism will be used. |
||||
* @see javax.validation.Validation#byProvider(Class) |
||||
* @see javax.validation.Validation#byDefaultProvider() |
||||
*/ |
||||
public void setProviderClass(Class<? extends ValidationProvider> providerClass) { |
||||
this.providerClass = providerClass; |
||||
} |
||||
|
||||
/** |
||||
* Specify a custom MessageInterpolator to use for this ValidatorFactory |
||||
* and its exposed default Validator. |
||||
*/ |
||||
public void setMessageInterpolator(MessageInterpolator messageInterpolator) { |
||||
this.messageInterpolator = messageInterpolator; |
||||
} |
||||
|
||||
/** |
||||
* Specify a custom TraversableResolver to use for this ValidatorFactory |
||||
* and its exposed default Validator. |
||||
*/ |
||||
public void setTraversableResolver(TraversableResolver traversableResolver) { |
||||
this.traversableResolver = traversableResolver; |
||||
} |
||||
|
||||
/** |
||||
* Specify a custom ConstraintValidatorFactory to use for this ValidatorFactory. |
||||
* <p>Default is a {@link SpringConstraintValidatorFactory}, delegating to the |
||||
* containing ApplicationContext for creating autowired ConstraintValidator instances. |
||||
*/ |
||||
public void setConstraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) { |
||||
this.constraintValidatorFactory = constraintValidatorFactory; |
||||
} |
||||
|
||||
/** |
||||
* Specify resource locations to load XML constraint mapping files from, if any. |
||||
*/ |
||||
public void setMappingLocations(Resource[] mappingLocations) { |
||||
this.mappingLocations = mappingLocations; |
||||
} |
||||
|
||||
/** |
||||
* Specify bean validation properties to be passed to the validation provider. |
||||
* <p>Can be populated with a String |
||||
* "value" (parsed via PropertiesEditor) or a "props" element in XML bean definitions. |
||||
* @see javax.validation.Configuration#addProperty(String, String) |
||||
*/ |
||||
public void setValidationProperties(Properties jpaProperties) { |
||||
CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.validationPropertyMap); |
||||
} |
||||
|
||||
/** |
||||
* Specify bean validation properties to be passed to the validation provider as a Map. |
||||
* <p>Can be populated with a |
||||
* "map" or "props" element in XML bean definitions. |
||||
* @see javax.validation.Configuration#addProperty(String, String) |
||||
*/ |
||||
public void setValidationPropertyMap(Map<String, String> validationProperties) { |
||||
if (validationProperties != null) { |
||||
this.validationPropertyMap.putAll(validationProperties); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Allow Map access to the bean validation properties to be passed to the validation provider, |
||||
* with the option to add or override specific entries. |
||||
* <p>Useful for specifying entries directly, for example via "validationPropertyMap[myKey]". |
||||
*/ |
||||
public Map<String, String> getValidationPropertyMap() { |
||||
return this.validationPropertyMap; |
||||
} |
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) { |
||||
this.applicationContext = applicationContext; |
||||
} |
||||
|
||||
|
||||
public void afterPropertiesSet() { |
||||
Configuration configuration = (this.providerClass != null ? |
||||
Validation.byProvider(this.providerClass).configure() : |
||||
Validation.byDefaultProvider().configure()); |
||||
|
||||
configuration.messageInterpolator(new LocaleContextMessageInterpolator( |
||||
this.messageInterpolator, configuration.getDefaultMessageInterpolator())); |
||||
|
||||
if (this.traversableResolver != null) { |
||||
configuration.traversableResolver(this.traversableResolver); |
||||
} |
||||
|
||||
ConstraintValidatorFactory targetConstraintValidatorFactory = this.constraintValidatorFactory; |
||||
if (targetConstraintValidatorFactory == null && this.applicationContext != null) { |
||||
targetConstraintValidatorFactory = |
||||
new SpringConstraintValidatorFactory(this.applicationContext.getAutowireCapableBeanFactory()); |
||||
} |
||||
if (targetConstraintValidatorFactory != null) { |
||||
configuration.constraintValidatorFactory(targetConstraintValidatorFactory); |
||||
} |
||||
|
||||
if (this.mappingLocations != null) { |
||||
for (Resource location : this.mappingLocations) { |
||||
try { |
||||
configuration.addMapping(location.getInputStream()); |
||||
} |
||||
catch (IOException ex) { |
||||
throw new IllegalStateException("Cannot read mapping resource: " + location); |
||||
} |
||||
} |
||||
} |
||||
|
||||
for (Map.Entry<String, String> entry : this.validationPropertyMap.entrySet()) { |
||||
configuration.addProperty(entry.getKey(), entry.getValue()); |
||||
} |
||||
|
||||
this.validatorFactory = configuration.buildValidatorFactory(); |
||||
setTargetValidator(this.validatorFactory.getValidator()); |
||||
} |
||||
|
||||
|
||||
public Validator getValidator() { |
||||
return this.validatorFactory.getValidator(); |
||||
} |
||||
|
||||
public ValidatorContext usingContext() { |
||||
return this.validatorFactory.usingContext(); |
||||
} |
||||
|
||||
public MessageInterpolator getMessageInterpolator() { |
||||
return this.validatorFactory.getMessageInterpolator(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.validation.beanvalidation; |
||||
|
||||
import java.util.Locale; |
||||
import javax.validation.MessageInterpolator; |
||||
|
||||
import org.springframework.context.i18n.LocaleContextHolder; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Delegates to a target {@link MessageInterpolator} implementation but enforces Spring's |
||||
* managed Locale. Typically used to wrap the validation provider's default interpolator. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
* @see org.springframework.context.i18n.LocaleContextHolder#getLocale() |
||||
*/ |
||||
public class LocaleContextMessageInterpolator implements MessageInterpolator { |
||||
|
||||
private final MessageInterpolator targetInterpolator; |
||||
|
||||
|
||||
/** |
||||
* Create a new LocaleContextMessageInterpolator, wrapping the given target interpolator. |
||||
* @param targetInterpolator the target MessageInterpolator to wrap |
||||
*/ |
||||
public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) { |
||||
Assert.notNull(targetInterpolator, "Target MessageInterpolator must not be null"); |
||||
this.targetInterpolator = targetInterpolator; |
||||
} |
||||
|
||||
LocaleContextMessageInterpolator(MessageInterpolator customInterpolator, MessageInterpolator defaultInterpolator) { |
||||
this.targetInterpolator = (customInterpolator != null ? customInterpolator : defaultInterpolator); |
||||
} |
||||
|
||||
|
||||
public String interpolate(String message, Context context) { |
||||
return this.targetInterpolator.interpolate(message, context, LocaleContextHolder.getLocale()); |
||||
} |
||||
|
||||
public String interpolate(String message, Context context, Locale locale) { |
||||
return this.targetInterpolator.interpolate(message, context, locale); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.validation.beanvalidation; |
||||
|
||||
import javax.validation.ConstraintValidator; |
||||
import javax.validation.ConstraintValidatorFactory; |
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* JSR-303 {@link ConstraintValidatorFactory} implementation that delegates to a |
||||
* Spring BeanFactory for creating autowired {@link ConstraintValidator} instances. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
* @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean(Class) |
||||
* @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory() |
||||
*/ |
||||
public class SpringConstraintValidatorFactory implements ConstraintValidatorFactory { |
||||
|
||||
private final AutowireCapableBeanFactory beanFactory; |
||||
|
||||
|
||||
/** |
||||
* Create a new SpringConstraintValidatorFactory for the given BeanFactory. |
||||
* @param beanFactory the target BeanFactory |
||||
*/ |
||||
public SpringConstraintValidatorFactory(AutowireCapableBeanFactory beanFactory) { |
||||
Assert.notNull(beanFactory, "BeanFactory must not be null"); |
||||
this.beanFactory = beanFactory; |
||||
} |
||||
|
||||
|
||||
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) { |
||||
return this.beanFactory.createBean(key); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.validation.beanvalidation; |
||||
|
||||
import java.util.Set; |
||||
import javax.validation.ConstraintViolation; |
||||
import javax.validation.metadata.BeanDescriptor; |
||||
|
||||
import org.springframework.util.Assert; |
||||
import org.springframework.validation.Errors; |
||||
import org.springframework.validation.Validator; |
||||
|
||||
/** |
||||
* Adapter that takes a JSR-303 <code>javax.validator.Validator</code> |
||||
* and exposes it as a Spring {@link org.springframework.validation.Validator} |
||||
* while also exposing the original JSR-303 Validator interface itself. |
||||
* |
||||
* <p>Can be used as a programmatic wrapper. Also serves as base class for |
||||
* {@link CustomValidatorBean} and {@link LocalValidatorFactoryBean}. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
*/ |
||||
public class SpringValidatorAdapter implements Validator, javax.validation.Validator { |
||||
|
||||
private javax.validation.Validator targetValidator; |
||||
|
||||
|
||||
/** |
||||
* Create a new SpringValidatorAdapter for the given JSR-303 Validator. |
||||
* @param targetValidator the JSR-303 Validator to wrap |
||||
*/ |
||||
public SpringValidatorAdapter(javax.validation.Validator targetValidator) { |
||||
Assert.notNull(targetValidator, "Target Validator must not be null"); |
||||
this.targetValidator = targetValidator; |
||||
} |
||||
|
||||
SpringValidatorAdapter() { |
||||
} |
||||
|
||||
void setTargetValidator(javax.validation.Validator targetValidator) { |
||||
this.targetValidator = targetValidator; |
||||
} |
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of Spring Validator interface
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
public boolean supports(Class<?> clazz) { |
||||
return true; |
||||
} |
||||
|
||||
public void validate(Object target, Errors errors) { |
||||
Set<ConstraintViolation<Object>> result = this.targetValidator.validate(target); |
||||
for (ConstraintViolation<Object> violation : result) { |
||||
errors.rejectValue(violation.getPropertyPath().toString(), |
||||
violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(), |
||||
violation.getConstraintDescriptor().getAttributes().values().toArray(), |
||||
violation.getMessage()); |
||||
} |
||||
} |
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of JSR-303 Validator interface
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) { |
||||
return this.targetValidator.validate(object, groups); |
||||
} |
||||
|
||||
public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) { |
||||
return this.targetValidator.validateProperty(object, propertyName, groups); |
||||
} |
||||
|
||||
public <T> Set<ConstraintViolation<T>> validateValue( |
||||
Class<T> beanType, String propertyName, Object value, Class<?>... groups) { |
||||
|
||||
return this.targetValidator.validateValue(beanType, propertyName, groups); |
||||
} |
||||
|
||||
public BeanDescriptor getConstraintsForClass(Class<?> clazz) { |
||||
return this.targetValidator.getConstraintsForClass(clazz); |
||||
} |
||||
|
||||
public <T> T unwrap(Class<T> type) { |
||||
return this.targetValidator.unwrap(type); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
/** |
||||
* Support classes for integrating a JSR-303 Bean Validation provider |
||||
* (such as Hibernate Validator 4.0) into a Spring ApplicationContext |
||||
* and in particular with Spring's data binding and validation APIs. |
||||
* |
||||
* <p>The central class is {@link LocalValidatorFactoryBean} which |
||||
* defines a shared ValidatorFactory/Validator setup for availability |
||||
* to other Spring components. |
||||
*/ |
||||
package org.springframework.validation.beanvalidation; |
||||
@ -0,0 +1,199 @@
@@ -0,0 +1,199 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.validation.beanvalidation; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
import java.util.Arrays; |
||||
import java.util.Iterator; |
||||
import java.util.Set; |
||||
import javax.validation.Constraint; |
||||
import javax.validation.ConstraintPayload; |
||||
import javax.validation.ConstraintValidator; |
||||
import javax.validation.ConstraintValidatorContext; |
||||
import javax.validation.ConstraintViolation; |
||||
import javax.validation.Valid; |
||||
import javax.validation.constraints.NotNull; |
||||
|
||||
import org.hibernate.validation.HibernateValidationProvider; |
||||
import static org.junit.Assert.*; |
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.validation.BeanPropertyBindingResult; |
||||
import org.springframework.validation.FieldError; |
||||
import org.springframework.validation.ObjectError; |
||||
|
||||
/** |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
*/ |
||||
public class ValidatorFactoryTests { |
||||
|
||||
@Test |
||||
public void testSimpleValidation() throws Exception { |
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); |
||||
validator.afterPropertiesSet(); |
||||
ValidPerson person = new ValidPerson(); |
||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person); |
||||
assertEquals(2, result.size()); |
||||
for (ConstraintViolation<ValidPerson> cv : result) { |
||||
String path = cv.getPropertyPath().toString(); |
||||
if ("name".equals(path) || "address.street".equals(path)) { |
||||
assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull); |
||||
} |
||||
else { |
||||
fail("Invalid constraint violation with path '" + path + "'"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void testSimpleValidationWithCustomProvider() throws Exception { |
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); |
||||
validator.setProviderClass(HibernateValidationProvider.class); |
||||
validator.afterPropertiesSet(); |
||||
ValidPerson person = new ValidPerson(); |
||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person); |
||||
assertEquals(2, result.size()); |
||||
for (ConstraintViolation<ValidPerson> cv : result) { |
||||
String path = cv.getPropertyPath().toString(); |
||||
if ("name".equals(path) || "address.street".equals(path)) { |
||||
assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull); |
||||
} |
||||
else { |
||||
fail("Invalid constraint violation with path '" + path + "'"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void testSimpleValidationWithClassLevel() throws Exception { |
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); |
||||
validator.afterPropertiesSet(); |
||||
ValidPerson person = new ValidPerson(); |
||||
person.setName("Juergen"); |
||||
person.getAddress().setStreet("Juergen's Street"); |
||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person); |
||||
assertEquals(1, result.size()); |
||||
Iterator<ConstraintViolation<ValidPerson>> iterator = result.iterator(); |
||||
ConstraintViolation cv = iterator.next(); |
||||
assertEquals("", cv.getPropertyPath().toString()); |
||||
assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid); |
||||
} |
||||
|
||||
@Test |
||||
public void testSpringValidation() throws Exception { |
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); |
||||
validator.afterPropertiesSet(); |
||||
ValidPerson person = new ValidPerson(); |
||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); |
||||
validator.validate(person, result); |
||||
assertEquals(2, result.getErrorCount()); |
||||
FieldError fieldError = result.getFieldError("name"); |
||||
assertEquals("name", fieldError.getField()); |
||||
System.out.println(Arrays.asList(fieldError.getCodes())); |
||||
System.out.println(fieldError.getDefaultMessage()); |
||||
fieldError = result.getFieldError("address.street"); |
||||
assertEquals("address.street", fieldError.getField()); |
||||
System.out.println(Arrays.asList(fieldError.getCodes())); |
||||
System.out.println(fieldError.getDefaultMessage()); |
||||
} |
||||
|
||||
@Test |
||||
public void testSpringValidationWithClassLevel() throws Exception { |
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); |
||||
validator.afterPropertiesSet(); |
||||
ValidPerson person = new ValidPerson(); |
||||
person.setName("Juergen"); |
||||
person.getAddress().setStreet("Juergen's Street"); |
||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); |
||||
validator.validate(person, result); |
||||
assertEquals(1, result.getErrorCount()); |
||||
ObjectError fieldError = result.getGlobalError(); |
||||
System.out.println(Arrays.asList(fieldError.getCodes())); |
||||
System.out.println(fieldError.getDefaultMessage()); |
||||
} |
||||
|
||||
|
||||
@NameAddressValid |
||||
private static class ValidPerson { |
||||
|
||||
@NotNull |
||||
private String name; |
||||
|
||||
@Valid |
||||
private ValidAddress address = new ValidAddress(); |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public ValidAddress getAddress() { |
||||
return address; |
||||
} |
||||
|
||||
public void setAddress(ValidAddress address) { |
||||
this.address = address; |
||||
} |
||||
} |
||||
|
||||
|
||||
private static class ValidAddress { |
||||
|
||||
@NotNull |
||||
private String street; |
||||
|
||||
public String getStreet() { |
||||
return street; |
||||
} |
||||
|
||||
public void setStreet(String street) { |
||||
this.street = street; |
||||
} |
||||
} |
||||
|
||||
|
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Constraint(validatedBy = NameAddressValidator.class) |
||||
public @interface NameAddressValid { |
||||
|
||||
String message() default "Street must not contain name"; |
||||
|
||||
Class<?>[] groups() default {}; |
||||
|
||||
Class<? extends ConstraintPayload>[] payload() default {}; |
||||
} |
||||
|
||||
|
||||
public static class NameAddressValidator implements ConstraintValidator<NameAddressValid, ValidPerson> { |
||||
|
||||
public void initialize(NameAddressValid constraintAnnotation) { |
||||
} |
||||
|
||||
public boolean isValid(ValidPerson value, ConstraintValidatorContext constraintValidatorContext) { |
||||
return (value.name == null || !value.address.street.contains(value.name)); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.core.convert.support; |
||||
|
||||
import org.springframework.core.convert.ConversionFailedException; |
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
import org.springframework.util.ObjectUtils; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* Converts a String array to a single element. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
*/ |
||||
class StringArrayToObject implements ConversionExecutor { |
||||
|
||||
private final ConversionExecutor elementConverter; |
||||
|
||||
|
||||
public StringArrayToObject(TypeDescriptor targetType, GenericConversionService conversionService) { |
||||
this.elementConverter = conversionService.getConversionExecutor(String.class, targetType); |
||||
} |
||||
|
||||
|
||||
public Object execute(Object source) throws ConversionFailedException { |
||||
String str = StringUtils.arrayToCommaDelimitedString(ObjectUtils.toObjectArray(source)); |
||||
return this.elementConverter.execute(str); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue