32
32
import java .nio .file .Path ;
33
33
import java .util .ArrayList ;
34
34
import java .util .Arrays ;
35
+ import java .util .HashMap ;
35
36
import java .util .List ;
36
37
import java .util .Map ;
38
+ import java .util .Optional ;
37
39
38
40
import org .codehaus .modello .ModelloException ;
39
41
import org .codehaus .modello .ModelloParameterConstants ;
57
59
public abstract class AbstractModelloGenerator implements ModelloGenerator {
58
60
private final Logger logger = LoggerFactory .getLogger (getClass ());
59
61
62
+ private static final Map <String , String > PLURAL_EXCEPTIONS = new HashMap <>();
63
+
64
+ static {
65
+ // Irregular names
66
+ PLURAL_EXCEPTIONS .put ("children" , "child" );
67
+ PLURAL_EXCEPTIONS .put ("feet" , "foot" );
68
+ PLURAL_EXCEPTIONS .put ("geese" , "goose" );
69
+ PLURAL_EXCEPTIONS .put ("indices" , "index" );
70
+ PLURAL_EXCEPTIONS .put ("men" , "man" );
71
+ PLURAL_EXCEPTIONS .put ("mice" , "mouse" );
72
+ PLURAL_EXCEPTIONS .put ("people" , "person" );
73
+ PLURAL_EXCEPTIONS .put ("teeth" , "tooth" );
74
+ PLURAL_EXCEPTIONS .put ("women" , "woman" );
75
+
76
+ // Invariant names
77
+ PLURAL_EXCEPTIONS .put ("aircraft" , "aircraft" );
78
+ PLURAL_EXCEPTIONS .put ("bison" , "bison" );
79
+ PLURAL_EXCEPTIONS .put ("deer" , "deer" );
80
+ PLURAL_EXCEPTIONS .put ("elk" , "elk" );
81
+ PLURAL_EXCEPTIONS .put ("fish" , "fish" );
82
+ PLURAL_EXCEPTIONS .put ("series" , "series" );
83
+ PLURAL_EXCEPTIONS .put ("sheep" , "sheep" );
84
+ PLURAL_EXCEPTIONS .put ("species" , "species" );
85
+
86
+ // Special "oes" exceptions
87
+ PLURAL_EXCEPTIONS .put ("buffaloes" , "buffalo" );
88
+ PLURAL_EXCEPTIONS .put ("cargoes" , "cargo" );
89
+ PLURAL_EXCEPTIONS .put ("echoes" , "echo" );
90
+ PLURAL_EXCEPTIONS .put ("goes" , "go" );
91
+ PLURAL_EXCEPTIONS .put ("haloes" , "halo" );
92
+ PLURAL_EXCEPTIONS .put ("heroes" , "hero" );
93
+ PLURAL_EXCEPTIONS .put ("mosquitoes" , "mosquito" );
94
+ PLURAL_EXCEPTIONS .put ("noes" , "no" );
95
+ PLURAL_EXCEPTIONS .put ("potatoes" , "potato" );
96
+ PLURAL_EXCEPTIONS .put ("tomatoes" , "tomato" );
97
+ PLURAL_EXCEPTIONS .put ("torpedoes" , "torpedo" );
98
+ PLURAL_EXCEPTIONS .put ("vetoes" , "veto" );
99
+ PLURAL_EXCEPTIONS .put ("volcanoes" , "volcano" );
100
+
101
+ // Special "ses" exceptions
102
+ PLURAL_EXCEPTIONS .put ("horses" , "horse" );
103
+ PLURAL_EXCEPTIONS .put ("licenses" , "license" );
104
+ PLURAL_EXCEPTIONS .put ("phases" , "phase" );
105
+
106
+ // Special "zzes" exceptions
107
+ PLURAL_EXCEPTIONS .put ("fezzes" , "fez" );
108
+ PLURAL_EXCEPTIONS .put ("whizzes" , "whiz" );
109
+
110
+ // Special "ies" exceptions
111
+ PLURAL_EXCEPTIONS .put ("movies" , "movie" );
112
+
113
+ // Special "ves" exceptions
114
+ PLURAL_EXCEPTIONS .put ("archives" , "archive" );
115
+ PLURAL_EXCEPTIONS .put ("relatives" , "relative" );
116
+ }
117
+
60
118
private Model model ;
61
119
62
120
private File outputDirectory ;
@@ -76,6 +134,7 @@ protected Logger getLogger() {
76
134
return logger ;
77
135
}
78
136
137
+ @ SuppressWarnings ("uncheked" )
79
138
protected void initialize (Model model , Map <String , Object > parameters ) throws ModelloException {
80
139
this .model = model ;
81
140
@@ -91,6 +150,9 @@ protected void initialize(Model model, Map<String, Object> parameters) throws Mo
91
150
encoding = (String ) parameters .get (ModelloParameterConstants .ENCODING );
92
151
93
152
licenseText = (List <String >) parameters .get (ModelloParameterConstants .LICENSE_TEXT );
153
+
154
+ Optional .ofNullable (parameters .get (ModelloParameterConstants .PLURAL_EXCEPTIONS ))
155
+ .ifPresent (o -> PLURAL_EXCEPTIONS .putAll ((Map <String , String >) o ));
94
156
}
95
157
96
158
protected Model getModel () {
@@ -150,6 +212,7 @@ protected boolean isClassInModel(String fieldType, Model model) {
150
212
151
213
/**
152
214
* Return the child fields of this class.
215
+ *
153
216
* @param modelClass current class
154
217
* @return the list of fields of this class
155
218
*/
@@ -194,23 +257,67 @@ protected String capitalise(String str) {
194
257
}
195
258
196
259
public static String singular (String name ) {
197
- if (StringUtils .isEmpty (name )) {
198
- return name ;
260
+ if (name == null || name .isEmpty ()) return name ;
261
+
262
+ String lower = name .toLowerCase ();
263
+
264
+ if (!lower .equals (name )) {
265
+ // we can have a case like otherArchives
266
+ String [] split = splitByUpperCase (name );
267
+ if (split != null && PLURAL_EXCEPTIONS .containsKey (split [1 ])) {
268
+ String plural = PLURAL_EXCEPTIONS .get (split [1 ]);
269
+ return split [0 ] + Character .toUpperCase (plural .charAt (0 )) + plural .substring (1 );
270
+ }
199
271
}
200
272
201
- if (name .endsWith ("ies" )) {
273
+ if (PLURAL_EXCEPTIONS .containsKey (lower )) {
274
+ return PLURAL_EXCEPTIONS .get (lower );
275
+ }
276
+
277
+ // Suffix-based rules
278
+ if (lower .endsWith ("ies" ) && name .length () > 3 ) {
202
279
return name .substring (0 , name .length () - 3 ) + "y" ;
203
- } else if (name .endsWith ("es" ) && name .endsWith ("ches" )) {
280
+ }
281
+ if (lower .endsWith ("aves" ) || lower .endsWith ("lves" ) || lower .endsWith ("rves" )) {
282
+ return name .substring (0 , name .length () - 3 ) + "f" ;
283
+ }
284
+ if (lower .endsWith ("ves" ) && !lower .endsWith ("fves" )) {
285
+ return name .substring (0 , name .length () - 3 ) + "fe" ;
286
+ }
287
+ if (lower .endsWith ("zzes" )) {
204
288
return name .substring (0 , name .length () - 2 );
205
- } else if (name .endsWith ("xes" )) {
289
+ }
290
+ if (lower .endsWith ("sses" )) {
206
291
return name .substring (0 , name .length () - 2 );
207
- } else if (name .endsWith ("s" ) && (name .length () != 1 )) {
292
+ }
293
+ if (lower .endsWith ("ses" )) {
294
+ return name .substring (0 , name .length () - 2 );
295
+ }
296
+ if (lower .endsWith ("ches" ) || lower .endsWith ("shes" )) {
297
+ return name .substring (0 , name .length () - 2 );
298
+ }
299
+ if (lower .endsWith ("xes" )) {
300
+ return name .substring (0 , name .length () - 2 );
301
+ }
302
+ if (lower .endsWith ("oes" )) {
303
+ return name .substring (0 , name .length () - 1 );
304
+ }
305
+ if (lower .endsWith ("s" ) && name .length () > 1 ) {
208
306
return name .substring (0 , name .length () - 1 );
209
307
}
210
308
211
309
return name ;
212
310
}
213
311
312
+ private static String [] splitByUpperCase (String name ) {
313
+ for (int i = name .length () - 1 ; i >= 0 ; i --) {
314
+ if (Character .isUpperCase (name .charAt (i ))) {
315
+ return new String [] {name .substring (0 , i ), name .substring (i ).toLowerCase ()};
316
+ }
317
+ }
318
+ return null ;
319
+ }
320
+
214
321
public static String uncapitalise (String str ) {
215
322
if (StringUtils .isEmpty (str )) {
216
323
return str ;
0 commit comments