java_gen/java_type: add support for default values
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index d011c96..ea1ce2a 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -70,13 +70,14 @@
 ANY = 0xFFFFFFFFFFFFFFFF
 
 class VersionOp:
-    def __init__(self, version=ANY, read=None, write=None):
+    def __init__(self, version=ANY, read=None, write=None, default=None):
         self.version = version
         self.read = read
         self.write = write
+        self.default = default
 
     def __str__(self):
-        return "[Version: %d, Read: '%s', Write: '%s']" % (self.version, self.read, self.write)
+        return "[Version: %d, Read: '%s', Write: '%s', Default: '%s' ]" % (self.version, self.read, self.write, self.default )
 
 ### FIXME: This class should really be cleaned up
 class JType(object):
@@ -85,14 +86,14 @@
         read from and written to ChannelBuffers.
 
     """
-    def __init__(self, pub_type, priv_type=None, read_op=None, write_op=None):
+    def __init__(self, pub_type, priv_type=None):
         self.pub_type = pub_type    # the type we expose externally, e.g. 'U8'
         if priv_type is None:
             priv_type = pub_type
         self.priv_type = priv_type  # the internal storage type
         self.ops = {}
 
-    def op(self, version=ANY, read=None, write=None, pub_type=ANY):
+    def op(self, version=ANY, read=None, write=None, default=None, pub_type=ANY):
         """
         define operations to be performed for reading and writing this type
         (when read_op, write_op is called). The operations 'read' and 'write'
@@ -108,7 +109,7 @@
 
         pub_types = [ pub_type ] if pub_type is not ANY else [ False, True ]
         for pub_type in pub_types:
-            self.ops[(version, pub_type)] = VersionOp(version, read, write)
+            self.ops[(version, pub_type)] = VersionOp(version, read, write, default)
         return self
 
     def format_value(self, value, pub_type=True):
@@ -184,6 +185,24 @@
         else:
             return _write_op.replace("$name", str(name)).replace("$version", version.of_version)
 
+    def default_op(self, version=None, pub_type=True):
+        """ return a Java stanza that returns a default value of this JType.
+        @param version JavaOFVersion
+        @return string containing generated Java expression.
+        """
+        ver = ANY if version is None else version.int_version
+        _default_op = None
+        if (ver, pub_type) in self.ops:
+            _default_op = self.ops[(ver, pub_type)].default or self.ops[(ANY, pub_type)].default
+        elif (ANY, pub_type) in self.ops:
+            _default_op = self.ops[(ANY, pub_type)].default
+        if _default_op is None:
+            _default_op = self.format_value(0) if self.is_primitive else "null"
+        if callable(_default_op):
+            return _default_op(version, name)
+        else:
+            return _default_op.replace("$version", version.of_version)
+
     def skip_op(self, version=None, length=None):
         """ return a java stanza that skips an instance of JType in the input ChannelBuffer 'bb'.
             This is used in the Reader implementations for virtual classes (because after the
@@ -200,7 +219,7 @@
     @property
     def is_array(self):
         """ return true iff the pub_type is a Java array (and thus requires special
-        treament for equals / toString etc.) """
+        treatment for equals / toString etc.) """
         return self.pub_type.endswith("[]")
 
 
@@ -218,33 +237,46 @@
         .op(read='U32.f(bb.readInt())', write='bb.writeInt(U32.t($name))', pub_type=True) \
         .op(read='bb.readInt()', write='bb.writeInt($name)', pub_type=False)
 u32_list = JType('List<U32>', 'int[]') \
-        .op(read='ChannelUtils.readList(bb, $length, U32.READER)', write='ChannelUtils.writeList(bb, $name)')
+        .op(
+                read='ChannelUtils.readList(bb, $length, U32.READER)',
+                write='ChannelUtils.writeList(bb, $name)',
+                default="ImmutableList.<U32>of()");
 u8obj = JType('U8', 'U8') \
-        .op(read='U8.of(bb.readByte())', write='bb.writeByte($name.getRaw())')
+        .op(read='U8.of(bb.readByte())', write='bb.writeByte($name.getRaw())', default="U8.ZERO")
 u32obj = JType('U32', 'U32') \
