On this page:
Basic Java Mapping for Classes
A Slice class is mapped to a Java class with the same name. The generated class contains a public data member for each Slice data member (just as for structures and exceptions). Consider the following class definition:
class TimeOfDay { short hour; // 0 - 23 short minute; // 0 - 59 short second; // 0 - 59 string tz; // e.g. GMT, PST, EDT... }
The Slice compiler generates the following code for this definition:
public class TimeOfDay extends com.zeroc.Ice.Value { public TimeOfDay(); public TimeOfDay(short hour, short minute, short second, String tz); public short hour; public short minute; public short second; public String tz; public TimeOfDay clone(); public static final String ice_staticId = "::...::TimeOfDay"; public static String ice_staticId(); @Override public String ice_id(); ... }
There are a several things to note about the generated code:
- The generated class
TimeOfDay
inherits fromcom.zeroc.Ice.Value
. This means that all classes implicitly inherit fromValue
, which is the ultimate ancestor of all classes. - The generated class contains a public member for each Slice data member.
- The generated class has a constructor that takes one argument for each data member, as well as a default constructor.
There is quite a bit to discuss here, so we will look at each item in turn.
Inheritance from Ice::Value
in Java
Classes implicitly inherit from a common base class, Value
, which is mapped to com.zeroc.Ice.Value
. Value
is a very simple base class with just a few methods:
public abstract class Value implements java.lang.Cloneable, java.io.Serializable { public Value clone(); public void ice_preMarshal(); public void ice_postUnmarshal(); public String ice_id(); public SlicedData ice_getSlicedData(); ... }
The Value
methods behave as follows:
ice_preMarshal
The Ice run time invokes this method prior to marshaling the object's state, providing the opportunity for a subclass to validate its declared data members.ice_postUnmarshal
The Ice run time invokes this method after unmarshaling an object's state. A subclass typically overrides this method when it needs to perform additional initialization using the values of its declared data members.clone
This method returns a shallow member-wise copy of the value.ice_id
This method returns the actual run-time type ID for a class instance. If you callice_id
through a reference to a base instance, the returned type id is the actual (possibly more derived) type ID of the instance.ice_getSlicedData
This functions returns theSlicedData
object if the value has been sliced during un-marshaling ornull
otherwise.
Class Data Members in Java
By default, data members of classes are mapped exactly as for structures and exceptions: for each data member in the Slice definition, the generated class contains a corresponding public data member. A JavaBean-style API is used for optional data members, and you can customize the mapping to force required members to use this same API.
If you wish to restrict access to a data member, you can modify its visibility using the protected
metadata directive. The presence of this directive causes the Slice compiler to generate the data member with protected visibility. As a result, the member can be accessed only by the class itself or by one of its subclasses. For example, the TimeOfDay
class shown below has the protected
metadata directive applied to each of its data members:
class TimeOfDay { ["protected"] short hour; // 0 - 23 ["protected"] short minute; // 0 - 59 ["protected"] short second; // 0 - 59 ["protected"] string tz; // e.g. GMT, PST, EDT... }
The Slice compiler produces the following generated code for this definition:
public class TimeOfDay extends ... { protected short hour; protected short minute; protected short second; protected String tz; public TimeOfDay(); public TimeOfDay(short hour, short minute, short second); // ... }
For a class in which all of the data members are protected, the metadata directive can be applied to the class itself rather than to each member individually. For example, we can rewrite the TimeOfDay
class as follows:
["protected"] class TimeOfDay { short hour; // 0 - 23 short minute; // 0 - 59 short second; // 0 - 59 string tz; // e.g. GMT, PST, EDT... }
You can optionally customize the mapping for data members to use getters and setters instead.
Class Operations in Java
Operations on classes are deprecated as of Ice 3.7. Skip this section unless you need to communicate with old applications that rely on this feature.
Operations in classes are not mapped at all into the corresponding Java class. The generated Java class is the same whether the Slice class has operations or not.
For a class that defines or inherits operations, the Slice-to-Java compiler generates instead a separate _<class-name>Disp
class that can be used to implement an Ice object with these operations. Let's change our example to add a class operation:
class FormattedTimeOfDay { short hour; // 0 - 23 short minute; // 0 - 59 short second; // 0 - 59 string tz; // e.g. GMT, PST, EDT... string format(); }
The Slice compiler generates the following code:
public class FormattedTimeOfDay extends com.zeroc.Ice.Value { // ... operation format() not mapped at all here } // Disp class for servant implementation public interface _FormattedTimeOfDayDisp extends com.zeroc.Ice.Object { String format(com.zeroc.Ice.Current __current); ... }
This Disp
class is the skeleton class for this Slice class. Skeleton classes are described in the Server-Side Java Mapping for Interfaces.
Value Factories in Java
Value factories allow you to create classes derived from the Java classes generated by the Slice compiler, and tell the Ice run time to create instances of these classes when unmarshaling. For example, with the following simple interface:
interface Time { TimeOfDay get(); }
The default behavior of the Ice run time will create and return an instance of the generated TimeOfDay
class.
If you wish, you can create your own custom derived class, and tell Ice to create and return these instances instead. For example:
public class CustomTimeOfDay extends TimeOfDay { public String format() { ... prints formatted data members ... } }
You then create and register a value factory for your custom class with your Ice communicator:
Communicator communicator = ...; communicator.getValueFactoryManager().add(type -> { assert(type.equals(TimeOfDay.ice_staticId())); return new CustomTimeOfDay(); }, TimeOfDay.ice_staticId());
Class Constructors in Java
Classes have a default constructor that initializes data members as follows:
Data Member Type | Default Value |
---|---|
string | Empty string |
enum | First enumerator in enumeration |
struct | Default-constructed value |
Numeric | Zero |
bool | False |
sequence | Null |
dictionary | Null |
class /interface | Null |
The constructor won't explicitly initialize a data member if the default Java behavior for that type produces the desired results.
If you wish to ensure that data members of primitive and enumerated types are initialized to specific values, you can declare default values in your Slice definition. The default constructor initializes each of these data members to its declared value instead.
The generated class also contains a second constructor that accepts one argument for each member of the class. This allows you to create and initialize a class in a single statement, for example:
TimeOfDay tod = new TimeOfDay(14, 45, 00, "PST"); // 14:45pm PST
For derived classes, the constructor requires an argument for every member of the class, including inherited members. For example, consider the the definition from Class Inheritance once more:
class TimeOfDay { short hour; // 0 - 23 short minute; // 0 - 59 short second; // 0 - 59 } class DateTime extends TimeOfDay { short day; // 1 - 31 short month; // 1 - 12 short year; // 1753 onwards }
The constructors for the generated classes are as follows:
public class TimeOfDay extends ... { public TimeOfDay() {} public TimeOfDay(short hour, short minute, short second) { this.hour = hour; this.minute = minute; this.second = second; } // ... } public class DateTime extends TimeOfDay { public DateTime() {} public DateTime(short hour, short minute, short second, short day, short month, short year) { super(hour, minute, second); this.day = day; this.month = month; this.year = year; } // ... }
If you want to instantiate and initialize a DateTime
instance, you must either use the default constructor or provide values for all of the data members of the instance, including data members of any base classes.