Programming with Exceptions

Use exceptions to indicate serious or unexpected error conditions, conditions from which the program cannot easily recover. This topic presents the following information:

About Java Exceptions

Java exceptions fall into two categories: either they extend java.lang.RuntimeException (these are called implicit exceptions) or they do not (these are called explicit exceptions). When a method uses an explicit exception to indicate an error, a Java program requires:

The following code shows a method getCustName that declares and throws a ValidationException.

public String getCustName(Customer cust) throws ValidationException {
  String name = cust.mName;
  if (name == null) {
    throw new ValidationException();
  }
  return name;
}

When you write code that calls a method that throws an exception, enclose the call in a try...catch block. For example, the following code calls getCustName, a method defined to throw a ValidationException. The try keyword indicates that you are about to call one or more methods that throw exceptions. The catch keyword marks the beginning of a code block that executes only when an exception is thrown.

public printName(Customer cust) {
  try {
    // Call the method(s) here.
    getCustName(cust);
  catch (ValidationException dae) {
    // Handle the error here.
    System.out.println(dae.getMessage());
  }
}

Java programs are more lenient about implicit exceptions: they do not have to be declared or caught. You can write a method that throws a RuntimeException (or a subclass of RuntimeException) without declaring it in the method signature (although you can do so, if you prefer).

About Exception Classes

The Business Components for Java framework provides many exception classes (for example, ValidationException and NameClashException). These classes extend oracle.jbo.JboException, which extends java.lang.RuntimeException. Therefore, a Business Component method can throw a Business Components for Java exception without a throws clause in the signature.

Business Components for Java exceptions have an attribute that stores an error message, and they support NLS translation and message formatting. JboException uses java.util.ListResourceBundle to format its messages. A resource bundle class defines constants and strings to use as error messages. The default format is:

{productCode}-{errorCode}: {messageBody}

For example,

ORA-10234: You cannot do that.

Business Component exception messages are derived from the following generalized set of parameters:

Parameter

Example

Product code

"OBCJ"

Error code

"03101"

ResourceBundle

"oracle.jbo.CSMessageBundle"

an optional set of parameters

"Vendor", "Oracle"

details

Any exception thrown in low-level code that is transformed
into a Business Component exception.

Messages may need to include information known only when the exception is thrown, so error message strings can include placeholders that refer to values in an array of Objects passed to the exception when it's thrown. When the message is formatted for display, these parameters are placed into slots in the message (the first slot is 0) using the standard formatting capabilities provided by java.text.MessageFormat. Following is a an entry from CSMessageBundle.java.

public static final String EXC_VAL_ATTR_SET_FAILED = "03101";
...
// Description: Generic Attribute validation failure.
// set<Attribute> method failed to set the value.
// Parameter 0: Ignored.
// Parameter 1: Entity Object/View Object name.
// Parameter 2: Attribute name.
// Parameter 3: New value
{EXC_VAL_ATTR_SET_FAILED, "Attribute set with value {3} for {2} in {1} failed."},

The JboException class provides the following methods for working with exceptions.

Method

Description

JboException(String message, 
String errorCode,
Object[] params)

Create a Formattable Exception Object.

JboException(Class resBundleClass, 
String errorCode,
Object[] params)

Create a Translatable Exception Object.

String getProductCode()

Return the Product code for the Message.

String getErrorCode()

Return the Error code.

String getLocalizedMessage(Locale loc)

Return the Message in the specific Locale.

Object[] getDetails()

Details are usually used to accommodate
lower-level exceptions. For example, if a
SQLException is thrown in some low-level code, the Business Components for Java
framework can catch it and represent it as
one of the Business Component exceptions.
The original SQLException becomes
the first entry in the detail.

String getResourceName()

Return the name of the ResourceBundle used to
resolve messages.

Object[] getErrorParameters()

Return the Parameters to the Error.

Creating Custom Exception Classes

You can use Business Component for Java exception classes in your own code to indicate errors, and you can create custom exception classes. For example, you can extend JboException and override the getProductCode method, making it return values appropriate for your exception.

You can throw a JboException by using a statement like this:

throw new JboException("Don't do that.", "101", null );

The drawback to this approach is that the hard-coded error message is not easy to localize.

Localizing Exception Messages

To make an exception localizable into different national languages, use the NLS framework. First, create a resource bundle for your error messages. The following code example defines a bundle named MyMsgBundle that stores three error messages.

import oracle.jbo.common.util.CheckedListResourceBundle;
public class MyMsgBundle extends CheckedListResourceBundle
// String Constants
public static final String BAD_EMPNO = "101";
public static final String DEPT_NOT_FOUND = "102";
public static final String NOT_IN_DEPT = "103";
...
/**
* Private 2-D array of key-value pairs
*/
private static final Object[][] sMessageStrings = {
...
{ BAD_EMPNO, "Invalid employee number." },
{ DEPT_NOT_FOUND, "Department {0} does not exist." }
{ NOT_IN_DEPT, "Employee {0} not found in Department {1}." }
...
}
}

Then you can use the resource bundle class to define a value to pass to the constructor for your exception class or JboException.

throw new JboException(MyMsgBundle.class   /* Class of Bundle */,
MyMsgBundle.DEPT_NOT_FOUND /* String Constant */,
new Object[1] { localVar1 } /* Arguments to message */
);

JboException provides a getLocalizedMessage method which returns the message formatted for the specified locale.

The NLS framework translates the message text when the client calls getLocalizedMessage rather than at creation time because the client may need to present the message in a number of different languages. This mechanism provides a single point for localizing and formatting messages.

Using JboExceptionHandler

JboExceptionHandler is user-installable exception handler for three-tier applications. When exceptions are brought over through the piggyback mechanism, the normal Java language throw does not quite work, because (among other things) the piggyback may have carried back more than one exceptions. Thus, instead of throwing the exception, a method on the JboExceptionHandler interface is invoked with each exception unloaded from the piggyback.

JboExceptionHandler defines:

void handleException(Exception ex, boolean lastEntryInPiggyback);

Where ex is the exception unloaded from the piggyback and lastEntryInPiggyback is a flag indicating whether the exception was the last entry on the piggyback. (Note that for two-tier execution there is no piggyback.)

If you do not install your own handler, the default handler is used. The default handler is implemented by the Application Module. (At the interface level, ApplicationModule implements JboExceptionHandler.) For jbo.client.remote, this implementation ignores the exception if lastEntryInPiggyback is false. If lastEntryInPiggyback is true, the exception is thrown.

To install your own handler, call the following method on the Application Module interface:

void setExceptionHandler(JboExceptionHandler hndlr);

and pass in your own implementation of the JboExceptionHandler interface.

Marshaling Exceptions

JboException can marshal itself across a network. It handles NLS issues for the middle tier, enabling one instance of a middle-tier component to serve (for example) French users and English users at the same time.

If your exception contains member data that must be marshalled, extend JboException and override readObject and writeObject. The Java serialization mechanism uses these methods to serialize/deserialize an object. For example, suppose you have the class MyException (shown below), and you want to carry memberA and memberB across tiers.

public class MyException extends JboException 
{
int memberA;
String memberB;
...
}

Write code like the following in MyException:

private void writeObject(ObjectOutputStream out) throws IOException { 
out.writeInt(memberA);
out.writeUTF(mEntityRowHandle);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 
memberA = in.readInt();
memberB = in.readUTF();
}