Mercurial > jhg
comparison src/org/tmatesoft/hg/core/HgCallbackTargetException.java @ 423:9c9c442b5f2e
Major refactoring of exception handling. Low-level API uses RuntimeExceptions, while checked are left for higher level
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Fri, 23 Mar 2012 22:51:18 +0100 |
parents | 2747b0723867 |
children | 31a89587eb04 |
comparison
equal
deleted
inserted
replaced
422:5d1cc7366d04 | 423:9c9c442b5f2e |
---|---|
14 * the terms of a license other than GNU General Public License | 14 * the terms of a license other than GNU General Public License |
15 * contact TMate Software at support@hg4j.com | 15 * contact TMate Software at support@hg4j.com |
16 */ | 16 */ |
17 package org.tmatesoft.hg.core; | 17 package org.tmatesoft.hg.core; |
18 | 18 |
19 import org.tmatesoft.hg.internal.ExceptionInfo; | |
19 import org.tmatesoft.hg.util.Path; | 20 import org.tmatesoft.hg.util.Path; |
20 | 21 |
21 | 22 |
22 | 23 |
23 /** | 24 /** |
24 * Checked exception that indicates errors in client code and tries to supply extra information about the context it occurred in. | 25 * Checked exception that client supplied callback code can use to indicates its own errors. |
25 * | 26 * |
26 * Generally, client need to pass own error information/exceptions from within implementations of the callback methods they supply. | 27 * <p>Generally, client need to pass own error information/exceptions from within implementations of the callback methods they supply. |
27 * However, there's no straightforward way to alter throws clause for these methods, and alternatives like generic {@link Exception} or | 28 * However, there's no straightforward way to alter throws clause for these methods, and alternatives like generic {@link Exception} or |
28 * library's own {@link HgException} are rather obscure. Suggested approach is to wrap whatever exception user code produces with | 29 * library's own {@link HgException} are rather obscure. Suggested approach is to wrap whatever exception user code produces with |
29 * {@link RuntimeException} subclass, {@link Wrap}. Then, unwrap and re-throw with checked {@link HgCallbackTargetException}. | 30 * {@link HgCallbackTargetException}, the only checked exception allowed out from a callback. |
30 * | 31 * |
31 * FIXME REVISIT perhaps, shall just throw HgCallbackTargetException from any handler, and do not catch anything in commands at all? | 32 * <p>It's intentionally not a subclass of {@link HgException} to avoid get mixed with library own errors and be processed separately. |
32 * FIXME decide whether shall root at HgException ("throws HgException, HgCallbackTargetException" looks a bit odd now) | 33 * |
34 * FIXME REVISIT shall just throw HgCallbackTargetException from any handler, and do not catch anything in commands at all. | |
33 * | 35 * |
34 * @author Artem Tikhomirov | 36 * @author Artem Tikhomirov |
35 * @author TMate Software Ltd. | 37 * @author TMate Software Ltd. |
36 */ | 38 */ |
37 @SuppressWarnings("serial") | 39 @SuppressWarnings("serial") |
38 public class HgCallbackTargetException extends HgException { | 40 public class HgCallbackTargetException extends Exception { |
41 | |
42 protected final ExceptionInfo<HgCallbackTargetException> details = new ExceptionInfo<HgCallbackTargetException>(this); | |
43 | |
39 /** | 44 /** |
40 * @param cause can't be <code>null</code> | 45 * @param cause can't be <code>null</code> |
41 */ | 46 */ |
42 public HgCallbackTargetException(Throwable cause) { | 47 public HgCallbackTargetException(Throwable cause) { |
43 super((String) null); | 48 super((String) null); |
44 if (cause == null) { | 49 if (cause == null) { |
45 throw new IllegalArgumentException(); | 50 throw new IllegalArgumentException(); |
46 } | 51 } |
47 if (cause.getClass() == Wrap.class) { | 52 initCause(cause); |
48 // eliminate wrapper | |
49 initCause(cause.getCause()); | |
50 } else { | |
51 initCause(cause); | |
52 } | |
53 } | 53 } |
54 | 54 |
55 @SuppressWarnings("unchecked") | 55 @SuppressWarnings("unchecked") |
56 public <T extends Exception> T getTargetException() { | 56 public <T extends Throwable> T getTargetException() { |
57 return (T) getCause(); | 57 return (T) getCause(); |
58 } | 58 } |
59 | 59 |
60 /** | 60 /** |
61 * Despite this exception is merely a way to give users access to their own exceptions, it may still supply | 61 * Despite this exception is merely a way to give users access to their own exceptions, it may still supply |
62 * valuable debugging information about what led to the error. | 62 * valuable debugging information about what led to the error. |
63 */ | 63 */ |
64 @Override | 64 @Override |
65 public String getMessage() { | 65 public String getMessage() { |
66 StringBuilder sb = new StringBuilder(); | 66 StringBuilder sb = new StringBuilder(); |
67 sb.append("Original exception thrown: "); | 67 sb.append("Error from callback. Original exception thrown: "); |
68 sb.append(getCause().getClass().getName()); | 68 sb.append(getCause().getClass().getName()); |
69 sb.append(" at "); | 69 sb.append(" at "); |
70 extras.appendDetails(sb); | 70 details.appendDetails(sb); |
71 return sb.toString(); | 71 return sb.toString(); |
72 } | 72 } |
73 | 73 |
74 @Override | |
75 public HgCallbackTargetException setRevision(Nodeid r) { | 74 public HgCallbackTargetException setRevision(Nodeid r) { |
76 return (HgCallbackTargetException) super.setRevision(r); | 75 return details.setRevision(r); |
77 } | |
78 @Override | |
79 public HgCallbackTargetException setRevisionIndex(int rev) { | |
80 return (HgCallbackTargetException) super.setRevisionIndex(rev); | |
81 } | |
82 @Override | |
83 public HgCallbackTargetException setFileName(Path name) { | |
84 return (HgCallbackTargetException) super.setFileName(name); | |
85 } | 76 } |
86 | 77 |
87 /** | 78 public HgCallbackTargetException setRevisionIndex(int rev) { |
88 * Given the approach high-level handlers throw RuntimeExceptions to indicate errors, and | 79 return details.setRevisionIndex(rev); |
89 * a need to throw reasonable checked exception from client code, clients may utilize this class | 80 } |
90 * to get their checked exceptions unwrapped by {@link HgCallbackTargetException} and serve as that | |
91 * exception cause, eliminating {@link RuntimeException} mediator. | |
92 */ | |
93 public static final class Wrap extends RuntimeException { | |
94 | 81 |
95 public Wrap(Throwable cause) { | 82 public HgCallbackTargetException setFileName(Path name) { |
96 super(cause); | 83 return details.setFileName(name); |
97 if (cause == null) { | |
98 throw new IllegalArgumentException(); | |
99 } | |
100 } | |
101 } | 84 } |
102 } | 85 } |