-        .op(read='U32.of(bb.readInt())', write='bb.writeInt($name.getRaw())')
+        .op(read='U32.of(bb.readInt())', write='bb.writeInt($name.getRaw())', default="U32.ZERO")
 u64 = JType('U64', 'U64') \
-        .op(read='U64.ofRaw(bb.readLong())', write='bb.writeLong($name.getValue())')
+        .op(read='U64.ofRaw(bb.readLong())', write='bb.writeLong($name.getValue())', default="U64.ZERO")
 of_port = JType("OFPort") \
-         .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)") \
-         .op(version=ANY, read="OFPort.read4Bytes(bb)", write="$name.write4Bytes(bb)")
+         .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="OFPort.NONE") \
+         .op(version=ANY, read="OFPort.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFPort.NONE")
 actions_list = JType('List<OFAction>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFActionVer$version.READER)', write='ChannelUtils.writeList(bb, $name);')
+        .op(read='ChannelUtils.readList(bb, $length, OFActionVer$version.READER)',
+            write='ChannelUtils.writeList(bb, $name);',
+            default='ImmutableList.<OFAction>of()')
 instructions_list = JType('List<OFInstruction>') \
         .op(read='ChannelUtils.readList(bb, $length, OFInstructionVer$version.READER)', \
-            write='ChannelUtils.writeList(bb, $name)')
+            write='ChannelUtils.writeList(bb, $name)',
+            default='ImmutableList.<OFInstruction>of()')
 buckets_list = JType('List<OFBucket>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFBucketVer$version.READER)', write='ChannelUtils.writeList(bb, $name)')
+        .op(read='ChannelUtils.readList(bb, $length, OFBucketVer$version.READER)',
+            write='ChannelUtils.writeList(bb, $name)',
+            default='ImmutableList.<OFBucket>of()')
 port_desc_list = JType('List<OFPortDesc>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFPortDescVer$version.READER)', write='ChannelUtils.writeList(bb, $name)')
+        .op(read='ChannelUtils.readList(bb, $length, OFPortDescVer$version.READER)',
+            write='ChannelUtils.writeList(bb, $name)',
+            default='ImmutableList.<OFPortDesc>of()')
 port_desc = JType('OFPortDesc') \
         .op(read='OFPortDescVer$version.READER.readFrom(bb)', \
             write='$name.writeTo(bb)')
 packet_queue_list = JType('List<OFPacketQueue>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFPacketQueueVer$version.READER)', write='ChannelUtils.writeList(bb, $name);')
+        .op(read='ChannelUtils.readList(bb, $length, OFPacketQueueVer$version.READER)',
+            write='ChannelUtils.writeList(bb, $name);',
+            default='ImmutableList.<OFPacketQueue>of()')
 octets = JType('byte[]') \
         .op(read='ChannelUtils.readBytes(bb, $length)', \
-            write='bb.writeBytes($name)')
+            write='bb.writeBytes($name)', \
+            default="new byte[0]");
 of_match = JType('Match') \
         .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \
             write='$name.writeTo(bb)');
@@ -253,65 +285,104 @@
         .op(version=ANY, read="bb.readByte()", write="bb.writeByte($name)")
 mac_addr = JType('MacAddress') \
         .op(read="MacAddress.read6Bytes(bb)", \
-            write="$name.write6Bytes(bb)")
+            write="$name.write6Bytes(bb)",
+            default="MacAddress.NONE")
 port_name = JType('String') \
         .op(read='ChannelUtils.readFixedLengthString(bb, 16)', \
-            write='ChannelUtils.writeFixedLengthString(bb, $name, 16)')
+            write='ChannelUtils.writeFixedLengthString(bb, $name, 16)',
+            default='""')
 desc_str = JType('String') \
         .op(read='ChannelUtils.readFixedLengthString(bb, 256)', \
-            write='ChannelUtils.writeFixedLengthString(bb, $name, 256)')
+            write='ChannelUtils.writeFixedLengthString(bb, $name, 256)',
+            default='""')
 serial_num = JType('String') \
         .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
-            write='ChannelUtils.writeFixedLengthString(bb, $name, 32)')
+            write='ChannelUtils.writeFixedLengthString(bb, $name, 32)',
+            default='""')
 table_name = JType('String') \
         .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
