1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.munkei;
21
22 import com.munkei.exception.ArgumentParsingException;
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.Field;
25 import java.lang.reflect.InvocationTargetException;
26 import java.lang.reflect.Method;
27 import java.lang.reflect.ParameterizedType;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.Iterator;
33 import java.util.List;
34
35
36
37
38
39
40
41 public class Option {
42
43 private Object subject;
44
45 private Field field;
46
47 private List<String> names;
48
49 Option(Object subject, Field field) {
50 if (subject == null) {
51 throw new NullPointerException("Subject may not be null");
52 }
53 if (field == null) {
54 throw new NullPointerException("Field may not be null");
55 }
56 if (!field.isAnnotationPresent(CommandLineOption.class)) {
57 throw new IllegalArgumentException(
58 "Field ''{}'' has not got an @Option annotation.");
59 }
60
61 this.subject = subject;
62 this.field = field;
63 }
64
65 void set(String name,
66 Iterator<String> it)
67 throws ArgumentParsingException {
68 Object value = ((takesValue())
69 ? convert(it.next(), getEffectiveClass())
70 : true);
71 String setterName = getCommandLineOption().setter();
72
73
74 if (getCommandLineOption().setter() != null
75 && !getCommandLineOption().setter().isEmpty()) {
76 Method setter;
77 try {
78 try {
79 setter = subject.getClass().getMethod(setterName,
80 String.class,
81 getField().getType());
82 } catch (NoSuchMethodException |
83 SecurityException ex) {
84
85 setter = subject.getClass().getMethod(setterName,
86 getField().getType());
87 }
88 setter.invoke(subject, value);
89 } catch (NoSuchMethodException |
90 SecurityException ex) {
91 throw new ArgumentParsingException(
92 ex,
93 "Could not get setter (''{0}(java.lang.String, {1})'') for field ''{2}''.",
94 setterName,
95 getField().getType().getName(),
96 getField().getName());
97 } catch (IllegalAccessException |
98 InvocationTargetException ex) {
99 throw new ArgumentParsingException(
100 ex,
101 "Failed to invoke setter (''{0}(java.lang.String, {1})'') for field ''{2}'' with value ''{3}''",
102 setterName,
103 getField().getType().getName(),
104 getField().getName(),
105 value);
106 }
107 return;
108 }
109
110
111 try {
112 boolean accessible = getField().isAccessible();
113 getField().setAccessible(true);
114 if (isCollection()) {
115 Collection collection;
116 if (getField().get(subject) == null) {
117 try {
118 Constructor<?> constructor = getField().getType().getConstructor();
119 collection = (Collection) constructor.newInstance();
120 getField().set(subject, collection);
121 } catch (NoSuchMethodException |
122 SecurityException |
123 InstantiationException |
124 IllegalAccessException |
125 IllegalArgumentException |
126 InvocationTargetException ex) {
127 throw new ArgumentParsingException(
128 ex,
129 "Could not create a collection for field ''{0}''.",
130 getField().getName());
131 }
132 } else {
133 collection = (Collection) getField().get(subject);
134 }
135 collection.add(value);
136 } else {
137 getField().set(subject, value);
138 }
139 getField().setAccessible(accessible);
140 } catch (IllegalArgumentException |
141 IllegalAccessException ex) {
142 throw new ArgumentParsingException(
143 ex,
144 "Could not directly set field ''{1}''.",
145 getField().getName());
146 }
147 }
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 static Object convert(String value, Class<?> to)
178 throws ArgumentParsingException {
179 if (value == null) {
180 throw new NullPointerException("Value may not be null.");
181 }
182 if (to == null) {
183 throw new NullPointerException("To may not be null.");
184 }
185
186
187 if (to.isAssignableFrom(String.class)) {
188 return value;
189 }
190
191
192 if (to.isAssignableFrom(Character.class)
193 && value.length() == 1) {
194 return new Character(value.charAt(0));
195 }
196
197
198 if (to.isAssignableFrom(Double.class)) {
199 return new Double(Double.parseDouble(value));
200 }
201 if (to.isAssignableFrom(Float.class)) {
202 return new Float(Float.parseFloat(value));
203 }
204 if (to.isAssignableFrom(Integer.class)) {
205 return new Integer(Integer.parseInt(value));
206 }
207 if (to.isAssignableFrom(Long.class)) {
208 return new Long(Long.parseLong(value));
209 }
210 if (to.isAssignableFrom(Short.class)) {
211 return new Short(Short.parseShort(value));
212 }
213
214
215 try {
216 Constructor<?> constructor = to.getConstructor(String.class);
217 Object instance = constructor.newInstance(value);
218 return instance;
219 } catch (NoSuchMethodException | SecurityException | InstantiationException |
220 IllegalAccessException | IllegalArgumentException |
221 InvocationTargetException ex) {
222
223 }
224
225 throw new ArgumentParsingException("Can't convert from String to ''{0}''.",
226 to.getName());
227 }
228
229 boolean takesValue() {
230 return !isBoolean();
231 }
232
233 boolean isBoolean() {
234 return Boolean.class.isAssignableFrom(getField().getType());
235 }
236
237 boolean hasName(String name) {
238 return getNames().contains(name);
239 }
240
241 CommandLineOption getCommandLineOption() {
242 return getField().getAnnotation(CommandLineOption.class);
243 }
244
245 List<String> getNames() {
246
247 if (names == null) {
248 names = new ArrayList<>();
249 names.addAll(Arrays.asList(getCommandLineOption().names()));
250
251 if (names.isEmpty()) {
252 names.add(getField().getName());
253 }
254
255
256 if (isBoolean() && getCommandLineOption().opposite()) {
257 for (String name : new ArrayList<>(getNames())) {
258 names.add("no-" + name);
259 }
260 }
261 }
262
263 return Collections.unmodifiableList(names);
264 }
265
266 Field getField() {
267 return field;
268 }
269
270 boolean isCollection() {
271 return Collection.class.isAssignableFrom(getField().getType());
272 }
273
274 Class<?> getEffectiveClass() {
275 return ((isCollection())
276 ? (Class<?>) ((ParameterizedType) getField().getGenericType())
277 .getActualTypeArguments()[0]
278 : getField().getType());
279 }
280
281 }