1
1
/*
2
- * Copyright 2002-2008 the original author or authors.
2
+ * Copyright 2002-2012 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
18
18
19
19
import java .io .Serializable ;
20
20
import java .util .ArrayList ;
21
+ import java .util .Collection ;
22
+ import java .util .LinkedHashSet ;
21
23
import java .util .List ;
24
+ import java .util .Set ;
22
25
23
26
import org .springframework .util .StringUtils ;
24
27
25
28
/**
26
29
* Default implementation of the {@link MessageCodesResolver} interface.
27
30
*
28
- * <p>Will create two message codes for an object error, in the following order:
31
+ * <p>Will create two message codes for an object error, in the following order (when
32
+ * using the {@link Format#PREFIX_ERROR_CODE prefixed}
33
+ * {@link #setMessageCodeFormatter(MessageCodeFormatter) formatter}):
29
34
* <ul>
30
35
* <li>1.: code + "." + object name
31
36
* <li>2.: code
68
73
* <li>7. try "typeMismatch"
69
74
* </ul>
70
75
*
76
+ * <p>By default the {@code errorCode}s will be placed at the beginning of constructed
77
+ * message strings. The {@link #setMessageCodeFormatter(MessageCodeFormatter)
78
+ * messageCodeFormatter} property can be used to specify an alternative concatenation
79
+ * {@link MessageCodeFormatter format}.
80
+ *
71
81
* <p>In order to group all codes into a specific category within your resource bundles,
72
82
* e.g. "validation.typeMismatch.name" instead of the default "typeMismatch.name",
73
83
* consider specifying a {@link #setPrefix prefix} to be applied.
74
84
*
75
85
* @author Juergen Hoeller
86
+ * @author Phillip Webb
87
+ * @author Chris Beams
76
88
* @since 1.0.1
77
89
*/
78
90
@ SuppressWarnings ("serial" )
@@ -83,9 +95,13 @@ public class DefaultMessageCodesResolver implements MessageCodesResolver, Serial
83
95
*/
84
96
public static final String CODE_SEPARATOR = "." ;
85
97
98
+ private static final MessageCodeFormatter DEFAULT_FORMATTER = Format .PREFIX_ERROR_CODE ;
99
+
86
100
87
101
private String prefix = "" ;
88
102
103
+ private MessageCodeFormatter formatter = DEFAULT_FORMATTER ;
104
+
89
105
90
106
/**
91
107
* Specify a prefix to be applied to any code built by this resolver.
@@ -96,6 +112,15 @@ public void setPrefix(String prefix) {
96
112
this .prefix = (prefix != null ? prefix : "" );
97
113
}
98
114
115
+ /**
116
+ * Specify the format for message codes built by this resolver.
117
+ * <p>The default is {@link Format#PREFIX_ERROR_CODE}.
118
+ * @since 3.2
119
+ */
120
+ public void setMessageCodeFormatter (MessageCodeFormatter formatter ) {
121
+ this .formatter = (formatter == null ? DEFAULT_FORMATTER : formatter );
122
+ }
123
+
99
124
/**
100
125
* Return the prefix to be applied to any code built by this resolver.
101
126
* <p>Returns an empty String in case of no prefix.
@@ -106,9 +131,7 @@ protected String getPrefix() {
106
131
107
132
108
133
public String [] resolveMessageCodes (String errorCode , String objectName ) {
109
- return new String [] {
110
- postProcessMessageCode (errorCode + CODE_SEPARATOR + objectName ),
111
- postProcessMessageCode (errorCode )};
134
+ return resolveMessageCodes (errorCode , objectName , "" , null );
112
135
}
113
136
114
137
/**
@@ -121,26 +144,32 @@ public String[] resolveMessageCodes(String errorCode, String objectName) {
121
144
* @return the list of codes
122
145
*/
123
146
public String [] resolveMessageCodes (String errorCode , String objectName , String field , Class <?> fieldType ) {
124
- List <String > codeList = new ArrayList <String >();
147
+ Set <String > codeList = new LinkedHashSet <String >();
125
148
List <String > fieldList = new ArrayList <String >();
126
149
buildFieldList (field , fieldList );
127
- for (String fieldInList : fieldList ) {
128
- codeList .add (postProcessMessageCode (errorCode + CODE_SEPARATOR + objectName + CODE_SEPARATOR + fieldInList ));
129
- }
150
+ addCodes (codeList , errorCode , objectName , fieldList );
130
151
int dotIndex = field .lastIndexOf ('.' );
131
152
if (dotIndex != -1 ) {
132
153
buildFieldList (field .substring (dotIndex + 1 ), fieldList );
133
154
}
134
- for (String fieldInList : fieldList ) {
135
- codeList .add (postProcessMessageCode (errorCode + CODE_SEPARATOR + fieldInList ));
136
- }
155
+ addCodes (codeList , errorCode , null , fieldList );
137
156
if (fieldType != null ) {
138
- codeList . add ( postProcessMessageCode ( errorCode + CODE_SEPARATOR + fieldType .getName () ));
157
+ addCode ( codeList , errorCode , null , fieldType .getName ());
139
158
}
140
- codeList . add ( postProcessMessageCode ( errorCode ) );
159
+ addCode ( codeList , errorCode , null , null );
141
160
return StringUtils .toStringArray (codeList );
142
161
}
143
162
163
+ private void addCodes (Collection <String > codeList , String errorCode , String objectName , Iterable <String > fields ) {
164
+ for (String field : fields ) {
165
+ addCode (codeList , errorCode , objectName , field );
166
+ }
167
+ }
168
+
169
+ private void addCode (Collection <String > codeList , String errorCode , String objectName , String field ) {
170
+ codeList .add (postProcessMessageCode (this .formatter .format (errorCode , objectName , field )));
171
+ }
172
+
144
173
/**
145
174
* Add both keyed and non-keyed entries for the supplied <code>field</code>
146
175
* to the supplied field list.
@@ -173,4 +202,53 @@ protected String postProcessMessageCode(String code) {
173
202
return getPrefix () + code ;
174
203
}
175
204
205
+
206
+ /**
207
+ * Common message code formats.
208
+ *
209
+ * @author Phil Webb
210
+ * @author Chris Beams
211
+ * @since 3.2
212
+ * @see MessageCodeFormatter
213
+ * @see DefaultMessageCodesResolver#setMessageCodeFormatter(MessageCodeFormatter)
214
+ */
215
+ public static enum Format implements MessageCodeFormatter {
216
+
217
+ /**
218
+ * Prefix the error code at the beginning of the generated message code. e.g.:
219
+ * {@code errorCode + "." + object name + "." + field}
220
+ */
221
+ PREFIX_ERROR_CODE {
222
+ public String format (String errorCode , String objectName , String field ) {
223
+ return toDelimitedString (errorCode , objectName , field );
224
+ }
225
+ },
226
+
227
+ /**
228
+ * Postfix the error code at the end of the generated message code. e.g.:
229
+ * {@code object name + "." + field + "." + errorCode}
230
+ */
231
+ POSTFIX_ERROR_CODE {
232
+ public String format (String errorCode , String objectName , String field ) {
233
+ return toDelimitedString (objectName , field , errorCode );
234
+ }
235
+ };
236
+
237
+ /**
238
+ * Concatenate the given elements, delimiting each with
239
+ * {@link DefaultMessageCodesResolver#CODE_SEPARATOR}, skipping zero-length or
240
+ * null elements altogether.
241
+ */
242
+ public static String toDelimitedString (String ... elements ) {
243
+ StringBuilder rtn = new StringBuilder ();
244
+ for (String element : elements ) {
245
+ if (StringUtils .hasLength (element )) {
246
+ rtn .append (rtn .length () == 0 ? "" : CODE_SEPARATOR );
247
+ rtn .append (element );
248
+ }
249
+ }
250
+ return rtn .toString ();
251
+ }
252
+ }
253
+
176
254
}
0 commit comments