-            write='ChannelUtils.writeFixedLengthString(bb, $name, 32)')
+            write='ChannelUtils.writeFixedLengthString(bb, $name, 32)',
+            default='""')
 ipv4 = JType("IPv4Address") \
         .op(read="IPv4Address.read4Bytes(bb)", \
-            write="$name.write4Bytes(bb)")
+            write="$name.write4Bytes(bb)",
+            default='IPv4Address.NONE')
 ipv6 = JType("IPv6Address") \
         .op(read="IPv6Address.read16Bytes(bb)", \
-            write="$name.write16Bytes(bb)")
+            write="$name.write16Bytes(bb)",
+            default='IPv6Address.NONE')
 packetin_reason = JType("OFPacketInReason")\
-        .op(read="OFPacketInReasonSerializerVer$version.readFrom(bb)", write="OFPacketInReasonSerializerVer$version.writeTo(bb, $name)")
-wildcards = JType("Wildcards")\
-        .op(read="Wildcards.of(bb.readInt())", write="bb.writeInt($name.getInt())");
+        .op(read="OFPacketInReasonSerializerVer$version.readFrom(bb)",
+            write="OFPacketInReasonSerializerVer$version.writeTo(bb, $name)")
 transport_port = JType("TransportPort")\
-        .op(read="TransportPort.read2Bytes(bb)", write="$name.write2Bytes(bb)")
+        .op(read="TransportPort.read2Bytes(bb)",
+            write="$name.write2Bytes(bb)",
+            default="TransportPort.NONE")
 eth_type = JType("EthType")\
-        .op(read="EthType.read2Bytes(bb)", write="$name.write2Bytes(bb)")
+        .op(read="EthType.read2Bytes(bb)",
+            write="$name.write2Bytes(bb)",
+            default="EthType.NONE")
 vlan_vid = JType("VlanVid")\
-        .op(read="VlanVid.read2Bytes(bb)", write="$name.write2Bytes(bb)")
+        .op(read="VlanVid.read2Bytes(bb)",
+            write="$name.write2Bytes(bb)",
+            default="VlanVid.NONE")
 vlan_pcp = JType("VlanPcp")\
-        .op(read="VlanPcp.readByte(bb)", write="$name.writeByte(bb)")
+        .op(read="VlanPcp.readByte(bb)",
+            write="$name.writeByte(bb)",
+            default="VlanPcp.NONE")
 ip_dscp = JType("IpDscp")\
-        .op(read="IpDscp.readByte(bb)", write="$name.writeByte(bb)")
+        .op(read="IpDscp.readByte(bb)",
+            write="$name.writeByte(bb)",
+            default="IpDscp.NONE")
 ip_ecn = JType("IpEcn")\
-        .op(read="IpEcn.readByte(bb)", write="$name.writeByte(bb)")
+        .op(read="IpEcn.readByte(bb)",
+            write="$name.writeByte(bb)",
+            default="IpEcn.NONE")
 ip_proto = JType("IpProtocol")\
-        .op(read="IpProtocol.readByte(bb)", write="$name.writeByte(bb)")
+        .op(read="IpProtocol.readByte(bb)",
+            write="$name.writeByte(bb)",
+            default="IpProtocol.NONE")
 icmpv4_type = JType("ICMPv4Type")\
-        .op(read="ICMPv4Type.readByte(bb)", write="$name.writeByte(bb)")
+        .op(read="ICMPv4Type.readByte(bb)",
+            write="$name.writeByte(bb)",
+            default="ICMPv4Type.NONE")
 icmpv4_code = JType("ICMPv4Code")\
-        .op(read="ICMPv4Code.readByte(bb)", write="$name.writeByte(bb)")
+        .op(read="ICMPv4Code.readByte(bb)",
+            write="$name.writeByte(bb)",
+            default="ICMPv4Code.NONE")
 arp_op = JType("ArpOpcode")\
-        .op(read="ArpOpcode.read2Bytes(bb)", write="$name.write2Bytes(bb)")
+        .op(read="ArpOpcode.read2Bytes(bb)",
+            write="$name.write2Bytes(bb)",
+            default="ArpOpcode.NONE")
 ipv6_flabel = JType("IPv6FlowLabel")\
-        .op(read="IPv6FlowLabel.read4Bytes(bb)", write="$name.write4Bytes(bb)")
+        .op(read="IPv6FlowLabel.read4Bytes(bb)",
+            write="$name.write4Bytes(bb)",
+            default="IPv6FlowLabel.NONE")
 metadata = JType("OFMetadata")\
