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 } |
