java_gen: OFOxm: add 'canonical' virtual attribute, test

This enables OFOxm objects to return a 'canonical' representation,
where trivial masks (all-0, all-1) are converted to the main
representation.
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index c2d43c2..0d1cc87 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -602,6 +602,7 @@
                     JavaVirtualMember(self, "mask", java_type.generic_t),
                     JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
                     JavaVirtualMember(self, "masked", java_type.boolean),
+                    JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
                    ]
         elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
             field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
@@ -611,6 +612,8 @@
             virtual_members += [
                     JavaVirtualMember(self, "matchField", field_type),
                     JavaVirtualMember(self, "masked", java_type.boolean),
+                    JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(model.oxm_map[self.name].type_name),
+                            custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
                    ]
             if not find(lambda x: x.name == "mask", self.ir_model_members):
                 virtual_members.append(JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
@@ -745,18 +748,21 @@
                 virtual_members += [
                     JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
                     JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
-                   ]
+                    ]
             else:
                 virtual_members += [
                     JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
                     JavaVirtualMember(self, "masked", java_type.boolean, "false"),
-                   ]
-
+                 ]
         if not find(lambda m: m.name == "version", self.ir_model_members):
             virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
 
         return tuple(virtual_members)
 
+    @memoize
+    def member_by_name(self, name):
+        return find(lambda m: m.name == name, self.members)
+
     def all_versions(self):
         return [ JavaOFVersion(int_version)
                  for int_version in of_g.unified[self.c_name]