On this page:
Basic Java Mapping for Operations
As we saw in the mapping for interfaces, for each operation on an interface, the proxy interface contains a corresponding method with the same name. To invoke an operation, you call it via the proxy. For example, here is part of the definitions for our file system:
name operation returns a value of type
string. Given a proxy to an object of type
Node, the client can invoke the operation as follows:
idempotent Operations in Java
You can add an
idempotent qualifier to a Slice operation. As far as the signature for the corresponding proxy method is concerned,
idempotent has no effect. For example, consider the following interface:
The proxy interface for this is:
idempotent affects an aspect of operation invocation, not interface, it makes sense for the two methods to be mapped the same.
Passing Parameters in Java
In Parameters in Java
The parameter passing rules for the Java mapping are very simple: each
in parameter of a Slice operation is mapped to a corresponding parameter in the mapped Java method.
Here is an interface with operations that pass parameters of various types from client to server:
The Slice compiler generates the following proxy for these definitions:
Given a proxy to a
ClientToServer interface, the client code can pass parameters as in the following example:
Out Parameters in Java
The mapping for an operation depends on how many values it returns, including out parameters and a non-
void return value:
- Zero values
The corresponding Java method returns
void. For the purposes of this discussion, we're not interested in these operations.
The corresponding Java method returns the mapped type, regardless of whether the Slice definition of the operation declared it as a return value or as an out parameter. Consider this example:
The mapping generates corresponding methods with identical signatures:
- Multiple values
The Slice compiler generates an extra nested class to hold the results of an operation that returns multiple values. The class is nested in the mapped interface (not the proxy interface) and has the name
Oprepresents the name of the operation. The leading character of the class name for a "result class" is always capitalized. The values of out parameters are provided in corresponding public fields of the same names. If the operation declares a return value, its value is provided in the field named
returnValue. If an out parameter is also named
returnValue, the field to hold the operation's return value is named
_returnValueinstead. The result class defines an empty constructor as well as a "one-shot" constructor that accepts and assigns a value for each of its fields. The corresponding Java method returns the result class type.
Here are the same Slice definitions we saw earlier, but this time with all parameters being passed in the
out direction, along with one additional operation to better demonstrate the mapping:
The Slice compiler generates the following code for these definitions:
We need to point out several things here:
- Result classes are generated for
op4because they return multiple values
- The result classes are generated as nested classes of interface
ServerToClient, and not
op4declares an out parameter named
Op4Resultdeclares a field named
_returnValueto hold the operation's return value
- No result class is necessary for
op3because it only returns one value; the mapped Java method declares a return type of
ServerToClientPrxeven though the Slice operation declared it as an out parameter
Null Parameters in Java
Some Slice types naturally have "empty" or "not there" semantics. Specifically, sequences, dictionaries, and strings all can be
null, but the corresponding Slice types do not have the concept of a null value. To make life with these types easier, whenever you pass
null as a parameter or return value of type sequence, dictionary, or string, the Ice run time automatically sends an empty sequence, dictionary, or string to the receiver.
This behavior is useful as a convenience feature: especially for deeply-nested data types, fields that are sequences, dictionaries, or strings automatically arrive as an empty value at the receiving end. This saves you having to explicitly initialize, for example, every string element in a large sequence before sending the sequence in order to avoid
NullPointerException. Note that using null parameters in this way does not create null semantics for Slice sequences, dictionaries, or strings. As far as the object model is concerned, these do not exist (only empty sequences, dictionaries, and strings do). For example, whether you send a string as
null or as an empty string makes no difference to the receiver: either way, the receiver sees an empty string.
Optional Parameters in Java
The mapping uses standard Java types to encapsulate optional parameters:
The mapped type for an optional
The mapped type for an optional
The mapped type for an optional
The mapped type for all other Slice types.
Optional return values and output parameters are mapped to instances of the above classes, depending on their types. For operations with optional in parameters, the proxy provides a set of overloaded methods that accept them as optional values, and another set of methods that accept them as required values. Consider the following operation:
The mapping for this operation is shown below:
For cases where you are passing values for all of the optional in parameters, it is more efficient to use the required mapping and avoid creating temporary optional values.
A client can invoke
execute as shown below:
null where an optional value is expected is equivalent to passing an instance whose value is unset.
Java's optional classes do not consider
null to be a legal value. Consider this example:
The Ice encoding allows
null values for class instances, so you can pass
addRequired and the server will receive it as
null. However, there's no way to pass an "optional value set to null" in the Java mapping. Passing
addOptional is equivalent to passing the value of
java.util.Optional.ofNullable((T)null), which is equivalent to passing the value of
java.util.Optional.empty(). In either case, the server will receive it as an optional whose value is not present.
A well-behaved program must not assume that an optional parameter always has a value. Calling
get on an optional instance for which no value is set raises
Exception Handling in Java
Slice exceptions are thrown as Java exceptions, so you can simply enclose one or more operation invocations in a
Typically, you will catch only a few exceptions of specific interest around an operation invocation; other exceptions, such as unexpected run-time errors, will typically be handled by exception handlers higher in the hierarchy. For example: