1 === YANG Java Binding: Mapping rules
\r
2 This chapter covers the details of mapping YANG to Java.
\r
4 NOTE: The following source code examples does not show canonical generated
\r
5 code, but rather illustrative example. Generated classes and interfaces may
\r
6 differ from this examples, but APIs are preserved.
\r
8 ==== General conversion rules
\r
10 ===== Package names of YANG models
\r
12 The package name consists of the following parts: +
\r
14 * *Opendaylight prefix* - Specifies the opendaylight prefix. Every package name
\r
15 starts with the prefix `org.opendaylight.yang.gen.v`.
\r
16 * *Java Binding version* - Specifies the YANG Java Binding version.
\r
17 Curent Binding version is `1`.
\r
18 * *Namespace* - Specified by the value of `namespace` substatement.
\r
19 URI is converted to package name structure.
\r
20 * *Revision* - Specifies the concatenation of word `rev` and value of `module`
\r
21 substatements `revision` argument value without leading zeros before month and day.
\r
22 For example: `rev201379`
\r
24 After the package name is generated, we check if it contains any Java keywords
\r
25 or starts with a digit. If so, then we add an underscore before the offending
\r
28 The following is a list of keywords which are prefixed with underscore:
\r
30 abstract, assert, boolean, break, byte, case, catch, char, class, const,
\r
31 continue, default, double, do, else, enum, extends, false, final, finally,
\r
32 float, for, goto, if, implements, import, instanceof, int, interface, long,
\r
33 native, new, null, package, private, protected, public, return, short, static,
\r
34 strictfp, super, switch, synchronized, this, throw, throws, transient, true, try,
\r
35 void, volatile, while
\r
37 As an example suppose following yang model:
\r
42 namespace "urn:2:case#module";
\r
44 organization "OPEN DAYLIGHT";
\r
45 contact "http://www.example.com/";
\r
46 revision 2013-07-09 {
\r
51 After applying rules (replacing digits and Java keywords) the resulting
\r
52 package name is `org.opendaylight.yang.gen.v1.urn._2._case.module.rev201379`
\r
54 ===== Additional Packages
\r
56 In cases when YANG statement contain some of specific YANG
\r
57 statements additional packages are generated to designate this containment.
\r
58 Table below provides details of parent statement and nested statements, which
\r
59 yields additional package generation:
\r
63 |Parent statement | Substatement
\r
64 |`list` |list, container, choice
\r
65 |`container` | list, container, choice
\r
66 |`choice` | leaf, list, leaf-list, container, case
\r
67 |`case` | list, container, choice
\r
68 |rpc `input` or `output` | list, container, (choice isn't supported)
\r
69 |`notification` | list, container, (choice isn't supported)
\r
70 |`augment` | list, container, choice, case |
\r
73 Substatements are not only mapped to Java setter methods in the interface
\r
74 representing the parent statement, but they also generate packages with
\r
75 names consisting of the parent statement package name with the parent statement
\r
78 For example, this YANG model considers the container statement `cont` as the
\r
79 direct substatement of the module.
\r
84 container cont-inner {
\r
93 Container `cont` is the parent statement for the substatements
\r
94 `cont-inner` and `outter-list`. `list outter-list` is the parent
\r
95 statement for substatement `list-in-list`.
\r
97 Java code is generated in the following structure: +
\r
99 * `org.opendaylight.yang.gen.v1.urn.module.rev201379` - package contains direct
\r
100 substatements of module statement
\r
102 * `org.opendaylight.yang.gen.v1.urn.module.rev201379.cont` - package contains
\r
103 substatements of `cont` container statement
\r
104 ** `ContInner.java` - interface representing container `cont-inner`
\r
105 ** `OutterList.java` - interface representing list `outer-list`
\r
106 * `org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.outter.list` - package
\r
107 contains substatements of outter-list list element
\r
108 ** `ListInList.java`
\r
110 ===== Class and interface names
\r
111 Some YANG statements are mapped to Java classes and interfaces. The name of YANG
\r
112 element may contain various characters which aren't permitted in Java class names.
\r
113 Firstly whitespaces are trimmed from YANG name. Next the characters space, -, `
\r
114 are deleted and the subsequent letter is capitalized. At the end, first letter is
\r
118 `example-name_ without_capitalization` would map to
\r
119 `ExampleNameWithoutCapitalization`.
\r
121 ===== Getter and setter names
\r
122 In some cases, YANG statements are converted to getter and/or setter methods.
\r
123 The process for getter is:
\r
125 . the name of YANG statement is converted to Java class name style as
\r
126 <<_class_and_interface_names,explained above>>.
\r
127 . the word `get` is added as prefix, if resulting type is `Boolean`, the name
\r
128 is prefixed with `is` prefix instead of `get`.
\r
129 . the return type of the getter method is set to Java type representing substatement
\r
131 The process for setter is:
\r
133 . the name of YANG statement is converted to Java class name style as
\r
134 <<_class_and_interface_names,explained above>>.
\r
135 . the word `set` is added as prefix
\r
136 . the input parameter name is set to element's name converted to Java parameter style
\r
137 . the return parameter is set to builder type
\r
139 ==== Statement specific mapping
\r
141 ===== module statement
\r
143 YANG `module` statement is converted to Java as two Java classes.
\r
144 Each of the classes is in the separate Java file. The names of Java files are
\r
145 composed as follows:
\r
146 `<module name><suffix>.java` where `<suffix>` is either data or service.
\r
148 ====== Data Interface
\r
150 Data Interface has a mapping similar to container, but contains only top level
\r
151 nodes defined in module.
\r
153 Data interface serves only as marker interface for type-safe APIs of
\r
154 `InstanceIdentifier`.
\r
156 ====== Service Interface
\r
158 Service Interface serves to describe RPC contract defined in the module.
\r
159 This RPC contract is defined by `rpc` statements.
\r
161 RPC implementation usually implement this interface and users of the RPCs
\r
162 use this interface to invoke RPCs.
\r
164 ===== container statement
\r
165 YANG containers are mapped to Java interfaces which extend the Java DataObject and
\r
166 Augmentable<container-interface>, where container-interface is the name of the mapped
\r
169 For example, the following YANG:
\r
179 is converted into this Java:
\r
184 public interface Cont extends ChildOf<...>, Augmentable<Cont> {
\r
188 ===== Leaf statement
\r
189 Each leaf has to contain at least one type substatement. The leaf is mapped to
\r
190 getter method of parent statement with return type equal to type substatement
\r
193 For example, the following YANG:
\r
205 is converted into this Java:
\r
210 public interface Cont extends DataObject, Augmentable<Cont> {
\r
211 String getLf(); // <1>
\r
215 <1> Represents `leaf lf`
\r
217 ===== leaf-list statement
\r
218 Each leaf-list has to contain one type substatement. The leaf-list is mapped
\r
219 to getter method of parent statement with return type equal to List of type
\r
220 substatement value.
\r
222 For example, the following YANG:
\r
234 is converted into this Java:
\r
239 public interface Cont extends DataObject, Augmentable<Cont> {
\r
240 List<String> getLfLst();
\r
244 ===== list statement
\r
246 `list` statements are mapped to Java interfaces and a getter method is
\r
247 generated in the interface associated with it's parent statement.
\r
248 The return type of getter the method is a Java List of objects implementing
\r
249 the interface generated corresponding to the `list statement.
\r
250 Mapping of `list` substatement to Java:
\r
252 //[options="header"]
\r
254 //|Substatement|Mapping to Java
\r
258 For example, the following YANG:
\r
265 key "leaf-in-list";
\r
273 The list statement `example-list` is mapped to the Java interface `ExampleList` and
\r
274 the `Cont` interface (parent of `ExampleList`) contains getter method with return
\r
275 type `List<ExampleList>`. The presence of a `key` statement, triggers generation
\r
276 of `ExampleListKey`, which may be used to identify item in list.
\r
278 The end result is this Java:
\r
283 package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont;
\r
285 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
286 import org.opendaylight.yangtools.yang.binding.Augmentable;
\r
287 import Java.util.List;
\r
288 import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.outter.list.ListInList;
\r
290 public interface OutterList extends DataObject, Augmentable<OutterList> {
\r
292 List<String> getLeafListInList();
\r
294 List<ListInList> getListInList();
\r
297 Returns Primary Key of Yang List Type
\r
299 OutterListKey getOutterListKey();
\r
304 .OutterListKey.java
\r
307 package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont;
\r
309 import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.OutterListKey;
\r
310 import Java.math.BigInteger;
\r
312 public class OutterListKey {
\r
314 private BigInteger _leafInList;
\r
316 public OutterListKey(BigInteger _leafInList) {
\r
318 this_leafInList = _leafInList;
\r
321 public BigInteger getLeafInList() {
\r
322 return _leafInList;
\r
326 public int hashCode() {
\r
327 final int prime = 31;
\r
329 result = prime * result + ((_leafInList == null) ? 0 : _leafInList.hashCode());
\r
334 public boolean equals(Object obj) {
\r
341 if (getClass() != obj.getClass()) {
\r
344 OutterListKey other = (OutterListKey) obj;
\r
345 if (_leafInList == null) {
\r
346 if (other._LeafInList != null) {
\r
349 } else if(!_leafInList.equals(other._leafInList)) {
\r
356 public String toString() {
\r
357 StringBuilder builder = new StringBuilder();
\r
358 builder.append("OutterListKey [_leafInList=");
\r
359 builder.append(_leafInList);
\r
360 builder.append("]");
\r
361 return builder.toString();
\r
366 ===== choice and case statements
\r
367 A `choice` element is mapped in mostly the same way a `list` element is. The
\r
368 `choice` element is mapped to and interface (marker interface) and a new getter
\r
369 method with the return type of a Java `List` of this marker interfaces is added
\r
370 to the interface corresponding to the parent statement. Any `case`
\r
371 substatements are mapped to Java interfaces which extend the marker interface.
\r
373 For example, the following YANG:
\r
379 choice example-choice {
\r
394 is converted into this Java:
\r
399 package org.opendaylight.yang.gen.v1.urn.module.rev201379;
\r
401 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
402 import org.opendaylight.yangtools.yang.binding.Augmentable;
\r
403 import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.ChoiceTest;
\r
405 public interface Cont extends DataObject, Augmentable<Cont> {
\r
407 ExampleChoice getExampleChoice();
\r
412 .ExampleChoice.java
\r
415 package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont;
\r
417 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
419 public interface ExampleChoice extends DataContainer {
\r
426 package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.example.choice;
\r
428 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
429 import org.opendaylight.yangtools.yang.binding.Augmentable;
\r
430 import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.ChoiceTest;
\r
432 public interface FooCase extends ExampleChoice, DataObject, Augmentable<FooCase> {
\r
442 package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.example.choice;
\r
444 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
445 import org.opendaylight.yangtools.yang.binding.Augmentable;
\r
446 import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.ChoiceTest;
\r
448 public interface BarCase extends ExampleChoice, DataObject, Augmentable<BarCase> {
\r
455 ===== grouping and uses statements
\r
456 `grouping`s are mapped to Java interfaces. `uses` statements in some element
\r
457 (using of concrete grouping) are mapped as extension of interface for this
\r
458 element with the interface which represents grouping.
\r
460 For example, the following YANG:
\r
476 is converted into this Java:
\r
481 package org.opendaylight.yang.gen.v1.urn.module.rev201379;
\r
483 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
485 public interface Grp extends DataObject {
\r
495 package org.opendaylight.yang.gen.v1.urn.module.rev201379;
\r
497 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
498 import org.opendaylight.yangtools.yang.binding.Augmentable;
\r
500 public interface Cont extends DataObject, Augmentable<Cont>, Grp {
\r
505 ===== rpc, input and output statements
\r
506 An `rpc` statement is mapped to Java as method of class `ModuleService.java`.
\r
507 Any substatements of an `rpc` are mapped as follows:
\r
511 |Rpc Substatement|Mapping
\r
512 |input|presence of input statement triggers generation of interface
\r
513 |output|presence of output statement triggers generation of interface
\r
516 For example, the following YANG:
\r
535 is converted into this Java:
\r
537 .ModuleService.java
\r
540 package org.opendaylight.yang.gen.v1.urn.module.rev201379;
\r
542 import Java.util.concurrent.Future;
\r
543 import org.opendaylight.yangtools.yang.common.RpcResult;
\r
545 public interface ModuleService {
\r
547 Future<RpcResult<RpcTest1Output>> rpcTest1(RpcTest1Input input);
\r
552 .RpcTest1Input.java
\r
555 package org.opendaylight.yang.gen.v1.urn.module.rev201379;
\r
557 public interface RpcTest1Input {
\r
559 String getLfInput();
\r
564 .RpcTest1Output.java
\r
567 package org.opendaylight.yang.gen.v1.urn.module.rev201379;
\r
569 public interface RpcTest1Output {
\r
571 String getLfOutput();
\r
577 ===== notification statement
\r
579 `notification` statements are mapped to Java interfaces which extend
\r
580 the Notification interface.
\r
582 For example, the following YANG:
\r
587 notification notif {
\r
591 is converted into this Java:
\r
596 package org.opendaylight.yang.gen.v1.urn.module.rev201379;
\r
599 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
600 import org.opendaylight.yangtools.yang.binding.Augmentable;
\r
601 import org.opendaylight.yangtools.yang.binding.Notification;
\r
603 public interface Notif extends DataObject, Augmentable<Notif>, Notification {
\r
607 ==== augment statement
\r
608 `augment` statements are mapped to Java interfaces. The interface starts with
\r
609 the same name as the name of augmented interface with a suffix corresponding to
\r
610 the order number of augmenting interface. The augmenting interface also extends
\r
611 `Augmentation<>` with actual type parameter equal to augmented interface.
\r
613 For example, the following YANG:
\r
622 leaf additional-value {
\r
628 is converted into this Java:
\r
633 package org.opendaylight.yang.gen.v1.urn.module.rev201379;
\r
635 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
636 import org.opendaylight.yangtools.yang.binding.Augmentable;
\r
638 public interface Cont extends DataObject, Augmentable<Cont> {
\r
646 package org.opendaylight.yang.gen.v1.urn.module.rev201379;
\r
648 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
649 import org.opendaylight.yangtools.yang.binding.Augmentation;
\r
651 public interface Cont1 extends DataObject, Augmentation<Cont> {
\r
656 ==== YANG Type mapping
\r
658 ===== typedef statement
\r
659 YANG `typedef` statements are mapped to Java classes. A `typedef` may contain following
\r
664 |Substatement | Behaviour
\r
665 |type| determines wrapped type and how class will be generated
\r
666 |descripton| Javadoc description
\r
667 |units| is not mapped
\r
668 |default|is not mapped
\r
671 ====== Valid Arguments Type
\r
673 Simple values of type argument are mapped as follows:
\r
677 |YANG Type | Java type
\r
684 |string|String or, wrapper class (if pattern substatement is specified)
\r
693 Complex values of type argument are mapped as follows:
\r
697 |Argument Type| Java type
\r
698 |enumeration| generated java enum
\r
699 |bits| generated class for bits
\r
700 |leafref| same type as referenced leaf
\r
701 |identityref| Class
\r
702 |union| generated java class
\r
703 |instance-identifier| `org.opendaylight.yangtools.yang.binding.InstanceIdentifier`
\r
706 ===== Enumeration Substatement Enum
\r
707 The YANG `enumeration` type has to contain some `enum` substatements. An `enumeration` is mapped as Java enum type (standalone class) and every YANG enum substatements is mapped to Java enum's predefined values.
\r
709 An `enum` statement can have following substatements:
\r
713 |Enum's Substatement | Java mapping
\r
714 |description|is not mapped in API
\r
715 |value| mapped as input parameter for every predefined value of enum
\r
718 For example, the following YANG:
\r
723 typedef typedef-enumeration {
\r
726 description "enum1 description";
\r
738 is converted into this Java:
\r
740 .TypedefEnumeration.java
\r
743 public enum TypedefEnumeration {
\r
750 private TypedefEnumeration(int value) {
\r
751 this.value = value;
\r
756 ===== Bits's Substatement Bit
\r
757 The YANG `bits` type has to contain some bit substatements. YANG `bits` is mapped to
\r
758 a Java class (standalone class) and every YANG `bits` substatements is mapped to a
\r
759 boolean attribute of that class. In addition, the class provides overridden versions
\r
760 of the Object methods `hashCode`, `toString`, and `equals`.
\r
762 For example, the following YANG:
\r
767 typedef typedef-bits {
\r
770 description "first-bit description";
\r
778 is converted into this Java:
\r
783 public class TypedefBits {
\r
785 private Boolean firstBit;
\r
786 private Boolean secondBit;
\r
788 public TypedefBits() {
\r
792 public Boolean getFirstBit() {
\r
796 public void setFirstBit(Boolean firstBit) {
\r
797 this.firstBit = firstBit;
\r
800 public Boolean getSecondBit() {
\r
804 public void setSecondBit(Boolean secondBit) {
\r
805 this.secondBit = secondBit;
\r
809 public int hashCode() {
\r
810 final int prime = 31;
\r
812 result = prime * result +
\r
813 ((firstBit == null) ? 0 : firstBit.hashCode());
\r
814 result = prime * result +
\r
815 ((secondBit == null) ? 0 : secondBit.hashCode());
\r
820 public boolean equals(Object obj) {
\r
827 if (getClass() != obj.getClass()) {
\r
830 TypedefBits other = (TypedefBits) obj;
\r
831 if (firstBit == null) {
\r
832 if (other.firstBit != null) {
\r
835 } else if(!firstBit.equals(other.firstBit)) {
\r
838 if (secondBit == null) {
\r
839 if (other.secondBit != null) {
\r
842 } else if(!secondBit.equals(other.secondBit)) {
\r
849 public String toString() {
\r
850 StringBuilder builder = new StringBuilder();
\r
851 builder.append("TypedefBits [firstBit=");
\r
852 builder.append(firstBit);
\r
853 builder.append(", secondBit=");
\r
854 builder.append(secondBit);
\r
855 builder.append("]");
\r
856 return builder.toString();
\r
861 ===== Union's Substatement Type
\r
862 If the type of a `typedef` is `union`, it has to contain `type` substatements.
\r
863 The `union typedef` is mapped to class and its `type` substatements are mapped
\r
864 to private class members. Every YANG union subtype gets its own Java constructor
\r
865 with a parameter which represent just that one attribute.
\r
867 For example, the following YANG:
\r
872 typedef typedef-union {
\r
880 is converted into this Java:
\r
885 public class TypedefUnion {
\r
887 private Integer int32;
\r
888 private String string;
\r
890 public TypedefUnion(Integer int32) {
\r
892 this.int32 = int32;
\r
895 public TypedefUnion(String string) {
\r
897 this.string = string;
\r
900 public Integer getInt32() {
\r
904 public String getString() {
\r
909 public int hashCode() {
\r
910 final int prime = 31;
\r
912 result = prime * result + ((int32 == null) ? 0 : int32.hashCode());
\r
913 result = prime * result + ((string == null) ? 0 : string.hashCode());
\r
918 public boolean equals(Object obj) {
\r
925 if (getClass() != obj.getClass()) {
\r
928 TypedefUnion other = (TypedefUnion) obj;
\r
929 if (int32 == null) {
\r
930 if (other.int32 != null) {
\r
933 } else if(!int32.equals(other.int32)) {
\r
936 if (string == null) {
\r
937 if (other.string != null) {
\r
940 } else if(!string.equals(other.string)) {
\r
947 public String toString() {
\r
948 StringBuilder builder = new StringBuilder();
\r
949 builder.append("TypedefUnion [int32=");
\r
950 builder.append(int32);
\r
951 builder.append(", string=");
\r
952 builder.append(string);
\r
953 builder.append("]");
\r
954 return builder.toString();
\r
959 ===== String Mapping
\r
960 The YANG `string` type can contain the substatements `length`
\r
961 and `pattern` which are mapped as follows:
\r
965 |Type substatements | Mapping to Java
\r
966 | length | not mapped
\r
969 . list of string constants = list of patterns +
\r
970 . list of Pattern objects +
\r
971 . static initialization block where list of Patterns is initialized from list of string of constants
\r
974 For example, the following YANG:
\r
979 typedef typedef-string {
\r
987 is converted into this Java:
\r
989 .TypedefString.java
\r
992 public class TypedefString {
\r
994 private static final List<Pattern> patterns = new ArrayList<Pattern>();
\r
995 public static final List<String> PATTERN`CONSTANTS = Arrays.asList("[a][.]*");
\r
998 for (String regEx : PATTERN`CONSTANTS) {
\r
999 patterns.add(Pattern.compile(regEx));
\r
1003 private String typedefString;
\r
1005 public TypedefString(String typedefString) {
\r
1007 // Pattern validation
\r
1008 this.typedefString = typedefString;
\r
1011 public String getTypedefString() {
\r
1012 return typedefString;
\r
1016 public int hashCode() {
\r
1017 final int prime = 31;
\r
1019 result = prime * result + ((typedefString == null) ? 0 : typedefString.hashCode());
\r
1024 public boolean equals(Object obj) {
\r
1025 if (this == obj) {
\r
1028 if (obj == null) {
\r
1031 if (getClass() != obj.getClass()) {
\r
1034 TypedefString other = (TypedefString) obj;
\r
1035 if (typedefString == null) {
\r
1036 if (other.typedefString != null) {
\r
1039 } else if(!typedefString.equals(other.typedefString)) {
\r
1046 public String toString() {
\r
1047 StringBuilder builder = new StringBuilder();
\r
1048 builder.append("TypedefString [typedefString=");
\r
1049 builder.append(typedefString);
\r
1050 builder.append("]");
\r
1051 return builder.toString();
\r
1056 ==== identity statement
\r
1057 The purpose of the `identity` statement is to define a new globally unique,
\r
1058 abstract, and untyped value.
\r
1060 The `base` substatement argument is the name of existing identity from which
\r
1061 the new identity is derived.
\r
1063 Given that, an `identity` statement is mapped to Java abstract class and
\r
1064 any `base` substatements are mapped as `extends` Java keyword.
\r
1065 The identity name is translated to class name.
\r
1067 For example, the following YANG:
\r
1072 identity toast-type {
\r
1076 identity white-bread {
\r
1081 is converted into this Java:
\r
1086 public abstract class ToastType extends BaseIdentity {
\r
1087 protected ToastType() {
\r
1096 public abstract class WhiteBread extends ToastType {
\r
1097 protected WhiteBread() {
\r