Exception and error handling

P4Java uses a small set of Java exceptions to signal errors that have occurred in either the Helix Server as a result of issuing a specific command to the server, or in the P4Java plumbing in response to things like TCP/IP connection errors or system configuration issues. (These exceptions are not used to signal file operation problems at the individual file level — see Helix Server file operations for details about individual file error handling.)

In general, P4Java exceptions are rooted in two different classes: the P4JavaException classes are intended for “normal” (that is, recoverable) errors that occur as the result of things like missing client files, a broken server connection, or an inappropriate command option; the P4JavaError classes are intended for more serious errors that are unlikely to be recoverable, including unintended null pointers or P4Java-internal errors. The P4JavaException class hierarchy is rooted in the normal java.lang.Exception tree, and any such exception is always declared in relevant method “throws” clauses; the P4JavaError classes, however, are rooted in java.lang.Error, and consequently do not need to be declared or explicitly caught. This allows a developer to catch all such P4JavaErrors, for example, in an outer loop, but to process “normal” P4JavaExceptions in inner blocks and loops as they occur.

Typically, application code should report a P4JavaError exception and then terminate either itself or whatever it was doing as soon as possible, as this exception indicates a serious error within P4Java. P4JavaException handling is more fine-grained and nuanced: A P4JavaException almost always signals a recoverable (or potentially-recoverable) error, and should be caught individually or at the class level. The following snippet represents a common pattern for P4Java error and exception handling around major functional blocks or processing loops:

try {
  // issue one or more server or client commands...
} catch (P4JavaError err) {
  panic(err); // causes app to exit after printing message to stderr...
} catch (RequestException rexc) {
  // process server-side Perforce error...
} catch (ConnectionException cexc) {
  // process Perforce connection exception...
} catch (P4JavaException exc) {
  // catchall...
} catch (Exception exc) {
  // Other-exception catchall...
}

Note the way RequestException and ConnectionException events are handled separately: RequestException exceptions are almost always thrown in response to a Helix Server error message and therefore include a severity and generic code that can be used or displayed (other P4JavaExceptions do not usually contain these), and ConnectionExceptions should normally result in the enclosing app explicitly closing or at least re-trying the associated connection, as processing can no longer continue on the current Helix Server connection.