Expand description
The Java CST as the other end of a rule. Spec §3.2.
The counterpart of crate::adapter::c, which does the same for C,
and of crate::adapter::cst, which does it for Rust. Reading two of
them side by side is the point: where they differ, the difference is
the language’s, and it is written down here rather than spread through
a renderer.
Values are resolved from the model, never from the overlay — the same rule the other two materialisers follow and for the same reason (spec §2.3).
§The four things Java forces that C does not
- No unsigned integer. Every Java integer is signed, so the width
of the IDL type cannot decide the Java type. What decides it is what
the field has to hold:
unsigned shorttakes anintbecause 65535 is not ashort, andunsigned longtakes alongbecause 4294967295 is not anint. Onlyunsigned long longhas no type wide enough, and it takes alongholding the bit pattern. The table below says which of the two every unsigned type is. - Arrays instead of declared collection types. C has to declare a
named struct for
sequence<long>; Java writesint[]. So there is no structural-name machinery here and no forward declaration — a Java class may name a class declared after it — butordered_typesis still what the walk uses, so two runs over one model produce the same file. - One public top-level type per file. Everything nests inside one outer class; see “Modules” below.
- No typedef. An IDL
typedefhas no Java declaration at all. It is not dropped: the member takes the target’s Java type and the outer class carries a comment naming the alias and what it resolved to.
§The integer mapping
| IDL | Java | what the field holds |
|---|---|---|
boolean | boolean | |
char | char | one code unit; the wire form is one octet |
wchar | char | one UTF-16 code unit |
int8 | byte | a number, -128..127 |
octet | byte | a bit pattern, which the codec writes as the number 0..255 |
uint8 | int | a number, 0..255 |
short | short | a number |
unsigned short | int | a number, 0..65535 |
long | int | a number |
unsigned long | long | a number, 0..4294967295 |
long long | long | a number |
unsigned long long | long | a bit pattern, not a number |
float | float | |
double | double | |
long double | org.zerodds.wire.Float128 | never a double |
The unsigned types, stated once more because this is the decision
that reaches the wire: uint8 and unsigned short are numbers in an
int; unsigned long is a number in a long; unsigned long long
is a pattern in a long, and writeU64(-1L) writes
ffffffffffffffff, which is 18446744073709551615. octet is the
exception, and follows the OMG mapping.
This is not a choice made here alone. runtime/java/.../Writer.java
had to make it first, for its own arguments: writeU8(int value)
says “a number in [0, 255], not a pattern: the argument is an int
because Java’s byte is signed, and 200 arriving as -56 would be a
caller who has already lost the value”; writeU32(long value) says
the same of 3735928559; writeU64(long pattern) says the opposite,
because there is no wider type. The generated code calls those
methods, so a field typed against a different rule would either not
compile or arrive already wrong.
octet is a byte. CORBA 3.3 part 3 §1.5.2 maps octet to byte,
the JacORB column measured in crates/wire-probe/src/corba_java.rs
does the same, and DDS-XTypes 1.3 §7.5.1 reuses that mapping for the
Plain Language Binding. A signed byte holds 200 as -56; the codec
says so at both ends: Writer.writeU8(byte) writes the number the
eight bits are and the reader’s (byte) readU8() keeps them, so the
wire form is unchanged. uint8 has no OMG mapping and stays a number
in an int.
§The shapes
| IDL | Java |
|---|---|
string, wstring | java.lang.String |
fixed<P,S> | java.math.BigDecimal |
sequence<T>, T[N] | T[] |
T[N][M] | T[][] |
map<K,V> | ZdMap_k_v, a java.util.LinkedHashMap of the boxed types (ZdEntry_k_v[] for a key Java compares by identity) |
union | a class with _d and one field per case |
enum | a class with one instance per enumerator, value() and from_int (CORBA 3.3 part 3 §1.5.9) |
bitmask | the unsigned holder of its bound, beside constants |
bitset | a class of one field per bitfield |
@optional T m | the boxed T, null when absent |
@external T m | the boxed T for a primitive, the reference otherwise |
typedef | nothing; a comment, and the target’s type at each use |
§fixed<P,S> is a BigDecimal
§1.5.6 of the OMG mapping says java.math.BigDecimal, and the JacORB
column follows it. So does this one. The digits a fixed-point value
carries on the wire come from the type (fixed<P,S>), and a
BigDecimal keeps its scale, so new BigDecimal("0.00") writes the
digits 0.00 has; Writer.writeFixed takes the decimal text, which
the codec gets from toPlainString(), and Reader.readFixed hands
back text the codec turns into a BigDecimal. What a BigDecimal does
not keep is leading zeroes (precision() of 0.00 is 1), so the
FixedDigitCount::ValueStringDigits axis, which counts the digits of
the text a caller wrote, sees the normalised text.
§The collections
A sequence<T> and an IDL array are both a Java T[], which is what
§1.5.7 does and what the JacORB column records (“a Java array — so a
sequence is allocated, not lengthened”). A multi-dimensional array is
a nested Java array, one [] per dimension.
A map<K,V> is a java.util.Map (XTypes 1.3 §7.5.1.3.5): a generated
class extending LinkedHashMap of the boxed key and value types, so
that the order the entries were put in is the order they go on the wire
in; MapEntryOrder sorts them when asked to. The codec reads and
writes the entries in the generated entry class, in order
(ZdMap….entries() and ZdMap….of(entries)), and the class carries
the operations of Table 47 that Java does not have. A key a
java.util.Map would compare by identity (a structure, a sequence)
keeps the array of entries.
§@optional is a boxed type and null
One field, not a field beside a boolean. A boolean _has_m and an
m are two things that can disagree, and nothing in the type system
stops them; null cannot disagree with itself. @optional long m
therefore takes java.lang.Long, because a primitive long has no
value that means absent — which is the case that decides this, and the
reason C needs the parallel flag it has.
§An enumeration is a class of instances
CORBA 3.3 part 3 §1.5.9, which DDS-XTypes 1.3 §7.5.1 reuses: a final
class with one public static final instance per enumerator, the
int constants _NAME, value() and from_int. A member of the
type is an instance of the class and the codec writes value().
The JacORB column records the same shape. from_int refuses a value
no enumerator has; the codec never meets that, because it reads a
value through the chain of enumerators and applies the position’s
try-construct behaviour to one it does not know (Table 18), and
assigns the instance of the enumerator it found.
§Modules are nested classes, in one file
Not packages. Two facts decide it. Java requires the public top-level
type of a file to be named after the file, so real packages mean many
files; and this function returns Vec<java::TypeDecl> with no file
boundary in it, so a package-per-module mapping could not be expressed
by the signature at all — the package would be lost between here and
the renderer, and module a { struct P; } and module b { struct P; }
would collide in one scope. That collision is the defect
MaterialiseError::NoModule was added for in the Rust column.
The consumer decides it the same way: tools/wireprobe compiles one
probe per corpus case, and runtime/java/run-tests.sh invokes
javac --release 8 -Xlint:all,-options -Werror over a directory of
sources. One generated file with one outer class is one javac
argument; it also keeps -Xlint:auxiliaryclass quiet, which a file of
several top-level classes would not.
So everything nests inside OUTER, each IDL module becomes a
public static final class of that name, and every reference to a
generated type is written from OUTER down — ZdTypes.a.P. The
qualification is not decoration: JLS §6.5.2 resolves the first
segment of a qualified name to a variable before a type, so a field
named common in a class that also names the type common.util.Point
would be a compile error that only some corpora would show.
§Identifiers
Through zerodds_lang_cst::java::escape_keyword, which appends an
underscore: the module package becomes the class package_ and the
enumeration class becomes class_. crates/wire-probe/src/ target_keywords.rs prefixes one instead — _package, _class —
because that is what JacORB was measured to emit over
tests/interop-corpus/identifier-target-keywords. Both avoid the
keyword and neither reaches the wire; this crate does not depend on
zerodds-wire-probe, and the one CST spelling keeps the four
generated columns’ identifiers consistent with each other rather than
with one ORB. Only a Java keyword moves, so the enumerators
template, virtual and friend keep their spelling here as they do
there.
§What is refused
any, ValueBase and an object reference have no Java data form
here and are named as MaterialiseError::NoLanguageForm rather than
left out of the class. A generator that leaves a member out emits a
type missing a field and reports success, which is the defect class
this whole file is arranged against.
Enums§
- Java
Mapping - The shape generated Java types take.
Constants§
- ARRAY_
LIST - What a new unbounded sequence is under
JavaMapping::Psm. - MAP_
PREFIX - The prefix a generated map class carries.
- OUTER
- The class every generated declaration nests inside.
- SEQUENCES
- The runtime class the Psm mapping’s codec calls for the one thing it
cannot decide by type: indexing, counting, allocating and filling a
sequence that may be an array or a
Collection. Overload resolution does it, and the class isorg.zerodds.wire.Sequences.
Functions§
- accessor
base.getX(): the read of a member underJavaMapping::Psm, and the pseudo l-value thatassignturns intobase.setX(value).- assign
place = value;, in the form the mapping in force can write.- assignment
- A statement the walk built as
place = valueor as the bare expressionplace = value, rewritten byassign; anything else is returned as it is. - boolean_
getter_ name isXfor abooleanmemberfield; seegetter_name.- declared_
path - Where a declaration sits, as Java has to write it:
ZdTypes.a.b.Name. - entry_
class_ of_ map_ class - The entry class of the map class
class(ZdMap<bound>_<key>_<value>, the bound being absent or_b<digits>or_bx):ZdEntry_<key>_<value>. - getter_
name getXfor the memberfield, which is the escaped Java name.- index
a[i]for an array, andSequences.at(v, i)for the sequence the codec marked withsequence_view.- java_
items - Build the Java declarations a rule application produced.
- java_
member_ type - The Java type of a value in a position that has to hold one, refusing the constructs Java cannot hold.
- java_
primitive - The Java primitive an IDL primitive becomes.
- map_
class_ name - The class of a
map<K,V>:ZdMap<bound>_<key>_<value>. - map_
entry_ name - The map entry class a
map<K,V>needs a name for. - map_
key_ supported - Whether the key type of a map is one a
java.util.Mapcan be keyed by: a primitive, a string, an enumeration or a bitmask, whose Java objects compare by value, and a structure, a union or a bit set, whose generated class hasequalsandhashCodeover its members (seeequals_and_hash_code). - mapping
- The mapping in force on this thread.
- sequence_
slot - The place an element of a sequence is written into: a pseudo
l-value that
assignturns intoSequences.put(v, i, value). - sequence_
view Sequences.view(v): marks the expression the codec indexes into, so thatindexcan tell a sequence from a nested array.- sequences_
alloc Sequences.alloc(v, n): a new container of the kindvis, with room fornelements.- sequences_
count Sequences.count(v): the length of an array or aCollection.- sequences_
first Sequences.first(v, n): the firstnelements, in a container of the kindvis.- setter_
name setXfor the memberfield; seegetter_name.- type_
tag - The name component an entry class takes from one of its halves.
- unsigned_
holder - The Java type an unsigned value of
bitsbits is held in. - with_
mapping - Run
bodywithmappingin force, and restore what was before — also whenbodypanics.