/
ConfigException.java
426 lines (355 loc) · 13.6 KB
/
ConfigException.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
/**
* Copyright (C) 2011-2012 Typesafe Inc. <http://typesafe.com>
*/
package com.typesafe.config;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import com.typesafe.config.impl.ConfigImplUtil;
/**
* All exceptions thrown by the library are subclasses of
* <code>ConfigException</code>.
*/
public abstract class ConfigException extends RuntimeException implements Serializable {
private static final long serialVersionUID = 1L;
final private transient ConfigOrigin origin;
protected ConfigException(ConfigOrigin origin, String message,
Throwable cause) {
super(origin.description() + ": " + message, cause);
this.origin = origin;
}
protected ConfigException(ConfigOrigin origin, String message) {
this(origin.description() + ": " + message, null);
}
protected ConfigException(String message, Throwable cause) {
super(message, cause);
this.origin = null;
}
protected ConfigException(String message) {
this(message, null);
}
/**
* Returns an "origin" (such as a filename and line number) for the
* exception, or null if none is available. If there's no sensible origin
* for a given exception, or the kind of exception doesn't meaningfully
* relate to a particular origin file, this returns null. Never assume this
* will return non-null, it can always return null.
*
* @return origin of the problem, or null if unknown/inapplicable
*/
public ConfigOrigin origin() {
return origin;
}
// we customize serialization because ConfigOrigin isn't
// serializable and we don't want it to be (don't want to
// support it)
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
ConfigImplUtil.writeOrigin(out, origin);
}
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {
in.defaultReadObject();
ConfigOrigin origin = ConfigImplUtil.readOrigin(in);
// circumvent "final"
Field f;
try {
f = ConfigException.class.getDeclaredField("origin");
} catch (NoSuchFieldException e) {
throw new IOException("ConfigException has no origin field?", e);
} catch (SecurityException e) {
throw new IOException("unable to fill out origin field in ConfigException", e);
}
f.setAccessible(true);
try {
f.set(this, origin);
} catch (IllegalArgumentException e) {
throw new IOException("unable to set origin field", e);
} catch (IllegalAccessException e) {
throw new IOException("unable to set origin field", e);
}
}
/**
* Exception indicating that the type of a value does not match the type you
* requested.
*
*/
public static class WrongType extends ConfigException {
private static final long serialVersionUID = 1L;
public WrongType(ConfigOrigin origin, String path, String expected, String actual,
Throwable cause) {
super(origin, path + " has type " + actual + " rather than " + expected, cause);
}
public WrongType(ConfigOrigin origin, String path, String expected, String actual) {
this(origin, path, expected, actual, null);
}
public WrongType(ConfigOrigin origin, String message, Throwable cause) {
super(origin, message, cause);
}
public WrongType(ConfigOrigin origin, String message) {
super(origin, message, null);
}
}
/**
* Exception indicates that the setting was never set to anything, not even
* null.
*/
public static class Missing extends ConfigException {
private static final long serialVersionUID = 1L;
public Missing(String path, Throwable cause) {
super("No configuration setting found for key '" + path + "'",
cause);
}
public Missing(String path) {
this(path, null);
}
protected Missing(ConfigOrigin origin, String message, Throwable cause) {
super(origin, message, cause);
}
protected Missing(ConfigOrigin origin, String message) {
this(origin, message, null);
}
}
/**
* Exception indicates that the setting was treated as missing because it
* was set to null.
*/
public static class Null extends Missing {
private static final long serialVersionUID = 1L;
private static String makeMessage(String path, String expected) {
if (expected != null) {
return "Configuration key '" + path
+ "' is set to null but expected " + expected;
} else {
return "Configuration key '" + path + "' is null";
}
}
public Null(ConfigOrigin origin, String path, String expected,
Throwable cause) {
super(origin, makeMessage(path, expected), cause);
}
public Null(ConfigOrigin origin, String path, String expected) {
this(origin, path, expected, null);
}
}
/**
* Exception indicating that a value was messed up, for example you may have
* asked for a duration and the value can't be sensibly parsed as a
* duration.
*
*/
public static class BadValue extends ConfigException {
private static final long serialVersionUID = 1L;
public BadValue(ConfigOrigin origin, String path, String message,
Throwable cause) {
super(origin, "Invalid value at '" + path + "': " + message, cause);
}
public BadValue(ConfigOrigin origin, String path, String message) {
this(origin, path, message, null);
}
public BadValue(String path, String message, Throwable cause) {
super("Invalid value at '" + path + "': " + message, cause);
}
public BadValue(String path, String message) {
this(path, message, null);
}
}
/**
* Exception indicating that a path expression was invalid. Try putting
* double quotes around path elements that contain "special" characters.
*
*/
public static class BadPath extends ConfigException {
private static final long serialVersionUID = 1L;
public BadPath(ConfigOrigin origin, String path, String message,
Throwable cause) {
super(origin,
path != null ? ("Invalid path '" + path + "': " + message)
: message, cause);
}
public BadPath(ConfigOrigin origin, String path, String message) {
this(origin, path, message, null);
}
public BadPath(String path, String message, Throwable cause) {
super(path != null ? ("Invalid path '" + path + "': " + message)
: message, cause);
}
public BadPath(String path, String message) {
this(path, message, null);
}
public BadPath(ConfigOrigin origin, String message) {
this(origin, null, message);
}
}
/**
* Exception indicating that there's a bug in something (possibly the
* library itself) or the runtime environment is broken. This exception
* should never be handled; instead, something should be fixed to keep the
* exception from occurring. This exception can be thrown by any method in
* the library.
*/
public static class BugOrBroken extends ConfigException {
private static final long serialVersionUID = 1L;
public BugOrBroken(String message, Throwable cause) {
super(message, cause);
}
public BugOrBroken(String message) {
this(message, null);
}
}
/**
* Exception indicating that there was an IO error.
*
*/
public static class IO extends ConfigException {
private static final long serialVersionUID = 1L;
public IO(ConfigOrigin origin, String message, Throwable cause) {
super(origin, message, cause);
}
public IO(ConfigOrigin origin, String message) {
this(origin, message, null);
}
}
/**
* Exception indicating that there was a parse error.
*
*/
public static class Parse extends ConfigException {
private static final long serialVersionUID = 1L;
public Parse(ConfigOrigin origin, String message, Throwable cause) {
super(origin, message, cause);
}
public Parse(ConfigOrigin origin, String message) {
this(origin, message, null);
}
}
/**
* Exception indicating that a substitution did not resolve to anything.
* Thrown by {@link Config#resolve}.
*/
public static class UnresolvedSubstitution extends Parse {
private static final long serialVersionUID = 1L;
public UnresolvedSubstitution(ConfigOrigin origin, String detail, Throwable cause) {
super(origin, "Could not resolve substitution to a value: " + detail, cause);
}
public UnresolvedSubstitution(ConfigOrigin origin, String detail) {
this(origin, detail, null);
}
}
/**
* Exception indicating that you tried to use a function that requires
* substitutions to be resolved, but substitutions have not been resolved
* (that is, {@link Config#resolve} was not called). This is always a bug in
* either application code or the library; it's wrong to write a handler for
* this exception because you should be able to fix the code to avoid it by
* adding calls to {@link Config#resolve}.
*/
public static class NotResolved extends BugOrBroken {
private static final long serialVersionUID = 1L;
public NotResolved(String message, Throwable cause) {
super(message, cause);
}
public NotResolved(String message) {
this(message, null);
}
}
/**
* Information about a problem that occurred in {@link Config#checkValid}. A
* {@link ConfigException.ValidationFailed} exception thrown from
* <code>checkValid()</code> includes a list of problems encountered.
*/
public static class ValidationProblem {
final private String path;
final private ConfigOrigin origin;
final private String problem;
public ValidationProblem(String path, ConfigOrigin origin, String problem) {
this.path = path;
this.origin = origin;
this.problem = problem;
}
/**
* Returns the config setting causing the problem.
* @return the path of the problem setting
*/
public String path() {
return path;
}
/**
* Returns where the problem occurred (origin may include info on the
* file, line number, etc.).
* @return the origin of the problem setting
*/
public ConfigOrigin origin() {
return origin;
}
/**
* Returns a description of the problem.
* @return description of the problem
*/
public String problem() {
return problem;
}
@Override
public String toString() {
return "ValidationProblem(" + path + "," + origin + "," + problem + ")";
}
}
/**
* Exception indicating that {@link Config#checkValid} found validity
* problems. The problems are available via the {@link #problems()} method.
* The <code>getMessage()</code> of this exception is a potentially very
* long string listing all the problems found.
*/
public static class ValidationFailed extends ConfigException {
private static final long serialVersionUID = 1L;
final private Iterable<ValidationProblem> problems;
public ValidationFailed(Iterable<ValidationProblem> problems) {
super(makeMessage(problems), null);
this.problems = problems;
}
public Iterable<ValidationProblem> problems() {
return problems;
}
private static String makeMessage(Iterable<ValidationProblem> problems) {
StringBuilder sb = new StringBuilder();
for (ValidationProblem p : problems) {
sb.append(p.origin().description());
sb.append(": ");
sb.append(p.path());
sb.append(": ");
sb.append(p.problem());
sb.append(", ");
}
if (sb.length() == 0)
throw new ConfigException.BugOrBroken(
"ValidationFailed must have a non-empty list of problems");
sb.setLength(sb.length() - 2); // chop comma and space
return sb.toString();
}
}
/**
* Some problem with a JavaBean we are trying to initialize.
* @since 1.3.0
*/
public static class BadBean extends BugOrBroken {
private static final long serialVersionUID = 1L;
public BadBean(String message, Throwable cause) {
super(message, cause);
}
public BadBean(String message) {
this(message, null);
}
}
/**
* Exception that doesn't fall into any other category.
*/
public static class Generic extends ConfigException {
private static final long serialVersionUID = 1L;
public Generic(String message, Throwable cause) {
super(message, cause);
}
public Generic(String message) {
this(message, null);
}
}
}