34
34
import java .lang .reflect .Field ;
35
35
import java .lang .reflect .InvocationTargetException ;
36
36
import java .lang .reflect .Modifier ;
37
+ import java .lang .reflect .ParameterizedType ;
38
+ import java .lang .reflect .Type ;
37
39
import java .security .AccessController ;
38
40
import java .security .PrivilegedAction ;
39
41
import java .util .ArrayDeque ;
40
42
import java .util .ArrayList ;
41
43
import java .util .Arrays ;
42
44
import java .util .Collections ;
45
+ import java .util .EnumSet ;
43
46
import java .util .HashMap ;
44
47
import java .util .HashSet ;
45
48
import java .util .LinkedHashMap ;
@@ -77,6 +80,11 @@ default public String getOptionsDescription() {
77
80
return "" ;
78
81
}
79
82
83
+ /**
84
+ * Constructs a formatted usage string from a table of fields.
85
+ * @param usageList The fields.
86
+ * @return A usage string.
87
+ */
80
88
public static String formatUsage (List <List <String >> usageList ) {
81
89
int [] maxWidth = new int [5 ];
82
90
@@ -118,6 +126,11 @@ public static String formatUsage(List<List<String>> usageList) {
118
126
return builder .toString ();
119
127
}
120
128
129
+ /**
130
+ * Constructs the usage string from the supplied Options subclass.
131
+ * @param options The options to construct a usage for.
132
+ * @return The usage string.
133
+ */
121
134
public static List <List <String >> getUsage (Class <? extends Options > options ) {
122
135
ArrayList <List <String >> list = new ArrayList <>();
123
136
ArrayList <List <String >> optionsList = new ArrayList <>();
@@ -175,28 +188,70 @@ public static List<List<String>> getUsage(Class<? extends Options> options) {
175
188
}
176
189
}
177
190
191
+ /**
192
+ * Returns a String representing the Enum constants from this class surrounded by '{', '}'
193
+ * and separated by a comma and a space.
194
+ * @param enumClazz The enum class to represent.
195
+ * @return A String containing all the enum constants.
196
+ */
197
+ public static String getEnumConstantString (Class <? extends Enum <?>> enumClazz ) {
198
+ Enum <?>[] constants = enumClazz .getEnumConstants ();
199
+ StringBuilder sb = new StringBuilder ();
200
+ sb .append ('{' );
201
+ for (Enum <?> o : constants ) {
202
+ sb .append (o .name ());
203
+ sb .append (", " );
204
+ }
205
+ sb .replace (sb .length () - 2 , sb .length (), "}" );
206
+ return sb .toString ();
207
+ }
208
+
178
209
public static String generateTypeDescription (Field f ) {
179
210
Class <?> clazz = f .getType ();
180
211
if (clazz .isEnum ()) {
181
- Object [] constants = clazz .getEnumConstants ();
182
- StringBuilder sb = new StringBuilder ();
183
- sb .append ("enum - {" );
184
- for (Object o : constants ) {
185
- sb .append (((Enum )o ).name ());
186
- sb .append (", " );
212
+ @ SuppressWarnings ("unchecked" ) //guarded by isEnum check
213
+ Class <? extends Enum <?>> enumClazz = (Class <? extends Enum <?>>) clazz ;
214
+ return "enum - " + getEnumConstantString (enumClazz );
215
+ } else if (clazz == EnumSet .class ) {
216
+ Type type = f .getGenericType ();
217
+ if (type instanceof ParameterizedType ) {
218
+ ParameterizedType typeName = (ParameterizedType ) type ;
219
+ // Should only have a single type parameter
220
+ Type enumType = typeName .getActualTypeArguments ()[0 ];
221
+ try {
222
+ @ SuppressWarnings ("unchecked" ) // type parameter to an enumset must be an enum
223
+ Class <? extends Enum <?>> enumClazz = (Class <? extends Enum <?>>) Class .forName (enumType .getTypeName ());
224
+ return "EnumSet - " + getEnumConstantString (enumClazz );
225
+ } catch (ClassNotFoundException e ) {
226
+ Logger .getLogger (Options .class .getName ()).warning ("Failed to load enum class '" + enumType .getTypeName () + "'" );
227
+ return typeName .getTypeName ();
228
+ }
229
+ } else {
230
+ return f .getGenericType ().getTypeName ();
187
231
}
188
- sb .replace (sb .length ()-2 ,sb .length (),"}" );
189
- return sb .toString ();
190
232
} else {
191
233
return f .getGenericType ().getTypeName ();
192
234
}
193
235
}
194
236
237
+ /**
238
+ * Gets the fields for this option's usage string.
239
+ * @param option The option annotation.
240
+ * @param f The annotated field.
241
+ * @param obj The parent options object, used to access the default value for this field.
242
+ * @return The fields for the usage string.
243
+ */
195
244
public static ArrayList <String > getOptionUsage (Option option , Field f , Options obj ) {
196
245
String typeString = generateTypeDescription (f );
197
246
return getOptionUsage (option ,f ,obj ,typeString );
198
247
}
199
248
249
+ /**
250
+ * Gets the usage for one of the default options (which don't have a parent options object).
251
+ * @param option The option annotation.
252
+ * @param type The type of the option.
253
+ * @return The fields for the usage string.
254
+ */
200
255
public static ArrayList <String > getOptionUsage (Option option , String type ) {
201
256
ArrayList <String > output = new ArrayList <>();
202
257
if (option .charName () != Option .EMPTY_CHAR ) {
@@ -211,6 +266,14 @@ public static ArrayList<String> getOptionUsage(Option option, String type) {
211
266
return output ;
212
267
}
213
268
269
+ /**
270
+ * Gets the usage fields for the supplied option.
271
+ * @param option The option annotation.
272
+ * @param f The field the annotation is attached to.
273
+ * @param obj The parent options object, used to access the default value for this field.
274
+ * @param type The type string used in the usage (may be the enum constants, or a short type descriptor).
275
+ * @return The fields for the usage string.
276
+ */
214
277
public static ArrayList <String > getOptionUsage (Option option , Field f , Options obj , String type ) {
215
278
ArrayList <String > output = new ArrayList <>();
216
279
if (option .charName () != Option .EMPTY_CHAR ) {
0 commit comments