Merge into master from pull request #42:
Big pull request - mainly to get the loxi_ir changes in (https://github.com/floodlight/loxigen/pull/42)
diff --git a/Makefile b/Makefile
index cb60398..146bdc5 100644
--- a/Makefile
+++ b/Makefile
@@ -42,18 +42,19 @@
 LOXI_TEMPLATE_FILES=$(shell find */templates -type f -a \
                                  \! \( -name '*.cache' -o -name '.*' \))
 INPUT_FILES = $(wildcard openflow_input/*)
+TEST_DATA = $(shell find test_data -name '*.data')
 
 all: c python
 
 c: .loxi_ts.c
 
-.loxi_ts.c: ${LOXI_PY_FILES} ${LOXI_TEMPLATE_FILES} ${INPUT_FILES}
+.loxi_ts.c: ${LOXI_PY_FILES} ${LOXI_TEMPLATE_FILES} ${INPUT_FILES ${TEST_DATA}
 	./loxigen.py --install-dir=${LOXI_OUTPUT_DIR} --lang=c
 	touch $@
 
 python: .loxi_ts.python
 
-.loxi_ts.python: ${LOXI_PY_FILES} ${LOXI_TEMPLATE_FILES} ${INPUT_FILES}
+.loxi_ts.python: ${LOXI_PY_FILES} ${LOXI_TEMPLATE_FILES} ${INPUT_FILES} ${TEST_DATA}
 	./loxigen.py --install-dir=${LOXI_OUTPUT_DIR} --lang=python
 	touch $@
 
@@ -68,11 +69,13 @@
 
 java: .loxi_ts.java
 
-.loxi_ts.java: ${LOXI_PY_FILES} ${LOXI_TEMPLATE_FILES} ${INPUT_FILES}
+.loxi_ts.java: ${LOXI_PY_FILES} ${LOXI_TEMPLATE_FILES} ${INPUT_FILES} ${TEST_DATA}
 	./loxigen.py --install-dir=${LOXI_OUTPUT_DIR} --lang=java
-	cd ${LOXI_OUTPUT_DIR}/openflowj; mvn package
 	touch $@
 
+java-eclipse: java
+	mkdir -p java-eclipse
+	rsync --checksum --delete -rv loxi_output/openflowj/ java_eclipse/
 
 clean:
 	rm -rf loxi_output # only delete generated files in the default directory
diff --git a/generic_utils.py b/generic_utils.py
index eeb26d6..ea9c589 100644
--- a/generic_utils.py
+++ b/generic_utils.py
@@ -31,6 +31,7 @@
 Intended to be imported into another namespace
 """
 
+import collections
 import functools
 import sys
 import of_g
@@ -99,8 +100,6 @@
 #
 ################################################################
 
-import collections
-
 class OrderedSet(collections.MutableSet):
     """
     A set implementations that retains insertion order.  From the receipe
@@ -164,12 +163,75 @@
             return len(self) == len(other) and list(self) == list(other)
         return set(self) == set(other)
 
-def find(iterable, func):
+################################################################
+#
+# OrderedDefaultDict
+#
+################################################################
+
+class OrderedDefaultDict(collections.OrderedDict):
+    """
+    A Dictionary that maintains insertion order where missing values
+    are provided by a factory function, i.e., a combination of
+    the semantics of collections.defaultdict and collections.OrderedDict.
+    """
+    def __init__(self, default_factory=None, *a, **kw):
+        if (default_factory is not None and
+                not callable(default_factory)):
+            raise TypeError('first argument must be callable')
+        collections.OrderedDict.__init__(self, *a, **kw)
+        self.default_factory = default_factory
+
+    def __getitem__(self, key):
+        try:
+            return collections.OrderedDict.__getitem__(self, key)
+        except KeyError:
+            return self.__missing__(key)
+
+    def __missing__(self, key):
+        if self.default_factory is None:
+            raise KeyError(key)
+        self[key] = value = self.default_factory()
+        return value
+
+    def __reduce__(self):
+        if self.default_factory is None:
+            args = tuple()
+        else:
+            args = self.default_factory,
+        return type(self), args, None, None, self.items()
+
+    def copy(self):
+        return self.__copy__()
+
+    def __copy__(self):
+        return type(self)(self.default_factory, self)
+
+    def __deepcopy__(self, memo):
+        import copy
+        return type(self)(self.default_factory,
+                          copy.deepcopy(self.items()))
+    def __repr__(self):
+        return 'OrderedDefaultDict(%s, %s)' % (self.default_factory,
+                                        collections.OrderedDict.__repr__(self))
+
+
+def find(func, iterable):
     """
     find the first item in iterable for which func returns something true'ish.
-    @raise KeyError if no item in iterable fulfills the condition
+    @returns None if no item in iterable fulfills the condition
     """
     for i in iterable:
         if func(i):
             return i
-    raise KeyError("Couldn't find value that matches: %s" % repr(func))
+    return None
+
+def count(func, iteratable):
+    """
+    count how the number of items in iterable for which func returns something true'ish.
+    """
+    c = 0
+    for i in iterable:
+        if func(i):
+            c +=1
+    return c
diff --git a/java_gen/codegen.py b/java_gen/codegen.py
index 0765c91..f3619d4 100644
--- a/java_gen/codegen.py
+++ b/java_gen/codegen.py
@@ -36,6 +36,7 @@
 import of_g
 from loxi_ir import *
 import lang_java
+import test_data
 
 import loxi_utils.loxi_utils as loxi_utils
 
@@ -43,17 +44,17 @@
 
 def gen_all_java(out, name):
     basedir= '%s/openflowj' % of_g.options.install_dir
-    srcdir = "%s/src/main/java/" % basedir
     print "Outputting to %s" % basedir
     if os.path.exists(basedir):
         shutil.rmtree(basedir)
     os.makedirs(basedir)
     copy_prewrite_tree(basedir)
 
-    gen = JavaGenerator(srcdir)
+    gen = JavaGenerator(basedir)
     gen.create_of_interfaces()
     gen.create_of_classes()
     gen.create_of_const_enums()
+    gen.create_of_factories()
 
     with open('%s/README.java-lang' % os.path.dirname(__file__)) as readme_src:
         out.writelines(readme_src.readlines())
@@ -67,11 +68,15 @@
         self.basedir = basedir
         self.java_model = java_model.model
 
-    def render_class(self, clazz, template, **context):
+    def render_class(self, clazz, template, src_dir=None, **context):
+        if not src_dir:
+            src_dir = "src/main/java/"
+
         context['class_name'] = clazz.name
         context['package'] = clazz.package
+        context['template_dir'] = self.templates_dir
 
-        filename = os.path.join(self.basedir, "%s/%s.java" % (clazz.package.replace(".", "/"), clazz.name))
+        filename = os.path.join(self.basedir, src_dir, "%s/%s.java" % (clazz.package.replace(".", "/"), clazz.name))
         dirname = os.path.dirname(filename)
         if not os.path.exists(dirname):
             os.makedirs(dirname)
@@ -87,6 +92,10 @@
             self.render_class(clazz=enum,
                     template='const.java', enum=enum, all_versions=self.java_model.versions)
 
+            for version in enum.versions:
+                clazz = java_model.OFGenericClass(package="org.openflow.protocol.ver{}".format(version.of_version), name="{}SerializerVer{}".format(enum.name, version.of_version))
+                self.render_class(clazz=clazz, template="const_serializer.java", enum=enum, version=version)
+
     def create_of_interfaces(self):
         """ Create the base interfaces for of classes"""
         for interface in self.java_model.interfaces:
@@ -98,14 +107,39 @@
     def create_of_classes(self):
         """ Create the OF classes with implementations for each of the interfaces and versions """
         for interface in self.java_model.interfaces:
-            if interface.name == "OFTableMod":
-                continue
-            if not loxi_utils.class_is_message(interface.c_name) and not loxi_utils.class_is_oxm(interface.c_name):
-                continue
             for java_class in interface.versioned_classes:
-                self.render_class(clazz=java_class,
-                        template='of_class.java', version=java_class.version, msg=java_class,
-                        impl_class=java_class.name)
+                if self.java_model.generate_class(java_class):
+                    if not java_class.is_virtual:
+                        self.render_class(clazz=java_class,
+                                template='of_class.java', version=java_class.version, msg=java_class,
+                                impl_class=java_class.name)
+
+                        self.create_unit_test(java_class.unit_test)
+                    else:
+                        disc = java_class.discriminator
+                        if disc:
+                            self.render_class(clazz=java_class,
+                                template='of_virtual_class.java', version=java_class.version, msg=java_class,
+                                impl_class=java_class.name, model=self.java_model)
+                        else:
+                            print "Class %s virtual but no discriminator" % java_class.name
+                else:
+                    print "Class %s ignored by generate_class" % java_class.name
+
+    def create_unit_test(self, unit_test):
+        if unit_test.has_test_data:
+            self.render_class(clazz=unit_test,
+                    template='unit_test.java', src_dir="src/test/java",
+                    version=unit_test.java_class.version,
+                    test=unit_test, msg=unit_test.java_class,
+                    test_data=unit_test.test_data)
+
+    def create_of_factories(self):
+        factory = self.java_model.of_factory
+        self.render_class(clazz=factory, template="of_factory_interface.java", factory=factory)
+        for factory_class in factory.factory_classes:
+            self.render_class(clazz=factory_class, template="of_factory_class.java", factory=factory_class, model=self.java_model)
+        self.render_class(clazz=java_model.OFGenericClass(package="org.openflow.protocol", name="OFFactories"), template="of_factories.java", versions=self.java_model.versions)
 
 def copy_prewrite_tree(basedir):
     """ Recursively copy the directory structure from ./java_gen/pre-write
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 35f334c..4ac497f 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -29,24 +29,27 @@
 # A lot of this stuff could/should probably be merged with the python utilities
 
 import collections
-from collections import namedtuple, defaultdict
+from collections import namedtuple, defaultdict, OrderedDict
 import logging
 import os
 import pdb
 import re
 
-from generic_utils import find, memoize, OrderedSet
+from generic_utils import find, memoize, OrderedSet, OrderedDefaultDict
 import of_g
 from loxi_ir import *
 import loxi_front_end.type_maps as type_maps
-import loxi_utils.loxi_utils as utils
+import loxi_utils.loxi_utils as loxi_utils
 import py_gen.util as py_utils
+import test_data
 
 import java_gen.java_type as java_type
 
 class JavaModel(object):
-    write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)))
-    virtual_interfaces = set(['OFOxm' ])
+    enum_blacklist = set(("OFDefinitions",))
+    enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
+    write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )))
+    virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
 
     @property
     @memoize
@@ -56,12 +59,15 @@
     @property
     @memoize
     def interfaces(self):
-        version_map_per_class = collections.defaultdict(lambda: {})
+        version_map_per_class = collections.OrderedDict()
 
         for raw_version, of_protocol in of_g.ir.items():
             jversion = JavaOFVersion(of_protocol.wire_version)
 
             for of_class in of_protocol.classes:
+                if not of_class.name in version_map_per_class:
+                    version_map_per_class[of_class.name] = collections.OrderedDict()
+
                 version_map_per_class[of_class.name][jversion] = of_class
 
         interfaces = []
@@ -72,26 +78,72 @@
 
     @property
     @memoize
+    def all_classes(self):
+        return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
+
+    @property
+    @memoize
     def enums(self):
-        enum_entry_version_value_map = collections.defaultdict(lambda: collections.defaultdict(lambda: collections.OrderedDict()))
+        name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
 
         for version in self.versions:
             of_protocol = of_g.ir[version.int_version]
             for enum in of_protocol.enums:
-                for entry_name, entry_value in enum.values:
-                    enum_entry_version_value_map[enum.name][entry_name][version] = entry_value
+                name_version_enum_map[enum.name][version] = enum
 
-        enums = [ JavaEnum(name, entry_version_value_map) for name, entry_version_value_map
-                        in enum_entry_version_value_map.items() ]
+        enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
+                        in name_version_enum_map.items() ]
 
+        # inelegant - need java name here
+        enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
         return enums
 
     @memoize
     def enum_by_name(self, name):
-        try:
-            return find(self.enums, lambda e: e.name == name)
-        except KeyError:
+        res = find(lambda e: e.name == name, self.enums)
+        if not res:
             raise KeyError("Could not find enum with name %s" % name)
+        return res
+
+    @property
+    @memoize
+    def of_factory(self):
+           return OFFactory(
+                    package="org.openflow.protocol",
+                    name="OFFactory",
+                    members=self.interfaces)
+
+    def generate_class(self, clazz):
+        if clazz.interface.name.startswith("OFMatchV"):
+            return True
+        elif clazz.name == "OFTableModVer10":
+            # tablemod ver 10 is a hack and has no oftype defined
+            return False
+        if loxi_utils.class_is_message(clazz.interface.c_name):
+            return True
+        if loxi_utils.class_is_oxm(clazz.interface.c_name):
+            return True
+        if loxi_utils.class_is_action(clazz.interface.c_name):
+            return True
+        if loxi_utils.class_is_instruction(clazz.interface.c_name):
+            return True
+        else:
+            return True
+
+
+class OFFactory(namedtuple("OFFactory", ("package", "name", "members"))):
+    @property
+    def factory_classes(self):
+            return [ OFFactoryClass(
+                    package="org.openflow.protocol.ver{}".format(version.of_version),
+                    name="OFFactoryVer{}".format(version.of_version),
+                    interface=self,
+                    version=version
+                    ) for version in model.versions ]
+
+
+OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
+OFFactoryClass = namedtuple("OFFactory", ("package", "name", "interface", "version"))
 
 model = JavaModel()
 
@@ -138,8 +190,8 @@
     def __init__(self, c_name, version_map):
         self.c_name = c_name
         self.version_map = version_map
-        self.name = java_type.name_c_to_caps_camel(c_name)
-        self.builder_name = self.name + "Builder"
+        self.name = java_type.name_c_to_caps_camel(c_name) if c_name != "of_header" else "OFMessage"
+        self.variable_name = self.name[2].lower() + self.name[3:]
         self.constant_name = c_name.upper().replace("OF_", "")
 
         pck_suffix, parent_interface = self.class_info()
@@ -150,18 +202,39 @@
             self.parent_interface = None
 
     def class_info(self):
-        if re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
+        if re.match(r'OF.+StatsRequest$', self.name):
+            return ("", "OFStatsRequest")
+        elif re.match(r'OF.+StatsReply$', self.name):
+            return ("", "OFStatsReply")
+        elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
             return ("", "OFFlowMod")
-        elif utils.class_is_message(self.c_name):
+        elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name):
+            return ("", "OFBsnHeader")
+        elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name):
+            return ("", "OFNiciraHeader")
+        elif re.match(r'OFMatch.*', self.name):
+            return ("", "Match")
+        elif loxi_utils.class_is_message(self.c_name):
             return ("", "OFMessage")
-        elif utils.class_is_action(self.c_name):
-            return ("action", "OFAction")
-        elif utils.class_is_oxm(self.c_name):
+        elif loxi_utils.class_is_action(self.c_name):
+            if re.match(r'OFActionBsn.*', self.name):
+                return ("action", "OFActionBsn")
+            elif re.match(r'OFActionNicira.*', self.name):
+                return ("action", "OFActionNicira")
+            else:
+                return ("action", "OFAction")
+        elif re.match(r'OFBsnVport.+$', self.name):
+            return ("", "OFBsnVport")
+        elif loxi_utils.class_is_oxm(self.c_name):
             return ("oxm", "OFOxm")
-        elif utils.class_is_instruction(self.c_name):
+        elif loxi_utils.class_is_instruction(self.c_name):
             return ("instruction", "OFInstruction")
-        elif utils.class_is_meter_band(self.c_name):
+        elif loxi_utils.class_is_meter_band(self.c_name):
             return ("meterband", "OFMeterBand")
+        elif loxi_utils.class_is_queue_prop(self.c_name):
+            return ("queueprop", "OFQueueProp")
+        elif loxi_utils.class_is_hello_elem(self.c_name):
+            return ("", "OFHelloElem")
         else:
             return ("", None)
 
@@ -185,22 +258,26 @@
     @property
     @memoize
     def is_virtual(self):
-        return self.name in model.virtual_interfaces
+        return self.name in model.virtual_interfaces or all(ir_class.virtual for ir_class in self.version_map.values())
+
+    @property
+    def is_universal(self):
+        return len(self.all_versions) == len(model.versions)
 
     @property
     @memoize
     def all_versions(self):
         return self.version_map.keys()
 
+    def has_version(self, version):
+        return version in self.version_map
+
     def versioned_class(self, version):
         return JavaOFClass(self, version, self.version_map[version])
 
     @property
     @memoize
     def versioned_classes(self):
-        if self.is_virtual:
-            return []
-        else:
             return [ self.versioned_class(version) for version in self.all_versions ]
 
 #######################################################################
@@ -218,12 +295,22 @@
         self.version = version
         self.constant_name = self.c_name.upper().replace("OF_", "")
         self.package = "org.openflow.protocol.ver%s" % version.of_version
+        self.generated = False
+
+    @property
+    @memoize
+    def unit_test(self):
+        return JavaUnitTest(self)
 
     @property
     def name(self):
         return "%sVer%s" % (self.interface.name, self.version.of_version)
 
     @property
+    def variable_name(self):
+        return self.name[3:]
+
+    @property
     def length(self):
         if self.is_fixed_length:
             return self.min_length
@@ -281,12 +368,30 @@
 
     @property
     def is_virtual(self):
-        return type_maps.class_is_virtual(self.c_name)
+        return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
+
+    @property
+    def discriminator(self):
+        return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
 
     @property
     def is_extension(self):
         return type_maps.message_is_extension(self.c_name, -1)
 
+    @property
+    def align(self):
+        return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
+
+    @property
+    @memoize
+    def superclass(self):
+        return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
+
+    @property
+    @memoize
+    def subclasses(self):
+        return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
+
 #######################################################################
 ### Member
 #######################################################################
@@ -363,6 +468,10 @@
         return isinstance(self.member, OFFieldLengthMember)
 
     @property
+    def is_discriminator(self):
+        return isinstance(self.member, OFDiscriminatorMember)
+
+    @property
     def is_length_value(self):
         return isinstance(self.member, OFLengthMember)
 
@@ -386,10 +495,18 @@
             return self.msg.version.int_version
         elif self.name == "length" or self.name == "len":
             return self.msg.length
-        elif self.java_type.public_type in ("int", "short", "byte") and self.member.value > 100:
-            return "0x%x" % self.member.value
         else:
-            return self.member.value
+            return self.java_type.format_value(self.member.value)
+
+    @property
+    def priv_value(self):
+        if self.name == "version":
+            return self.msg.version.int_version
+        elif self.name == "length" or self.name == "len":
+            return self.msg.length
+        else:
+            return self.java_type.format_value(self.member.value, pub_type=False)
+
 
     @property
     def is_writeable(self):
@@ -403,7 +520,7 @@
         if hasattr(self.member, "length"):
             return self.member.length
         else:
-            count, base = utils.type_dec_to_count_base(self.member.type)
+            count, base = loxi_utils.type_dec_to_count_base(self.member.type)
             return of_g.of_base_types[base]['bytes'] * count
 
     @staticmethod
@@ -441,51 +558,111 @@
             return False
         return (self.name,) == (other.name,)
 
+
+#######################################################################
+### Unit Test
+#######################################################################
+
+class JavaUnitTest(object):
+    def __init__(self, java_class):
+        self.java_class = java_class
+        self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
+                                                     name=java_class.c_name[3:])
+    @property
+    def package(self):
+        return self.java_class.package
+
+    @property
+    def name(self):
+        return self.java_class.name + "Test"
+
+    @property
+    def has_test_data(self):
+        return test_data.exists(self.data_file_name)
+
+    @property
+    @memoize
+    def test_data(self):
+        return test_data.read(self.data_file_name)
+
+
 #######################################################################
 ### Enums
 #######################################################################
 
 class JavaEnum(object):
-    def __init__(self, c_name, entry_version_value_map):
+    def __init__(self, c_name, version_enum_map):
         self.c_name = c_name
         self.name   = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
 
         # Port_features has constants that start with digits
         self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
 
+        self.version_enums = version_enum_map
+
+        entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
+        for version, ir_enum in version_enum_map.items():
+            for ir_entry in ir_enum.entries:
+                if "virtual" in ir_entry.params:
+                    continue
+                entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
+
         self.entries = [ JavaEnumEntry(self, name, version_value_map)
-                         for (name, version_value_map) in entry_version_value_map.items() ]
+                         for (name, version_value_map) in entry_name_version_value_map.items() ]
+
+        self.entries = [ e for e in self.entries if e.name not in model.enum_entry_blacklist[self.name] ]
         self.package = "org.openflow.protocol"
 
+    def wire_type(self, version):
+        ir_enum = self.version_enums[version]
+        if "wire_type" in ir_enum.params:
+            return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
+        else:
+            return java_type.u8
+
+    @property
+    def versions(self):
+        return self.version_enums.keys()
+
     @memoize
     def entry_by_name(self, name):
-        try:
-            return find(self.entries, lambda e: e.name == name)
-        except KeyError:
+        res = find(lambda e: e.name == name, self.entries)
+        if res:
+            return res
+        else:
             raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
 
     @memoize
     def entry_by_c_name(self, name):
-        try:
-            return find(self.entries, lambda e: e.c_name == name)
-        except KeyError:
+        res = find(lambda e: e.c_name == name, self.entries)
+        if res:
+            return res
+        else:
             raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
 
     @memoize
     def entry_by_version_value(self, version, value):
-        try:
-            return find(self.entries, lambda e: e.values[version] == value if version in e.values else False )
-        except KeyError:
+        res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
+        if res:
+            return res
+        else:
             raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
 
 # values: Map JavaVersion->Value
 class JavaEnumEntry(object):
     def __init__(self, enum, name, values):
+        self.enum = enum
         self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
         self.values = values
 
+    def has_value(self, version):
+        return version in self.values
+
     def value(self, version):
-        res = self.version_value_map[version]
+        return self.values[version]
+
+    def format_value(self, version):
+        res = self.enum.wire_type(version).format_value(self.values[version])
         return res
 
     def all_values(self, versions, not_present=None):
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 8580f37..38ce1ff 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -1,3 +1,4 @@
+import loxi_utils.loxi_utils as loxi_utils
 import os
 import errno
 import re
@@ -21,19 +22,43 @@
         return camel
 
 
-ANY = 0xFFFFFFFFFFFFFFFF
+java_primitive_types = set("byte char short int long".split(" "))
+java_primitives_info = {
+        'byte' : (True, 8),
+        'char' : (False, 16),
+        'short' : (True, 16),
+        'int' : (True, 32),
+        'long' : (True, 64),
+}
 
+def format_primitive_value(t, value):
+    signed, bits = java_primitives_info[t]
+    max = (1 << bits)-1
+    if value > max:
+        raise Exception("Value %d to large for type %s" % (value, t))
+
+    if signed:
+        max_pos = (1 << (bits-1)) - 1
+
+        if  value > max_pos:
+            if t == "long":
+                return str((1 << bits) - value)
+            else:
+                return "(%s) 0x%x" % (t, value)
+        else:
+            return "0x%x" % value
+
+ANY = 0xFFFFFFFFFFFFFFFF
 
 class VersionOp:
     def __init__(self, version=ANY, read=None, write=None):
         self.version = version
         self.read = read
         self.write = write
-        
+
     def __str__(self):
         return "[Version: %d, Read: '%s', Write: '%s']" % (self.version, self.read, self.write)
 
-
 class JType(object):
     """ Wrapper class to hold C to Java type conversion information """
     def __init__(self, pub_type, priv_type=None, size=None, read_op=None, write_op=None):
@@ -44,16 +69,25 @@
         self.size = size            # bytes on the wire; None == variable length or hard to calc
         self.ops = {}
 #        if read_op is None:
-#            read_op = 'ChannelUtils.read%s(bb)' % self.pub_type
+#            read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type
 #        if write_op is None:
-#            write_op = 'ChannelUtils.write%s(bb, $name)'  % self.pub_type
+#            write_op = 'ChannelUtilsVer$version.write%s(bb, $name)'  % self.pub_type
 #        self._read_op = read_op
 #        self._write_op = write_op
 
-    def op(self, version=ANY, read=None, write=None):
-        self.ops[version] = VersionOp(version, read, write)
+    def op(self, version=ANY, read=None, write=None, pub_type=ANY):
+        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)
         return self
 
+    def format_value(self, value, pub_type=True):
+        t = self.pub_type if pub_type else self.priv_type
+        if t in java_primitive_types:
+            return format_primitive_value(t, value)
+        else:
+            return value
+
     @property
     def public_type(self):
         """ return the public type """
@@ -67,91 +101,98 @@
         """ Is the private type different from the public one?"""
         return self.pub_type != self.priv_type
 
-    def read_op(self, version=None, length=None):
+    def read_op(self, version=None, length=None, pub_type=True):
         if length is None:
-            length = "length - bb.readerIndex()";
+            length = "length - (bb.readerIndex() - start)";
 
         ver = ANY if version is None else version.int_version
         _read_op = None
-        if ver in self.ops:
-            _read_op = self.ops[ver].read or self.ops[ANY].read 
-        elif ANY in self.ops:
-            _read_op = self.ops[ANY].read
+        if (ver, pub_type) in self.ops:
+            _read_op = self.ops[(ver, pub_type)].read or self.ops[(ANY, pub_type)].read
+        elif (ANY, pub_type) in self.ops:
+            _read_op = self.ops[(ANY, pub_type)].read
         if _read_op is None:
-            _read_op = 'ChannelUtils.read%s(bb)' % self.pub_type
+            _read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type
         if callable(_read_op):
             return _read_op(version)
         else:
             return _read_op.replace("$length", str(length)).replace("$version", version.of_version)
 
-    def write_op(self, version=None, name=None):
+    def write_op(self, version=None, name=None, pub_type=True):
         ver = ANY if version is None else version.int_version
         _write_op = None
-        if ver in self.ops:
-            _write_op = self.ops[ver].write or self.ops[ANY].write
-        elif ANY in self.ops:
-            _write_op = self.ops[ANY].write
+        if (ver, pub_type) in self.ops:
+            _write_op = self.ops[(ver, pub_type)].write or self.ops[(ANY, pub_type)].write
+        elif (ANY, pub_type) in self.ops:
+            _write_op = self.ops[(ANY, pub_type)].write
         if _write_op is None:
-            _write_op = 'ChannelUtils.write%s(bb, $name)' % self.pub_type
+            _write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type
         if callable(_write_op):
             return _write_op(version, name)
         else:
             return _write_op.replace("$name", str(name)).replace("$version", version.of_version)
 
-hello_elem_list = JType("List<OFHelloElement>") \
-        .op(read='ChannelUtils.readHelloElementList(bb)', write='ChannelUtils.writeHelloElementList(bb)')
+    def skip_op(self, version=None, length=None):
+        return self.read_op(version, length)
+
+    @property
+    def is_primitive(self):
+        return self.pub_type in java_primitive_types
+
+    @property
+    def is_array(self):
+        return self.pub_type.endswith("[]")
+
+
 u8 =  JType('byte',  size=1) \
         .op(read='bb.readByte()', write='bb.writeByte($name)')
 u8_list =  JType('List<U8>',  size=1) \
-        .op(read='bb.readByte()', write='bb.writeByte($name)')
+        .op(read='ChannelUtils.readList(bb, $length, U8.READER)', write='ChannelUtils.writeList(bb, $name)')
 u16 = JType('int', 'int', size=2) \
         .op(read='U16.f(bb.readShort())', write='bb.writeShort(U16.t($name))')
 u32 = JType('int', 'int', size=4) \
         .op(read='bb.readInt()', write='bb.writeInt($name)')
 u32_list = JType('List<U32>', 'int[]', size=4) \
-        .op(read='bb.readInt()', write='bb.writeInt($name)')
+        .op(read='ChannelUtils.readList(bb, $length, U32.READER)', write='ChannelUtils.writeList(bb, $name)')
 u64 = JType('U64', 'U64', size=8) \
         .op(read='U64.of(bb.readLong())', write='bb.writeLong($name.getValue())')
 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)")
 one_byte_array = JType('byte[]', size=1) \
-        .op(read='ChannelUtils.readBytes(bb, 1)', write='ChannelUtils.writeBytes(bb, $name)')
+        .op(read='ChannelUtils.readBytes(bb, 1)', write='bb.writeBytes($name)')
 two_byte_array = JType('byte[]', size=2) \
-        .op(read='ChannelUtils.readBytes(bb, 2)', write='ChannelUtils.writeBytes(bb, $name)')
+        .op(read='ChannelUtils.readBytes(bb, 2)', write='bb.writeBytes($name)')
 three_byte_array = JType('byte[]', size=3) \
-        .op(read='ChannelUtils.readBytes(bb, 3)', write='ChannelUtils.writeBytes(bb, $name)')
+        .op(read='ChannelUtils.readBytes(bb, 3)', write='bb.writeBytes($name)')
 four_byte_array = JType('byte[]', size=4) \
-        .op(read='ChannelUtils.readBytes(bb, 4)', write='ChannelUtils.writeBytes(bb, $name)')
+        .op(read='ChannelUtils.readBytes(bb, 4)', write='bb.writeBytes($name)')
 five_byte_array = JType('byte[]', size=5) \
-        .op(read='ChannelUtils.readBytes(bb, 5)', write='ChannelUtils.writeBytes(bb, $name)')
+        .op(read='ChannelUtils.readBytes(bb, 5)', write='bb.writeBytes($name)')
 six_byte_array = JType('byte[]', size=6) \
-        .op(read='ChannelUtils.readBytes(bb, 6)', write='ChannelUtils.writeBytes(bb, $name)')
+        .op(read='ChannelUtils.readBytes(bb, 6)', write='bb.writeBytes($name)')
 seven_byte_array = JType('byte[]', size=7) \
-        .op(read='ChannelUtils.readBytes(bb, 7)', write='ChannelUtils.writeBytes(bb, $name)')
-actions_list = JType('List<OFAction>', size='ChannelUtils.calcListSize($name)') \
-        .op(read='ChannelUtils.readActionsList(bb, $length)', write='ChannelUtils.writeActionsList(bb, $name);')
-instructions_list = JType('List<OFInstruction>', size='ChannelUtils.calcListSize($name)') \
-        .op(read='ChannelUtils.readInstructionsList(bb, $length)', \
+        .op(read='ChannelUtils.readBytes(bb, 7)', write='bb.writeBytes($name)')
+actions_list = JType('List<OFAction>') \
+        .op(read='ChannelUtils.readList(bb, $length, OFActionVer$version.READER)', write='ChannelUtils.writeList(bb, $name);')
+instructions_list = JType('List<OFInstruction>') \
+        .op(read='ChannelUtils.readList(bb, $length, OFInstructionVer$version.READER)', \
             write='ChannelUtils.writeList(bb, $name)')
-buckets_list = JType('List<OFBucket>', size='ChannelUtils.calcListSize($name)') \
-        .op(read='ChannelUtils.readBucketList(bb, $length)', \
-            write='ChannelUtils.writeList(bb, $name)')
-port_desc_list = JType('List<OFPhysicalPort>', size='ChannelUtils.calcListSize($name)') \
-        .op(read='ChannelUtils.readPhysicalPortList(bb, $length)', \
-            write='ChannelUtils.writeList(bb, $name)')
+buckets_list = JType('List<OFBucket>', size='ChannelUtilsVer$version.calcListSize($name)') \
+        .op(read='ChannelUtils.readList(bb, $length, OFBucketVer$version.READER)', write='ChannelUtils.writeList(bb, $name)')
+port_desc_list = JType('List<OFPhysicalPort>', size='ChannelUtilsVer$version.calcListSize($name)') \
+        .op(read='ChannelUtils.readList(bb, $length, OFPhysicalPort.READER)', write='ChannelUtils.writeList(bb, $name)')
 port_desc = JType('OFPortDesc', size='$name.getLength()') \
-        .op(read='null; // TODO OFPortDescVer$version.READER.read(bb)', \
+        .op(read='OFPortDescVer$version.READER.readFrom(bb)', \
             write='$name.writeTo(bb)')
-packet_queue_list = JType('List<OFPacketQueue>', size='ChannelUtils.calcListSize($name)') \
-        .op(read='ChannelUtils.readPacketQueueList(bb, $length)', \
-            write='ChannelUtils.writeList(bb, $name)')
+packet_queue_list = JType('List<OFPacketQueue>', size='ChannelUtilsVer$version.calcListSize($name)') \
+        .op(read='ChannelUtils.readList(bb, $length, OFPacketQueueVer$version.READER)', write='ChannelUtils.writeList(bb, $name);')
 octets = JType('byte[]', size="$length") \
         .op(read='ChannelUtils.readBytes(bb, $length)', \
             write='bb.writeBytes($name)')
 of_match = JType('Match', size="$name.getLength()") \
-        .op(read='ChannelUtils.readOFMatch(bb)', \
-            write='ChannelUtils.writeOFMatch(bb, $name)')
+        .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \
+            write='$name.writeTo(bb)');
 flow_mod_cmd = JType('OFFlowModCommand', 'short', size="$name.getLength()") \
         .op(version=1, read="bb.readShort()", write="bb.writeShort($name)") \
         .op(version=ANY, read="bb.readByte()", write="bb.writeByte($name)")
@@ -176,6 +217,17 @@
 ipv6 = JType("IPv6") \
         .op(read="IPv6.read16Bytes(bb)", \
             write="$name.write16Bytes(bb)")
+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())");
+transport_port = JType("TransportPort")\
+        .op(read="TransportPort.read2Bytes(bb)", write="$name.write2Bytes(bb)")
+oxm = JType("OFOxm")\
+        .op(read="OFOxmVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
+meter_features = JType("OFMeterFeatures")\
+        .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
+
 
 default_mtype_to_jtype_convert_map = {
         'uint8_t' : u8,
@@ -208,17 +260,33 @@
         'of_table_name_t': table_name,
         'of_ipv4_t': ipv4,
         'of_ipv6_t': ipv6,
-        'of_wc_bmap_t': JType("Wildcards")
+        'of_wc_bmap_t': wildcards,
+        'of_oxm_t': oxm,
+        'of_meter_features_t': meter_features,
         }
 
 ## This is where we drop in special case handling for certain types
 exceptions = {
-        'OFPacketIn': {
-            'data' : octets
+        'of_packet_in': {
+            'data' : octets,
+            'reason': packetin_reason
+            },
+        'of_oxm_tcp_src' : {
+            'value' : transport_port
             },
 }
 
 
+enum_wire_types = {
+        "uint8_t": JType("byte").op(read="bb.readByte()", write="bb.writeByte($name)"),
+        "uint16_t": JType("short").op(read="bb.readShort()", write="bb.writeShort($name)"),
+        "uint32_t": JType("int").op(read="bb.readInt()", write="bb.writeInt($name)"),
+        "uint64_t": JType("long").op(read="bb.readLong()", write="bb.writeLong($name)"),
+}
+
+def convert_enum_wire_type_to_jtype(wire_type):
+    return enum_wire_types[wire_type]
+
 def make_standard_list_jtype(c_type):
     m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type)
     if not m:
@@ -226,20 +294,21 @@
     base_name = m.group(1)
     java_base_name = name_c_to_caps_camel(base_name)
     return JType("List<OF%s>" % java_base_name) \
-        .op(read='ChannelUtils.read%sList(bb)' % java_base_name, \
-            write='ChannelUtils.write%sList(bb, $name)' % java_base_name)
+        .op(read= 'ChannelUtils.readList(bb, $length, OF%sVer$version.READER)' % java_base_name, \
+            write='ChannelUtils.writeList(bb, $name)')
 
 def convert_to_jtype(obj_name, field_name, c_type):
     """ Convert from a C type ("uint_32") to a java type ("U32")
     and return a JType object with the size, internal type, and marshalling functions"""
     if obj_name in exceptions and field_name in exceptions[obj_name]:
         return exceptions[obj_name][field_name]
-    elif field_name == "type" and c_type == "uint8_t":
+    elif ( obj_name == "of_header" or loxi_utils.class_is_message(obj_name)) and field_name == "type" and c_type == "uint8_t":
         return JType("OFType", 'byte', size=1) \
             .op(read='bb.readByte()', write='bb.writeByte($name)')
     elif field_name == "type" and re.match(r'of_action.*', obj_name):
         return JType("OFActionType", 'short', size=2) \
-            .op(read='bb.readShort()', write='bb.writeShort($name)')
+            .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
+            .op(read="OFActionTypeSerializerVer$version.readFrom(bb)", write="OFActionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
     elif field_name == "version" and c_type == "uint8_t":
         return JType("OFVersion", 'byte', size=1) \
             .op(read='bb.readByte()', write='bb.writeByte($name)')
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFFlowMod.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFFlowMod.java
deleted file mode 100644
index 06d8049..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFFlowMod.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.openflow.protocol;
-
-public interface OFFlowMod extends OFMessage {
-
-    public interface Builder extends OFMessage.Builder {
-
-    }
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessage.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessage.java
deleted file mode 100644
index c1e4456..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessage.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.openflow.protocol;
-
-public interface OFMessage {
-    int getXid();
-
-    OFType getType();
-
-    OFVersion getVersion();
-
-    interface Builder {
-
-    }
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageWriter.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageWriter.java
index 84e5507..bcca1fd 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageWriter.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageWriter.java
@@ -4,5 +4,5 @@
 import org.openflow.exceptions.OFParseError;
 
 public interface OFMessageWriter<T> {
-    public int write(ChannelBuffer bb, T message) throws OFParseError;
+    public void write(ChannelBuffer bb, T message) throws OFParseError;
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFObject.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFObject.java
index 4a7557f..aae6178 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFObject.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFObject.java
@@ -1,19 +1,8 @@
 package org.openflow.protocol;
 
-import org.jboss.netty.buffer.ChannelBuffer;
 
 /**
- *  Base interface of all OpenFlow objects (e.g., messages, actions, stats, etc.)
- *
- *  All objects have a length and can be read and written from a buffer.
- *  When writing, the length field is dynamically updated, so it need not be
- *  managed manually.  However, you can override the auto calculated length with
- *  overrideLength() call, if, for example, you want to intentionally create
- *  malformed packets, for example, for negative testing.
+ * Base interface of all OpenFlow objects (e.g., messages, actions, stats, etc.)
  */
-
-
-public interface OFObject {
-    void writeTo(ChannelBuffer bb);
-    int getLength();
+public interface OFObject extends Writeable {
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/Wildcards.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/Wildcards.java
index 25b2c21..8c03b93 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/Wildcards.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/Wildcards.java
@@ -1,5 +1,656 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
 package org.openflow.protocol;
 
-public class Wildcards {
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
 
-}
+import com.google.common.base.Joiner;
+
+/**
+ * a more user friendly representation of the wildcards bits in an OpenFlow
+ * match. The Wildcards object is
+ * <ul>
+ * <li>immutable (i.e., threadsafe)</li>
+ * <li>instance managed (don't instantiate it yourself), instead call "of"</li>
+ * <ul>
+ * <p>
+ * You can construct a Wildcard object from either its integer representation
+ * </p>
+ * <code>
+ *    Wildcard.of(0x3820e0);
+ *  </code>
+ * <p>
+ * Or start with either an empty or full wildcard, and select/unselect foo.
+ * </p>
+ * <code>
+ *  Wildcard w = Wildcards.NONE
+ *                .set(Flag.DL_SRC, Flag. DL_DST, Flag.DL_VLAN_PCP)
+ *                .setNwDstMask(8)
+ *                .setNwSrcMask(8);
+ *  </code>
+ * <p>
+ * <b>Remember:</b> Wildcards objects are immutable. set... operations have
+ * <b>NO EFFECT</b> on the current wildcard object. You HAVE to use the returned
+ * changed object.
+ * </p>
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class Wildcards {
+    public class OFWildcardFlags {
+        final public static int OFPFW_ALL = ((1 << 22) - 1);
+
+        final public static int OFPFW_IN_PORT = 1 << 0; /* Switch input port. */
+        final public static int OFPFW_DL_VLAN = 1 << 1; /* VLAN id. */
+        final public static int OFPFW_DL_SRC = 1 << 2; /* Ethernet source address. */
+        final public static int OFPFW_DL_DST = 1 << 3; /*
+                                                        * Ethernet destination
+                                                        * address.
+                                                        */
+        final public static int OFPFW_DL_TYPE = 1 << 4; /* Ethernet frame type. */
+        final public static int OFPFW_NW_PROTO = 1 << 5; /* IP protocol. */
+        final public static int OFPFW_TP_SRC = 1 << 6; /* TCP/UDP source port. */
+        final public static int OFPFW_TP_DST = 1 << 7; /* TCP/UDP destination port. */
+
+        /*
+         * IP source address wildcard bit count. 0 is exact match, 1 ignores the
+         * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
+         * the entire field. This is the *opposite* of the usual convention where
+         * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded.
+         */
+        final public static int OFPFW_NW_SRC_SHIFT = 8;
+        final public static int OFPFW_NW_SRC_BITS = 6;
+        final public static int OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT;
+        final public static int OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT;
+
+        /* IP destination address wildcard bit count. Same format as source. */
+        final public static int OFPFW_NW_DST_SHIFT = 14;
+        final public static int OFPFW_NW_DST_BITS = 6;
+        final public static int OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT;
+        final public static int OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT;
+
+        final public static int OFPFW_DL_VLAN_PCP = 1 << 20; /* VLAN priority. */
+        final public static int OFPFW_NW_TOS = 1 << 21; /*
+                                                         * IP ToS (DSCP field, 6
+                                                         * bits).
+                                                         */
+
+        final public static int OFPFW_ALL_SANITIZED = (((1 << 22) - 1)
+                                                       & ~OFPFW_NW_SRC_MASK & ~OFPFW_NW_DST_MASK)
+                                                      | OFPFW_NW_SRC_ALL
+                                                      | OFPFW_NW_DST_ALL;
+
+
+    }
+
+    public final static Wildcards FULL = new Wildcards(OFWildcardFlags.OFPFW_ALL_SANITIZED);
+    private static final int FULL_INT = FULL.getInt();
+
+    public final static Wildcards EXACT = new Wildcards(0);
+
+    // floodlight common case: matches on inport + l2
+    public final static int INT_INPORT_L2_MATCH = 0x3820e0;
+    public final static Wildcards INPORT_L2_MATCH = new Wildcards(
+            INT_INPORT_L2_MATCH);
+
+    /**
+     * enum type for the binary flags that can be set in the wildcards field of
+     * an OFWildcardFlags. Replaces the unwieldy c-ish int constants in OFWildcardFlags.
+     */
+    public static enum Flag {
+        IN_PORT(OFWildcardFlags.OFPFW_IN_PORT),  /* Switch input port. */
+        DL_VLAN(OFWildcardFlags.OFPFW_DL_VLAN), /* VLAN id. */
+        DL_SRC(OFWildcardFlags.OFPFW_DL_SRC), /* Ethernet source address. */
+        DL_DST(OFWildcardFlags.OFPFW_DL_DST), /* Ethernet destination addr */
+        DL_TYPE(OFWildcardFlags.OFPFW_DL_TYPE), /* Ethernet frame type. */
+        NW_PROTO(OFWildcardFlags.OFPFW_NW_PROTO), /* IP protocol. */
+        TP_SRC(OFWildcardFlags.OFPFW_TP_SRC), /* TCP/UDP source port. */
+        TP_DST(OFWildcardFlags.OFPFW_TP_DST), /* TCP/UDP destination port. */
+        DL_VLAN_PCP(OFWildcardFlags.OFPFW_DL_VLAN_PCP), /* VLAN priority. */
+        NW_SRC(-1) { /*
+                      * virtual NW_SRC flag => translates to the strange 6 bits
+                      * in the header
+                      */
+            @Override
+            boolean isBolean() {
+                return false;
+            }
+
+            @Override
+            int getInt(int flags) {
+                return ((flags & OFWildcardFlags.OFPFW_NW_SRC_MASK) >> OFWildcardFlags.OFPFW_NW_SRC_SHIFT);
+            }
+
+            @Override
+            int setInt(int flags, int srcMask) {
+                return (flags & ~OFWildcardFlags.OFPFW_NW_SRC_MASK) | (srcMask << OFWildcardFlags.OFPFW_NW_SRC_SHIFT);
+            }
+
+            @Override
+            int wildcard(int flags) {
+                return flags & ~OFWildcardFlags.OFPFW_NW_SRC_MASK;
+            }
+
+            @Override
+            int matchOn(int flags) {
+                return flags | OFWildcardFlags.OFPFW_NW_SRC_ALL;
+            }
+
+            @Override
+            boolean isPartiallyOn(int flags) {
+                int intValue = getInt(flags);
+                return intValue > 0 && intValue < 32;
+            }
+
+            @Override
+            boolean isFullyOn(int flags) {
+                return getInt(flags) >= 32;
+            }
+
+        },
+        NW_DST(-1) { /*
+                      * virtual NW_SRC flag => translates to the strange 6 bits
+                      * in the header
+                      */
+            @Override
+            boolean isBolean() {
+                return false;
+            }
+
+            @Override
+            int getInt(int flags) {
+                return ((flags & OFWildcardFlags.OFPFW_NW_DST_MASK) >> OFWildcardFlags.OFPFW_NW_DST_SHIFT);
+            }
+
+            @Override
+            int setInt(int flags, int srcMask) {
+                return (flags & ~OFWildcardFlags.OFPFW_NW_DST_MASK) | (srcMask << OFWildcardFlags.OFPFW_NW_DST_SHIFT);
+            }
+
+            @Override
+            int wildcard(int flags) {
+                return flags & ~OFWildcardFlags.OFPFW_NW_DST_MASK;
+            }
+
+            @Override
+            int matchOn(int flags) {
+                return flags | OFWildcardFlags.OFPFW_NW_DST_ALL;
+            }
+
+            @Override
+            boolean isFullyOn(int flags) {
+                return getInt(flags) >= 32;
+            }
+        },
+        NW_TOS(OFWildcardFlags.OFPFW_NW_TOS); /* IP ToS (DSCP field, 6 bits). */
+
+        final int bitPosition;
+
+        Flag(int bitPosition) {
+            this.bitPosition = bitPosition;
+        }
+
+        /**
+         * @return a modified OF-1.0 flags field with this flag cleared (match
+         *         on this field)
+         */
+        int matchOn(int flags) {
+            return flags & ~this.bitPosition;
+        }
+
+        /**
+         * @return a modified OF-1.0 flags field with this flag set (wildcard
+         *         this field)
+         */
+        int wildcard(int flags) {
+            return flags | this.bitPosition;
+        }
+
+        /**
+         * @return true iff this is a true boolean flag that can either be off
+         *         or on.True in OF-1.0 for all fields except NW_SRC and NW_DST
+         */
+        boolean isBolean() {
+            return false;
+        }
+
+        /**
+         * @return true iff this wildcard field is currently 'partially on'.
+         *         Always false for true Boolean Flags. Can be true in OF-1.0
+         *         for NW_SRC, NW_DST.
+         */
+        boolean isPartiallyOn(int flags) {
+            return false;
+        }
+
+        /**
+         * @return true iff this wildcard field currently fully on (fully
+         *         wildcarded). Equivalent to the boolean flag being set in the
+         *         bitmask for bit flags, and to the wildcarded bit length set
+         *         to >=32 for NW_SRC and NW_DST
+         * @param flags
+         * @return
+         */
+        boolean isFullyOn(int flags) {
+            return (flags & this.bitPosition) != 0;
+        }
+
+        /**
+         * set the integer representation of this flag. only for NW_SRC and
+         * NW_DST
+         */
+        int setInt(int flags, int srcMask) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * set the integer representation of this flag. only for NW_SRC and
+         * NW_DST
+         */
+        int getInt(int flags) {
+            throw new UnsupportedOperationException();
+        }
+
+
+    }
+
+    private final int flags;
+
+    /** private constructor. use Wildcard.of() instead */
+    private Wildcards(int flags) {
+        this.flags = flags;
+    }
+
+    /**
+     * return a wildcard object matching the given int flags. May reuse / cache
+     * frequently used wildcard instances. Don't rely on it though (use equals
+     * not ==).
+     *
+     * @param flags
+     * @return
+     */
+    public static Wildcards of(int paramFlags) {
+        int flags = paramFlags; //sanitizeInt(paramFlags);
+        switch(flags) {
+            case 0x0000:
+                return EXACT;
+            case OFWildcardFlags.OFPFW_ALL_SANITIZED:
+                return FULL;
+            case INT_INPORT_L2_MATCH:
+                return INPORT_L2_MATCH;
+            default:
+                return new Wildcards(flags);
+        }
+    }
+
+    /** convience method return a wildcard for exactly one set flag */
+    public static Wildcards of(Wildcards.Flag setFlag) {
+        return Wildcards.of(setFlag.wildcard(0));
+    }
+
+    /** convience method return a wildcard for exactly two set flags */
+    public static Wildcards of(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
+        return Wildcards.of(setFlag.wildcard(setFlag2.wildcard(0)));
+    }
+
+    /** convience method return a wildcard for an arbitrary number of set flags */
+    public static Wildcards of(Wildcards.Flag... setFlags) {
+        int flags = 0;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.wildcard(0);
+        return Wildcards.of(flags);
+    }
+
+    /** convience method return a wildcards for ofmatches that match on one flag */
+    public static Wildcards ofMatches(Wildcards.Flag setFlag) {
+        return Wildcards.of(setFlag.matchOn(FULL_INT));
+    }
+
+    /**
+     * convience method return a wildcard for for an ofmatch that match on two
+     * flags
+     */
+    public static Wildcards ofMatches(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
+        return Wildcards.of(setFlag.matchOn(setFlag2.matchOn(FULL_INT)));
+    }
+
+    /**
+     * convience method return a wildcard for an ofmatch that amtch on an
+     * arbitrary number of set flags
+     */
+    public static Wildcards ofMatches(Wildcards.Flag... setFlags) {
+        int flags = FULL_INT;
+        for (Wildcards.Flag flag : setFlags)
+           flags = flag.matchOn(flags);
+        return Wildcards.of(flags);
+    }
+
+    public static Wildcards ofMatches(Set<Wildcards.Flag> wSet) {
+        int flags = FULL_INT;
+        for (Wildcards.Flag flag : wSet)
+           flags = flag.matchOn(flags);
+        return Wildcards.of(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags set
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag flag) {
+        int flags = flag.wildcard(this.flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags set
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag flag, Wildcards.Flag flag2) {
+        int flags = flag.wildcard(flag2.wildcard(this.flags));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags wildcarded
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag... setFlags) {
+        int flags = this.flags;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.wildcard(flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flag
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag flag) {
+        int flags = flag.matchOn(this.flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flags
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag flag, Wildcards.Flag flag2) {
+        int flags = flag.matchOn(flag2.matchOn(this.flags));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flags
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag... setFlags) {
+        int flags = this.flags;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.matchOn(flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return the nw src mask in normal CIDR style, e.g., 8 means x.x.x.x/8
+     * means 8 bits wildcarded
+     */
+    public int getNwSrcMask() {
+        return Math.max(0, 32 - Flag.NW_SRC.getInt(flags));
+    }
+
+    /**
+     * return the nw dst mask in normal CIDR style, e.g., 8 means x.x.x.x/8
+     * means 8 bits wildcarded
+     */
+    public int getNwDstMask() {
+        return Math.max(0, 32 - Flag.NW_DST.getInt(flags));
+    }
+
+    /**
+     * return a Wildcard object that has the given nwSrcCidrMask set.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     *
+     * @param srcCidrMask
+     *            source mask to set in <b>normal CIDR notation</b>, i.e., 8
+     *            means x.x.x.x/8
+     * @return a modified object
+     */
+    public Wildcards withNwSrcMask(int srcCidrMask) {
+        int flags = Flag.NW_SRC.setInt(this.flags, Math.max(0, 32 - srcCidrMask));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcard object that has the given nwDstCidrMask set.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     *
+     * @param dstCidrMask
+     *            dest mask to set in <b>normal CIDR notation</b>, i.e., 8 means
+     *            x.x.x.x/8
+     * @return a modified object
+     */
+    public Wildcards withNwDstMask(int dstCidrMask) {
+        int flags = Flag.NW_DST.setInt(this.flags, Math.max(0, 32 - dstCidrMask));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcard object that is inverted to this wildcard object.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     * @return a modified object
+     */
+    public Wildcards inverted() {
+        return Wildcards.of(flags ^ OFWildcardFlags.OFPFW_ALL_SANITIZED);
+    }
+
+    public boolean isWildcarded(Flag flag) {
+        return flag.isFullyOn(flags);
+    }
+
+    /**
+     * return all wildcard flags that are fully wildcarded as an EnumSet. Do not
+     * modify. Note: some flags (like NW_SRC and NW_DST) that are partially
+     * wildcarded are not returned in this set.
+     *
+     * @return the EnumSet of wildcards
+     */
+    public EnumSet<Wildcards.Flag> getWildcardedFlags() {
+        EnumSet<Wildcards.Flag> res = EnumSet.noneOf(Wildcards.Flag.class);
+        for (Wildcards.Flag flag : Flag.values()) {
+            if (flag.isFullyOn(flags)) {
+                res.add(flag);
+            }
+        }
+        return res;
+    }
+
+    /** return the OpenFlow 'wire' integer representation of these wildcards */
+    public int getInt() {
+        return flags;
+    }
+
+    /**
+     * return the OpenFlow 'wire' integer representation of these wildcards.
+     * Sanitize nw_src and nw_dst to be max. 32 (values > 32 are technically
+     * possible, but don't make semantic sense)
+     */
+    public static int sanitizeInt(int flags) {
+        if (((flags & OFWildcardFlags.OFPFW_NW_SRC_MASK) >> OFWildcardFlags.OFPFW_NW_SRC_SHIFT) > 32) {
+            flags = (flags & ~OFWildcardFlags.OFPFW_NW_SRC_MASK) | OFWildcardFlags.OFPFW_NW_SRC_ALL;
+        }
+        if (((flags & OFWildcardFlags.OFPFW_NW_DST_MASK) >> OFWildcardFlags.OFPFW_NW_DST_SHIFT) > 32) {
+            flags = (flags & ~OFWildcardFlags.OFPFW_NW_DST_MASK) | OFWildcardFlags.OFPFW_NW_DST_ALL;
+        }
+        return flags;
+    }
+
+    /**
+     * is this a wildcard set that has all flags set + and full (/0) nw_src and
+     * nw_dst wildcarding ?
+     */
+    public boolean isFull() {
+        return flags == OFWildcardFlags.OFPFW_ALL || flags == OFWildcardFlags.OFPFW_ALL_SANITIZED;
+    }
+
+    /** is this a wildcard of an exact match */
+    public boolean isExact() {
+        return flags == 0;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + flags;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Wildcards other = (Wildcards) obj;
+        if (flags != other.flags)
+            return false;
+        return true;
+    }
+
+    private final static Joiner pipeJoiner = Joiner.on("|");
+
+    @Override
+    public String toString() {
+        List<String> res = new ArrayList<String>();
+        for (Wildcards.Flag flag : Flag.values()) {
+            if (flag.isFullyOn(flags)) {
+                res.add(flag.name().toLowerCase());
+            }
+        }
+
+        if (Flag.NW_SRC.isPartiallyOn(flags)) {
+            res.add("nw_src(/" + getNwSrcMask() + ")");
+        }
+
+        if (Flag.NW_DST.isPartiallyOn(flags)) {
+            res.add("nw_dst(/" + getNwDstMask() + ")");
+        }
+
+        return pipeJoiner.join(res);
+    }
+
+    private final static Joiner commaJoiner = Joiner.on(", ");
+
+    /** a Java expression that constructs 'this' wildcards set */
+    public String toJava() {
+        if(isFull()) {
+            return "Wildcards.FULL";
+        } else  if (isExact()){
+            return "Wildcards.EXACT";
+        }
+
+        StringBuilder b = new StringBuilder();
+
+        EnumSet<Flag> myFlags = getWildcardedFlags();
+        if (myFlags.size() < 3) {
+            // default to start with empty
+            b.append("Wildcards.of("
+                     + commaJoiner.join(prefix("Flag.", myFlags.iterator())) + ")");
+        } else {
+            // too many - start with full
+
+            EnumSet<Flag> invFlags = inverted().getWildcardedFlags();
+            b.append("Wildcards.ofMatches("
+                     + commaJoiner.join(prefix("Flag.", invFlags.iterator())) + ")");
+        }
+        if (Flag.NW_SRC.isPartiallyOn(flags)) {
+            b.append(".setNwSrcMask(" + getNwSrcMask() + ")");
+        }
+        if (Flag.NW_DST.isPartiallyOn(flags)) {
+            b.append(".setNwDstMask(" + getNwDstMask() + ")");
+        }
+        return b.toString();
+    }
+
+    private Iterator<String> prefix(final String prefix, final Iterator<?> i) {
+        return new Iterator<String>() {
+
+            @Override
+            public boolean hasNext() {
+                return i.hasNext();
+            }
+
+            @Override
+            public String next() {
+                Object next = i.next();
+                return next == null ? null : prefix + next.toString();
+            }
+
+            @Override
+            public void remove() {
+                i.remove();
+            }
+        };
+    }
+
+
+}
\ No newline at end of file
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/Writeable.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/Writeable.java
new file mode 100644
index 0000000..0ff7df6
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/Writeable.java
@@ -0,0 +1,7 @@
+package org.openflow.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+public interface Writeable {
+    void writeTo(ChannelBuffer bb);
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java
index 99b7de4..d35f709 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java
@@ -5,23 +5,23 @@
 import org.openflow.types.OFValueType;
 
 public interface Match extends OFObject {
-    
+
     /*
      * Preconditions
-     * On preconditions (from the OF1.1 spec, page 28, the OF1.0 spec failed to explicitly 
+     * On preconditions (from the OF1.1 spec, page 28, the OF1.0 spec failed to explicitly
      * specify this, but it is the behavior of Of1.0 switches):
-     * Protocol-specific fields within ofp_match will be ignored within a single table when 
-     * the corresponding protocol is not specified in the match. The MPLS match fields will 
-     * be ignored unless the Ethertype is specified as MPLS. Likewise, the IP header and 
-     * transport header fields will be ignored unless the Ethertype is specified as either 
-     * IPv4 or ARP. The tp_src and tp_dst fields will be ignored unless the network protocol 
-     * specified is as TCP, UDP or SCTP. Fields that are ignored donÕt need to be wildcarded 
+     * Protocol-specific fields within ofp_match will be ignored within a single table when
+     * the corresponding protocol is not specified in the match. The MPLS match fields will
+     * be ignored unless the Ethertype is specified as MPLS. Likewise, the IP header and
+     * transport header fields will be ignored unless the Ethertype is specified as either
+     * IPv4 or ARP. The tp_src and tp_dst fields will be ignored unless the network protocol
+     * specified is as TCP, UDP or SCTP. Fields that are ignored don�t need to be wildcarded
      * and should be set to 0.
      */
-    
+
     /**
      * Returns the value for the given field from this match.
-     * 
+     *
      * @param field Match field to retrieve
      * @return Value of match field
      */
@@ -30,7 +30,7 @@
     /**
      * Returns the masked value for the given field from this match.
      * Precondition: field is partially wildcarded.
-     * 
+     *
      * @param field Match field to retrieve
      * @return Masked value of match field or null if no mask
      */
@@ -38,44 +38,44 @@
 
     /**
      * Returns true if this match object supports the given match field.
-     * 
+     *
      * @param field Match field
-     * @return 
+     * @return
      */
     public boolean supports(MatchField<?> field);
 
     /**
-     * true iff field supports a bitmask mask that wildcards part of the field 
+     * true iff field supports a bitmask mask that wildcards part of the field
      * (note: not all possible values of this bitmask have to be acceptable)
-     * 
+     *
      * @param field Match field
-     * @return 
+     * @return
      */
     public boolean supportsMasked(MatchField<?> field);
 
     /**
-     * True iff this field is currently fully specified in the match, i.e., the 
+     * True iff this field is currently fully specified in the match, i.e., the
      * match will only select packets that match the exact value of getField(field).
-     * 
+     *
      * @param field Match field
-     * @return 
+     * @return
      */
     public boolean isExact(MatchField<?> field);
 
     /**
-     * True if this field is currently logically unspecified in the match, i.e, the 
-     * value returned by getValue(f) has no impact on whether a packet will be selected 
+     * True if this field is currently logically unspecified in the match, i.e, the
+     * value returned by getValue(f) has no impact on whether a packet will be selected
      * by the match or not.
-     * 
+     *
      * @param field
      * @return
      */
     public boolean isFullyWildcarded(MatchField<?> field);
 
     /**
-     * True if this field is currently partially specified in the match, i.e, the 
+     * True if this field is currently partially specified in the match, i.e, the
      * match will select packets that match (p.value & getMask(field)) == getValue(field).
-     * 
+     *
      * @param field
      * @return
      */
@@ -85,5 +85,8 @@
      * Returns a builder to build new instances of this type of match object.
      * @return Match builder
      */
-    public MatchBuilder getBuilder();
+    public MatchBuilder createBuilder();
+
+    interface Builder extends MatchBuilder {
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilder.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilder.java
index 4372e30..be7b8b0 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilder.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilder.java
@@ -3,14 +3,77 @@
 import org.openflow.types.Masked;
 import org.openflow.types.OFValueType;
 
-public interface MatchBuilder extends Match {
-    public <F extends OFValueType<F>> MatchBuilder setExact(MatchField<F> field, F value);
-    
-    public <F extends OFValueType<F>> MatchBuilder setMasked(MatchField<F> field, F value, F mask);    
+public interface MatchBuilder {
+    /**
+     * Returns the value for the given field from this match.
+     *
+     * @param field Match field to retrieve
+     * @return Value of match field
+     */
+    public <F extends OFValueType<F>> F get(MatchField<F> field) throws UnsupportedOperationException;
 
-    public <F extends OFValueType<F>> MatchBuilder setMasked(MatchField<F> field, Masked<F> valueWithMask);    
+    /**
+     * Returns the masked value for the given field from this match.
+     * Precondition: field is partially wildcarded.
+     *
+     * @param field Match field to retrieve
+     * @return Masked value of match field or null if no mask
+     */
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field) throws UnsupportedOperationException;
+
+    /**
+     * Returns true if this match object supports the given match field.
+     *
+     * @param field Match field
+     * @return
+     */
+    public boolean supports(MatchField<?> field);
+
+    /**
+     * true iff field supports a bitmask mask that wildcards part of the field
+     * (note: not all possible values of this bitmask have to be acceptable)
+     *
+     * @param field Match field
+     * @return
+     */
+    public boolean supportsMasked(MatchField<?> field);
+
+    /**
+     * True iff this field is currently fully specified in the match, i.e., the
+     * match will only select packets that match the exact value of getField(field).
+     *
+     * @param field Match field
+     * @return
+     */
+    public boolean isExact(MatchField<?> field);
+
+    /**
+     * True if this field is currently logically unspecified in the match, i.e, the
+     * value returned by getValue(f) has no impact on whether a packet will be selected
+     * by the match or not.
+     *
+     * @param field
+     * @return
+     */
+    public boolean isFullyWildcarded(MatchField<?> field);
+
+    /**
+     * True if this field is currently partially specified in the match, i.e, the
+     * match will select packets that match (p.value & getMask(field)) == getValue(field).
+     *
+     * @param field
+     * @return
+     */
+    public boolean isPartiallyMasked(MatchField<?> field);
+
+
+    public <F extends OFValueType<F>> MatchBuilder setExact(MatchField<F> field, F value);
+
+    public <F extends OFValueType<F>> MatchBuilder setMasked(MatchField<F> field, F value, F mask);
+
+    public <F extends OFValueType<F>> MatchBuilder setMasked(MatchField<F> field, Masked<F> valueWithMask);
 
     public <F extends OFValueType<F>> MatchBuilder wildcard(MatchField<F> field);
-    
+
     public Match getMatch();
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilderVer10.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilderVer10.java
deleted file mode 100644
index 62c77e5..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilderVer10.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.openflow.protocol.match;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.types.EthType;
-import org.openflow.types.IPv4;
-import org.openflow.types.IpDscp;
-import org.openflow.types.IpProtocol;
-import org.openflow.types.MacAddress;
-import org.openflow.types.Masked;
-import org.openflow.types.OFPort;
-import org.openflow.types.OFValueType;
-import org.openflow.types.U16;
-import org.openflow.types.VlanPcp;
-import org.openflow.types.VlanVid;
-
-public class MatchBuilderVer10 implements MatchBuilder {
-
-    interface BuilderParamHandler<T> {
-        public T get(MatchBuilderVer10 builder);
-
-        public void set(MatchBuilderVer10 builder, T value);
-    }
-
-    // public static Map<MatchField<?,?>, BuilderParamHandler<?>>
-    // handlerMap = new HashMap();
-
-    protected int wildcards;
-    protected OFPort inputPort;
-    protected MacAddress dataLayerSource;
-    protected MacAddress dataLayerDestination;
-    protected VlanVid dataLayerVirtualLan;
-    protected VlanPcp dataLayerVirtualLanPriorityCodePoint;
-    protected EthType dataLayerType;
-    protected IpDscp ipDscp;
-    protected IpProtocol networkProtocol;
-    protected IPv4 networkSource;
-    protected IPv4 networkDestination;
-    protected U16 transportSource;
-    protected U16 transportDestination;
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <F extends OFValueType<F>> F get(final MatchField<F> match) {
-        switch (match.id) {
-            case IN_PORT:
-                return (F) inputPort;
-            case ETH_SRC:
-                return (F) dataLayerSource;
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public <F extends OFValueType<F>> Masked<F>
-            getMasked(MatchField<F> field)
-                                        throws UnsupportedOperationException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public <F extends OFValueType<F>> MatchBuilder setExact(final MatchField<F> match, final F value) {
-        switch (match.id) {
-            case IN_PORT:
-                inputPort = (OFPort) value;
-                break;
-            case ETH_SRC:
-                dataLayerSource = (MacAddress) value;
-                break;
-            default:
-                break;
-        }
-        return this;
-    }
-    
-    @Override
-    public <F extends OFValueType<F>> MatchBuilder
-            setMasked(MatchField<F> field, Masked<F> valueWithMask) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public <F extends OFValueType<F>> MatchBuilder
-            setMasked(MatchField<F> field, F value, F mask) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public <F extends OFValueType<F>> MatchBuilder wildcard(final MatchField<F> match) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public OFPort getInputPort() {
-        return inputPort;
-    }
-
-    public void setInputPort(final OFPort inputPort) {
-        this.inputPort = inputPort;
-    }
-
-    public MacAddress getDataLayerSource() {
-        return dataLayerSource;
-    }
-
-    public void setDataLayerSource(final MacAddress dataLayerSource) {
-        this.dataLayerSource = dataLayerSource;
-    }
-
-    @Override
-    public boolean supports(final MatchField<?> field) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public boolean supportsMasked(final MatchField<?> field) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public boolean isExact(final MatchField<?> field) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public boolean isFullyWildcarded(final MatchField<?> field) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public boolean isPartiallyMasked(final MatchField<?> field) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public MatchBuilder getBuilder() {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public int getLength() {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
-    @Override
-    public void writeTo(final ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-
-    }
-/*
-    @Override
-    public <M> void setMasked(final MatchField<?, M> match, final M value) {
-        // TODO Auto-generated method stub
-
-    }
-*/
-    @Override
-    public Match getMatch() {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/ver10/ChannelUtilsVer10.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/ver10/ChannelUtilsVer10.java
new file mode 100644
index 0000000..50acc7f
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/ver10/ChannelUtilsVer10.java
@@ -0,0 +1,30 @@
+package org.openflow.protocol.ver10;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFBsnVportQInQ;
+import org.openflow.protocol.match.Match;
+
+/**
+ * Collection of helper functions for reading and writing into ChannelBuffers
+ *
+ * @author capveg
+ */
+
+public class ChannelUtilsVer10 {
+    public static Match readOFMatch(final ChannelBuffer bb) throws OFParseError {
+        return OFMatchV1Ver10.READER.readFrom(bb);
+    }
+
+    // TODO these need to be figured out / removed
+    public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public static void writeOFBsnVportQInQ(ChannelBuffer bb,
+            OFBsnVportQInQ vport) {
+        throw new UnsupportedOperationException("not implemented");
+
+    }
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/ver11/ChannelUtilsVer11.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/ver11/ChannelUtilsVer11.java
new file mode 100644
index 0000000..1322acd
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/ver11/ChannelUtilsVer11.java
@@ -0,0 +1,39 @@
+package org.openflow.protocol.ver11;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFBsnVportQInQ;
+import org.openflow.protocol.OFMatchBmap;
+import org.openflow.protocol.match.Match;
+
+
+/**
+ * Collection of helper functions for reading and writing into ChannelBuffers
+ *
+ * @author capveg
+ */
+
+public class ChannelUtilsVer11 {
+    public static Match readOFMatch(final ChannelBuffer bb) throws OFParseError {
+        return OFMatchV2Ver11.READER.readFrom(bb);
+    }
+
+    // TODO these need to be figured out / removed
+    public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public static void writeOFBsnVportQInQ(ChannelBuffer bb,
+            OFBsnVportQInQ vport) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+
+    public static OFMatchBmap readOFMatchBmap(ChannelBuffer bb) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public static void writeOFMatchBmap(ChannelBuffer bb, OFMatchBmap match) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/ver12/ChannelUtilsVer12.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/ver12/ChannelUtilsVer12.java
new file mode 100644
index 0000000..c194fbc
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/ver12/ChannelUtilsVer12.java
@@ -0,0 +1,40 @@
+package org.openflow.protocol.ver12;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFBsnVportQInQ;
+import org.openflow.protocol.OFMatchBmap;
+import org.openflow.protocol.match.Match;
+
+
+/**
+ * Collection of helper functions for reading and writing into ChannelBuffers
+ *
+ * @author capveg
+ */
+
+public class ChannelUtilsVer12 {
+    public static Match readOFMatch(final ChannelBuffer bb) throws OFParseError {
+        return OFMatchV3Ver12.READER.readFrom(bb);
+    }
+
+    // TODO these need to be figured out / removed
+
+    public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public static void writeOFBsnVportQInQ(ChannelBuffer bb,
+            OFBsnVportQInQ vport) {
+        throw new UnsupportedOperationException("not implemented");
+
+    }
+
+    public static OFMatchBmap readOFMatchBmap(ChannelBuffer bb) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public static void writeOFMatchBmap(ChannelBuffer bb, OFMatchBmap match) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/ver13/ChannelUtilsVer13.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/ver13/ChannelUtilsVer13.java
new file mode 100644
index 0000000..bcfbdbc
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/ver13/ChannelUtilsVer13.java
@@ -0,0 +1,38 @@
+package org.openflow.protocol.ver13;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFBsnVportQInQ;
+import org.openflow.protocol.OFMatchBmap;
+import org.openflow.protocol.match.Match;
+
+/**
+ * Collection of helper functions for reading and writing into ChannelBuffers
+ *
+ * @author capveg
+ */
+
+public class ChannelUtilsVer13 {
+    public static Match readOFMatch(final ChannelBuffer bb) throws OFParseError {
+        return OFMatchV3Ver13.READER.readFrom(bb);
+    }
+
+    // TODO these need to be figured out / removed
+
+    public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public static void writeOFBsnVportQInQ(ChannelBuffer bb,
+            OFBsnVportQInQ vport) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public static OFMatchBmap readOFMatchBmap(ChannelBuffer bb) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public static void writeOFMatchBmap(ChannelBuffer bb, OFMatchBmap match) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/OFMeterBand.java b/java_gen/pre-written/src/main/java/org/openflow/types/OFMeterBand.java
deleted file mode 100644
index d15812b..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/types/OFMeterBand.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.openflow.types;
-
-public interface OFMeterBand {
-
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/OFPhysicalPort.java b/java_gen/pre-written/src/main/java/org/openflow/types/OFPhysicalPort.java
index 7755a4a..6eb07b1 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/OFPhysicalPort.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/OFPhysicalPort.java
@@ -2,6 +2,8 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFMessageReader;
+import org.openflow.protocol.Writeable;
 
 /**
  * A wrapper around the OpenFlow physical port description. The interfaces to
@@ -10,16 +12,16 @@
  * @author capveg
  */
 
-public class OFPhysicalPort implements OFValueType<OFPhysicalPort> {
+public class OFPhysicalPort implements OFValueType<OFPhysicalPort>, Writeable {
 
     static final int LENGTH = 4;
-    
+
     private final int port;
-    
+
     private OFPhysicalPort(int port) {
         this.port = port;
     }
-    
+
     public static OFPhysicalPort of(int port) {
         return new OFPhysicalPort(port);
     }
@@ -56,6 +58,11 @@
         c.writeInt(this.port);
     }
 
+    @Override
+    public void writeTo(ChannelBuffer bb) {
+        write4Bytes(bb);
+    }
+
     public static OFPhysicalPort read4Bytes(ChannelBuffer c) throws OFParseError {
         return OFPhysicalPort.of((int)(c.readUnsignedInt() & 0xFFFFFFFF));
     }
@@ -68,4 +75,13 @@
     public int getPortNumber() {
         return port;
     }
+
+    public final static Reader READER = new Reader();
+    private static class Reader implements OFMessageReader<OFPhysicalPort> {
+        @Override
+        public OFPhysicalPort readFrom(ChannelBuffer bb) throws OFParseError {
+            return OFPhysicalPort.read4Bytes(bb);
+        }
+
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/OFPort.java b/java_gen/pre-written/src/main/java/org/openflow/types/OFPort.java
index 9dc197f..f6dc408 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/OFPort.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/OFPort.java
@@ -520,7 +520,7 @@
     }
 
     public static OFPort read2Bytes(ChannelBuffer c) throws OFParseError {
-        return OFPort.of((c.readUnsignedShort() & 0x0FFFF));
+        return OFPort.ofShort(c.readShort());
     }
 
     public void write4Bytes(ChannelBuffer c) {
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/U32.java b/java_gen/pre-written/src/main/java/org/openflow/types/U32.java
index 003f35d..88d6b15 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/U32.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/U32.java
@@ -17,7 +17,61 @@
 
 package org.openflow.types;
 
-public class U32 {
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFMessageReader;
+import org.openflow.protocol.Writeable;
+
+public class U32 implements Writeable {
+    private final int raw;
+
+    private U32(int raw) {
+        this.raw = raw;
+    }
+
+    public static U32 of(long value) {
+        return new U32(U32.t(value));
+    }
+
+    public static U32 ofRaw(int value) {
+        return new U32(value);
+    }
+
+    long getValue() {
+        return f(raw);
+    }
+
+    int getRaw() {
+        return raw;
+    }
+
+    @Override
+    public String toString() {
+        return "" + f(raw);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + raw;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        U32 other = (U32) obj;
+        if (raw != other.raw)
+            return false;
+        return true;
+    }
+
     public static long f(final int i) {
         return i & 0xffffffffL;
     }
@@ -25,4 +79,19 @@
     public static int t(final long l) {
         return (int) l;
     }
+
+    @Override
+    public void writeTo(ChannelBuffer bb) {
+        bb.writeInt(raw);
+    }
+
+    public final static Reader READER = new Reader();
+
+    private static class Reader implements OFMessageReader<U32> {
+        @Override
+        public U32 readFrom(ChannelBuffer bb) throws OFParseError {
+            return new U32(bb.readInt());
+        }
+    }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/U64.java b/java_gen/pre-written/src/main/java/org/openflow/types/U64.java
index c0cd475..750398f 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/U64.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/U64.java
@@ -32,6 +32,10 @@
         return new U64(raw);
     }
 
+    public static U64 parseHex(String hex) {
+        return new U64(new BigInteger(hex, 16).longValue());
+    }
+
     public long getValue() {
         return raw;
     }
@@ -60,4 +64,27 @@
     public static long t(final BigInteger l) {
         return l.longValue();
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (int) (raw ^ (raw >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        U64 other = (U64) obj;
+        if (raw != other.raw)
+            return false;
+        return true;
+    }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/U8.java b/java_gen/pre-written/src/main/java/org/openflow/types/U8.java
index 1cdf0e5..2bd34bf 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/U8.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/U8.java
@@ -17,8 +17,66 @@
 
 package org.openflow.types;
 
-public class U8 {
-    byte data;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFMessageReader;
+import org.openflow.protocol.Writeable;
+
+public class U8 implements Writeable {
+    private final byte raw;
+
+    private U8(byte raw) {
+        this.raw = raw;
+    }
+
+    public static final U8 of(short value) {
+        return new U8(t(value));
+    }
+
+    public static final U8 ofRaw(byte value) {
+        return new U8(value);
+    }
+
+    public short getValue() {
+        return f(raw);
+    }
+
+    public byte getRaw() {
+        return raw;
+    }
+
+    @Override
+    public String toString() {
+        return "" + f(raw);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + raw;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        U8 other = (U8) obj;
+        if (raw != other.raw)
+            return false;
+        return true;
+    }
+
+
+    @Override
+    public void writeTo(ChannelBuffer bb) {
+        bb.writeByte(raw);
+    }
 
     public static short f(final byte i) {
         return (short) (i & 0xff);
@@ -28,7 +86,14 @@
         return (byte) l;
     }
 
-    public byte getValue() {
-        return data;
+
+    public final static Reader READER = new Reader();
+
+    private static class Reader implements OFMessageReader<U8> {
+        @Override
+        public U8 readFrom(ChannelBuffer bb) throws OFParseError {
+            return new U8(bb.readByte());
+        }
     }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/util/ChannelUtils.java b/java_gen/pre-written/src/main/java/org/openflow/util/ChannelUtils.java
index dab6ff2..e9a3356 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/util/ChannelUtils.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/util/ChannelUtils.java
@@ -3,31 +3,13 @@
 import java.util.List;
 
 import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.OFBsnInterface;
-import org.openflow.protocol.OFBsnVportQInQ;
-import org.openflow.protocol.OFBsnVportQInQT;
-import org.openflow.protocol.OFBucket;
-import org.openflow.protocol.OFFlowStatsEntry;
-import org.openflow.protocol.OFGroupDescStatsEntry;
-import org.openflow.protocol.OFGroupStatsEntry;
-import org.openflow.protocol.OFHelloElem;
-import org.openflow.protocol.OFMeterFeatures;
-import org.openflow.protocol.OFMeterStats;
-import org.openflow.protocol.OFPacketQueue;
-import org.openflow.protocol.OFPortStatsEntry;
-import org.openflow.protocol.OFQueueStatsEntry;
-import org.openflow.protocol.OFTableFeature;
-import org.openflow.protocol.OFTableFeatures;
-import org.openflow.protocol.OFTableStatsEntry;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.instruction.OFInstruction;
-import org.openflow.protocol.match.Match;
-import org.openflow.types.OFFlowModCmd;
-import org.openflow.types.OFHelloElement;
-import org.openflow.types.OFMeterBand;
-import org.openflow.types.OFPhysicalPort;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFMessageReader;
+import org.openflow.protocol.Writeable;
 
 import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
 
 /**
  * Collection of helper functions for reading and writing into ChannelBuffers
@@ -36,6 +18,24 @@
  */
 
 public class ChannelUtils {
+    public static String readFixedLengthString(ChannelBuffer bb, int length) {
+        byte[] dst = new byte[length];
+        bb.readBytes(dst, 0, length);
+        return new String(dst, Charsets.US_ASCII);
+    }
+
+    public static void writeFixedLengthString(ChannelBuffer bb, String string,
+            int length) {
+        int l = string.length();
+        if (l > length) {
+            throw new IllegalArgumentException("Error writing string: length="
+                    + l + " > max Length=" + length);
+        }
+        bb.writeBytes(string.getBytes(Charsets.US_ASCII));
+        if (l < length) {
+            bb.writeZero(length - l);
+        }
+    }
 
     static public byte[] readBytes(final ChannelBuffer bb, final int length) {
         byte byteArray[] = new byte[length];
@@ -43,274 +43,25 @@
         return byteArray;
     }
 
-    static public void writeBytes(final ChannelBuffer bb, final byte byteArray[]) {
+    static public void writeBytes(final ChannelBuffer bb,
+            final byte byteArray[]) {
         bb.writeBytes(byteArray);
     }
 
-    public static List<OFPhysicalPort> readPhysicalPortList(final ChannelBuffer bb,
-            final int i) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static List<OFInstruction> readInstructionsList(final ChannelBuffer bb,
-            final int i) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static Match readOFMatch(final ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static OFFlowModCmd readOFFlowModCmd(final ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static List<OFAction> readActionsList(final ChannelBuffer bb, final int i) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static List<OFBsnInterface> readBsnInterfaceList(final ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static OFPhysicalPort readPhysicalPort(final ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static List<OFPacketQueue> readPacketQueueList(final ChannelBuffer bb,
-            final int i) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static List<OFHelloElement> readHelloElementList(final ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static List<OFBucket> readBucketList(final ChannelBuffer bb, final int i) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static List<OFMeterBand> readMeterBandList(final ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeOFMatch(ChannelBuffer bb, Match match) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static void writeList(ChannelBuffer bb, List<?> ports) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static void writeOFFlowModCmd(ChannelBuffer bb, OFFlowModCmd command) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static String readFixedLengthString(ChannelBuffer bb, int length) {
-        byte[] dst = new byte[length];
-        bb.readBytes(dst, 0, length);
-        return new String(dst, Charsets.US_ASCII);
-    }
-
-    public static void writeFixedLengthString(ChannelBuffer bb, String string, int length) {
-        int l = string.length();
-        if(l > length) {
-            throw new IllegalArgumentException("Error writing string: length="+l+" > max Length="+length);
+    public static <T> List<T> readList(ChannelBuffer bb, int length, OFMessageReader<T> reader) throws OFParseError {
+        int end = bb.readerIndex() + length;
+        Builder<T> builder = ImmutableList.<T>builder();
+        while(bb.readerIndex() < end) {
+            builder.add(reader.readFrom(bb));
         }
-        bb.writeBytes(string.getBytes(Charsets.US_ASCII));
-        if(l < length) {
-            bb.writeZero(length - l);
+        if(bb.readerIndex() != end) {
+            throw new IllegalStateException("Overread length: length="+length + " overread by "+ (bb.readerIndex() - end) + " reader: "+reader);
         }
+        return builder.build();
     }
 
-    public static void writeBsnInterfaceList(ChannelBuffer bb, List<OFBsnInterface> interfaces) {
-        // TODO Auto-generated method stub
-
+    public static void writeList(ChannelBuffer bb, List<? extends Writeable> writeables) {
+        for(Writeable w: writeables)
+            w.writeTo(bb);
     }
-
-    public static void writeTableFeatureList(ChannelBuffer bb,
-            List<OFTableFeature> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static void writeBsnInterface(ChannelBuffer bb,
-            List<OFBsnInterface> interfaces) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static void writeFlowStatsEntry(ChannelBuffer bb,
-            List<OFFlowStatsEntry> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static List<OFFlowStatsEntry> readFlowStatsEntry(ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeTableStatsEntryList(ChannelBuffer bb,
-            List<OFTableStatsEntry> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static List<OFTableStatsEntry> readTableStatsEntryList(
-            ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static List<OFFlowStatsEntry> readFlowStatsEntryList(ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeFlowStatsEntryList(ChannelBuffer bb,
-            List<OFFlowStatsEntry> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static void writeGroupDescStatsEntryList(ChannelBuffer bb,
-            List<OFGroupDescStatsEntry> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static List<OFGroupDescStatsEntry> readGroupDescStatsEntryList(
-            ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeOFBsnVportQInQT(ChannelBuffer bb,
-            OFBsnVportQInQT vport) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static void writeMeterBandList(ChannelBuffer bb,
-            List<OFMeterBand> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static int writeActionsList(ChannelBuffer bb, List<OFAction> actions) {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
-    public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writePortStatsEntryList(ChannelBuffer bb,
-            List<OFPortStatsEntry> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static void write(ChannelBuffer bb, OFPhysicalPort desc) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static List<OFPortStatsEntry> readPortStatsEntryList(ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeOFBsnVportQInQ(ChannelBuffer bb,
-            OFBsnVportQInQ vport) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static List<OFHelloElem> readHelloElemList(ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeHelloElemList(ChannelBuffer bb,
-            List<OFHelloElem> elements) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static List<OFGroupStatsEntry> readGroupStatsEntryList(
-            ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeGroupStatsEntryList(ChannelBuffer bb,
-            List<OFGroupStatsEntry> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static List<OFQueueStatsEntry> readQueueStatsEntryList(
-            ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeQueueStatsEntryList(ChannelBuffer bb,
-            List<OFQueueStatsEntry> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static OFMeterFeatures readOFMeterFeatures(ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeOFMeterFeatures(ChannelBuffer bb,
-            OFMeterFeatures features) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static List<OFMeterStats> readMeterStatsList(ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeMeterStatsList(ChannelBuffer bb,
-            List<OFMeterStats> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public static List<OFTableFeatures> readTableFeaturesList(ChannelBuffer bb) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public static void writeTableFeaturesList(ChannelBuffer bb,
-            List<OFTableFeatures> entries) {
-        // TODO Auto-generated method stub
-
-    }
-
-
 }
diff --git a/java_gen/pre-written/src/test/java/Test.java b/java_gen/pre-written/src/test/java/Test.java
deleted file mode 100644
index e83700d..0000000
--- a/java_gen/pre-written/src/test/java/Test.java
+++ /dev/null
@@ -1,30 +0,0 @@
-import org.openflow.protocol.match.MatchBuilderVer10;
-import org.openflow.types.MacAddress;
-import org.openflow.types.OFPort;
-
-
-public class Test {
-
-    private static volatile OFPort port;
-    private static volatile MacAddress ethSrc;
-
-    /**
-     * @param args
-     */
-    public static void main(String[] args) {
-        MacAddress mac = MacAddress.of("01:02:03:04:05:06");
-
-        long start = System.currentTimeMillis();
-        for(int i=0; i < 10000000; i++) {
-            MatchBuilderVer10 m = new MatchBuilderVer10();
-            // m.set(MatchField.IN_PORT, OFPort.CONTROLLER);
-            m.setInputPort(OFPort.CONTROLLER);
-            port = m.getInputPort(); //m.get(MatchField.IN_PORT);
-            m.setDataLayerSource(mac);
-            ethSrc = m.getDataLayerSource(); //(MatchField.ETH_SRC);
-        }
-        long end = System.currentTimeMillis();
-        System.out.println("end-start: "+ (end-start));
-    }
-
-}
diff --git a/java_gen/templates/_imports.java b/java_gen/templates/_imports.java
index 7700546..5b86571 100644
--- a/java_gen/templates/_imports.java
+++ b/java_gen/templates/_imports.java
@@ -1,12 +1,17 @@
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import org.openflow.protocol.*;
 import org.openflow.protocol.action.*;
+import org.openflow.protocol.meterband.*;
 import org.openflow.protocol.instruction.*;
 import org.openflow.protocol.match.*;
 import org.openflow.protocol.oxm.*;
+import org.openflow.protocol.queueprop.*;
 import org.openflow.types.*;
 import org.openflow.types.*;
 import org.openflow.util.*;
 import org.openflow.exceptions.*;
 import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import com.google.common.collect.ImmutableList;
diff --git a/java_gen/templates/_singleton.java b/java_gen/templates/_singleton.java
new file mode 100644
index 0000000..8ea9f01
--- /dev/null
+++ b/java_gen/templates/_singleton.java
@@ -0,0 +1,10 @@
+
+    private ${msg.name}() {}
+
+    private final static class Holder {
+        private static final ${msg.name} INSTANCE = new ${msg.name}();
+    }
+
+    public static ${msg.name} getInstance() {
+        return Holder.INSTANCE;
+    }
diff --git a/java_gen/templates/const.java b/java_gen/templates/const.java
index 7870529..11c09ab 100644
--- a/java_gen/templates/const.java
+++ b/java_gen/templates/const.java
@@ -37,16 +37,7 @@
 
 public enum ${class_name} {
 //:: for i, entry in enumerate(enum.entries):
-//::     values = [ ("0x%x" % val) if val is not None else "-1" for val in entry.all_values(all_versions) ]
-     ${entry.name}(new int[] { ${ ", ".join( values) } } )${ ", " if i < len(enum.entries)-1 else ";" }
+     ${entry.name}${ ", " if i < len(enum.entries)-1 else ";" }
 //:: #endfor
 
-    private final int[] wireValues;
-    ${class_name}(int[] wireValues) {
-        this.wireValues = wireValues;
-    }
-
-    public int getWireValue(OFVersion version) {
-        return this.wireValues[version.getWireVersion()];
-    }
 }
diff --git a/java_gen/templates/const_serializer.java b/java_gen/templates/const_serializer.java
new file mode 100644
index 0000000..4e21070
--- /dev/null
+++ b/java_gen/templates/const_serializer.java
@@ -0,0 +1,85 @@
+//:: # Copyright 2013, Big Switch Networks, Inc.
+//:: #
+//:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+//:: # the following special exception:
+//:: #
+//:: # LOXI Exception
+//:: #
+//:: # As a special exception to the terms of the EPL, you may distribute libraries
+//:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+//:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+//:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+//:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+//:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+//:: #
+//:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//:: #
+//:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+//:: # a copy of the EPL at:
+//:: #
+//:: # http::: #www.eclipse.org/legal/epl-v10.html
+//:: #
+//:: # Unless required by applicable law or agreed to in writing, software
+//:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+//:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+//:: # EPL for the specific language governing permissions and limitations
+//:: # under the EPL.
+//::
+//:: import itertools
+//:: import of_g
+//:: include('_copyright.java')
+
+//:: include('_autogen.java')
+
+package ${package};
+
+import org.openflow.types.*;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFVersion;
+import ${enum.package}.${enum.name};
+
+public class ${class_name} {
+    //:: wire_type = enum.wire_type(version)
+    //:: int_wire_type = enum.wire_type(version).pub_type
+    //:: entries = sorted([ (entry, entry.value(version)) for entry in enum.entries if entry.has_value(version) ], lambda (_,va), (_2,vb): va.__cmp__(vb))
+
+    //:: for entry, _ in entries:
+    public final static ${int_wire_type} ${entry.name}_VAL = ${entry.format_value(version)};
+    //:: #endfor
+
+    public static ${enum.name} readFrom(ChannelBuffer bb) throws OFParseError {
+        try {
+            return ofWireValue(${wire_type.read_op(version)});
+        } catch (IllegalArgumentException e) {
+            throw new OFParseError(e);
+        }
+    }
+
+    public static void writeTo(ChannelBuffer bb, ${enum.name} e) {
+        ${wire_type.write_op(version=version, name="toWireValue(e)")};
+    }
+
+    public static ${enum.name} ofWireValue(${int_wire_type} val) {
+        switch(val) {
+        //:: for entry, _ in entries:
+            case ${entry.name}_VAL:
+                return ${enum.name}.${entry.name};
+        //:: #endfor
+            default:
+                throw new IllegalArgumentException("Illegal wire value for type ${enum.name} in version ${version}: " + val);
+        }
+    }
+
+    public static ${int_wire_type} toWireValue(${enum.name} e) {
+        switch(e) {
+        //:: for entry, _ in entries:
+            case ${entry.name}:
+                return ${entry.name}_VAL;
+        //:: #endfor
+            default:
+                throw new IllegalArgumentException("Illegal enum value for type ${enum.name} in version ${version}: " + e);
+        }
+    }
+
+}
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.Builder.java b/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
new file mode 100644
index 0000000..58afcd0
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
@@ -0,0 +1,77 @@
+
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setExact(
+            MatchField<F> field, F value) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setMasked(
+            MatchField<F> field, F value, F mask) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setMasked(
+            MatchField<F> field, Masked<F> valueWithMask) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder wildcard(MatchField<F> field) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public Match getMatch() {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.java b/java_gen/templates/custom/OFMatchV1Ver10.java
new file mode 100644
index 0000000..ec7bfcc
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV1Ver10.java
@@ -0,0 +1,44 @@
+
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
diff --git a/java_gen/templates/custom/OFMatchV2Ver11.Builder.java b/java_gen/templates/custom/OFMatchV2Ver11.Builder.java
new file mode 100644
index 0000000..58afcd0
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV2Ver11.Builder.java
@@ -0,0 +1,77 @@
+
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setExact(
+            MatchField<F> field, F value) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setMasked(
+            MatchField<F> field, F value, F mask) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setMasked(
+            MatchField<F> field, Masked<F> valueWithMask) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder wildcard(MatchField<F> field) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public Match getMatch() {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
diff --git a/java_gen/templates/custom/OFMatchV2Ver11.java b/java_gen/templates/custom/OFMatchV2Ver11.java
new file mode 100644
index 0000000..ec7bfcc
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV2Ver11.java
@@ -0,0 +1,44 @@
+
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
diff --git a/java_gen/templates/custom/OFMatchV3Ver12.Builder.java b/java_gen/templates/custom/OFMatchV3Ver12.Builder.java
new file mode 100644
index 0000000..58afcd0
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3Ver12.Builder.java
@@ -0,0 +1,77 @@
+
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setExact(
+            MatchField<F> field, F value) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setMasked(
+            MatchField<F> field, F value, F mask) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setMasked(
+            MatchField<F> field, Masked<F> valueWithMask) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder wildcard(MatchField<F> field) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public Match getMatch() {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
diff --git a/java_gen/templates/custom/OFMatchV3Ver12.java b/java_gen/templates/custom/OFMatchV3Ver12.java
new file mode 100644
index 0000000..ec7bfcc
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3Ver12.java
@@ -0,0 +1,44 @@
+
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
diff --git a/java_gen/templates/custom/OFMatchV3Ver13.Builder.java b/java_gen/templates/custom/OFMatchV3Ver13.Builder.java
new file mode 100644
index 0000000..58afcd0
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3Ver13.Builder.java
@@ -0,0 +1,77 @@
+
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setExact(
+            MatchField<F> field, F value) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setMasked(
+            MatchField<F> field, F value, F mask) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder setMasked(
+            MatchField<F> field, Masked<F> valueWithMask) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> MatchBuilder wildcard(MatchField<F> field) {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public Match getMatch() {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
diff --git a/java_gen/templates/custom/OFMatchV3Ver13.java b/java_gen/templates/custom/OFMatchV3Ver13.java
new file mode 100644
index 0000000..ec7bfcc
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3Ver13.java
@@ -0,0 +1,44 @@
+
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        // FIXME yotam - please replace with real implementation
+        return null;
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        // FIXME yotam - please replace with real implementation
+        return false;
+    }
diff --git a/java_gen/templates/of_class.java b/java_gen/templates/of_class.java
index 9665c49..0781dcf 100644
--- a/java_gen/templates/of_class.java
+++ b/java_gen/templates/of_class.java
@@ -26,6 +26,7 @@
 //:: # under the EPL.
 //::
 //:: from loxi_ir import *
+//:: import os
 //:: import itertools
 //:: import of_g
 //:: include('_copyright.java')
@@ -64,12 +65,15 @@
     // Accessors for OF message fields
 //:: include("_field_accessors.java", msg=msg, generate_setters=False, builder=False)
 
+    //:: if os.path.exists("%s/custom/%s.java" % (template_dir, msg.name)):
+    //:: include("custom/%s.java" % msg.name, msg=msg)
+    //:: #endif
 
-    public ${msg.name}.Builder createBuilder() {
-        return new BuilderImplWithParent(this);
+    public ${msg.interface.name}.Builder createBuilder() {
+        return new BuilderWithParent(this);
     }
 
-    static class BuilderImplWithParent implements ${msg.interface.name}.Builder {
+    static class BuilderWithParent implements ${msg.interface.name}.Builder {
         final ${impl_class} parentMessage;
 
         // OF message fields
@@ -78,7 +82,7 @@
         private ${prop.java_type.public_type} ${prop.name};
 //:: #endfor
 
-        BuilderImplWithParent(${impl_class} parentMessage) {
+        BuilderWithParent(${impl_class} parentMessage) {
             this.parentMessage = parentMessage;
         }
 
@@ -92,9 +96,13 @@
                              for prop in msg.data_members])}
                     );
         }
+        //:: if os.path.exists("%s/custom/%s.Builder.java" % (template_dir, msg.name)):
+        //:: include("custom/%s.Builder.java" % msg.name, msg=msg)
+        //:: #endif
+
     }
 
-    static class BuilderImpl implements ${msg.interface.name}.Builder {
+    static class Builder implements ${msg.interface.name}.Builder {
         // OF message fields
 //:: for prop in msg.data_members:
         private boolean ${prop.name}Set;
@@ -111,36 +119,46 @@
                          for prop in msg.data_members])}
                 );
         }
+        //:: if os.path.exists("%s/custom/%s.Builder.java" % (template_dir, msg.name)):
+        //:: include("custom/%s.Builder.java" % msg.name, msg=msg)
+        //:: #endif
+
     }
 
     final static Reader READER = new Reader();
     static class Reader implements OFMessageReader<${msg.interface.name}> {
         @Override
         public ${msg.interface.name} readFrom(ChannelBuffer bb) throws OFParseError {
+            int start = bb.readerIndex();
 //:: fields_with_length_member = {}
 //:: for prop in msg.members:
 //:: if prop.is_data:
-            ${prop.java_type.public_type} ${prop.name} = ${prop.java_type.read_op(version,
+            ${prop.java_type.public_type} ${prop.name} = ${prop.java_type.read_op(version, pub_type=True,
                     length=fields_with_length_member[prop.c_name] if prop.c_name in fields_with_length_member else None)};
 //:: elif prop.is_pad:
             // pad: ${prop.length} bytes
             bb.skipBytes(${prop.length});
 //:: elif prop.is_fixed_value:
             // fixed value property ${prop.name} == ${prop.value}
-            ${prop.java_type.priv_type} ${prop.name} = ${prop.java_type.read_op(version)};
-            if(${prop.name} != ${prop.value})
+            ${prop.java_type.priv_type} ${prop.name} = ${prop.java_type.read_op(version, pub_type=False)};
+            if(${prop.name} != ${prop.priv_value})
                 throw new OFParseError("Wrong ${prop.name}: Expected=${prop.enum_value}(${prop.value}), got="+${prop.name});
 //:: elif prop.is_length_value:
-            ${prop.java_type.public_type} ${prop.name} = ${prop.java_type.read_op(version)};
+            ${prop.java_type.public_type} ${prop.name} = ${prop.java_type.read_op(version, pub_type=False)};
             if(${prop.name} < MINIMUM_LENGTH)
                 throw new OFParseError("Wrong ${prop.name}: Expected to be >= " + MINIMUM_LENGTH + ", was: " + ${prop.name});
 //:: elif prop.is_field_length_value:
 //::        fields_with_length_member[prop.member.field_name] = prop.name
-            int ${prop.name} = ${prop.java_type.read_op(version)};
+            int ${prop.name} = ${prop.java_type.read_op(version, pub_type=False)};
 //:: else:
     // fixme: todo ${prop.name}
 //:: #endif
 //:: #endfor
+            //:: if msg.align:
+            // align message to ${msg.align} bytes
+            bb.skipBytes(((length + ${msg.align-1})/${msg.align} * ${msg.align} ) - length );
+            //:: #endif
+
             return new ${impl_class}(
                     ${",\n                      ".join(
                          [ prop.name for prop in msg.data_members])}
@@ -155,33 +173,34 @@
     final static Writer WRITER = new Writer();
     static class Writer implements OFMessageWriter<${impl_class}> {
         @Override
-        public int write(ChannelBuffer bb, ${impl_class} message) {
-//:: if not msg.is_fixed_length:
+        public void write(ChannelBuffer bb, ${impl_class} message) {
             int startIndex = bb.writerIndex();
-//:: #end
-
 //:: fields_with_length_member = {}
 //:: for prop in msg.members:
 //:: if prop.c_name in fields_with_length_member:
             int ${prop.name}StartIndex = bb.writerIndex();
 //:: #endif
 //:: if prop.is_data:
-            ${prop.java_type.write_op(version, "message." + prop.name)};
+            ${prop.java_type.write_op(version, "message." + prop.name, pub_type=True)};
 //:: elif prop.is_pad:
             // pad: ${prop.length} bytes
             bb.writeZero(${prop.length});
 //:: elif prop.is_fixed_value:
             // fixed value property ${prop.name} = ${prop.value}
-            ${prop.java_type.write_op(version, prop.value)};
+            ${prop.java_type.write_op(version, prop.value, pub_type=False)};
 //:: elif prop.is_length_value:
             // ${prop.name} is length of variable message, will be updated at the end
+//:: if not msg.is_fixed_length:
+            int lengthIndex = bb.writerIndex();
+//:: #end
             ${prop.java_type.write_op(version, 0)};
+
 //:: elif prop.is_field_length_value:
 //::        fields_with_length_member[prop.member.field_name] = prop.name
             // ${prop.name} is length indicator for ${prop.member.field_name}, will be
             // udpated when ${prop.member.field_name} has been written
             int ${prop.name}Index = bb.writerIndex();
-            ${prop.java_type.write_op(version, 0)};
+            ${prop.java_type.write_op(version, 0, pub_type=False)};
 //:: else:
             // FIXME: todo write ${prop.name}
 //:: #endif
@@ -193,17 +212,77 @@
 //:: #endif
 //:: #endfor
 
-//:: if msg.is_fixed_length:
-            return LENGTH;
-//:: else:
+//:: if not msg.is_fixed_length:
             // update length field
             int length = bb.writerIndex() - startIndex;
-            bb.setShort(startIndex + 2, length);
-            return length;
+            bb.setShort(lengthIndex, length);
+            //:: if msg.align:
+            // align message to ${msg.align} bytes
+            bb.writeZero( ((length + ${msg.align-1})/${msg.align} * ${msg.align}) - length);
+            //:: #endif
 //:: #end
 
         }
     }
 
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder("${msg.name}(");
+        //:: for i, prop in enumerate(msg.data_members):
+        //:: if i > 0:
+        b.append(", ");
+        //:: #endif
+        b.append("${prop.name}=").append(${ "Arrays.toString(%s)" % prop.name if prop.java_type.is_array else prop.name });
+        //:: #endfor
+        b.append(")");
+        return b.toString();
+    }
+
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ${msg.name} other = (${msg.name}) obj;
+
+        //:: for prop in msg.data_members:
+        //:: if prop.java_type.is_primitive:
+        if( ${prop.name} != other.${prop.name})
+            return false;
+        //:: elif prop.java_type.is_array:
+        if (!Arrays.equals(${prop.name}, other.${prop.name}))
+                return false;
+        //:: else:
+        if (${prop.name} == null) {
+            if (other.${prop.name} != null)
+                return false;
+        } else if (!${prop.name}.equals(other.${prop.name}))
+            return false;
+        //:: #endif
+        //:: #endfor
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+
+        //:: for prop in msg.data_members:
+        //:: if prop.java_type.is_primitive:
+        result = prime * result + ${prop.name};
+        //:: elif prop.java_type.is_array:
+        result = prime * result + Arrays.hashCode(${prop.name});
+        //:: else:
+        result = prime * result + ((${prop.name} == null) ? 0 : ${prop.name}.hashCode());
+        //:: #endif
+        //:: #endfor
+        return result;
+    }
+
 
 }
diff --git a/java_gen/templates/of_factories.java b/java_gen/templates/of_factories.java
new file mode 100644
index 0000000..cce134d
--- /dev/null
+++ b/java_gen/templates/of_factories.java
@@ -0,0 +1,49 @@
+//:: # Copyright 2013, Big Switch Networks, Inc.
+//:: #
+//:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+//:: # the following special exception:
+//:: #
+//:: # LOXI Exception
+//:: #
+//:: # As a special exception to the terms of the EPL, you may distribute libraries
+//:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+//:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+//:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+//:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+//:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+//:: #
+//:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//:: #
+//:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+//:: # a copy of the EPL at:
+//:: #
+//:: # http::: #www.eclipse.org/legal/epl-v10.html
+//:: #
+//:: # Unless required by applicable law or agreed to in writing, software
+//:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+//:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+//:: # EPL for the specific language governing permissions and limitations
+//:: # under the EPL.
+//::
+//:: import itertools
+//:: import of_g
+//:: include('_copyright.java')
+
+//:: include('_autogen.java')
+
+package org.openflow.protocol;
+
+//:: include("_imports.java")
+
+public final class OFFactories {
+    public static OFFactory getFactory(OFVersion version) {
+        switch(version) {
+            //:: for v in versions:
+            case ${v.constant_version}:
+                return org.openflow.protocol.ver${v.of_version}.OFFactoryVer${v.of_version}.getInstance();
+            //:: #endfor
+            default:
+                throw new IllegalArgumentException("Unknown version: "+version);
+            }
+    }
+}
diff --git a/java_gen/templates/of_factory_class.java b/java_gen/templates/of_factory_class.java
new file mode 100644
index 0000000..8620787
--- /dev/null
+++ b/java_gen/templates/of_factory_class.java
@@ -0,0 +1,56 @@
+//:: # Copyright 2013, Big Switch Networks, Inc.
+//:: #
+//:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+//:: # the following special exception:
+//:: #
+//:: # LOXI Exception
+//:: #
+//:: # As a special exception to the terms of the EPL, you may distribute libraries
+//:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+//:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+//:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+//:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+//:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+//:: #
+//:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//:: #
+//:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+//:: # a copy of the EPL at:
+//:: #
+//:: # http::: #www.eclipse.org/legal/epl-v10.html
+//:: #
+//:: # Unless required by applicable law or agreed to in writing, software
+//:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+//:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+//:: # EPL for the specific language governing permissions and limitations
+//:: # under the EPL.
+//::
+//:: import itertools
+//:: import of_g
+//:: include('_copyright.java')
+
+//:: include('_autogen.java')
+
+package ${factory.package};
+
+//:: include("_imports.java")
+
+public class ${factory.name} implements ${factory.interface.name} {
+//:: for i in factory.interface.members:
+    //:: if i.is_virtual:
+    //::    continue
+    //:: #endif
+
+//::   if i.has_version(factory.version) and model.generate_class(i.versioned_class(factory.version)):
+    public ${i.name}.Builder create${i.name[2:]}Builder() {
+        return new ${i.versioned_class(factory.version).name}.Builder();
+    }
+//:: else:
+    public ${i.name}.Builder create${i.name[2:]}Builder() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException("${i.name} not supported in version ${factory.version}");
+    }
+//:: #endif
+//:: #endfor
+
+    //:: include("_singleton.java", msg=factory)
+}
diff --git a/java_gen/templates/of_factory_interface.java b/java_gen/templates/of_factory_interface.java
new file mode 100644
index 0000000..467504e
--- /dev/null
+++ b/java_gen/templates/of_factory_interface.java
@@ -0,0 +1,45 @@
+//:: # Copyright 2013, Big Switch Networks, Inc.
+//:: #
+//:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+//:: # the following special exception:
+//:: #
+//:: # LOXI Exception
+//:: #
+//:: # As a special exception to the terms of the EPL, you may distribute libraries
+//:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+//:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+//:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+//:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+//:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+//:: #
+//:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//:: #
+//:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+//:: # a copy of the EPL at:
+//:: #
+//:: # http::: #www.eclipse.org/legal/epl-v10.html
+//:: #
+//:: # Unless required by applicable law or agreed to in writing, software
+//:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+//:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+//:: # EPL for the specific language governing permissions and limitations
+//:: # under the EPL.
+//::
+//:: import itertools
+//:: import of_g
+//:: include('_copyright.java')
+
+//:: include('_autogen.java')
+
+package org.openflow.protocol;
+
+//:: include("_imports.java")
+
+public interface ${factory.name} {
+//:: for i in factory.members:
+    //:: if i.is_virtual:
+    //::    continue
+    //:: #endif
+    ${i.name}.Builder create${i.name[2:]}Builder()${ "" if i.is_universal else " throws UnsupportedOperationException"};
+//:: #endfor
+}
diff --git a/java_gen/templates/of_interface.java b/java_gen/templates/of_interface.java
index b969d50..4dec92f 100644
--- a/java_gen/templates/of_interface.java
+++ b/java_gen/templates/of_interface.java
@@ -35,7 +35,7 @@
 
 //:: include("_imports.java", msg=msg)
 
-public interface ${msg.name} ${"extends %s" % msg.parent_interface if msg.parent_interface else ""} {
+public interface ${msg.name} extends OFObject${", %s" % msg.parent_interface if msg.parent_interface else ""}{
 //:: for prop in msg.members:
     ${prop.java_type.public_type} get${prop.title_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
 //:: #endfor
@@ -51,6 +51,5 @@
         Builder set${prop.title_name}(${prop.java_type.public_type} ${prop.name})${ "" if prop.is_universal else " throws UnsupportedOperationException"};
 //:: #endif
 //:: #endfor
-
     }
 }
diff --git a/java_gen/templates/of_virtual_class.java b/java_gen/templates/of_virtual_class.java
new file mode 100644
index 0000000..f1ac849
--- /dev/null
+++ b/java_gen/templates/of_virtual_class.java
@@ -0,0 +1,102 @@
+//:: # Copyright 2013, Big Switch Networks, Inc.
+//:: #
+//:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+//:: # the following special exception:
+//:: #
+//:: # LOXI Exception
+//:: #
+//:: # As a special exception to the terms of the EPL, you may distribute libraries
+//:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+//:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+//:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+//:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+//:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+//:: #
+//:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//:: #
+//:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+//:: # a copy of the EPL at:
+//:: #
+//:: # http::: #www.eclipse.org/legal/epl-v10.html
+//:: #
+//:: # Unless required by applicable law or agreed to in writing, software
+//:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+//:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+//:: # EPL for the specific language governing permissions and limitations
+//:: # under the EPL.
+//::
+//:: from loxi_ir import *
+//:: import os
+//:: import itertools
+//:: import of_g
+//:: include('_copyright.java')
+
+//:: include('_autogen.java')
+
+package ${msg.package};
+
+//:: include("_imports.java", msg=msg)
+
+abstract class ${msg.name} implements ${msg.interface.name} {
+    // version: ${version}
+    private final static byte WIRE_VERSION = ${version.int_version};
+//:: if msg.is_fixed_length:
+    private final static int LENGTH = ${msg.length};
+//:: else:
+    private final static int MINIMUM_LENGTH = ${msg.min_length};
+//:: #endif
+
+
+    public final static ${msg.name}.Reader READER = new Reader();
+
+    static class Reader implements OFMessageReader<${msg.interface.name}> {
+        @Override
+        public ${msg.interface.name} readFrom(ChannelBuffer bb) throws OFParseError {
+            int start = bb.readerIndex();
+//:: fields_with_length_member = {}
+//::    for prop in msg.members:
+//::       if prop.is_data:
+            ${prop.java_type.skip_op(version,
+                    length=fields_with_length_member[prop.c_name] if prop.c_name in fields_with_length_member else None)};
+//:: elif prop.is_pad:
+            // pad: ${prop.length} bytes
+            bb.skipBytes(${prop.length});
+//:: elif prop.is_fixed_value:
+            // fixed value property ${prop.name} == ${prop.value}
+            ${prop.java_type.priv_type} ${prop.name} = ${prop.java_type.read_op(version, pub_type=False)};
+            if(${prop.name} != ${prop.value})
+                throw new OFParseError("Wrong ${prop.name}: Expected=${prop.enum_value}(${prop.value}), got="+${prop.name});
+//:: elif prop.is_length_value:
+            ${prop.java_type.public_type} ${prop.name} = ${prop.java_type.read_op(version, pub_type=True)};
+            if(${prop.name} < MINIMUM_LENGTH)
+                throw new OFParseError("Wrong ${prop.name}: Expected to be >= " + MINIMUM_LENGTH + ", was: " + ${prop.name});
+//:: elif prop.is_field_length_value:
+//::        fields_with_length_member[prop.member.field_name] = prop.name
+            int ${prop.name} = ${prop.java_type.read_op(version)};
+//:: elif prop.is_discriminator:
+            ${prop.java_type.priv_type} ${prop.name} = ${prop.java_type.read_op(version, pub_type=False)};
+            bb.readerIndex(start);
+            switch(${prop.name}) {
+//::     for sub in msg.subclasses:
+//::           if not model.generate_class(sub):
+               // skip ${sub.name} - excluded from generation
+//::           else:
+//::           m = sub.get_member(prop.name)
+//::           if not m.is_fixed_value:
+//::                  raise Exception("subtype %s of %s does not have fixed value for discriminator %s" %
+//::                           (sub.name, msg.name, prop.name))
+//::           #endif
+               case ${m.priv_value}:
+                   // discriminator value ${m.enum_value}=${m.value} for class ${sub.name}
+                   return ${sub.name}.READER.readFrom(bb);
+//:: #endif    # generate_class
+//:: #endfor
+               default:
+                   throw new OFParseError("Unknown value for discriminator ${prop.name} of class ${msg.name}: " + ${prop.name});
+            }
+//::        break
+//:: #endif
+//:: #endfor
+        }
+    }
+}
diff --git a/java_gen/templates/unit_test.java b/java_gen/templates/unit_test.java
new file mode 100644
index 0000000..45472f2
--- /dev/null
+++ b/java_gen/templates/unit_test.java
@@ -0,0 +1,102 @@
+//:: # Copyright 2013, Big Switch Networks, Inc.
+//:: #
+//:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+//:: # the following special exception:
+//:: #
+//:: # LOXI Exception
+//:: #
+//:: # As a special exception to the terms of the EPL, you may distribute libraries
+//:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+//:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+//:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+//:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+//:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+//:: #
+//:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//:: #
+//:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+//:: # a copy of the EPL at:
+//:: #
+//:: # http::: #www.eclipse.org/legal/epl-v10.html
+//:: #
+//:: # Unless required by applicable law or agreed to in writing, software
+//:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+//:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+//:: # EPL for the specific language governing permissions and limitations
+//:: # under the EPL.
+//::
+//:: from loxi_ir import *
+//:: import itertools
+//:: import of_g
+//:: include('_copyright.java')
+
+//:: include('_autogen.java')
+
+package ${test.package};
+
+//:: include("_imports.java", msg=msg)
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class ${test.name} {
+    //:: var_type = msg.interface.name
+    //:: var_name = msg.interface.variable_name
+    OFFactory factory;
+
+    final static byte[] ${msg.constant_name}_SERIALIZED =
+        new byte[] { ${", ".join("%s0x%x" % (("" if ord(c)<128 else "(byte) "),  ord(c)) for c in test_data["binary"] ) } };
+
+    @Before
+    public void setup() {
+        factory = OFFactories.getFactory(OFVersion.${version.constant_version});
+    }
+
+    //:: if "java" in test_data:
+    @Test
+    public void testWrite() {
+        ${var_type}.Builder builder = factory.create${var_type[2:]}Builder();
+        ${test_data["java"]};
+        ${var_type} ${var_name} = builder.getMessage();
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        ${var_name}.writeTo(bb);
+        byte[] written = new byte[bb.readableBytes()];
+        bb.readBytes(written);
+
+        assertArrayEquals(${msg.constant_name}_SERIALIZED, written);
+    }
+
+    @Test
+    public void testRead() throws Exception {
+        ${var_type}.Builder builder = factory.create${var_type[2:]}Builder();
+        ${test_data["java"]};
+        ${var_type} ${var_name}Built = builder.getMessage();
+
+        ChannelBuffer input = ChannelBuffers.copiedBuffer(${msg.constant_name}_SERIALIZED);
+
+        // FIXME should invoke the overall reader once implemented
+        ${var_type} ${var_name}Read = ${msg.name}.READER.readFrom(input);
+
+        assertEquals(${var_name}Built, ${var_name}Read);
+   }
+   //:: else:
+   // FIXME: No java stanza in test_data for this class. Add for more comprehensive unit testing
+   //:: #endif
+
+   @Test
+   public void testReadWrite() throws Exception {
+       ChannelBuffer input = ChannelBuffers.copiedBuffer(${msg.constant_name}_SERIALIZED);
+
+       // FIXME should invoke the overall reader once implemented
+       ${var_type} ${var_name} = ${msg.name}.READER.readFrom(input);
+
+       // write message again
+       ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+       ${var_name}.writeTo(bb);
+       byte[] written = new byte[bb.readableBytes()];
+       bb.readBytes(written);
+
+       assertArrayEquals(${msg.constant_name}_SERIALIZED, written);
+   }
+
+}
diff --git a/loxi_front_end/frontend.py b/loxi_front_end/frontend.py
index d25c2eb..c093a95 100644
--- a/loxi_front_end/frontend.py
+++ b/loxi_front_end/frontend.py
@@ -46,6 +46,10 @@
             return OFFieldLengthMember(name=m_ast[2], oftype=m_ast[1], field_name='actions')
         else:
             return OFDataMember(name=m_ast[2], oftype=m_ast[1])
+    elif m_ast[0] == 'discriminator':
+        return OFDiscriminatorMember(name=m_ast[2], oftype=m_ast[1])
+    else:
+        raise InputError("Dont know how to create member: %s" % m_ast[0])
 
 def create_ofinput(ast):
     """
@@ -60,11 +64,31 @@
 
     for decl_ast in ast:
         if decl_ast[0] == 'struct':
-            members = [create_member(m_ast) for m_ast in decl_ast[3]]
-            ofclass = OFClass(name=decl_ast[1], superclass=decl_ast[2], members=members)
+            # 0: "struct"
+            # 1: name
+            # 2: potentially list of [param_name, param_value]
+            # 3: super_class or None
+            # 4: list of members
+            superclass = decl_ast[3]
+            members = [create_member(m_ast) for m_ast in decl_ast[4]]
+
+            discriminators = [ m for m in members if isinstance(m, OFDiscriminatorMember) ]
+            if len(discriminators) > 1:
+                raise InputError("%s: Cannot support more than one discriminator by class - got %s" %
+                        (decl_ast[1], repr(discriminators)))
+            ofclass = OFClass(name=decl_ast[1], members=members, superclass=superclass,
+                    virtual = len(discriminators) > 0,
+                    params = { param: value for param, value in decl_ast[2] })
             ofinput.classes.append(ofclass)
         if decl_ast[0] == 'enum':
-            enum = OFEnum(name=decl_ast[1], values=[(x[0], x[1]) for x in decl_ast[2]])
+            # 0: "enum"
+            # 1: name
+            # 2: potentially list of [param_name, param_value]
+            # 3: list of [constant_name, constant_value]+
+            enum = OFEnum(name=decl_ast[1],
+                    entries=[OFEnumEntry(name=x[0], value=x[2], params={param:value for param, value in x[1] }) for x in decl_ast[3]],
+                    params = { param: value for param, value in decl_ast[2] }
+                    )
             ofinput.enums.append(enum)
         elif decl_ast[0] == 'metadata':
             if decl_ast[1] == 'version':
diff --git a/loxi_front_end/parser.py b/loxi_front_end/parser.py
index 7893008..25bfde4 100644
--- a/loxi_front_end/parser.py
+++ b/loxi_front_end/parser.py
@@ -51,19 +51,36 @@
 
 # Structs
 pad_member = P.Group(kw('pad') - s('(') - integer - s(')'))
+discriminator_member = P.Group(tag('discriminator') + any_type + identifier + s('==') + s('?'))
 type_member = P.Group(tag('type') + any_type + identifier + s('==') + integer)
 data_member = P.Group(tag('data') + any_type - identifier)
-struct_member = pad_member | type_member | data_member;
+
+struct_param_name = kw("align")
+struct_param = P.Group(struct_param_name - s('=') - any_type)
+struct_param_list = P.Forward()
+struct_param_list << struct_param + P.Optional(s(',') - P.Optional(struct_param_list))
+
+struct_member = pad_member | type_member | discriminator_member | data_member;
 parent = (s(':') - identifier) | tag(None)
-struct = kw('struct') - identifier - parent - s('{') + \
+struct = kw('struct') - identifier - P.Group(P.Optional(s('(') - struct_param_list - s(')'))) - parent - s('{') + \
          P.Group(P.ZeroOrMore(struct_member - s(';'))) + \
          s('}') - s(';')
 
 # Enums
-enum_member = P.Group(identifier + s('=') + integer)
+enum_param_name = kw("wire_type") | kw("bitmask") | kw("complete")
+enum_param = P.Group(enum_param_name  - s('=') - any_type)
+enum_param_list = P.Forward()
+enum_param_list << enum_param + P.Optional(s(',') + P.Optional(enum_param_list))
+
+enum_member_param_name = kw("virtual")
+enum_member_param = P.Group(enum_member_param_name  - s('=') - any_type)
+enum_member_param_list = P.Forward()
+enum_member_param_list << enum_member_param + P.Optional(s(',') + P.Optional(enum_member_param_list))
+
+enum_member = P.Group(identifier - P.Group(P.Optional(s('(') - enum_member_param_list - s(')'))) - s('=') + integer)
 enum_list = P.Forward()
 enum_list << enum_member + P.Optional(s(',') + P.Optional(enum_list))
-enum = kw('enum') - identifier - s('{') + \
+enum = kw('enum') - identifier - P.Group(P.Optional(s('(') - enum_param_list - s(')'))) - s('{') + \
          P.Group(P.Optional(enum_list)) + \
          s('}') - s(';')
 
diff --git a/loxi_ir.py b/loxi_ir.py
index 824524b..7bbe22f 100644
--- a/loxi_ir.py
+++ b/loxi_ir.py
@@ -25,6 +25,7 @@
 # EPL for the specific language governing permissions and limitations
 # under the EPL.
 
+from generic_utils import find
 from collections import namedtuple
 
 # This module is intended to be imported like this: from loxi_ir import *
@@ -35,10 +36,12 @@
     'OFClass',
     'OFDataMember',
     'OFTypeMember',
+    'OFDiscriminatorMember',
     'OFLengthMember',
     'OFFieldLengthMember',
     'OFPadMember',
     'OFEnum',
+    'OFEnumEntry'
 ]
 
 """
@@ -70,9 +73,13 @@
 The members are in the same order as on the wire.
 
 @param name
+@param superclass name of the super class
 @param members List of *Member objects
+@param params optional dictionary of parameters
 """
-OFClass = namedtuple('OFClass', ['name', 'superclass', 'members'])
+class OFClass(namedtuple('OFClass', ['name', 'superclass', 'members', 'virtual', 'params'])):
+    def member_by_name(self, name):
+        return find(self.members, lambda m: hasattr(m, "name") and m.name == name)
 
 """
 Normal field
@@ -85,6 +92,16 @@
 OFDataMember = namedtuple('OFDataMember', ['name', 'oftype'])
 
 """
+Field that declares that this is an abstract super-class and
+that the sub classes will be discriminated based on this field.
+E.g., 'type' is the discriminator member of the abstract superclass
+of_action.
+
+@param name
+"""
+OFDiscriminatorMember = namedtuple('OFDiscriminatorMember', ['name', 'oftype'])
+
+"""
 Field used to determine the type of an OpenFlow object
 
 @param name
@@ -131,6 +148,13 @@
 All values are Python ints.
 
 @param name
-@param values List of (name, value) tuples in input order
+@param entries List of OFEnumEntry objects in input order
+@params dict of optional params. Currently defined:
+       - wire_type: the low_level type of the enum values (uint8,...)
 """
-OFEnum = namedtuple('OFEnum', ['name', 'values'])
+class OFEnum(namedtuple('OFEnum', ['name', 'entries', 'params'])):
+    @property
+    def values(self):
+        return [(e.name, e.value) for e in self.entries]
+
+OFEnumEntry = namedtuple('OFEnumEntry', ['name', 'value', 'params'])
diff --git a/loxigen.py b/loxigen.py
index 9bddf4b..dcd547e 100755
--- a/loxigen.py
+++ b/loxigen.py
@@ -447,10 +447,10 @@
                 versions[version_name]['classes'][ofclass.name] = legacy_members
 
             for enum in ofinput.enums:
-                for name, value in enum.values:
+                for entry in enum.entries:
                     identifiers.add_identifier(
-                        translation.loxi_name(name),
-                        name, enum.name, value, wire_version,
+                        translation.loxi_name(entry.name),
+                        entry.name, enum.name, entry.value, wire_version,
                         of_g.identifiers, of_g.identifiers_by_group)
 
         for wire_version, ofinputs in ofinputs_by_version.items():
diff --git a/openflow_input/bsn b/openflow_input/bsn
index 16f3323..0aa674b 100644
--- a/openflow_input/bsn
+++ b/openflow_input/bsn
@@ -34,7 +34,7 @@
     uint16_t length;
     uint32_t xid;
     uint32_t experimenter == 0x5c16c7;
-    uint32_t subtype;
+    uint32_t subtype == ?;
 };
 
 // BSN extension action
@@ -42,7 +42,7 @@
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter == 0x5c16c7;
-    uint32_t subtype;
+    uint32_t subtype == ?;
     pad(4);
 };
 
diff --git a/openflow_input/bsn_vport b/openflow_input/bsn_vport
index 4da4638..52f7c1d 100644
--- a/openflow_input/bsn_vport
+++ b/openflow_input/bsn_vport
@@ -38,14 +38,14 @@
 // When the ingress or egress VID has this value, no outer tag should be used.
 // In this case, the corresponding TPID is ignored.
 
-enum ofp_bsn_vport_q_in_q_untagged {
+enum ofp_bsn_vport_q_in_q_untagged(wire_type=uint16_t, complete=False) {
     OF_BSN_VPORT_Q_IN_Q_UNTAGGED = 0xffff,
 };
 
 // BSN Virtual port object header
 // FIXME For now, inheritance is not exercised.  See below.
 struct of_bsn_vport {
-    uint16_t type;  /* Discriminate virtual port type */
+    uint16_t type == ?;  /* Discriminate virtual port type */
     uint16_t length; /* Length in bytes of this structure with this header */
     /* Remainder of data is specific to the port type */
 };
diff --git a/openflow_input/nicira b/openflow_input/nicira
index f76be27..ba2048d 100644
--- a/openflow_input/nicira
+++ b/openflow_input/nicira
@@ -34,7 +34,7 @@
     uint16_t length;
     uint32_t xid;
     uint32_t experimenter == 0x2320;
-    uint32_t subtype;
+    uint32_t subtype == ?;
 };
 
 // Nicira extension action
@@ -42,7 +42,7 @@
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter == 0x2320;
-    uint16_t subtype;
+    uint16_t subtype == ?;
     pad(2);
     pad(4);
 };
diff --git a/openflow_input/oxm-1.2 b/openflow_input/oxm-1.2
index e75d218..5006cff 100644
--- a/openflow_input/oxm-1.2
+++ b/openflow_input/oxm-1.2
@@ -33,7 +33,7 @@
 #version 4
 
 struct of_oxm {
-    uint32_t type_len;
+    uint32_t type_len == ?;
 };
 
 struct of_oxm_arp_op : of_oxm {
diff --git a/openflow_input/standard-1.0 b/openflow_input/standard-1.0
index 64c60d5..d78d5bd 100644
--- a/openflow_input/standard-1.0
+++ b/openflow_input/standard-1.0
@@ -61,7 +61,7 @@
     OFPQ_MIN_RATE_UNCFG = 0xffff,
 };
 
-enum ofp_type {
+enum ofp_type(wire_type=uint8_t) {
     OFPT_HELLO = 0,
     OFPT_ERROR = 1,
     OFPT_ECHO_REQUEST = 2,
@@ -86,7 +86,7 @@
     OFPT_QUEUE_GET_CONFIG_REPLY = 21,
 };
 
-enum ofp_port_config {
+enum ofp_port_config(wire_type=uint32_t, bitmask=True) {
     OFPPC_PORT_DOWN = 0x1,
     OFPPC_NO_STP = 0x2,
     OFPPC_NO_RECV = 0x4,
@@ -96,16 +96,19 @@
     OFPPC_NO_PACKET_IN = 0x40,
 };
 
-enum ofp_port_state {
+enum ofp_port_state(wire_type=uint32_t, bitmask=True) {
     OFPPS_STP_LISTEN = 0,
     OFPPS_LINK_DOWN = 1,
     OFPPS_STP_LEARN = 0x100,
     OFPPS_STP_FORWARD = 0x200,
     OFPPS_STP_BLOCK = 0x300,
-    OFPPS_STP_MASK = 0x300,
+    OFPPS_STP_MASK(virtual=True) = 0x300,
 };
 
-enum ofp_port {
+// FIXME: these constants are currently 32 bit due to implementation
+// details of loci, which is in violation of the OpenFlow spec.
+// Should recast to 32 bits and fix/glue the c backend
+enum ofp_port(wire_type=uint16_t, complete=False) {
     OFPP_MAX = 0xffffff00,
     OFPP_IN_PORT = 0xfffffff8,
     OFPP_TABLE = 0xfffffff9,
@@ -117,7 +120,7 @@
     OFPP_NONE = 0xffffffff,
 };
 
-enum ofp_port_features {
+enum ofp_port_features(wire_type=uint32_t, bitmask=True) {
     OFPPF_10MB_HD = 0x1,
     OFPPF_10MB_FD = 0x2,
     OFPPF_100MB_HD = 0x4,
@@ -132,12 +135,12 @@
     OFPPF_PAUSE_ASYM = 0x800,
 };
 
-enum ofp_queue_properties {
+enum ofp_queue_properties(wire_type=uint32_t) {
     OFPQT_NONE = 0,
     OFPQT_MIN_RATE = 1,
 };
 
-enum ofp_flow_wildcards {
+enum ofp_flow_wildcards(wire_type=uint32_t, bitmask=True) {
     OFPFW_IN_PORT = 0x1,
     OFPFW_DL_VLAN = 0x2,
     OFPFW_DL_SRC = 0x4,
@@ -159,7 +162,7 @@
     OFPFW_ALL = 0x3fffff,
 };
 
-enum ofp_action_type {
+enum ofp_action_type(wire_type=uint16_t) {
     OFPAT_OUTPUT = 0,
     OFPAT_SET_VLAN_VID = 1,
     OFPAT_SET_VLAN_PCP = 2,
@@ -175,7 +178,7 @@
     OFPAT_VENDOR = 0xffff,
 };
 
-enum ofp_capabilities {
+enum ofp_capabilities(wire_type=uint32_t, bitmask=True) {
     OFPC_FLOW_STATS = 0x1,
     OFPC_TABLE_STATS = 0x2,
     OFPC_PORT_STATS = 0x4,
@@ -186,14 +189,14 @@
     OFPC_ARP_MATCH_IP = 0x80,
 };
 
-enum ofp_config_flags {
+enum ofp_config_flags(wire_type=uint32_t, bitmask=True) {
     OFPC_FRAG_NORMAL = 0x0,
     OFPC_FRAG_DROP = 0x1,
     OFPC_FRAG_REASM = 0x2,
     OFPC_FRAG_MASK = 0x3,
 };
 
-enum ofp_flow_mod_command {
+enum ofp_flow_mod_command(wire_type=uint16_t) {
     OFPFC_ADD = 0,
     OFPFC_MODIFY = 1,
     OFPFC_MODIFY_STRICT = 2,
@@ -201,17 +204,17 @@
     OFPFC_DELETE_STRICT = 4,
 };
 
-enum ofp_flow_mod_flags {
+enum ofp_flow_mod_flags(wire_type=uint16_t, bitmask=True) {
     OFPFF_SEND_FLOW_REM = 0x1,
     OFPFF_CHECK_OVERLAP = 0x2,
     OFPFF_EMERG = 0x4,
 };
 
-enum ofp_stats_reply_flags {
+enum ofp_stats_reply_flags(wire_type=uint16_t, bitmask=True) {
     OFPSF_REPLY_MORE = 0x1,
 };
 
-enum ofp_stats_types {
+enum ofp_stats_types(wire_type=uint16_t) {
     OFPST_DESC = 0,
     OFPST_FLOW = 1,
     OFPST_AGGREGATE = 2,
@@ -221,24 +224,24 @@
     OFPST_VENDOR = 0xffff,
 };
 
-enum ofp_packet_in_reason {
+enum ofp_packet_in_reason(wire_type=uint8_t) {
     OFPR_NO_MATCH = 0,
     OFPR_ACTION = 1,
 };
 
-enum ofp_flow_removed_reason {
+enum ofp_flow_removed_reason(wire_type=uint8_t) {
     OFPRR_IDLE_TIMEOUT = 0,
     OFPRR_HARD_TIMEOUT = 1,
     OFPRR_DELETE = 2,
 };
 
-enum ofp_port_reason {
+enum ofp_port_reason(wire_type=uint8_t) {
     OFPPR_ADD = 0,
     OFPPR_DELETE = 1,
     OFPPR_MODIFY = 2,
 };
 
-enum ofp_error_type {
+enum ofp_error_type(wire_type=uint16_t) {
     OFPET_HELLO_FAILED = 0,
     OFPET_BAD_REQUEST = 1,
     OFPET_BAD_ACTION = 2,
@@ -247,12 +250,12 @@
     OFPET_QUEUE_OP_FAILED = 5,
 };
 
-enum ofp_hello_failed_code {
+enum ofp_hello_failed_code(wire_type=uint16_t) {
     OFPHFC_INCOMPATIBLE = 0,
     OFPHFC_EPERM = 1,
 };
 
-enum ofp_bad_request_code {
+enum ofp_bad_request_code(wire_type=uint16_t) {
     OFPBRC_BAD_VERSION = 0,
     OFPBRC_BAD_TYPE = 1,
     OFPBRC_BAD_STAT = 2,
@@ -264,7 +267,7 @@
     OFPBRC_BUFFER_UNKNOWN = 8,
 };
 
-enum ofp_bad_action_code {
+enum ofp_bad_action_code(wire_type=uint16_t) {
     OFPBAC_BAD_TYPE = 0,
     OFPBAC_BAD_LEN = 1,
     OFPBAC_BAD_VENDOR = 2,
@@ -276,7 +279,7 @@
     OFPBAC_BAD_QUEUE = 8,
 };
 
-enum ofp_flow_mod_failed_code {
+enum ofp_flow_mod_failed_code(wire_type=uint16_t) {
     OFPFMFC_ALL_TABLES_FULL = 0,
     OFPFMFC_OVERLAP = 1,
     OFPFMFC_EPERM = 2,
@@ -285,12 +288,12 @@
     OFPFMFC_UNSUPPORTED = 5,
 };
 
-enum ofp_port_mod_failed_code {
+enum ofp_port_mod_failed_code(wire_type=uint16_t) {
     OFPPMFC_BAD_PORT = 0,
     OFPPMFC_BAD_HW_ADDR = 1,
 };
 
-enum ofp_queue_op_failed_code {
+enum ofp_queue_op_failed_code(wire_type=uint16_t) {
     OFPQOFC_BAD_PORT = 0,
     OFPQOFC_BAD_QUEUE = 1,
     OFPQOFC_EPERM = 2,
@@ -299,7 +302,7 @@
 /* XXX rename to of_message */
 struct of_header {
     uint8_t version;
-    uint8_t type;
+    uint8_t type == ?;
     uint16_t length;
     uint32_t xid;
 };
@@ -535,7 +538,7 @@
 };
 
 struct of_action {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
@@ -577,7 +580,7 @@
     uint32_t xid;
     of_match_t match;
     uint64_t cookie;
-    of_fm_cmd_t _command;
+    of_fm_cmd_t _command == ?;
     uint16_t idle_timeout;
     uint16_t hard_timeout;
     uint16_t priority;
@@ -762,7 +765,7 @@
     uint8_t type == 16;
     uint16_t length;
     uint32_t xid;
-    uint16_t stats_type;
+    uint16_t stats_type == ?;
     uint16_t flags;
 };
 
@@ -771,7 +774,7 @@
     uint8_t type == 17;
     uint16_t length;
     uint32_t xid;
-    uint16_t stats_type;
+    uint16_t stats_type == ?;
     uint16_t flags;
 };
 
@@ -934,7 +937,7 @@
 // END OF STATS OBJECTS
 
 struct of_queue_prop {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
diff --git a/openflow_input/standard-1.1 b/openflow_input/standard-1.1
index 4366af8..1047127 100644
--- a/openflow_input/standard-1.1
+++ b/openflow_input/standard-1.1
@@ -63,7 +63,7 @@
     OFPQ_MIN_RATE_UNCFG = 0xffff,
 };
 
-enum ofp_port {
+enum ofp_port(wire_type=uint32_t) {
     OFPP_MAX = 0xffffff00,
     OFPP_IN_PORT = 0xfffffff8,
     OFPP_TABLE = 0xfffffff9,
@@ -74,11 +74,11 @@
     OFPP_LOCAL = 0xfffffffe,
 };
 
-enum ofp_port_no {
+enum ofp_port_no(wire_type=uint32_t, complete=False) {
     OFPP_ANY = 0xffffffff,
 };
 
-enum ofp_type {
+enum ofp_type(wire_type=uint8_t) {
     OFPT_HELLO = 0,
     OFPT_ERROR = 1,
     OFPT_ECHO_REQUEST = 2,
@@ -105,22 +105,22 @@
     OFPT_QUEUE_GET_CONFIG_REPLY = 23,
 };
 
-enum ofp_config_flags {
+enum ofp_config_flags(wire_type=uint16_t, bitmask=True) {
     OFPC_FRAG_NORMAL = 0,
     OFPC_FRAG_DROP = 1,
     OFPC_FRAG_REASM = 2,
-    OFPC_FRAG_MASK = 3,
+    OFPC_FRAG_MASK(virtual=True) = 3,
     OFPC_INVALID_TTL_TO_CONTROLLER = 4,
 };
 
-enum ofp_table_config {
+enum ofp_table_config(wire_type=uint32_t, bitmask=True) {
     OFPTC_TABLE_MISS_CONTROLLER = 0,
     OFPTC_TABLE_MISS_CONTINUE = 1,
     OFPTC_TABLE_MISS_DROP = 2,
-    OFPTC_TABLE_MISS_MASK = 3,
+    OFPTC_TABLE_MISS_MASK(virtual=True) = 3,
 };
 
-enum ofp_capabilities {
+enum ofp_capabilities(wire_type=uint32_t, bitmask=True) {
     OFPC_FLOW_STATS = 0x1,
     OFPC_TABLE_STATS = 0x2,
     OFPC_PORT_STATS = 0x4,
@@ -130,20 +130,20 @@
     OFPC_ARP_MATCH_IP = 0x80,
 };
 
-enum ofp_port_config {
+enum ofp_port_config(wire_type=uint32_t, bitmask=True) {
     OFPPC_PORT_DOWN = 0x1,
     OFPPC_NO_RECV = 0x4,
     OFPPC_NO_FWD = 0x20,
     OFPPC_NO_PACKET_IN = 0x40,
 };
 
-enum ofp_port_state {
+enum ofp_port_state(wire_type=uint32_t, bitmask=True) {
     OFPPS_LINK_DOWN = 0x1,
     OFPPS_BLOCKED = 0x2,
     OFPPS_LIVE = 0x4,
 };
 
-enum ofp_port_features {
+enum ofp_port_features(wire_type=uint32_t, bitmask=True) {
     OFPPF_10MB_HD = 0x1,
     OFPPF_10MB_FD = 0x2,
     OFPPF_100MB_HD = 0x4,
@@ -162,18 +162,18 @@
     OFPPF_PAUSE_ASYM = 0x8000,
 };
 
-enum ofp_port_reason {
+enum ofp_port_reason(wire_type=uint8_t) {
     OFPPR_ADD = 0,
     OFPPR_DELETE = 1,
     OFPPR_MODIFY = 2,
 };
 
-enum ofp_packet_in_reason {
+enum ofp_packet_in_reason(wire_type=uint8_t) {
     OFPR_NO_MATCH = 0,
     OFPR_ACTION = 1,
 };
 
-enum ofp_action_type {
+enum ofp_action_type(wire_type=uint16_t) {
     OFPAT_OUTPUT = 0,
     OFPAT_SET_VLAN_VID = 1,
     OFPAT_SET_VLAN_PCP = 2,
@@ -202,7 +202,7 @@
     OFPAT_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_flow_mod_command {
+enum ofp_flow_mod_command(wire_type=uint8_t) {
     OFPFC_ADD = 0,
     OFPFC_MODIFY = 1,
     OFPFC_MODIFY_STRICT = 2,
@@ -210,13 +210,13 @@
     OFPFC_DELETE_STRICT = 4,
 };
 
-enum ofp_group_mod_command {
+enum ofp_group_mod_command(wire_type=uint16_t) {
     OFPGC_ADD = 0,
     OFPGC_MODIFY = 1,
     OFPGC_DELETE = 2,
 };
 
-enum ofp_flow_wildcards {
+enum ofp_flow_wildcards(wire_type=uint32_t, bitmask=True) {
     OFPFW_IN_PORT = 0x1,
     OFPFW_DL_VLAN = 0x2,
     OFPFW_DL_VLAN_PCP = 0x4,
@@ -227,19 +227,19 @@
     OFPFW_TP_DST = 0x80,
     OFPFW_MPLS_LABEL = 0x100,
     OFPFW_MPLS_TC = 0x200,
-    OFPFW_ALL = 0x3ff,
+    OFPFW_ALL(virtual=True) = 0x3ff,
 };
 
-enum ofp_vlan_id {
+enum ofp_vlan_id(wire_type=uint16_t) {
     OFPVID_ANY = 0xfffe,
     OFPVID_NONE = 0xffff,
 };
 
-enum ofp_match_type {
+enum ofp_match_type(wire_type=uint16_t) {
     OFPMT_STANDARD = 0,
 };
 
-enum ofp_instruction_type {
+enum ofp_instruction_type(wire_type=uint16_t, bitmask=True) {
     OFPIT_GOTO_TABLE = 0x1,
     OFPIT_WRITE_METADATA = 0x2,
     OFPIT_WRITE_ACTIONS = 0x3,
@@ -248,32 +248,32 @@
     OFPIT_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_flow_mod_flags {
+enum ofp_flow_mod_flags(wire_type=uint16_t, bitmask=True) {
     OFPFF_SEND_FLOW_REM = 0x1,
     OFPFF_CHECK_OVERLAP = 0x2,
 };
 
-enum ofp_group {
+enum ofp_group(wire_type=uint32_t, complete=False) {
     OFPG_MAX = 0xffffff00,
     OFPG_ALL = 0xfffffffc,
     OFPG_ANY = 0xffffffff,
 };
 
-enum ofp_group_type {
+enum ofp_group_type(wire_type=uint8_t) {
     OFPGT_ALL = 0,
     OFPGT_SELECT = 1,
     OFPGT_INDIRECT = 2,
     OFPGT_FF = 3,
 };
 
-enum ofp_flow_removed_reason {
+enum ofp_flow_removed_reason(wire_type=uint8_t) {
     OFPRR_IDLE_TIMEOUT = 0,
     OFPRR_HARD_TIMEOUT = 1,
     OFPRR_DELETE = 2,
     OFPRR_GROUP_DELETE = 3,
 };
 
-enum ofp_error_type {
+enum ofp_error_type(wire_type=uint16_t) {
     OFPET_HELLO_FAILED = 0,
     OFPET_BAD_REQUEST = 1,
     OFPET_BAD_ACTION = 2,
@@ -287,12 +287,12 @@
     OFPET_SWITCH_CONFIG_FAILED = 10,
 };
 
-enum ofp_hello_failed_code {
+enum ofp_hello_failed_code(wire_type=uint16_t) {
     OFPHFC_INCOMPATIBLE = 0,
     OFPHFC_EPERM = 1,
 };
 
-enum ofp_bad_request_code {
+enum ofp_bad_request_code(wire_type=uint16_t) {
     OFPBRC_BAD_VERSION = 0,
     OFPBRC_BAD_TYPE = 1,
     OFPBRC_BAD_STAT = 2,
@@ -305,7 +305,7 @@
     OFPBRC_BAD_TABLE_ID = 9,
 };
 
-enum ofp_bad_action_code {
+enum ofp_bad_action_code(wire_type=uint16_t) {
     OFPBAC_BAD_TYPE = 0,
     OFPBAC_BAD_LEN = 1,
     OFPBAC_BAD_EXPERIMENTER = 2,
@@ -321,7 +321,7 @@
     OFPBAC_BAD_TAG = 12,
 };
 
-enum ofp_bad_instruction_code {
+enum ofp_bad_instruction_code(wire_type=uint16_t) {
     OFPBIC_UNKNOWN_INST = 0,
     OFPBIC_UNSUP_INST = 1,
     OFPBIC_BAD_TABLE_ID = 2,
@@ -330,7 +330,7 @@
     OFPBIC_UNSUP_EXP_INST = 5,
 };
 
-enum ofp_bad_match_code {
+enum ofp_bad_match_code(wire_type=uint16_t) {
     OFPBMC_BAD_TYPE = 0,
     OFPBMC_BAD_LEN = 1,
     OFPBMC_BAD_TAG = 2,
@@ -341,7 +341,7 @@
     OFPBMC_BAD_VALUE = 7,
 };
 
-enum ofp_flow_mod_failed_code {
+enum ofp_flow_mod_failed_code(wire_type=uint16_t) {
     OFPFMFC_UNKNOWN = 0,
     OFPFMFC_TABLE_FULL = 1,
     OFPFMFC_BAD_TABLE_ID = 2,
@@ -351,7 +351,7 @@
     OFPFMFC_BAD_COMMAND = 6,
 };
 
-enum ofp_group_mod_failed_code {
+enum ofp_group_mod_failed_code(wire_type=uint16_t) {
     OFPGMFC_GROUP_EXISTS = 0,
     OFPGMFC_INVALID_GROUP = 1,
     OFPGMFC_WEIGHT_UNSUPPORTED = 2,
@@ -363,30 +363,30 @@
     OFPGMFC_UNKNOWN_GROUP = 8,
 };
 
-enum ofp_port_mod_failed_code {
+enum ofp_port_mod_failed_code(wire_type=uint16_t) {
     OFPPMFC_BAD_PORT = 0,
     OFPPMFC_BAD_HW_ADDR = 1,
     OFPPMFC_BAD_CONFIG = 2,
     OFPPMFC_BAD_ADVERTISE = 3,
 };
 
-enum ofp_table_mod_failed_code {
+enum ofp_table_mod_failed_code(wire_type=uint16_t) {
     OFPTMFC_BAD_TABLE = 0,
     OFPTMFC_BAD_CONFIG = 1,
 };
 
-enum ofp_queue_op_failed_code {
+enum ofp_queue_op_failed_code(wire_type=uint16_t) {
     OFPQOFC_BAD_PORT = 0,
     OFPQOFC_BAD_QUEUE = 1,
     OFPQOFC_EPERM = 2,
 };
 
-enum ofp_switch_config_failed_code {
+enum ofp_switch_config_failed_code(wire_type=uint16_t) {
     OFPSCFC_BAD_FLAGS = 0,
     OFPSCFC_BAD_LEN = 1,
 };
 
-enum ofp_stats_types {
+enum ofp_stats_types(wire_type=uint16_t) {
     OFPST_DESC = 0,
     OFPST_FLOW = 1,
     OFPST_AGGREGATE = 2,
@@ -398,11 +398,11 @@
     OFPST_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_stats_reply_flags {
+enum ofp_stats_reply_flags(wire_type=uint16_t, bitmask=True) {
     OFPSF_REPLY_MORE = 0x1,
 };
 
-enum ofp_queue_properties {
+enum ofp_queue_properties(wire_type=uint16_t) {
     OFPQT_NONE = 0,
     OFPQT_MIN_RATE = 1,
 };
@@ -410,7 +410,7 @@
 /* XXX rename to of_message */
 struct of_header {
     uint8_t version;
-    uint8_t type;
+    uint8_t type == ?;
     uint16_t length;
     uint32_t xid;
 };
@@ -747,7 +747,7 @@
 };
 
 struct of_action {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
@@ -794,7 +794,7 @@
 };
 
 struct of_instruction {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
@@ -849,7 +849,7 @@
     uint64_t cookie;
     uint64_t cookie_mask;
     uint8_t table_id;
-    of_fm_cmd_t _command;
+    of_fm_cmd_t _command == ?;
     uint16_t idle_timeout;
     uint16_t hard_timeout;
     uint16_t priority;
@@ -1107,7 +1107,7 @@
     uint8_t type == 18;
     uint16_t length;
     uint32_t xid;
-    uint16_t stats_type;
+    uint16_t stats_type == ?;
     uint16_t flags;
     pad(4);
 };
@@ -1117,7 +1117,7 @@
     uint8_t type == 19;
     uint16_t length;
     uint32_t xid;
-    uint16_t stats_type;
+    uint16_t stats_type == ?;
     uint16_t flags;
     pad(4);
 };
@@ -1348,7 +1348,7 @@
 // END OF STATS OBJECTS
 
 struct of_queue_prop {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
diff --git a/openflow_input/standard-1.2 b/openflow_input/standard-1.2
index b49c83f..e4c8ec2 100644
--- a/openflow_input/standard-1.2
+++ b/openflow_input/standard-1.2
@@ -59,7 +59,7 @@
     OFPQ_MAX_RATE_UNCFG = 0xffff,
 };
 
-enum ofp_port {
+enum ofp_port(wire_type=uint32_t) {
     OFPP_MAX = 0xffffff00,
     OFPP_IN_PORT = 0xfffffff8,
     OFPP_TABLE = 0xfffffff9,
@@ -70,11 +70,11 @@
     OFPP_LOCAL = 0xfffffffe,
 };
 
-enum ofp_port_no {
+enum ofp_port_no(wire_type=uint32_t, complete=False) {
     OFPP_ANY = 0xffffffff,
 };
 
-enum ofp_type {
+enum ofp_type(wire_type=uint8_t) {
     OFPT_HELLO = 0,
     OFPT_ERROR = 1,
     OFPT_ECHO_REQUEST = 2,
@@ -103,7 +103,7 @@
     OFPT_ROLE_REPLY = 25,
 };
 
-enum ofp_config_flags {
+enum ofp_config_flags(wire_type=uint16_t, bitmask=True) {
     OFPC_FRAG_NORMAL = 0,
     OFPC_FRAG_DROP = 1,
     OFPC_FRAG_REASM = 2,
@@ -111,19 +111,19 @@
     OFPC_INVALID_TTL_TO_CONTROLLER = 4,
 };
 
-enum ofp_table_config {
+enum ofp_table_config(wire_type=uint32_t, bitmask=True) {
     OFPTC_TABLE_MISS_CONTROLLER = 0,
     OFPTC_TABLE_MISS_CONTINUE = 1,
     OFPTC_TABLE_MISS_DROP = 2,
     OFPTC_TABLE_MISS_MASK = 3,
 };
 
-enum ofp_table {
+enum ofp_table(wire_type=uint8_t, complete=False) {
     OFPTT_MAX = 0xfe,
     OFPTT_ALL = 0xff,
 };
 
-enum ofp_capabilities {
+enum ofp_capabilities(wire_type=uint32_t, bitmask=True) {
     OFPC_FLOW_STATS = 0x1,
     OFPC_TABLE_STATS = 0x2,
     OFPC_PORT_STATS = 0x4,
@@ -133,20 +133,20 @@
     OFPC_PORT_BLOCKED = 0x100,
 };
 
-enum ofp_port_config {
+enum ofp_port_config(wire_type=uint32_t, bitmask=True) {
     OFPPC_PORT_DOWN = 0x1,
     OFPPC_NO_RECV = 0x4,
     OFPPC_NO_FWD = 0x20,
     OFPPC_NO_PACKET_IN = 0x40,
 };
 
-enum ofp_port_state {
+enum ofp_port_state(wire_type=uint32_t, bitmask=True) {
     OFPPS_LINK_DOWN = 0x1,
     OFPPS_BLOCKED = 0x2,
     OFPPS_LIVE = 0x4,
 };
 
-enum ofp_port_features {
+enum ofp_port_features(wire_type=uint32_t, bitmask=True) {
     OFPPF_10MB_HD = 0x1,
     OFPPF_10MB_FD = 0x2,
     OFPPF_100MB_HD = 0x4,
@@ -165,30 +165,30 @@
     OFPPF_PAUSE_ASYM = 0x8000,
 };
 
-enum ofp_port_reason {
+enum ofp_port_reason(wire_type=uint8_t) {
     OFPPR_ADD = 0,
     OFPPR_DELETE = 1,
     OFPPR_MODIFY = 2,
 };
 
-enum ofp_match_type {
+enum ofp_match_type(wire_type=uint16_t) {
     OFPMT_STANDARD = 0,
     OFPMT_OXM = 1,
 };
 
-enum ofp_oxm_class {
+enum ofp_oxm_class(wire_type=uint16_t) {
     OFPXMC_NXM_0 = 0,
     OFPXMC_NXM_1 = 1,
     OFPXMC_OPENFLOW_BASIC = 0x8000,
     OFPXMC_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_vlan_id {
+enum ofp_vlan_id(wire_type=uint16_t) {
     OFPVID_NONE = 0,
     OFPVID_PRESENT = 0x1000,
 };
 
-enum ofp_action_type {
+enum ofp_action_type(wire_type=uint16_t) {
     OFPAT_OUTPUT = 0,
     OFPAT_COPY_TTL_OUT = 0xb,
     OFPAT_COPY_TTL_IN = 0xc,
@@ -206,12 +206,12 @@
     OFPAT_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_controller_max_len {
+enum ofp_controller_max_len(wire_type=uint16_t, complete=False) {
     OFPCML_MAX = 0xffe5,
     OFPCML_NO_BUFFER = 0xffff,
 };
 
-enum ofp_instruction_type {
+enum ofp_instruction_type(wire_type=uint16_t, bitmask=True) {
     OFPIT_GOTO_TABLE = 0x1,
     OFPIT_WRITE_METADATA = 0x2,
     OFPIT_WRITE_ACTIONS = 0x3,
@@ -220,7 +220,7 @@
     OFPIT_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_flow_mod_command {
+enum ofp_flow_mod_command(wire_type=uint8_t) {
     OFPFC_ADD = 0,
     OFPFC_MODIFY = 1,
     OFPFC_MODIFY_STRICT = 2,
@@ -228,45 +228,45 @@
     OFPFC_DELETE_STRICT = 4,
 };
 
-enum ofp_flow_mod_flags {
+enum ofp_flow_mod_flags(wire_type=uint16_t, bitmask=True) {
     OFPFF_SEND_FLOW_REM = 0x1,
     OFPFF_CHECK_OVERLAP = 0x2,
     OFPFF_RESET_COUNTS = 0x4,
 };
 
-enum ofp_group {
+enum ofp_group(wire_type=uint32_t, complete=False) {
     OFPG_MAX = 0xffffff00,
     OFPG_ALL = 0xfffffffc,
     OFPG_ANY = 0xffffffff,
 };
 
-enum ofp_group_mod_command {
+enum ofp_group_mod_command(wire_type=uint16_t) {
     OFPGC_ADD = 0,
     OFPGC_MODIFY = 1,
     OFPGC_DELETE = 2,
 };
 
-enum ofp_group_type {
+enum ofp_group_type(wire_type=uint8_t) {
     OFPGT_ALL = 0,
     OFPGT_SELECT = 1,
     OFPGT_INDIRECT = 2,
     OFPGT_FF = 3,
 };
 
-enum ofp_packet_in_reason {
+enum ofp_packet_in_reason(wire_type=uint8_t) {
     OFPR_NO_MATCH = 0,
     OFPR_ACTION = 1,
     OFPR_INVALID_TTL = 2,
 };
 
-enum ofp_flow_removed_reason {
+enum ofp_flow_removed_reason(wire_type=uint8_t) {
     OFPRR_IDLE_TIMEOUT = 0,
     OFPRR_HARD_TIMEOUT = 1,
     OFPRR_DELETE = 2,
     OFPRR_GROUP_DELETE = 3,
 };
 
-enum ofp_error_type {
+enum ofp_error_type(wire_type=uint16_t) {
     OFPET_HELLO_FAILED = 0,
     OFPET_BAD_REQUEST = 1,
     OFPET_BAD_ACTION = 2,
@@ -282,12 +282,12 @@
     OFPET_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_hello_failed_code {
+enum ofp_hello_failed_code(wire_type=uint16_t) {
     OFPHFC_INCOMPATIBLE = 0,
     OFPHFC_EPERM = 1,
 };
 
-enum ofp_bad_request_code {
+enum ofp_bad_request_code(wire_type=uint16_t) {
     OFPBRC_BAD_VERSION = 0,
     OFPBRC_BAD_TYPE = 1,
     OFPBRC_BAD_STAT = 2,
@@ -303,7 +303,7 @@
     OFPBRC_BAD_PACKET = 12,
 };
 
-enum ofp_bad_action_code {
+enum ofp_bad_action_code(wire_type=uint16_t) {
     OFPBAC_BAD_TYPE = 0,
     OFPBAC_BAD_LEN = 1,
     OFPBAC_BAD_EXPERIMENTER = 2,
@@ -322,7 +322,7 @@
     OFPBAC_BAD_SET_ARGUMENT = 15,
 };
 
-enum ofp_bad_instruction_code {
+enum ofp_bad_instruction_code(wire_type=uint16_t) {
     OFPBIC_UNKNOWN_INST = 0,
     OFPBIC_UNSUP_INST = 1,
     OFPBIC_BAD_TABLE_ID = 2,
@@ -334,7 +334,7 @@
     OFPBIC_EPERM = 8,
 };
 
-enum ofp_bad_match_code {
+enum ofp_bad_match_code(wire_type=uint16_t) {
     OFPBMC_BAD_TYPE = 0,
     OFPBMC_BAD_LEN = 1,
     OFPBMC_BAD_TAG = 2,
@@ -349,7 +349,7 @@
     OFPBMC_EPERM = 11,
 };
 
-enum ofp_flow_mod_failed_code {
+enum ofp_flow_mod_failed_code(wire_type=uint16_t) {
     OFPFMFC_UNKNOWN = 0,
     OFPFMFC_TABLE_FULL = 1,
     OFPFMFC_BAD_TABLE_ID = 2,
@@ -360,7 +360,7 @@
     OFPFMFC_BAD_FLAGS = 7,
 };
 
-enum ofp_group_mod_failed_code {
+enum ofp_group_mod_failed_code(wire_type=uint16_t) {
     OFPGMFC_GROUP_EXISTS = 0,
     OFPGMFC_INVALID_GROUP = 1,
     OFPGMFC_WEIGHT_UNSUPPORTED = 2,
@@ -378,7 +378,7 @@
     OFPGMFC_EPERM = 14,
 };
 
-enum ofp_port_mod_failed_code {
+enum ofp_port_mod_failed_code(wire_type=uint16_t) {
     OFPPMFC_BAD_PORT = 0,
     OFPPMFC_BAD_HW_ADDR = 1,
     OFPPMFC_BAD_CONFIG = 2,
@@ -386,31 +386,31 @@
     OFPPMFC_EPERM = 4,
 };
 
-enum ofp_table_mod_failed_code {
+enum ofp_table_mod_failed_code(wire_type=uint16_t) {
     OFPTMFC_BAD_TABLE = 0,
     OFPTMFC_BAD_CONFIG = 1,
     OFPTMFC_EPERM = 2,
 };
 
-enum ofp_queue_op_failed_code {
+enum ofp_queue_op_failed_code(wire_type=uint16_t) {
     OFPQOFC_BAD_PORT = 0,
     OFPQOFC_BAD_QUEUE = 1,
     OFPQOFC_EPERM = 2,
 };
 
-enum ofp_switch_config_failed_code {
+enum ofp_switch_config_failed_code(wire_type=uint16_t) {
     OFPSCFC_BAD_FLAGS = 0,
     OFPSCFC_BAD_LEN = 1,
     OFPSCFC_EPERM = 2,
 };
 
-enum ofp_role_request_failed_code {
+enum ofp_role_request_failed_code (wire_type=uint16_t){
     OFPRRFC_STALE = 0,
     OFPRRFC_UNSUP = 1,
     OFPRRFC_BAD_ROLE = 2,
 };
 
-enum ofp_stats_types {
+enum ofp_stats_types(wire_type=uint16_t) {
     OFPST_DESC = 0,
     OFPST_FLOW = 1,
     OFPST_AGGREGATE = 2,
@@ -423,24 +423,24 @@
     OFPST_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_stats_reply_flags {
+enum ofp_stats_reply_flags(wire_type=uint16_t, bitmask=True) {
     OFPSF_REPLY_MORE = 0x1,
 };
 
-enum ofp_group_capabilities {
+enum ofp_group_capabilities(wire_type=uint32_t, bitmask=True) {
     OFPGFC_SELECT_WEIGHT = 0x1,
     OFPGFC_SELECT_LIVENESS = 0x2,
     OFPGFC_CHAINING = 0x4,
     OFPGFC_CHAINING_CHECKS = 0x8,
 };
 
-enum ofp_queue_properties {
+enum ofp_queue_properties(wire_type=uint16_t) {
     OFPQT_MIN_RATE = 0x1,
     OFPQT_MAX_RATE = 0x2,
     OFPQT_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_controller_role {
+enum ofp_controller_role(wire_type=uint32_t) {
     OFPCR_ROLE_NOCHANGE = 0,
     OFPCR_ROLE_EQUAL = 1,
     OFPCR_ROLE_MASTER = 2,
@@ -450,7 +450,7 @@
 /* XXX rename to of_message */
 struct of_header {
     uint8_t version;
-    uint8_t type;
+    uint8_t type == ?;
     uint16_t length;
     uint32_t xid;
 };
@@ -599,7 +599,7 @@
     pad(4);
 };
 
-struct of_match_v3 {
+struct of_match_v3(align=8) {
     uint16_t type == 1;
     uint16_t length;
     list(of_oxm_t) oxm_list;
@@ -704,13 +704,13 @@
 };
 
 struct of_action {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
 
 struct of_instruction {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
@@ -765,7 +765,7 @@
     uint64_t cookie;
     uint64_t cookie_mask;
     uint8_t table_id;
-    of_fm_cmd_t _command;
+    of_fm_cmd_t _command == ?;
     uint16_t idle_timeout;
     uint16_t hard_timeout;
     uint16_t priority;
@@ -1067,7 +1067,7 @@
     uint8_t type == 18;
     uint16_t length;
     uint32_t xid;
-    uint16_t stats_type;
+    uint16_t stats_type == ?;
     uint16_t flags;
     pad(4);
 };
@@ -1077,7 +1077,7 @@
     uint8_t type == 19;
     uint16_t length;
     uint32_t xid;
-    uint16_t stats_type;
+    uint16_t stats_type == ?;
     uint16_t flags;
     pad(4);
 };
@@ -1338,7 +1338,7 @@
 // END OF STATS OBJECTS
 
 struct of_queue_prop {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index ab32abe..b9c5475 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -58,11 +58,11 @@
     OFPQ_MIN_RATE_UNCFG = 0xffff,
 };
 
-enum ofp_port_no {
+enum ofp_port_no(wire_type=uint32_t, complete=False) {
     OFPP_ANY = 0xffffffff,
 };
 
-enum ofp_port {
+enum ofp_port(wire_type=uint32_t) {
     OFPP_MAX = 0xffffff00,
     OFPP_IN_PORT = 0xfffffff8,
     OFPP_TABLE = 0xfffffff9,
@@ -73,7 +73,7 @@
     OFPP_LOCAL = 0xfffffffe,
 };
 
-enum ofp_type {
+enum ofp_type(wire_type=uint8_t) {
     OFPT_HELLO = 0,
     OFPT_ERROR = 1,
     OFPT_ECHO_REQUEST = 2,
@@ -106,23 +106,23 @@
     OFPT_METER_MOD = 29,
 };
 
-enum ofp_config_flags {
+enum ofp_config_flags(wire_type=uint16_t, bitmask=True) {
     OFPC_FRAG_NORMAL = 0,
     OFPC_FRAG_DROP = 1,
     OFPC_FRAG_REASM = 2,
     OFPC_FRAG_MASK = 3,
 };
 
-enum ofp_table_config {
+enum ofp_table_config(wire_type=uint32_t, bitmask=True) {
     OFPTC_DEPRECATED_MASK = 0x3,
 };
 
-enum ofp_table {
+enum ofp_table(wire_type=uint8_t, complete=False) {
     OFPTT_MAX = 0xfe,
     OFPTT_ALL = 0xff,
 };
 
-enum ofp_capabilities {
+enum ofp_capabilities(wire_type=uint32_t, bitmask=True) {
     OFPC_FLOW_STATS = 0x1,
     OFPC_TABLE_STATS = 0x2,
     OFPC_PORT_STATS = 0x4,
@@ -132,20 +132,20 @@
     OFPC_PORT_BLOCKED = 0x100,
 };
 
-enum ofp_port_config {
+enum ofp_port_config(wire_type=uint32_t, bitmask=True) {
     OFPPC_PORT_DOWN = 0x1,
     OFPPC_NO_RECV = 0x4,
     OFPPC_NO_FWD = 0x20,
     OFPPC_NO_PACKET_IN = 0x40,
 };
 
-enum ofp_port_state {
+enum ofp_port_state(wire_type=uint32_t, bitmask=True) {
     OFPPS_LINK_DOWN = 0x1,
     OFPPS_BLOCKED = 0x2,
     OFPPS_LIVE = 0x4,
 };
 
-enum ofp_port_features {
+enum ofp_port_features(wire_type=uint32_t, bitmask=True) {
     OFPPF_10MB_HD = 0x1,
     OFPPF_10MB_FD = 0x2,
     OFPPF_100MB_HD = 0x4,
@@ -164,30 +164,32 @@
     OFPPF_PAUSE_ASYM = 0x8000,
 };
 
-enum ofp_port_reason {
+enum ofp_port_reason(wire_type=uint8_t) {
     OFPPR_ADD = 0,
     OFPPR_DELETE = 1,
     OFPPR_MODIFY = 2,
 };
 
-enum ofp_match_type {
+enum ofp_match_type(wire_type=uint16_t) {
     OFPMT_STANDARD = 0,
     OFPMT_OXM = 1,
 };
 
-enum ofp_oxm_class {
+enum ofp_oxm_class(wire_type=uint16_t) {
     OFPXMC_NXM_0 = 0,
     OFPXMC_NXM_1 = 1,
     OFPXMC_OPENFLOW_BASIC = 0x8000,
     OFPXMC_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_vlan_id {
+enum ofp_vlan_id(wire_type=uint16_t) {
     OFPVID_NONE = 0,
     OFPVID_PRESENT = 0x1000,
 };
 
-enum ofp_ipv6exthdr_flags {
+// FIXME: OF spec specified this as '9' bits, implicitly adding
+// to full byte
+enum ofp_ipv6exthdr_flags(wire_type=uint16_t, bitmask=True) {
     OFPIEH_NONEXT = 0x1,
     OFPIEH_ESP = 0x2,
     OFPIEH_AUTH = 0x4,
@@ -199,7 +201,7 @@
     OFPIEH_UNSEQ = 0x100,
 };
 
-enum ofp_action_type {
+enum ofp_action_type(wire_type=uint16_t) {
     OFPAT_OUTPUT = 0,
     OFPAT_COPY_TTL_OUT = 0xb,
     OFPAT_COPY_TTL_IN = 0xc,
@@ -219,12 +221,12 @@
     OFPAT_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_controller_max_len {
+enum ofp_controller_max_len(wire_type=uint16_t, complete=False) {
     OFPCML_MAX = 0xffe5,
     OFPCML_NO_BUFFER = 0xffff,
 };
 
-enum ofp_instruction_type {
+enum ofp_instruction_type(wire_type=uint16_t, bitmask=True) {
     OFPIT_GOTO_TABLE = 0x1,
     OFPIT_WRITE_METADATA = 0x2,
     OFPIT_WRITE_ACTIONS = 0x3,
@@ -234,7 +236,7 @@
     OFPIT_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_flow_mod_command {
+enum ofp_flow_mod_command(wire_type=uint8_t) {
     OFPFC_ADD = 0,
     OFPFC_MODIFY = 1,
     OFPFC_MODIFY_STRICT = 2,
@@ -242,7 +244,7 @@
     OFPFC_DELETE_STRICT = 4,
 };
 
-enum ofp_flow_mod_flags {
+enum ofp_flow_mod_flags(wire_type=uint16_t, bitmask=True) {
     OFPFF_SEND_FLOW_REM = 0x1,
     OFPFF_CHECK_OVERLAP = 0x2,
     OFPFF_RESET_COUNTS = 0x4,
@@ -250,65 +252,65 @@
     OFPFF_NO_BYT_COUNTS = 0x10,
 };
 
-enum ofp_group {
+enum ofp_group(wire_type=uint32_t, complete=False) {
     OFPG_MAX = 0xffffff00,
     OFPG_ALL = 0xfffffffc,
     OFPG_ANY = 0xffffffff,
 };
 
-enum ofp_group_mod_command {
+enum ofp_group_mod_command(wire_type=uint16_t) {
     OFPGC_ADD = 0,
     OFPGC_MODIFY = 1,
     OFPGC_DELETE = 2,
 };
 
-enum ofp_group_type {
+enum ofp_group_type(wire_type=uint8_t) {
     OFPGT_ALL = 0,
     OFPGT_SELECT = 1,
     OFPGT_INDIRECT = 2,
     OFPGT_FF = 3,
 };
 
-enum ofp_packet_in_reason {
+enum ofp_packet_in_reason(wire_type=uint8_t) {
     OFPR_NO_MATCH = 0,
     OFPR_ACTION = 1,
     OFPR_INVALID_TTL = 2,
 };
 
-enum ofp_flow_removed_reason {
+enum ofp_flow_removed_reason(wire_type=uint8_t) {
     OFPRR_IDLE_TIMEOUT = 0,
     OFPRR_HARD_TIMEOUT = 1,
     OFPRR_DELETE = 2,
     OFPRR_GROUP_DELETE = 3,
 };
 
-enum ofp_meter {
+enum ofp_meter(wire_type=uint32_t, complete=False) {
     OFPM_MAX = 0xffff0000,
     OFPM_SLOWPATH = 0xfffffffd,
     OFPM_CONTROLLER = 0xfffffffe,
     OFPM_ALL = 0xffffffff,
 };
 
-enum ofp_meter_band_type {
+enum ofp_meter_band_type(wire_type=uint16_t) {
     OFPMBT_DROP = 0x1,
     OFPMBT_DSCP_REMARK = 0x2,
     OFPMBT_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_meter_mod_command {
+enum ofp_meter_mod_command(wire_type=uint16_t) {
     OFPMC_ADD = 0,
     OFPMC_MODIFY = 1,
     OFPMC_DELETE = 2,
 };
 
-enum ofp_meter_flags {
+enum ofp_meter_flags(wire_type=uint16_t, bitmask=True) {
     OFPMF_KBPS = 0x1,
     OFPMF_PKTPS = 0x2,
     OFPMF_BURST = 0x4,
     OFPMF_STATS = 0x8,
 };
 
-enum ofp_error_type {
+enum ofp_error_type(wire_type=uint16_t) {
     OFPET_HELLO_FAILED = 0,
     OFPET_BAD_REQUEST = 1,
     OFPET_BAD_ACTION = 2,
@@ -326,12 +328,12 @@
     OFPET_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_hello_failed_code {
+enum ofp_hello_failed_code(wire_type=uint16_t) {
     OFPHFC_INCOMPATIBLE = 0,
     OFPHFC_EPERM = 1,
 };
 
-enum ofp_bad_request_code {
+enum ofp_bad_request_code(wire_type=uint16_t) {
     OFPBRC_BAD_VERSION = 0,
     OFPBRC_BAD_TYPE = 1,
     OFPBRC_BAD_MULTIPART = 2,
@@ -348,7 +350,7 @@
     OFPBRC_MULTIPART_BUFFER_OVERFLOW = 13,
 };
 
-enum ofp_bad_action_code {
+enum ofp_bad_action_code(wire_type=uint16_t) {
     OFPBAC_BAD_TYPE = 0,
     OFPBAC_BAD_LEN = 1,
     OFPBAC_BAD_EXPERIMENTER = 2,
@@ -367,7 +369,7 @@
     OFPBAC_BAD_SET_ARGUMENT = 15,
 };
 
-enum ofp_bad_instruction_code {
+enum ofp_bad_instruction_code(wire_type=uint16_t) {
     OFPBIC_UNKNOWN_INST = 0,
     OFPBIC_UNSUP_INST = 1,
     OFPBIC_BAD_TABLE_ID = 2,
@@ -379,7 +381,7 @@
     OFPBIC_EPERM = 8,
 };
 
-enum ofp_bad_match_code {
+enum ofp_bad_match_code(wire_type=uint16_t) {
     OFPBMC_BAD_TYPE = 0,
     OFPBMC_BAD_LEN = 1,
     OFPBMC_BAD_TAG = 2,
@@ -394,7 +396,7 @@
     OFPBMC_EPERM = 11,
 };
 
-enum ofp_flow_mod_failed_code {
+enum ofp_flow_mod_failed_code(wire_type=uint16_t) {
     OFPFMFC_UNKNOWN = 0,
     OFPFMFC_TABLE_FULL = 1,
     OFPFMFC_BAD_TABLE_ID = 2,
@@ -405,7 +407,7 @@
     OFPFMFC_BAD_FLAGS = 7,
 };
 
-enum ofp_group_mod_failed_code {
+enum ofp_group_mod_failed_code(wire_type=uint16_t) {
     OFPGMFC_GROUP_EXISTS = 0,
     OFPGMFC_INVALID_GROUP = 1,
     OFPGMFC_WEIGHT_UNSUPPORTED = 2,
@@ -423,7 +425,7 @@
     OFPGMFC_EPERM = 14,
 };
 
-enum ofp_port_mod_failed_code {
+enum ofp_port_mod_failed_code(wire_type=uint16_t) {
     OFPPMFC_BAD_PORT = 0,
     OFPPMFC_BAD_HW_ADDR = 1,
     OFPPMFC_BAD_CONFIG = 2,
@@ -431,31 +433,31 @@
     OFPPMFC_EPERM = 4,
 };
 
-enum ofp_table_mod_failed_code {
+enum ofp_table_mod_failed_code(wire_type=uint16_t) {
     OFPTMFC_BAD_TABLE = 0,
     OFPTMFC_BAD_CONFIG = 1,
     OFPTMFC_EPERM = 2,
 };
 
-enum ofp_queue_op_failed_code {
+enum ofp_queue_op_failed_code(wire_type=uint16_t) {
     OFPQOFC_BAD_PORT = 0,
     OFPQOFC_BAD_QUEUE = 1,
     OFPQOFC_EPERM = 2,
 };
 
-enum ofp_switch_config_failed_code {
+enum ofp_switch_config_failed_code(wire_type=uint16_t) {
     OFPSCFC_BAD_FLAGS = 0,
     OFPSCFC_BAD_LEN = 1,
     OFPSCFC_EPERM = 2,
 };
 
-enum ofp_role_request_failed_code {
+enum ofp_role_request_failed_code(wire_type=uint16_t){
     OFPRRFC_STALE = 0,
     OFPRRFC_UNSUP = 1,
     OFPRRFC_BAD_ROLE = 2,
 };
 
-enum ofp_meter_mod_failed_code {
+enum ofp_meter_mod_failed_code(wire_type=uint16_t) {
     OFPMMFC_UNKNOWN = 0,
     OFPMMFC_METER_EXISTS = 1,
     OFPMMFC_INVALID_METER = 2,
@@ -470,7 +472,7 @@
     OFPMMFC_OUT_OF_BANDS = 11,
 };
 
-enum ofp_table_features_failed_code {
+enum ofp_table_features_failed_code(wire_type=uint16_t) {
     OFPTFFC_BAD_TABLE = 0,
     OFPTFFC_BAD_METADATA = 1,
     OFPTFFC_BAD_TYPE = 2,
@@ -479,7 +481,7 @@
     OFPTFFC_EPERM = 5,
 };
 
-enum ofp_multipart_types {
+enum ofp_multipart_types(wire_type=uint16_t) {
     OFPMP_DESC = 0,
     OFPMP_FLOW = 1,
     OFPMP_AGGREGATE = 2,
@@ -497,15 +499,15 @@
     OFPMP_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_multipart_request_flags {
+enum ofp_multipart_request_flags(wire_type=uint16_t, bitmask=True) {
     OFPMPF_REQ_MORE = 0x1,
 };
 
-enum ofp_multipart_reply_flags {
+enum ofp_multipart_reply_flags(wire_type=uint16_t, bitmask=True) {
     OFPMPF_REPLY_MORE = 0x1,
 };
 
-enum ofp_table_feature_prop_type {
+enum ofp_table_feature_prop_type(wire_type=uint16_t) {
     OFPTFPT_INSTRUCTIONS = 0,
     OFPTFPT_INSTRUCTIONS_MISS = 1,
     OFPTFPT_NEXT_TABLES = 2,
@@ -524,34 +526,34 @@
     OFPTFPT_EXPERIMENTER_MISS = 0xffff,
 };
 
-enum ofp_group_capabilities {
+enum ofp_group_capabilities(wire_type=uint32_t, bitmask=True) {
     OFPGFC_SELECT_WEIGHT = 0x1,
     OFPGFC_SELECT_LIVENESS = 0x2,
     OFPGFC_CHAINING = 0x4,
     OFPGFC_CHAINING_CHECKS = 0x8,
 };
 
-enum ofp_queue_properties {
+enum ofp_queue_properties(wire_type=uint16_t) {
     OFPQT_MIN_RATE = 0x1,
     OFPQT_MAX_RATE = 0x2,
     OFPQT_EXPERIMENTER = 0xffff,
 };
 
-enum ofp_controller_role {
+enum ofp_controller_role(wire_type=uint32_t) {
     OFPCR_ROLE_NOCHANGE = 0,
     OFPCR_ROLE_EQUAL = 1,
     OFPCR_ROLE_MASTER = 2,
     OFPCR_ROLE_SLAVE = 3,
 };
 
-enum ofp_hello_elem_type {
+enum ofp_hello_elem_type(wire_type=uint16_t) {
     OFPHET_VERSIONBITMAP = 1,
 };
 
 /* XXX rename to of_message */
 struct of_header {
     uint8_t version;
-    uint8_t type;
+    uint8_t type == ?;
     uint16_t length;
     uint32_t xid;
 };
@@ -567,7 +569,7 @@
 };
 
 struct of_hello_elem {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t length;
 };
 
@@ -723,7 +725,7 @@
 };
 
 // FIXME Does this need to be v4?
-struct of_match_v3 {
+struct of_match_v3(align=8) {
     uint16_t type == 1;
     uint16_t length;
     list(of_oxm_t) oxm_list;
@@ -849,13 +851,13 @@
 };
 
 struct of_action {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
 
 struct of_instruction {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
 };
 
@@ -915,7 +917,7 @@
     uint64_t cookie;
     uint64_t cookie_mask;
     uint8_t table_id;
-    of_fm_cmd_t _command;
+    of_fm_cmd_t _command == ?;
     uint16_t idle_timeout;
     uint16_t hard_timeout;
     uint16_t priority;
@@ -1101,7 +1103,7 @@
 };
 
 struct of_meter_band {
-    uint16_t        type;
+    uint16_t        type == ?;
     uint16_t        len;
 //    uint32_t        rate;  // These are excluded b/c this is the header
 //    uint32_t        burst_size;  // These are excluded b/c this is the header
@@ -1255,7 +1257,7 @@
     uint8_t type == 18;
     uint16_t length;
     uint32_t xid;
-    uint16_t stats_type;
+    uint16_t stats_type == ?;
     uint16_t flags;
     pad(4);
 };
@@ -1265,7 +1267,7 @@
     uint8_t type == 19;
     uint16_t length;
     uint32_t xid;
-    uint16_t stats_type;
+    uint16_t stats_type == ?;
     uint16_t flags;
     pad(4);
 };
@@ -1775,7 +1777,7 @@
 // END OF STATS OBJECTS
 
 struct of_queue_prop {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
diff --git a/test_data/__init__.py b/test_data/__init__.py
index f21770b..7a55c11 100644
--- a/test_data/__init__.py
+++ b/test_data/__init__.py
@@ -45,6 +45,9 @@
                 result.append(dirname + '/' + filename)
     return sorted(result)
 
+def exists(name):
+    return os.path.exists(os.path.join(_test_data_dir, name))
+
 def read(name):
     """
     Read, parse, and return a test data file
diff --git a/test_data/of10/hello.data b/test_data/of10/hello.data
index 3dc2b44..d29dff9 100644
--- a/test_data/of10/hello.data
+++ b/test_data/of10/hello.data
@@ -7,3 +7,5 @@
 -- c
 obj = of_hello_new(OF_VERSION_1_0);
 of_hello_xid_set(obj, 305419896);
+-- java
+builder.setXid(0x12345678)
diff --git a/test_data/of10/packet_in.data b/test_data/of10/packet_in.data
index 8168e3b..2cd98b0 100644
--- a/test_data/of10/packet_in.data
+++ b/test_data/of10/packet_in.data
@@ -27,3 +27,11 @@
 of_packet_in_reason_set(obj, 1);
 of_packet_in_total_len_set(obj, 9);
 of_packet_in_xid_set(obj, 305419896);
+-- java
+builder
+   .setXid(0x12345678)
+   .setBufferId(0xabcdef01)
+   .setTotalLen(9)
+   .setInPort(OFPort.LOCAL)
+   .setReason(OFPacketInReason.ACTION)
+   .setData(new byte[] { 0x61, 0x62, 0x63 } );
diff --git a/test_data/of13/flow_add.data b/test_data/of13/flow_add.data
index c66518f..d01c209 100644
--- a/test_data/of13/flow_add.data
+++ b/test_data/of13/flow_add.data
@@ -50,3 +50,23 @@
     instructions=[
         ofp.instruction.goto_table(table_id=4),
         ofp.instruction.goto_table(table_id=7)])
+-- java
+builder.setXid(0x12345678)
+    .setCookie(U64.parseHex("FEDCBA9876543210"))
+    .setCookieMask(U64.parseHex("FF00FF00FF00FF00"))
+    .setTableId((byte) 3)
+    .setIdleTimeout(5)
+    .setHardTimeout(10)
+    .setPriority(6000)
+    .setBufferId(50)
+    .setOutPort(OFPort.of(6))
+    .setOutGroup(8)
+    .setFlags(0)
+    .setMatch(factory.createMatchV3Builder().getMessage()) // FIXME: @yotam: replace once we have generic ofmatch
+    .setInstructions(
+        ImmutableList.<OFInstruction>of(
+            factory.createInstructionGotoTableBuilder().setTableId((byte) 4).getMessage(),
+            factory.createInstructionGotoTableBuilder().setTableId((byte) 7).getMessage()
+        )
+    );
+
diff --git a/test_data/of13/packet_in.data b/test_data/of13/packet_in.data
index e7d602a..71e17b1 100644
--- a/test_data/of13/packet_in.data
+++ b/test_data/of13/packet_in.data
@@ -29,3 +29,21 @@
         ofp.oxm.arp_op(value=1),
         ofp.oxm.in_port_masked(value=4, value_mask=5)]),
     data="abc")
+-- java
+builder
+   .setXid(0x12345678)
+   .setBufferId(100)
+   .setTotalLen(17000)
+   .setReason(OFPacketInReason.ACTION)
+   .setTableId((byte) 20)
+   .setCookie(U64.parseHex("FEDCBA9876543210"))
+   .setMatch(
+        factory.createMatchV3Builder().setOxmList(
+            ImmutableList.of(
+                factory.createOxmArpOpBuilder().setValue(1).getMessage(),
+                factory.createOxmInPortMaskedBuilder().setValue(OFPort.of(4)).setValueMask(OFPort.of(5)).getMessage()
+            )
+        ).getMessage()
+    )
+    .setData(new byte[] { 97, 98, 99 } );
+
diff --git a/utest/test_frontend.py b/utest/test_frontend.py
index 609a262..9249273 100755
--- a/utest/test_frontend.py
+++ b/utest/test_frontend.py
@@ -81,26 +81,26 @@
         # Not testing the parser, just making sure the AST is what we expect
         expected_ast = [
             ['metadata', 'version', '1'],
-            ['enum', 'ofp_port_config', [
-                ['OFPPC_PORT_DOWN', 1],
-                ['OFPPC_NO_STP', 2],
-                ['OFPPC_NO_RECV', 4],
-                ['OFPPC_NO_RECV_STP', 8],
-                ['OFPPC_NO_FLOOD', 16],
-                ['OFPPC_NO_FWD', 32],
-                ['OFPPC_NO_PACKET_IN', 64]]],
+            ['enum', 'ofp_port_config', [], [
+                ['OFPPC_PORT_DOWN', [], 1],
+                ['OFPPC_NO_STP', [], 2],
+                ['OFPPC_NO_RECV', [], 4],
+                ['OFPPC_NO_RECV_STP', [], 8],
+                ['OFPPC_NO_FLOOD', [], 16],
+                ['OFPPC_NO_FWD', [], 32],
+                ['OFPPC_NO_PACKET_IN', [], 64]]],
             ['metadata', 'version', '2'],
-            ['struct', 'of_echo_reply', None, [
+            ['struct', 'of_echo_reply', [], None, [
                 ['data', 'uint8_t', 'version'],
                 ['type', 'uint8_t', 'type', 3],
                 ['data', 'uint16_t', 'length'],
                 ['data', 'uint32_t', 'xid'],
                 ['data', 'of_octets_t', 'data']]],
-            ['enum', 'ofp_queue_op_failed_code', [
-                ['OFPQOFC_BAD_PORT', 0],
-                ['OFPQOFC_BAD_QUEUE', 1],
-                ['OFPQOFC_EPERM', 2]]],
-            ['struct', 'of_packet_queue', None, [
+            ['enum', 'ofp_queue_op_failed_code', [], [
+                ['OFPQOFC_BAD_PORT', [], 0],
+                ['OFPQOFC_BAD_QUEUE', [], 1],
+                ['OFPQOFC_EPERM', [], 2]]],
+            ['struct', 'of_packet_queue', [], None, [
                 ['data', 'uint32_t', 'queue_id'],
                 ['data', 'uint16_t', 'len'],
                 ['pad', 2],
@@ -111,32 +111,32 @@
         ofinput = frontend.create_ofinput(ast)
         self.assertEquals(set([1, 2]), ofinput.wire_versions)
         expected_classes = [
-            OFClass('of_echo_reply', None, [
+            OFClass(name='of_echo_reply', superclass=None, members=[
                 OFDataMember('version', 'uint8_t'), # XXX
                 OFTypeMember('type', 'uint8_t', 3),
                 OFLengthMember('length', 'uint16_t'),
                 OFDataMember('xid', 'uint32_t'),
-                OFDataMember('data', 'of_octets_t')]),
-            OFClass('of_packet_queue', None, [
+                OFDataMember('data', 'of_octets_t')], virtual=False, params={}),
+            OFClass(name='of_packet_queue', superclass=None, members=[
                 OFDataMember('queue_id', 'uint32_t'),
                 OFLengthMember('len', 'uint16_t'),
                 OFPadMember(2),
-                OFDataMember('properties', 'list(of_queue_prop_t)')]),
+                OFDataMember('properties', 'list(of_queue_prop_t)')], virtual=False, params={}),
         ]
         self.assertEquals(expected_classes, ofinput.classes)
         expected_enums = [
-            OFEnum('ofp_port_config', [
-                ('OFPPC_PORT_DOWN', 1),
-                ('OFPPC_NO_STP', 2),
-                ('OFPPC_NO_RECV', 4),
-                ('OFPPC_NO_RECV_STP', 8),
-                ('OFPPC_NO_FLOOD', 16),
-                ('OFPPC_NO_FWD', 32),
-                ('OFPPC_NO_PACKET_IN', 64)]),
-            OFEnum('ofp_queue_op_failed_code', [
-                ('OFPQOFC_BAD_PORT', 0),
-                ('OFPQOFC_BAD_QUEUE', 1),
-                ('OFPQOFC_EPERM', 2)]),
+            OFEnum(name='ofp_port_config', entries=[
+                OFEnumEntry('OFPPC_PORT_DOWN', 1, {}),
+                OFEnumEntry('OFPPC_NO_STP', 2, {}),
+                OFEnumEntry('OFPPC_NO_RECV', 4, {}),
+                OFEnumEntry('OFPPC_NO_RECV_STP', 8, {}),
+                OFEnumEntry('OFPPC_NO_FLOOD', 16, {}),
+                OFEnumEntry('OFPPC_NO_FWD', 32, {}),
+                OFEnumEntry('OFPPC_NO_PACKET_IN', 64, {})], params={}),
+            OFEnum(name='ofp_queue_op_failed_code', entries=[
+                OFEnumEntry('OFPQOFC_BAD_PORT', 0, {}),
+                OFEnumEntry('OFPQOFC_BAD_QUEUE', 1, {}),
+                OFEnumEntry('OFPQOFC_EPERM', 2, {})], params={}),
         ]
         self.assertEquals(expected_enums, ofinput.enums)
 
@@ -145,7 +145,7 @@
 #version 1
 
 struct of_queue_prop {
-    uint16_t type;
+    uint16_t type == ?;
     uint16_t len;
     pad(4);
 };
@@ -163,12 +163,12 @@
         expected_ast = [
             ['metadata', 'version', '1'],
 
-            ['struct', 'of_queue_prop', None, [
-                ['data', 'uint16_t', 'type'],
+            ['struct', 'of_queue_prop', [], None, [
+                ['discriminator', 'uint16_t', 'type'],
                 ['data', 'uint16_t', 'len'],
                 ['pad', 4]]],
 
-            ['struct', 'of_queue_prop_min_rate', 'of_queue_prop', [
+            ['struct', 'of_queue_prop_min_rate', [], 'of_queue_prop', [
                 ['type', 'uint16_t', 'type', 1],
                 ['data', 'uint16_t', 'len'],
                 ['pad', 4],
@@ -179,16 +179,16 @@
 
         ofinput = frontend.create_ofinput(ast)
         expected_classes = [
-            OFClass('of_queue_prop', None, [
-                OFDataMember('type', 'uint16_t'),
+            OFClass(name='of_queue_prop', superclass=None, members=[
+                OFDiscriminatorMember('type', 'uint16_t'),
                 OFLengthMember('len', 'uint16_t'),
-                OFPadMember(4)]),
-            OFClass('of_queue_prop_min_rate', 'of_queue_prop', [
+                OFPadMember(4)], virtual=True, params={}),
+            OFClass(name='of_queue_prop_min_rate', superclass='of_queue_prop', members= [
                 OFTypeMember('type', 'uint16_t', 1),
                 OFLengthMember('len', 'uint16_t'),
                 OFPadMember(4),
                 OFDataMember('rate', 'uint16_t'),
-                OFPadMember(6)]),
+                OFPadMember(6)], virtual=False, params= {}),
         ]
         self.assertEquals(expected_classes, ofinput.classes)
 
diff --git a/utest/test_parser.py b/utest/test_parser.py
index c24665c..8199096 100755
--- a/utest/test_parser.py
+++ b/utest/test_parser.py
@@ -42,7 +42,7 @@
 struct foo { };
 """
         ast = parser.parse(src)
-        self.assertEquals(ast, [['struct', 'foo', None, []]])
+        self.assertEquals(ast, [['struct', 'foo', [], None, []]])
 
     def test_one_field(self):
         src = """\
@@ -52,7 +52,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', None, [['data', 'uint32_t', 'bar']]]])
+            [['struct', 'foo', [], None, [['data', 'uint32_t', 'bar']]]])
 
     def test_multiple_fields(self):
         src = """\
@@ -64,7 +64,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', None,
+            [['struct', 'foo', [], None,
                 [['data', 'uint32_t', 'bar'],
                  ['data', 'uint8_t', 'baz'],
                  ['data', 'uint64_t', 'abc']]]])
@@ -77,7 +77,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', None, [['data', 'uint32_t[4]', 'bar']]]])
+            [['struct', 'foo', [], None, [['data', 'uint32_t[4]', 'bar']]]])
 
     def test_list_type(self):
         src = """\
@@ -87,7 +87,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', None, [['data', 'list(of_action_t)', 'bar']]]])
+            [['struct', 'foo', [], None, [['data', 'list(of_action_t)', 'bar']]]])
 
     def test_pad_member(self):
         src = """\
@@ -97,7 +97,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', None, [['pad', 1]]]])
+            [['struct', 'foo', [], None, [['pad', 1]]]])
 
     def test_type_member(self):
         src = """\
@@ -107,7 +107,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', None, [['type', 'uint16_t', 'foo', 0x10]]]])
+            [['struct', 'foo', [], None, [['type', 'uint16_t', 'foo', 0x10]]]])
 
     def test_inheritance(self):
         src = """\
@@ -117,7 +117,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', 'bar', [['type', 'uint16_t', 'foo', 0x10]]]])
+            [['struct', 'foo', [], 'bar', [['type', 'uint16_t', 'foo', 0x10]]]])
 
 class EnumTests(unittest.TestCase):
     def test_empty(self):
@@ -126,7 +126,7 @@
 };
 """
         ast = parser.parse(src)
-        self.assertEquals(ast, [['enum', 'foo', []]])
+        self.assertEquals(ast, [['enum', 'foo', [], []]])
 
     def test_one(self):
         src = """\
@@ -135,7 +135,7 @@
 };
 """
         ast = parser.parse(src)
-        self.assertEquals(ast, [['enum', 'foo', [['BAR', 1]]]])
+        self.assertEquals(ast, [['enum', 'foo', [], [['BAR', [], 1]]]])
 
     def test_multiple(self):
         src = """\
@@ -146,7 +146,7 @@
 };
 """
         ast = parser.parse(src)
-        self.assertEquals(ast, [['enum', 'foo', [['OFP_A', 1], ['OFP_B', 2], ['OFP_C', 3]]]])
+        self.assertEquals(ast, [['enum', 'foo', [], [['OFP_A', [], 1], ['OFP_B', [], 2], ['OFP_C', [], 3]]]])
 
     def test_trailing_comma(self):
         src = """\
@@ -157,7 +157,7 @@
 };
 """
         ast = parser.parse(src)
-        self.assertEquals(ast, [['enum', 'foo', [['OFP_A', 1], ['OFP_B', 2], ['OFP_C', 3]]]])
+        self.assertEquals(ast, [['enum', 'foo', [], [['OFP_A', [], 1], ['OFP_B', [], 2], ['OFP_C', [], 3]]]])
 
 class TestMetadata(unittest.TestCase):
     def test_version(self):
@@ -175,7 +175,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', None, []], ['struct', 'bar', None, []]])
+            [['struct', 'foo', [], None, []], ['struct', 'bar', [], None, []]])
 
     def test_comments(self):
         src = """\
@@ -189,7 +189,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', None, [['data', 'uint32_t', 'a']]]])
+            [['struct', 'foo', [], None, [['data', 'uint32_t', 'a']]]])
 
     def test_mixed(self):
         src = """\
@@ -201,9 +201,9 @@
         ast = parser.parse(src)
         self.assertEquals(ast,
             [['metadata', 'version', '1'],
-             ['struct', 'foo', None, []],
+             ['struct', 'foo', [], None, []],
              ['metadata', 'version', '2'],
-             ['struct', 'bar', None, []]])
+             ['struct', 'bar', [], None, []]])
 
 class TestErrors(unittest.TestCase):
     def syntax_error(self, src, regex):