-        .op(read="OFMetadata.read8Bytes(bb)", write="$name.write8Bytes(bb)")
+        .op(read="OFMetadata.read8Bytes(bb)",
+            write="$name.write8Bytes(bb)",
+            default="OFMetadata.NONE")
 oxm = JType("OFOxm<?>")\
         .op(  read="OFOxmVer$version.READER.readFrom(bb)",
               write="$name.writeTo(bb)")
 oxm_list = JType("OFOxmList") \
         .op(
             read= 'OFOxmList.readFrom(bb, $length, OFOxmVer$version.READER)', \
-            write='$name.writeTo(bb)')
+            write='$name.writeTo(bb)',
+            default="OFOxmList.EMPTY")
 meter_features = JType("OFMeterFeatures")\
-        .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
+        .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)",
+            write="$name.writeTo(bb)")
+flow_wildcards = JType("int") \
+        .op(read='bb.readInt()',
+            write='bb.writeInt($name)',
+            default="OFFlowWildcardsSerializerVer$version.ALL_VAL")
+table_stats_wildcards = JType("int") \
+        .op(read='bb.readInt()',
+            write='bb.writeInt($name)')
 
 port_speed = JType("PortSpeed")
-boolean = JType("boolean")
+boolean = JType("boolean").op(default="false")
 
 generic_t = JType("T")
 
@@ -341,7 +412,7 @@
         'of_table_name_t': table_name,
         'of_ipv4_t': ipv4,
         'of_ipv6_t': ipv6,
-        'of_wc_bmap_t': wildcards,
+        'of_wc_bmap_t': flow_wildcards,
         'of_oxm_t': oxm,
         'of_meter_features_t': meter_features,
         }
@@ -397,6 +468,12 @@
         'of_oxm_mpls_label_masked' : { 'value' : u32obj, 'value_mask' : u32obj },
         'of_oxm_mpls_tc' : { 'value' : u8obj },
         'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
+
+        'of_table_stats_entry': { 'wildcards': table_stats_wildcards },
+        'of_match_v1': { 'vlan_vid' : vlan_vid, 'vlan_pcp': vlan_pcp,
+                'eth_type': eth_type, 'ip_dscp': ip_dscp, 'ip_proto': ip_proto,
+                'tcp_src': transport_port, 'tcp_dst': transport_port
+                }
 }
 
 
@@ -407,11 +484,17 @@
     for protocol in of_g.ir.values():
         for enum in protocol.enums:
             java_name = name_c_to_caps_camel(re.sub(r'_t$', "", enum.name))
-            java_type = java_name if not enum.is_bitmask else "Set<{}>".format(java_name)
+            if enum.is_bitmask:
+                java_type = "Set<{}>".format(java_name)
+                default_value = "ImmutableSet.<{}>of()".format(java_name)
+            else:
+                java_type = java_name
+                default_value = "null"
             enum_types[enum.name] = \
                     JType(java_type)\
-                      .op(read = "{}SerializerVer$version.readFrom(bb)".format(java_name),
-                          write ="{}SerializerVer$version.writeTo(bb, $name)".format(java_name))
+                      .op(read="{}SerializerVer$version.readFrom(bb)".format(java_name),
+                          write="{}SerializerVer$version.writeTo(bb, $name)".format(java_name),
+                          default=default_value)
     return enum_types
 
 def make_match_field_jtype(sub_type_name="?"):
@@ -429,10 +512,12 @@
     # read op assumes the class has a public final static field READER that implements
     # OFMessageReader<$class> i.e., can deserialize an instance of class from a ChannelBuffer
     # write op assumes class implements Writeable
-    return JType("List<OF%s>" % java_base_name) \
+    return JType("List<OF{}>".format(java_base_name)) \
         .op(
-            read= 'ChannelUtils.readList(bb, $length, OF%sVer$version.READER)' % java_base_name, \
-            write='ChannelUtils.writeList(bb, $name)')
+            read= 'ChannelUtils.readList(bb, $length, OF{}Ver$version.READER)'.format(java_base_name), \
+            write='ChannelUtils.writeList(bb, $name)',
+            default="ImmutableList.<OF{}>of()".format(java_base_name)
+            )