diff --git a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
index 18bfcc3c045de2e61f1ad8f5f15776b4495397d2..ea3c11ec5d7812d234c20eac2823ca4b8b33cdba 100644
--- a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
@@ -43,14 +43,14 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
         LoggerFactory.getLogger(AllSwitchStatisticsResource.class);
     
     @Get("json")
-    public Map<String, Object> retrieve() {
+    public Map<String, StatsReply> retrieve() {
         String statType = (String) getRequestAttributes().get(CoreWebRoutable.STR_STAT_TYPE);
         
         return retrieveInternal(statType);
     }
 
-    private Map<String, Object> retrieveInternal(String statType) {
-        HashMap<String, Object> model = new HashMap<String, Object>();
+    private Map<String, StatsReply> retrieveInternal(String statType) {
+        HashMap<String, StatsReply> model = new HashMap<String, StatsReply>();
 
         OFStatsType type = null;
         REQUESTTYPE rType = null;
@@ -108,9 +108,9 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
             for (GetConcurrentStatsThread curThread : activeThreads) {
                 if (curThread.getState() == State.TERMINATED) {
                     if (rType == REQUESTTYPE.OFSTATS) {
-                        model.put(curThread.getSwitchId().toString(), curThread.getStatisticsReply());
+                        model.put(curThread.getSwitchId().toString(), new StatsReply(curThread.getSwitchId(), curThread.getStatisticsReply(), type));
                     } else if (rType == REQUESTTYPE.OFFEATURES) {
-                        model.put(curThread.getSwitchId().toString(), curThread.getFeaturesReply());
+                        model.put(curThread.getSwitchId().toString(), new StatsReply(curThread.getSwitchId(), curThread.getFeaturesReply(), type));
                     }
                     pendingRemovalThreads.add(curThread);
                 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/MatchSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/MatchSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..c242cc6305711654eff318152d0348b6e5e34a89
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/MatchSerializer.java
@@ -0,0 +1,164 @@
+package net.floodlightcontroller.core.web.serializers;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import net.floodlightcontroller.util.MatchUtils;
+
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+/**
+ * Serialize any Match in JSON.
+ * 
+ * Use automatically by Jackson via JsonSerialize(using=MatchSerializer.class),
+ * or use the static function within this class within another serializer.
+ * 
+ * @author Ryan Izard, ryan.izard@bigswitch.com, rizard@g.clemson.edu
+ */
+public class MatchSerializer extends JsonSerializer<Match> {
+	protected static Logger logger = LoggerFactory.getLogger(OFActionListSerializer.class);
+
+	@Override
+	public void serialize(Match match, JsonGenerator jGen, SerializerProvider serializer) throws IOException,
+	JsonProcessingException {
+		serializeMatch(jGen, match);
+	}
+
+	public static void serializeMatch(JsonGenerator jGen, Match match) throws IOException, JsonProcessingException {
+		// list flow matches
+		jGen.writeObjectFieldStart("match");
+		Iterator<MatchField<?>> mi = match.getMatchFields().iterator(); // get iter to any match field type
+		Match m = match;
+
+		while (mi.hasNext()) {
+			MatchField<?> mf = mi.next();
+			switch (mf.id) {
+			case IN_PORT:
+				jGen.writeStringField(MatchUtils.STR_IN_PORT, m.get(MatchField.IN_PORT).toString());
+				break;
+			case IN_PHY_PORT:
+				jGen.writeStringField(MatchUtils.STR_IN_PHYS_PORT, m.get(MatchField.IN_PHY_PORT).toString());
+				break;
+			case ARP_OP:
+				jGen.writeNumberField(MatchUtils.STR_ARP_OPCODE, m.get(MatchField.ARP_OP).getOpcode());
+				break;
+			case ARP_SHA:
+				jGen.writeStringField(MatchUtils.STR_ARP_SHA, m.get(MatchField.ARP_SHA).toString());
+				break;
+			case ARP_SPA:
+				jGen.writeStringField(MatchUtils.STR_ARP_SPA, m.get(MatchField.ARP_SPA).toString());
+				break;
+			case ARP_THA:
+				jGen.writeStringField(MatchUtils.STR_ARP_DHA, m.get(MatchField.ARP_THA).toString());
+				break;
+			case ARP_TPA:
+				jGen.writeStringField(MatchUtils.STR_ARP_DPA, m.get(MatchField.ARP_TPA).toString());
+				break;
+			case ETH_TYPE:
+				jGen.writeNumberField(MatchUtils.STR_DL_TYPE, m.get(MatchField.ETH_TYPE).getValue());
+				break;
+			case ETH_SRC:
+				jGen.writeStringField(MatchUtils.STR_DL_SRC, m.get(MatchField.ETH_SRC).toString());
+				break;
+			case ETH_DST:
+				jGen.writeStringField(MatchUtils.STR_DL_DST, m.get(MatchField.ETH_DST).toString());
+				break;
+			case VLAN_VID:
+				jGen.writeNumberField(MatchUtils.STR_DL_VLAN, m.get(MatchField.VLAN_VID).getVlan());
+				break;
+			case VLAN_PCP:
+				jGen.writeNumberField(MatchUtils.STR_DL_VLAN_PCP, m.get(MatchField.VLAN_PCP).getValue());
+				break;
+			case ICMPV4_TYPE:
+				jGen.writeNumberField(MatchUtils.STR_ICMP_TYPE, m.get(MatchField.ICMPV4_TYPE).getType());
+				break;
+			case ICMPV4_CODE:
+				jGen.writeNumberField(MatchUtils.STR_ICMP_CODE, m.get(MatchField.ICMPV4_CODE).getCode());
+				break;
+			case ICMPV6_TYPE:
+				jGen.writeNumberField(MatchUtils.STR_ICMPV6_TYPE, m.get(MatchField.ICMPV6_TYPE).getValue());
+				break;
+			case ICMPV6_CODE:
+				jGen.writeNumberField(MatchUtils.STR_ICMPV6_CODE, m.get(MatchField.ICMPV6_CODE).getValue());
+				break;
+			case IP_DSCP:
+				jGen.writeNumberField(MatchUtils.STR_NW_DSCP, m.get(MatchField.IP_DSCP).getDscpValue());
+				break;
+			case IP_ECN:
+				jGen.writeNumberField(MatchUtils.STR_NW_ECN, m.get(MatchField.IP_ECN).getEcnValue());
+				break;
+			case IP_PROTO:
+				jGen.writeNumberField(MatchUtils.STR_NW_PROTO, m.get(MatchField.IP_PROTO).getIpProtocolNumber());
+				break;
+			case IPV4_SRC:
+				jGen.writeStringField(MatchUtils.STR_NW_SRC, m.get(MatchField.IPV4_SRC).toString());
+				break;
+			case IPV4_DST:
+				jGen.writeStringField(MatchUtils.STR_NW_DST, m.get(MatchField.IPV4_DST).toString());
+				break;
+			case IPV6_SRC:
+				jGen.writeStringField(MatchUtils.STR_IPV6_SRC, m.get(MatchField.IPV6_SRC).toString());
+				break;
+			case IPV6_DST:
+				jGen.writeStringField(MatchUtils.STR_IPV6_DST, m.get(MatchField.IPV6_DST).toString());
+				break;
+			case IPV6_FLABEL:
+				jGen.writeNumberField(MatchUtils.STR_IPV6_FLOW_LABEL, m.get(MatchField.IPV6_FLABEL).getIPv6FlowLabelValue());
+				break;
+			case IPV6_ND_SLL:
+				jGen.writeNumberField(MatchUtils.STR_IPV6_ND_SSL, m.get(MatchField.IPV6_ND_SLL).getLong());
+				break;
+			case IPV6_ND_TARGET:
+				jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TARGET, m.get(MatchField.IPV6_ND_TARGET).getZeroCompressStart());
+				break;
+			case IPV6_ND_TLL:
+				jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TTL, m.get(MatchField.IPV6_ND_TLL).getLong());
+				break;
+			case METADATA:
+				jGen.writeNumberField(MatchUtils.STR_METADATA, m.get(MatchField.METADATA).getValue().getValue());
+				break;
+			case MPLS_LABEL:
+				jGen.writeNumberField(MatchUtils.STR_MPLS_LABEL, m.get(MatchField.MPLS_LABEL).getValue());
+				break;
+			case MPLS_TC:
+				jGen.writeNumberField(MatchUtils.STR_MPLS_TC, m.get(MatchField.MPLS_TC).getValue());
+				break;
+			case MPLS_BOS:
+				jGen.writeStringField(MatchUtils.STR_MPLS_BOS, m.get(MatchField.MPLS_BOS).toString());
+				break;
+			case SCTP_SRC:
+				jGen.writeNumberField(MatchUtils.STR_SCTP_SRC, m.get(MatchField.SCTP_SRC).getPort());
+				break;
+			case SCTP_DST:
+				jGen.writeNumberField(MatchUtils.STR_SCTP_DST, m.get(MatchField.SCTP_DST).getPort());
+				break;
+			case TCP_SRC:
+				jGen.writeNumberField(MatchUtils.STR_TCP_SRC, m.get(MatchField.TCP_SRC).getPort());
+				break;
+			case TCP_DST:
+				jGen.writeNumberField(MatchUtils.STR_TCP_DST, m.get(MatchField.TCP_DST).getPort());
+				break;
+			case UDP_SRC:
+				jGen.writeNumberField(MatchUtils.STR_UDP_SRC, m.get(MatchField.UDP_SRC).getPort());
+				break;
+			case UDP_DST:
+				jGen.writeNumberField(MatchUtils.STR_UDP_DST, m.get(MatchField.UDP_DST).getPort());
+				break;
+			default:
+				// either a BSN or unknown match type
+				break;
+			} // end switch of match type
+		} // end while over non-wildcarded matches
+
+		jGen.writeEndObject(); // end match
+	}
+}
+
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/OFActionListSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/OFActionListSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb17f34f9400fea90755c996c5341e869ee8b863
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/OFActionListSerializer.java
@@ -0,0 +1,268 @@
+package net.floodlightcontroller.core.web.serializers;
+
+import java.io.IOException;
+import java.util.List;
+
+import net.floodlightcontroller.util.ActionUtils;
+import net.floodlightcontroller.util.MatchUtils;
+
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionEnqueue;
+import org.projectfloodlight.openflow.protocol.action.OFActionExperimenter;
+import org.projectfloodlight.openflow.protocol.action.OFActionGroup;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.action.OFActionPopMpls;
+import org.projectfloodlight.openflow.protocol.action.OFActionPushMpls;
+import org.projectfloodlight.openflow.protocol.action.OFActionPushPbb;
+import org.projectfloodlight.openflow.protocol.action.OFActionPushVlan;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetMplsLabel;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetMplsTc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetMplsTtl;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwEcn;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwTos;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwTtl;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetQueue;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetTpDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetTpSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmArpOp;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmArpSha;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmArpSpa;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmArpTha;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmArpTpa;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIcmpv4Code;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIcmpv4Type;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpDscp;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpEcn;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpProto;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4Dst;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4Src;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmMetadata;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsBos;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsTc;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmSctpDst;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmSctpSrc;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmTcpDst;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmTcpSrc;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmUdpDst;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmUdpSrc;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanPcp;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+/**
+ * Serialize any List of OFAction in JSON.
+ * 
+ * Use automatically by Jackson via JsonSerialize(using=OFActionListSerializer.class),
+ * or use the static function within this class within another serializer.
+ * 
+ * @author Ryan Izard, ryan.izard@bigswitch.com, rizard@g.clemson.edu
+ */
+public class OFActionListSerializer extends JsonSerializer<List<OFAction>> {
+    protected static Logger logger = LoggerFactory.getLogger(OFActionListSerializer.class);
+	
+	@Override
+	public void serialize(List<OFAction> actions, JsonGenerator jGen, SerializerProvider serializer) throws IOException,
+			JsonProcessingException {
+		jGen.writeStartObject();
+		serializeActions(jGen, actions);
+		jGen.writeEndObject();
+	}
+    
+	/**
+     * Write a JSON string given a list of OFAction. Supports OF1.0 - OF1.3.
+     * This is the only place actions are serialized, for any OF version. Because
+     * some OF version share actions, it makes sense to have them in one place.
+     * @param jsonGenerator
+     * @param actions
+     * @throws IOException
+     * @throws JsonProcessingException
+     */
+    public static void serializeActions(JsonGenerator jsonGenerator, List<OFAction> actions) throws IOException, JsonProcessingException {
+        if (actions.isEmpty()) {
+            jsonGenerator.writeStringField("none", "drop");
+        }
+        for (OFAction a : actions) {
+            switch (a.getType()) {
+            case OUTPUT:
+                jsonGenerator.writeStringField(ActionUtils.STR_OUTPUT, ((OFActionOutput)a).getPort().toString());
+                break;
+            /* begin OF1.0 ONLY actions */
+            case SET_VLAN_VID:
+                jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_SET_VID, ((OFActionSetVlanVid)a).getVlanVid().getVlan());
+                break;
+            case SET_VLAN_PCP:
+                jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_SET_PCP, ((OFActionSetVlanPcp)a).getVlanPcp().getValue());
+                break;
+            case SET_QUEUE:
+                jsonGenerator.writeNumberField(ActionUtils.STR_QUEUE_SET, ((OFActionSetQueue)a).getQueueId());
+                break;
+            case SET_DL_SRC:
+                jsonGenerator.writeStringField(ActionUtils.STR_DL_SRC_SET, ((OFActionSetDlSrc)a).getDlAddr().toString());
+                break;
+            case SET_DL_DST:
+                jsonGenerator.writeStringField(ActionUtils.STR_DL_DST_SET, ((OFActionSetDlDst)a).getDlAddr().toString());
+                break;
+            case SET_NW_SRC:
+                jsonGenerator.writeStringField(ActionUtils.STR_NW_SRC_SET, ((OFActionSetNwSrc)a).getNwAddr().toString());
+                break;
+            case SET_NW_DST:
+                jsonGenerator.writeStringField(ActionUtils.STR_NW_DST_SET, ((OFActionSetNwDst)a).getNwAddr().toString());
+                break;
+            case SET_NW_TOS:
+                jsonGenerator.writeNumberField(ActionUtils.STR_NW_TOS_SET, ((OFActionSetNwTos)a).getNwTos());
+                break;    
+            case SET_TP_SRC:
+                jsonGenerator.writeNumberField(ActionUtils.STR_TP_SRC_SET, ((OFActionSetTpSrc)a).getTpPort().getPort());
+                break;
+            case SET_TP_DST:
+                jsonGenerator.writeNumberField(ActionUtils.STR_TP_DST_SET, ((OFActionSetTpDst)a).getTpPort().getPort());
+                break;
+            /* end OF1.0 ONLY actions; begin OF1.1+ actions */
+            case ENQUEUE:
+                jsonGenerator.writeNumberField(ActionUtils.STR_ENQUEUE, ((OFActionEnqueue)a).getPort().getPortNumber());
+                break;
+            case GROUP:
+                jsonGenerator.writeStringField(ActionUtils.STR_GROUP, ((OFActionGroup)a).getGroup().toString());
+                break;
+            case STRIP_VLAN:
+                jsonGenerator.writeString(ActionUtils.STR_VLAN_STRIP);
+                break;
+            case PUSH_VLAN:
+                jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_PUSH, ((OFActionPushVlan)a).getEthertype().getValue());
+                break;
+            case PUSH_MPLS:
+                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_PUSH, ((OFActionPushMpls)a).getEthertype().getValue());
+                break;
+            case PUSH_PBB:
+                jsonGenerator.writeNumberField(ActionUtils.STR_PBB_PUSH, ((OFActionPushPbb)a).getEthertype().getValue());
+                break;
+            case POP_VLAN:
+                jsonGenerator.writeString(ActionUtils.STR_VLAN_POP);
+                break;
+            case POP_MPLS:
+                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_POP, ((OFActionPopMpls)a).getEthertype().getValue());
+                break;
+            case POP_PBB:
+                jsonGenerator.writeString(ActionUtils.STR_PBB_POP);
+                break;
+            case COPY_TTL_IN:
+                jsonGenerator.writeString(ActionUtils.STR_TTL_IN_COPY);
+                break;
+            case COPY_TTL_OUT:
+                jsonGenerator.writeString(ActionUtils.STR_TTL_OUT_COPY);
+                break;
+            case DEC_NW_TTL:
+                jsonGenerator.writeString(ActionUtils.STR_NW_TTL_DEC);
+                break;
+            case DEC_MPLS_TTL:
+                jsonGenerator.writeString(ActionUtils.STR_MPLS_TTL_DEC);
+                break;
+            case SET_MPLS_LABEL:
+                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_LABEL_SET, ((OFActionSetMplsLabel)a).getMplsLabel());
+                break;
+            case SET_MPLS_TC:
+                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_TC_SET, ((OFActionSetMplsTc)a).getMplsTc());
+                break;
+            case SET_MPLS_TTL:
+                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_TTL_SET, ((OFActionSetMplsTtl)a).getMplsTtl());
+                break;
+            case SET_NW_ECN:
+                jsonGenerator.writeNumberField(ActionUtils.STR_NW_ECN_SET, ((OFActionSetNwEcn)a).getNwEcn().getEcnValue());
+                break;
+            case SET_NW_TTL:
+                jsonGenerator.writeNumberField(ActionUtils.STR_NW_TTL_SET, ((OFActionSetNwTtl)a).getNwTtl());
+                break;
+            case EXPERIMENTER:
+                jsonGenerator.writeNumberField(ActionUtils.STR_EXPERIMENTER, ((OFActionExperimenter)a).getExperimenter());
+                break;
+            case SET_FIELD:
+                if (((OFActionSetField)a).getField() instanceof OFOxmArpOp) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_ARP_OPCODE, ((OFOxmArpOp) ((OFActionSetField) a).getField()).getValue().getOpcode());
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmArpSha) {
+                    jsonGenerator.writeStringField(MatchUtils.STR_ARP_SHA, ((OFOxmArpSha) ((OFActionSetField) a).getField()).getValue().toString()); // macaddress formats string already
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmArpTha) {
+                    jsonGenerator.writeStringField(MatchUtils.STR_ARP_DHA, ((OFOxmArpTha) ((OFActionSetField) a).getField()).getValue().toString());
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmArpSpa) {
+                    jsonGenerator.writeStringField(MatchUtils.STR_ARP_SPA, ((OFOxmArpSpa) ((OFActionSetField) a).getField()).getValue().toString()); // ipaddress formats string already
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmArpTpa) {
+                    jsonGenerator.writeStringField(MatchUtils.STR_ARP_DPA, ((OFOxmArpTpa) ((OFActionSetField) a).getField()).getValue().toString()); 
+                } 
+                /* DATA LAYER */
+                else if (((OFActionSetField)a).getField() instanceof OFOxmEthType) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_DL_TYPE, ((OFOxmEthType) ((OFActionSetField) a).getField()).getValue().getValue());
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmEthSrc) {
+                    jsonGenerator.writeStringField(MatchUtils.STR_DL_SRC, ((OFOxmEthSrc) ((OFActionSetField) a).getField()).getValue().toString());
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmEthDst) {
+                    jsonGenerator.writeStringField(MatchUtils.STR_DL_DST, ((OFOxmEthDst) ((OFActionSetField) a).getField()).getValue().toString()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmVlanVid) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_DL_VLAN, ((OFOxmVlanVid) ((OFActionSetField) a).getField()).getValue().getVlan()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmVlanPcp) {
+                } 
+                /* ICMP */
+                else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Code) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_ICMP_CODE, ((OFOxmIcmpv4Code) ((OFActionSetField) a).getField()).getValue().getCode()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Type) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_ICMP_TYPE, ((OFOxmIcmpv4Type) ((OFActionSetField) a).getField()).getValue().getType()); 
+                } 
+                /* NETWORK LAYER */
+                else if (((OFActionSetField)a).getField() instanceof OFOxmIpProto) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_NW_PROTO, ((OFOxmIpProto) ((OFActionSetField) a).getField()).getValue().getIpProtocolNumber()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Src) {
+                    jsonGenerator.writeStringField(MatchUtils.STR_NW_SRC, ((OFOxmIpv4Src) ((OFActionSetField) a).getField()).getValue().toString()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Dst) {
+                    jsonGenerator.writeStringField(MatchUtils.STR_NW_DST, ((OFOxmIpv4Dst) ((OFActionSetField) a).getField()).getValue().toString()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmIpEcn) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_NW_ECN, ((OFOxmIpEcn) ((OFActionSetField) a).getField()).getValue().getEcnValue()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmIpDscp) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_NW_DSCP, ((OFOxmIpDscp) ((OFActionSetField) a).getField()).getValue().getDscpValue()); 
+                } 
+                /* TRANSPORT LAYER, TCP, UDP, and SCTP */
+                else if (((OFActionSetField)a).getField() instanceof OFOxmTcpSrc) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_TCP_SRC, ((OFOxmTcpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmTcpDst) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_TCP_DST, ((OFOxmTcpDst) ((OFActionSetField) a).getField()).getValue().getPort()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmUdpSrc) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_UDP_SRC, ((OFOxmUdpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmUdpDst) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_UDP_DST, ((OFOxmUdpDst) ((OFActionSetField) a).getField()).getValue().getPort()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmSctpSrc) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_SCTP_SRC, ((OFOxmSctpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmSctpDst) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_SCTP_DST, ((OFOxmSctpDst) ((OFActionSetField) a).getField()).getValue().getPort()); 
+                }
+                /* MPLS */
+                else if (((OFActionSetField)a).getField() instanceof OFOxmMplsLabel) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_MPLS_LABEL, ((OFOxmMplsLabel) ((OFActionSetField) a).getField()).getValue().getValue()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmMplsTc) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_MPLS_TC, ((OFOxmMplsTc) ((OFActionSetField) a).getField()).getValue().getValue()); 
+                } else if (((OFActionSetField)a).getField() instanceof OFOxmMplsBos) {
+                    jsonGenerator.writeStringField(MatchUtils.STR_MPLS_TC, ((OFOxmMplsBos) ((OFActionSetField) a).getField()).getValue().toString()); 
+                } 
+                /* METADATA */
+                else if (((OFActionSetField)a).getField() instanceof OFOxmMetadata) {
+                    jsonGenerator.writeNumberField(MatchUtils.STR_METADATA, ((OFOxmMetadata) ((OFActionSetField) a).getField()).getValue().getValue().getValue()); 
+                } else {
+                    logger.error("Could not decode Set-Field action field: {}", ((OFActionSetField) a));
+                    // need to get a logger in here somehow log.error("Could not decode Set-Field action field: {}", ((OFActionSetField) a));
+                }
+            } // end switch over action type
+        } // end for over all actions
+    } // end method
+}
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/OFFlowModSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/OFFlowModSerializer.java
index b9462235c89348d82d7ffa1119cffe3bea6438bf..a0ebe5b006d43a77097ae14ae6717d27a7f830fc 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/OFFlowModSerializer.java
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/OFFlowModSerializer.java
@@ -1,158 +1,102 @@
 package net.floodlightcontroller.core.web.serializers;
 
 /**
-*    Copyright 2011,2012 Big Switch Networks, Inc. 
-*    Originally created by David Erickson, Stanford University
-* 
-*    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.
-**/
+ *    Copyright 2011,2012 Big Switch Networks, Inc. 
+ *    Originally created by David Erickson, Stanford University
+ * 
+ *    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.
+ **/
 
 import java.io.IOException;
-import java.util.List;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonGenerator.Feature;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
 
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstructionExperimenter;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstructionGotoTable;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstructionMeter;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteActions;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteMetadata;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.ver10.OFFlowModFlagsSerializerVer10;
+import org.projectfloodlight.openflow.protocol.ver11.OFFlowModFlagsSerializerVer11;
+import org.projectfloodlight.openflow.protocol.ver12.OFFlowModFlagsSerializerVer12;
+import org.projectfloodlight.openflow.protocol.ver13.OFFlowModFlagsSerializerVer13;
+import org.projectfloodlight.openflow.protocol.ver14.OFFlowModFlagsSerializerVer14;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Serialize an OFFlowMod into JSON format 
- * for output from the static flow pusher.
+ * Serialize any OFFlowMod in JSON.
+ * 
+ * Use automatically by Jackson via JsonSerialize(using=OFFlowModSerializer.class),
+ * or use the static function within this class within another serializer.
  * 
  * @author Ryan Izard, ryan.izard@bigswitch.com, rizard@g.clemson.edu
  */
 public class OFFlowModSerializer extends JsonSerializer<OFFlowMod> {
+    protected static Logger logger = LoggerFactory.getLogger(OFFlowModSerializer.class);
+
+	@Override
+	public void serialize(OFFlowMod fm, JsonGenerator jGen, SerializerProvider serializer)
+			throws IOException, JsonProcessingException {
+		
+	}
+
+	public static void serializeFlowMod(JsonGenerator jGen, OFFlowMod flowMod) throws IOException, JsonProcessingException {
+		
+        jGen.configure(Feature.WRITE_NUMBERS_AS_STRINGS, true); // IMHO this just looks nicer and is easier to read if everything is quoted
+		
+		jGen.writeStartObject();
+		jGen.writeStringField("version", flowMod.getVersion().toString()); // return the enum names
+		jGen.writeStringField("command", flowMod.getCommand().toString());
+		jGen.writeNumberField("cookie", flowMod.getCookie().getValue());
+		jGen.writeNumberField("cookieMask", flowMod.getCookieMask().getValue());
+		jGen.writeStringField("tableId", flowMod.getTableId().toString());
+		jGen.writeNumberField("priority", flowMod.getPriority());
+		jGen.writeNumberField("idleTimeoutSec", flowMod.getIdleTimeout());
+		jGen.writeNumberField("hardTimeoutSec", flowMod.getHardTimeout());
+		jGen.writeStringField("outGroup", flowMod.getOutGroup().toString());
+		jGen.writeStringField("outPort", flowMod.getOutPort().toString());
+
+		switch (flowMod.getVersion()) {
+		case OF_10:
+			jGen.writeNumberField("flags", OFFlowModFlagsSerializerVer10.toWireValue(flowMod.getFlags()));
+			break;
+		case OF_11:
+			jGen.writeNumberField("flags", OFFlowModFlagsSerializerVer11.toWireValue(flowMod.getFlags()));
+			break;
+		case OF_12:
+			jGen.writeNumberField("flags", OFFlowModFlagsSerializerVer12.toWireValue(flowMod.getFlags()));
+			break;
+		case OF_13:
+			jGen.writeNumberField("flags", OFFlowModFlagsSerializerVer13.toWireValue(flowMod.getFlags()));
+			break;
+		case OF_14:
+			jGen.writeNumberField("flags", OFFlowModFlagsSerializerVer14.toWireValue(flowMod.getFlags()));
+			break;
+		default:
+			logger.error("Could not decode OFVersion {}", flowMod.getVersion());
+			break;
+		}
 
-    @Override
-    public void serialize(OFFlowMod fm, JsonGenerator jGen, SerializerProvider serializer)
-                                  throws IOException, JsonProcessingException {
-        jGen.writeStartObject();
-        jGen.writeStringField("command", fm.getCommand().toString());
-        jGen.writeStringField("buffer-id", fm.getBufferId().toString());
-        jGen.writeStringField("cookie", fm.getCookie().toString());
-        if (fm.getVersion() != OFVersion.OF_10) {
-        	jGen.writeStringField("cookie-mask", fm.getCookieMask().toString());
-        }
-        jGen.writeStringField("flags", fm.getFlags().toString());
-        jGen.writeNumberField("hard-timeout", fm.getHardTimeout());
-        jGen.writeNumberField("idle-timeout", fm.getIdleTimeout());
-        jGen.writeNumberField("priority", fm.getPriority());
-        if (fm.getVersion() != OFVersion.OF_10) {
-        	jGen.writeStringField("table-id", fm.getTableId().toString());
-        }
-        jGen.writeStringField("of-type", fm.getType().toString());
-        jGen.writeStringField("of-version", fm.getVersion().toString());
-        jGen.writeStringField("out-port", fm.getOutPort().toString());
-        if (fm.getVersion() != OFVersion.OF_10) {
-        	jGen.writeStringField("out-group", fm.getOutGroup().toString());
-        }
-        
-        serializeMatch(fm.getMatch(), jGen);
-        
-        if (fm.getVersion() != OFVersion.OF_10) {
-        	serializeInstructions(fm.getInstructions(), jGen);
-        } else {
-            serializeActions(fm.getActions(), "actions", jGen);
-        }
-      
-        jGen.writeEndObject();
-    }
+		MatchSerializer.serializeMatch(jGen, flowMod.getMatch());
 
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-	public void serializeMatch(Match match, JsonGenerator jGen)
-            throws IOException, JsonProcessingException {
-        if (match == null)
-            jGen.writeStringField("match", "null");
-        else {
-            jGen.writeFieldName("match");
-            jGen.writeStartArray();
-            for (MatchField mf : match.getMatchFields()) {
-                jGen.writeString(match.get(mf).toString());
-            }
-            jGen.writeEndArray();
-        }
-    }
-    
-	public void serializeInstructions(List<OFInstruction> instructions, JsonGenerator jGen)
-            throws IOException, JsonProcessingException {
-        if (instructions == null)
-            jGen.writeStringField("instructions", "null");
-        else {
-            jGen.writeFieldName("instructions");
-            jGen.writeStartArray();
-            for (OFInstruction instruction : instructions) {
-            	switch (instruction.getType()) {
-            	case APPLY_ACTIONS:
-            		serializeActions(((OFInstructionApplyActions) instruction).getActions(), "apply-actions", jGen);
-            		break;
-            	case WRITE_ACTIONS:
-            		serializeActions(((OFInstructionWriteActions) instruction).getActions(), "write-actions", jGen);
-            		break;
-            	case CLEAR_ACTIONS:
-            		jGen.writeStringField("clear-actions", "n/a");
-            		break;
-            	case GOTO_TABLE:
-            		jGen.writeStringField("goto-table", ((OFInstructionGotoTable) instruction).getTableId().toString());
-            		break;
-            	case METER:
-            		jGen.writeNumberField("goto-meter", ((OFInstructionMeter) instruction).getMeterId());
-            		break;
-            	case WRITE_METADATA:
-            		jGen.writeFieldName("write-metadata");
-            		jGen.writeStartArray();
-            		jGen.writeStringField("metadata", ((OFInstructionWriteMetadata) instruction).getMetadata().toString());
-            		jGen.writeStringField("metadata-mask", ((OFInstructionWriteMetadata) instruction).getMetadataMask().toString());
-            		jGen.writeEndArray();
-            		break;
-            	case EXPERIMENTER:
-            		jGen.writeNumberField("metadata", ((OFInstructionExperimenter) instruction).getExperimenter());
-            		break;
-            	default:
-            		jGen.writeStringField("unknown-instruction", "Could not determine instruction type during JSON output serialization");
-            		break;
-            	}
-            }
-            jGen.writeEndArray();
-        }
-    }
-    
-    public void serializeActions(List<OFAction> actions, String fieldName, JsonGenerator jGen)
-            throws IOException, JsonProcessingException {
-        if (actions == null) {
-        	jGen.writeStartObject();
-            jGen.writeStringField(fieldName, "null");
-            jGen.writeEndObject();
-        } else {
-        	jGen.writeStartObject();
-            jGen.writeArrayFieldStart(fieldName);
-            for (OFAction action : actions) {
-                jGen.writeString(action.toString());
-            }
-            jGen.writeEndArray();
-            jGen.writeEndObject();
-        }
-    }
+		// handle OF1.1+ instructions with actions within
+		if (flowMod.getVersion() == OFVersion.OF_10) {
+			OFActionListSerializer.serializeActions(jGen, flowMod.getActions());
+		} else {
+			OFInstructionListSerializer.serializeInstructionList(jGen, flowMod.getInstructions());
+		} // end not-empty instructions (else)
+		jGen.writeEndObject();
+	} // end method
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/OFInstructionListSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/OFInstructionListSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..e16b1854826c709812cb9e79ab5cb638671efb68
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/OFInstructionListSerializer.java
@@ -0,0 +1,80 @@
+package net.floodlightcontroller.core.web.serializers;
+
+import java.io.IOException;
+import java.util.List;
+
+import net.floodlightcontroller.util.InstructionUtils;
+
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionExperimenter;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionGotoTable;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionMeter;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteActions;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteMetadata;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+/**
+ * Serialize any List of OFInstruction in JSON.
+ * 
+ * Use automatically by Jackson via JsonSerialize(using=OFInstructionListSerializer.class),
+ * or use the static function within this class within another serializer.
+ * 
+ * @author Ryan Izard, ryan.izard@bigswitch.com, rizard@g.clemson.edu
+ */
+public class OFInstructionListSerializer extends JsonSerializer<List<OFInstruction>> {
+
+	@Override
+	public void serialize(List<OFInstruction> instructions, JsonGenerator jGen, SerializerProvider serializer) throws IOException,
+			JsonProcessingException {
+		serializeInstructionList(jGen, instructions);
+	}
+	
+	public static void serializeInstructionList(JsonGenerator jGen, List<OFInstruction> instructions) throws IOException, JsonProcessingException {
+		jGen.writeObjectFieldStart("instructions");
+        if (instructions.isEmpty()) {
+            jGen.writeStringField("none", "drop");
+        } else {
+            for (OFInstruction i : instructions) {
+                switch (i.getType()) {
+                case CLEAR_ACTIONS:
+                    jGen.writeObjectFieldStart(InstructionUtils.STR_CLEAR_ACTIONS);
+                    break;
+                case WRITE_METADATA:
+                    jGen.writeStartObject();
+                    jGen.writeNumberField(InstructionUtils.STR_WRITE_METADATA, ((OFInstructionWriteMetadata)i).getMetadata().getValue());
+                    jGen.writeNumberField(InstructionUtils.STR_WRITE_METADATA + "_mask", ((OFInstructionWriteMetadata)i).getMetadataMask().getValue());
+                    break;
+                case EXPERIMENTER:
+                    jGen.writeStartObject();
+                    jGen.writeNumberField(InstructionUtils.STR_EXPERIMENTER, ((OFInstructionExperimenter)i).getExperimenter());
+                    break;
+                case GOTO_TABLE:
+                    jGen.writeStartObject();
+                    jGen.writeNumberField(InstructionUtils.STR_GOTO_TABLE, ((OFInstructionGotoTable)i).getTableId().getValue());
+                    break;
+                case METER:
+                    jGen.writeStartObject();
+                    jGen.writeNumberField(InstructionUtils.STR_GOTO_METER, ((OFInstructionMeter)i).getMeterId());
+                    break;
+                case APPLY_ACTIONS:
+                    jGen.writeObjectFieldStart(InstructionUtils.STR_APPLY_ACTIONS);
+                    OFActionListSerializer.serializeActions(jGen, ((OFInstructionApplyActions)i).getActions());
+                    break;
+                case WRITE_ACTIONS:
+                    jGen.writeObjectFieldStart(InstructionUtils.STR_WRITE_ACTIONS);
+                    OFActionListSerializer.serializeActions(jGen, ((OFInstructionWriteActions)i).getActions());
+                default:
+                    // shouldn't ever get here
+                    break;
+                } // end switch on instruction
+                jGen.writeEndObject(); // end specific instruction
+            } // end for instructions
+            jGen.writeEndObject();
+        } // end process instructions (OF1.1+ only)
+    } // end not-empty instructions (else)
+}
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java
index e001f62f8bec506d89ebb9bea34e8e8081219e36..b176bbc1cdd86024e5c49f2554067a88db460b4d 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java
@@ -19,7 +19,6 @@ package net.floodlightcontroller.core.web.serializers;
 
 import java.io.IOException;
 import java.util.List;
-import java.util.Iterator;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonGenerator.Feature;
@@ -29,9 +28,6 @@ import com.fasterxml.jackson.databind.SerializerProvider;
 
 import net.floodlightcontroller.core.web.OFStatsTypeStrings;
 import net.floodlightcontroller.core.web.StatsReply;
-import net.floodlightcontroller.util.ActionUtils;
-import net.floodlightcontroller.util.InstructionUtils;
-import net.floodlightcontroller.util.MatchUtils;
 
 import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
@@ -60,15 +56,18 @@ import org.projectfloodlight.openflow.protocol.ver11.OFPortConfigSerializerVer11
 import org.projectfloodlight.openflow.protocol.ver10.OFPortConfigSerializerVer10;
 import org.projectfloodlight.openflow.protocol.OFAggregateStatsReply;
 import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.protocol.match.*;
-import org.projectfloodlight.openflow.protocol.oxm.*;
-import org.projectfloodlight.openflow.protocol.instruction.*;
-import org.projectfloodlight.openflow.protocol.action.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Serialize a DPID as colon-separated hexadecimal
+ * Serialize any OFStatsReply or OFFeaturesReply in JSON
+ * wrapped by a StatsReply object.
+ * 
+ * Use automatically by Jackson via JsonSerialize(using=StatsReplySerializer.class),
+ * or use the static functions within this class to serializer a specific OFStatType
+ * within another serializer.
+ * 
+ * @author Ryan Izard, ryan.izard@bigswitch.com, rizard@g.clemson.edu
  */
 public class StatsReplySerializer extends JsonSerializer<StatsReply> {
     protected static Logger logger = LoggerFactory.getLogger(StatsReplySerializer.class);
@@ -105,7 +104,7 @@ public class StatsReplySerializer extends JsonSerializer<StatsReply> {
         
         jGen.configure(Feature.WRITE_NUMBERS_AS_STRINGS, true); // IMHO this just looks nicer and is easier to read if everything is quoted
         jGen.writeStartObject();
-        jGen.writeStringField("dpid", reply.getDatapathId().toString());
+        //jGen.writeStringField("dpid", reply.getDatapathId().toString());
         switch (reply.getStatType()) {
         case PORT:
             // handle port
@@ -156,7 +155,7 @@ public class StatsReplySerializer extends JsonSerializer<StatsReply> {
         jGen.writeEndObject();
     }
 
-    public void serializePortReply(List<OFPortStatsReply> portReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
+    public static void serializePortReply(List<OFPortStatsReply> portReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
         OFPortStatsReply portReply = portReplies.get(0); // we will get only one PortReply and it will contains many OFPortStatsEntry ?
         jGen.writeStringField("version", portReply.getVersion().toString()); //return the enum name
         jGen.writeFieldName("port");
@@ -184,7 +183,8 @@ public class StatsReplySerializer extends JsonSerializer<StatsReply> {
         }
         jGen.writeEndArray();
     }
-    public void serializeFlowReply(List<OFFlowStatsReply> flowReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
+    
+    public static void serializeFlowReply(List<OFFlowStatsReply> flowReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
         for (OFFlowStatsReply flowReply : flowReplies) { // for each flow stats reply
             //Dose the switch will reply multiple OFFlowStatsReply ?
             //Or we juse need to use the first item of the list.
@@ -196,7 +196,7 @@ public class StatsReplySerializer extends JsonSerializer<StatsReply> {
                 // list flow stats/info
                 jGen.writeStringField("version", entry.getVersion().toString()); // return the enum name
                 jGen.writeNumberField("cookie", entry.getCookie().getValue());
-                jGen.writeNumberField("tableId", entry.getTableId().getValue());
+                jGen.writeStringField("tableId", entry.getTableId().toString());
                 jGen.writeNumberField("packetCount", entry.getPacketCount().getValue());
                 jGen.writeNumberField("byteCount", entry.getByteCount().getValue());
                 jGen.writeNumberField("durationSeconds", entry.getDurationSec());
@@ -224,364 +224,22 @@ public class StatsReplySerializer extends JsonSerializer<StatsReply> {
                 		break;
                 }
    
-                // list flow matches
-                jGen.writeObjectFieldStart("match");
-                Iterator<MatchField<?>> mi = entry.getMatch().getMatchFields().iterator(); // get iter to any match field type
-                Match m = entry.getMatch();
-
-                while (mi.hasNext()) {
-                    MatchField<?> mf = mi.next();
-                    switch (mf.id) {
-                    case IN_PORT:
-                        jGen.writeNumberField(MatchUtils.STR_IN_PORT, m.get(MatchField.IN_PORT).getPortNumber());
-                        break;
-                    case IN_PHY_PORT:
-                        jGen.writeNumberField(MatchUtils.STR_IN_PHYS_PORT, m.get(MatchField.IN_PHY_PORT).getPortNumber());
-                        break;
-                    case ARP_OP:
-                        jGen.writeNumberField(MatchUtils.STR_ARP_OPCODE, m.get(MatchField.ARP_OP).getOpcode());
-                        break;
-                    case ARP_SHA:
-                        jGen.writeStringField(MatchUtils.STR_ARP_SHA, m.get(MatchField.ARP_SHA).toString());
-                        break;
-                    case ARP_SPA:
-                        jGen.writeStringField(MatchUtils.STR_ARP_SPA, m.get(MatchField.ARP_SPA).toString());
-                        break;
-                    case ARP_THA:
-                        jGen.writeStringField(MatchUtils.STR_ARP_DHA, m.get(MatchField.ARP_THA).toString());
-                        break;
-                    case ARP_TPA:
-                        jGen.writeStringField(MatchUtils.STR_ARP_DPA, m.get(MatchField.ARP_TPA).toString());
-                        break;
-                    case ETH_TYPE:
-                        jGen.writeNumberField(MatchUtils.STR_DL_TYPE, m.get(MatchField.ETH_TYPE).getValue());
-                        break;
-                    case ETH_SRC:
-                        jGen.writeStringField(MatchUtils.STR_DL_SRC, m.get(MatchField.ETH_SRC).toString());
-                        break;
-                    case ETH_DST:
-                        jGen.writeStringField(MatchUtils.STR_DL_DST, m.get(MatchField.ETH_DST).toString());
-                        break;
-                    case VLAN_VID:
-                        jGen.writeNumberField(MatchUtils.STR_DL_VLAN, m.get(MatchField.VLAN_VID).getVlan());
-                        break;
-                    case VLAN_PCP:
-                        jGen.writeNumberField(MatchUtils.STR_DL_VLAN_PCP, m.get(MatchField.VLAN_PCP).getValue());
-                        break;
-                    case ICMPV4_TYPE:
-                        jGen.writeNumberField(MatchUtils.STR_ICMP_TYPE, m.get(MatchField.ICMPV4_TYPE).getType());
-                        break;
-                    case ICMPV4_CODE:
-                        jGen.writeNumberField(MatchUtils.STR_ICMP_CODE, m.get(MatchField.ICMPV4_CODE).getCode());
-                        break;
-                    case ICMPV6_TYPE:
-                        jGen.writeNumberField(MatchUtils.STR_ICMPV6_TYPE, m.get(MatchField.ICMPV6_TYPE).getValue());
-                        break;
-                    case ICMPV6_CODE:
-                        jGen.writeNumberField(MatchUtils.STR_ICMPV6_CODE, m.get(MatchField.ICMPV6_CODE).getValue());
-                        break;
-                    case IP_DSCP:
-                        jGen.writeNumberField(MatchUtils.STR_NW_DSCP, m.get(MatchField.IP_DSCP).getDscpValue());
-                        break;
-                    case IP_ECN:
-                        jGen.writeNumberField(MatchUtils.STR_NW_ECN, m.get(MatchField.IP_ECN).getEcnValue());
-                        break;
-                    case IP_PROTO:
-                        jGen.writeNumberField(MatchUtils.STR_NW_PROTO, m.get(MatchField.IP_PROTO).getIpProtocolNumber());
-                        break;
-                    case IPV4_SRC:
-                        jGen.writeStringField(MatchUtils.STR_NW_SRC, m.get(MatchField.IPV4_SRC).toString());
-                        break;
-                    case IPV4_DST:
-                        jGen.writeStringField(MatchUtils.STR_NW_DST, m.get(MatchField.IPV4_DST).toString());
-                        break;
-                    case IPV6_SRC:
-                        jGen.writeStringField(MatchUtils.STR_IPV6_SRC, m.get(MatchField.IPV6_SRC).toString());
-                        break;
-                    case IPV6_DST:
-                        jGen.writeStringField(MatchUtils.STR_IPV6_DST, m.get(MatchField.IPV6_DST).toString());
-                        break;
-                    case IPV6_FLABEL:
-                        jGen.writeNumberField(MatchUtils.STR_IPV6_FLOW_LABEL, m.get(MatchField.IPV6_FLABEL).getIPv6FlowLabelValue());
-                        break;
-                    case IPV6_ND_SLL:
-                        jGen.writeNumberField(MatchUtils.STR_IPV6_ND_SSL, m.get(MatchField.IPV6_ND_SLL).getLong());
-                        break;
-                    case IPV6_ND_TARGET:
-                        jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TARGET, m.get(MatchField.IPV6_ND_TARGET).getZeroCompressStart());
-                        break;
-                    case IPV6_ND_TLL:
-                        jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TTL, m.get(MatchField.IPV6_ND_TLL).getLong());
-                        break;
-                    case METADATA:
-                        jGen.writeNumberField(MatchUtils.STR_METADATA, m.get(MatchField.METADATA).getValue().getValue());
-                        break;
-                    case MPLS_LABEL:
-                        jGen.writeNumberField(MatchUtils.STR_MPLS_LABEL, m.get(MatchField.MPLS_LABEL).getValue());
-                        break;
-                    case MPLS_TC:
-                        jGen.writeNumberField(MatchUtils.STR_MPLS_TC, m.get(MatchField.MPLS_TC).getValue());
-                        break;
-                    case SCTP_SRC:
-                        jGen.writeNumberField(MatchUtils.STR_SCTP_SRC, m.get(MatchField.SCTP_SRC).getPort());
-                        break;
-                    case SCTP_DST:
-                        jGen.writeNumberField(MatchUtils.STR_SCTP_DST, m.get(MatchField.SCTP_DST).getPort());
-                        break;
-                    case TCP_SRC:
-                        jGen.writeNumberField(MatchUtils.STR_TCP_SRC, m.get(MatchField.TCP_SRC).getPort());
-                        break;
-                    case TCP_DST:
-                        jGen.writeNumberField(MatchUtils.STR_TCP_DST, m.get(MatchField.TCP_DST).getPort());
-                        break;
-                    case UDP_SRC:
-                        jGen.writeNumberField(MatchUtils.STR_UDP_SRC, m.get(MatchField.UDP_SRC).getPort());
-                        break;
-                    case UDP_DST:
-                        jGen.writeNumberField(MatchUtils.STR_UDP_DST, m.get(MatchField.UDP_DST).getPort());
-                        break;
-                    default:
-                        // either a BSN or unknown match type
-                        break;
-                    } // end switch of match type
-                } // end while over non-wildcarded matches
-
-                jGen.writeEndObject(); // end match
+                MatchSerializer.serializeMatch(jGen, entry.getMatch());
 
                 // handle OF1.1+ instructions with actions within
                 if (entry.getVersion() == OFVersion.OF_10) {
-                    serializeActions(jGen, entry.getActions());
+                	OFActionListSerializer.serializeActions(jGen, entry.getActions());
                 } else {
-                    List<OFInstruction> instructions = entry.getInstructions();
-                    jGen.writeObjectFieldStart("instructions");
-                    if (instructions.isEmpty()) {
-                        jGen.writeStringField("none", "drop");
-                    } else {
-                        for (OFInstruction i : instructions) {
-                            switch (i.getType()) {
-                            case CLEAR_ACTIONS:
-                                jGen.writeObjectFieldStart(InstructionUtils.STR_CLEAR_ACTIONS);
-                                break;
-                            case WRITE_METADATA:
-                                jGen.writeStartObject();
-                                jGen.writeNumberField(InstructionUtils.STR_WRITE_METADATA, ((OFInstructionWriteMetadata)i).getMetadata().getValue());
-                                jGen.writeNumberField(InstructionUtils.STR_WRITE_METADATA + "_mask", ((OFInstructionWriteMetadata)i).getMetadataMask().getValue());
-                                break;
-                            case EXPERIMENTER:
-                                jGen.writeStartObject();
-                                jGen.writeNumberField(InstructionUtils.STR_EXPERIMENTER, ((OFInstructionExperimenter)i).getExperimenter());
-                                break;
-                            case GOTO_TABLE:
-                                jGen.writeStartObject();
-                                jGen.writeNumberField(InstructionUtils.STR_GOTO_TABLE, ((OFInstructionGotoTable)i).getTableId().getValue());
-                                break;
-                            case METER:
-                                jGen.writeStartObject();
-                                jGen.writeNumberField(InstructionUtils.STR_GOTO_METER, ((OFInstructionMeter)i).getMeterId());
-                                break;
-                            case APPLY_ACTIONS:
-                                jGen.writeObjectFieldStart(InstructionUtils.STR_APPLY_ACTIONS);
-                                serializeActions(jGen, ((OFInstructionApplyActions)i).getActions());
-                                break;
-                            case WRITE_ACTIONS:
-                                jGen.writeObjectFieldStart(InstructionUtils.STR_WRITE_ACTIONS);
-                                serializeActions(jGen, ((OFInstructionWriteActions)i).getActions());
-                            default:
-                                // shouldn't ever get here
-                                break;
-                            } // end switch on instruction
-                            jGen.writeEndObject(); // end specific instruction
-                        } // end for instructions
-                        jGen.writeEndObject();
-                    } // end process instructions (OF1.1+ only)
-                } // end not-empty instructions (else)
+                   OFInstructionListSerializer.serializeInstructionList(jGen, entry.getInstructions());
+                }
+                    
                 jGen.writeEndObject();
             } // end for each OFFlowStatsReply entry
             jGen.writeEndArray();
         } // end for each OFStatsReply
     } // end method
 
-    /**
-     * Write a JSON string given a list of OFAction. Supports OF1.0 - OF1.3.
-     * This is the only place actions are serialized, for any OF version. Because
-     * some OF version share actions, it makes sense to have them in one place.
-     * @param jsonGenerator
-     * @param actions
-     * @throws IOException
-     * @throws JsonProcessingException
-     */
-    public void serializeActions(JsonGenerator jsonGenerator, List<OFAction> actions) throws IOException, JsonProcessingException {
-        //jsonGenerator.writeStartObject();
-        if (actions.isEmpty()) {
-            jsonGenerator.writeStringField("none", "drop");
-        }
-        for (OFAction a : actions) {
-            switch (a.getType()) {
-            case OUTPUT:
-                jsonGenerator.writeNumberField(ActionUtils.STR_OUTPUT, ((OFActionOutput)a).getPort().getPortNumber());
-                break;
-            /* begin OF1.0 ONLY actions */
-            case SET_VLAN_VID:
-                jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_SET_VID, ((OFActionSetVlanVid)a).getVlanVid().getVlan());
-                break;
-            case SET_VLAN_PCP:
-                jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_SET_PCP, ((OFActionSetVlanPcp)a).getVlanPcp().getValue());
-                break;
-            case SET_QUEUE:
-                jsonGenerator.writeNumberField(ActionUtils.STR_QUEUE_SET, ((OFActionSetQueue)a).getQueueId());
-                break;
-            case SET_DL_SRC:
-                jsonGenerator.writeStringField(ActionUtils.STR_DL_SRC_SET, ((OFActionSetDlSrc)a).getDlAddr().toString());
-                break;
-            case SET_DL_DST:
-                jsonGenerator.writeStringField(ActionUtils.STR_DL_DST_SET, ((OFActionSetDlDst)a).getDlAddr().toString());
-                break;
-            case SET_NW_SRC:
-                jsonGenerator.writeStringField(ActionUtils.STR_NW_SRC_SET, ((OFActionSetNwSrc)a).getNwAddr().toString());
-                break;
-            case SET_NW_DST:
-                jsonGenerator.writeStringField(ActionUtils.STR_NW_DST_SET, ((OFActionSetNwDst)a).getNwAddr().toString());
-                break;
-            case SET_NW_TOS:
-                jsonGenerator.writeNumberField(ActionUtils.STR_NW_TOS_SET, ((OFActionSetNwTos)a).getNwTos());
-                break;    
-            case SET_TP_SRC:
-                jsonGenerator.writeNumberField(ActionUtils.STR_TP_SRC_SET, ((OFActionSetTpSrc)a).getTpPort().getPort());
-                break;
-            case SET_TP_DST:
-                jsonGenerator.writeNumberField(ActionUtils.STR_TP_DST_SET, ((OFActionSetTpDst)a).getTpPort().getPort());
-                break;
-            /* end OF1.0 ONLY actions; begin OF1.1+ actions */
-            case ENQUEUE:
-                jsonGenerator.writeNumberField(ActionUtils.STR_ENQUEUE, ((OFActionEnqueue)a).getPort().getPortNumber());
-                break;
-            case GROUP:
-                jsonGenerator.writeNumberField(ActionUtils.STR_GROUP, ((OFActionGroup)a).getGroup().getGroupNumber());
-                break;
-            case STRIP_VLAN:
-                jsonGenerator.writeString(ActionUtils.STR_VLAN_STRIP);
-                break;
-            case PUSH_VLAN:
-                jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_PUSH, ((OFActionPushVlan)a).getEthertype().getValue());
-                break;
-            case PUSH_MPLS:
-                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_PUSH, ((OFActionPushMpls)a).getEthertype().getValue());
-                break;
-            case PUSH_PBB:
-                jsonGenerator.writeNumberField(ActionUtils.STR_PBB_PUSH, ((OFActionPushPbb)a).getEthertype().getValue());
-                break;
-            case POP_VLAN:
-                jsonGenerator.writeString(ActionUtils.STR_VLAN_POP);
-                break;
-            case POP_MPLS:
-                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_POP, ((OFActionPopMpls)a).getEthertype().getValue());
-                break;
-            case POP_PBB:
-                jsonGenerator.writeString(ActionUtils.STR_PBB_POP);
-                break;
-            case COPY_TTL_IN:
-                jsonGenerator.writeString(ActionUtils.STR_TTL_IN_COPY);
-                break;
-            case COPY_TTL_OUT:
-                jsonGenerator.writeString(ActionUtils.STR_TTL_OUT_COPY);
-                break;
-            case DEC_NW_TTL:
-                jsonGenerator.writeString(ActionUtils.STR_NW_TTL_DEC);
-                break;
-            case DEC_MPLS_TTL:
-                jsonGenerator.writeString(ActionUtils.STR_MPLS_TTL_DEC);
-                break;
-            case SET_MPLS_LABEL:
-                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_LABEL_SET, ((OFActionSetMplsLabel)a).getMplsLabel());
-                break;
-            case SET_MPLS_TC:
-                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_TC_SET, ((OFActionSetMplsTc)a).getMplsTc());
-                break;
-            case SET_MPLS_TTL:
-                jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_TTL_SET, ((OFActionSetMplsTtl)a).getMplsTtl());
-                break;
-            case SET_NW_ECN:
-                jsonGenerator.writeNumberField(ActionUtils.STR_NW_ECN_SET, ((OFActionSetNwEcn)a).getNwEcn().getEcnValue());
-                break;
-            case SET_NW_TTL:
-                jsonGenerator.writeNumberField(ActionUtils.STR_NW_TTL_SET, ((OFActionSetNwTtl)a).getNwTtl());
-                break;
-            case EXPERIMENTER:
-                jsonGenerator.writeNumberField(ActionUtils.STR_EXPERIMENTER, ((OFActionExperimenter)a).getExperimenter());
-                break;
-            case SET_FIELD:
-                if (((OFActionSetField)a).getField() instanceof OFOxmArpOp) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_ARP_OPCODE, ((OFOxmArpOp) ((OFActionSetField) a).getField()).getValue().getOpcode());
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmArpSha) {
-                    jsonGenerator.writeStringField(MatchUtils.STR_ARP_SHA, ((OFOxmArpSha) ((OFActionSetField) a).getField()).getValue().toString()); // macaddress formats string already
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmArpTha) {
-                    jsonGenerator.writeStringField(MatchUtils.STR_ARP_DHA, ((OFOxmArpTha) ((OFActionSetField) a).getField()).getValue().toString());
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmArpSpa) {
-                    jsonGenerator.writeStringField(MatchUtils.STR_ARP_SPA, ((OFOxmArpSpa) ((OFActionSetField) a).getField()).getValue().toString()); // ipaddress formats string already
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmArpTpa) {
-                    jsonGenerator.writeStringField(MatchUtils.STR_ARP_DPA, ((OFOxmArpTpa) ((OFActionSetField) a).getField()).getValue().toString()); 
-                } 
-                /* DATA LAYER */
-                else if (((OFActionSetField)a).getField() instanceof OFOxmEthType) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_DL_TYPE, ((OFOxmEthType) ((OFActionSetField) a).getField()).getValue().getValue());
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmEthSrc) {
-                    jsonGenerator.writeStringField(MatchUtils.STR_DL_SRC, ((OFOxmEthSrc) ((OFActionSetField) a).getField()).getValue().toString());
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmEthDst) {
-                    jsonGenerator.writeStringField(MatchUtils.STR_DL_DST, ((OFOxmEthDst) ((OFActionSetField) a).getField()).getValue().toString()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmVlanVid) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_DL_VLAN, ((OFOxmVlanVid) ((OFActionSetField) a).getField()).getValue().getVlan()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmVlanPcp) {
-                } 
-                /* ICMP */
-                else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Code) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_ICMP_CODE, ((OFOxmIcmpv4Code) ((OFActionSetField) a).getField()).getValue().getCode()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Type) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_ICMP_TYPE, ((OFOxmIcmpv4Type) ((OFActionSetField) a).getField()).getValue().getType()); 
-                } 
-                /* NETWORK LAYER */
-                else if (((OFActionSetField)a).getField() instanceof OFOxmIpProto) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_NW_PROTO, ((OFOxmIpProto) ((OFActionSetField) a).getField()).getValue().getIpProtocolNumber()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Src) {
-                    jsonGenerator.writeStringField(MatchUtils.STR_NW_SRC, ((OFOxmIpv4Src) ((OFActionSetField) a).getField()).getValue().toString()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Dst) {
-                    jsonGenerator.writeStringField(MatchUtils.STR_NW_DST, ((OFOxmIpv4Dst) ((OFActionSetField) a).getField()).getValue().toString()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmIpEcn) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_NW_ECN, ((OFOxmIpEcn) ((OFActionSetField) a).getField()).getValue().getEcnValue()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmIpDscp) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_NW_DSCP, ((OFOxmIpDscp) ((OFActionSetField) a).getField()).getValue().getDscpValue()); 
-                } 
-                /* TRANSPORT LAYER, TCP, UDP, and SCTP */
-                else if (((OFActionSetField)a).getField() instanceof OFOxmTcpSrc) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_TCP_SRC, ((OFOxmTcpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmTcpDst) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_TCP_DST, ((OFOxmTcpDst) ((OFActionSetField) a).getField()).getValue().getPort()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmUdpSrc) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_UDP_SRC, ((OFOxmUdpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmUdpDst) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_UDP_DST, ((OFOxmUdpDst) ((OFActionSetField) a).getField()).getValue().getPort()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmSctpSrc) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_SCTP_SRC, ((OFOxmSctpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmSctpDst) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_SCTP_DST, ((OFOxmSctpDst) ((OFActionSetField) a).getField()).getValue().getPort()); 
-                }
-                /* MPLS */
-                else if (((OFActionSetField)a).getField() instanceof OFOxmMplsLabel) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_MPLS_LABEL, ((OFOxmMplsLabel) ((OFActionSetField) a).getField()).getValue().getValue()); 
-                } else if (((OFActionSetField)a).getField() instanceof OFOxmMplsTc) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_MPLS_TC, ((OFOxmMplsTc) ((OFActionSetField) a).getField()).getValue().getValue()); 
-                } // MPLS_BOS not implemented in loxi
-                /* METADATA */
-                else if (((OFActionSetField)a).getField() instanceof OFOxmMetadata) {
-                    jsonGenerator.writeNumberField(MatchUtils.STR_METADATA, ((OFOxmMetadata) ((OFActionSetField) a).getField()).getValue().getValue().getValue()); 
-                } else {
-                    logger.error("Could not decode Set-Field action field: {}", ((OFActionSetField) a));
-                    // need to get a logger in here somehow log.error("Could not decode Set-Field action field: {}", ((OFActionSetField) a));
-                }
-            } // end switch over action type
-        } // end for over all actions
-    } // end method
-
-    public void serializeDescReply(List<OFDescStatsReply> descReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
+    public static void serializeDescReply(List<OFDescStatsReply> descReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
         OFDescStatsReply descReply = descReplies.get(0); // There are only one descReply from the switch
         jGen.writeObjectFieldStart("desc"); 
         jGen.writeStringField("version", descReply.getVersion().toString()); //return the enum name
@@ -592,7 +250,8 @@ public class StatsReplySerializer extends JsonSerializer<StatsReply> {
         jGen.writeStringField("datapathDescription", descReply.getDpDesc()); 
         jGen.writeEndObject(); // end match
     }
-    public void serializeAggregateReply(List<OFAggregateStatsReply> aggregateReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
+    
+    public static void serializeAggregateReply(List<OFAggregateStatsReply> aggregateReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
         OFAggregateStatsReply aggregateReply = aggregateReplies.get(0); // There are only one aggregateReply from the switch
         jGen.writeObjectFieldStart("aggregate"); 
         jGen.writeStringField("version", aggregateReply.getVersion().toString()); //return the enum name
@@ -602,7 +261,7 @@ public class StatsReplySerializer extends JsonSerializer<StatsReply> {
         jGen.writeEndObject(); // end match
     }
 
-    public void serializePortDescReply(List<OFPortDescStatsReply> portDescReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
+    public static void serializePortDescReply(List<OFPortDescStatsReply> portDescReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
         OFPortDescStatsReply portDescReply = portDescReplies.get(0); // we will get only one PortDescReply and it will contains many OFPortDescStatsEntry ?
         jGen.writeStringField("version", portDescReply.getVersion().toString()); //return the enum name
         jGen.writeFieldName("portDesc");
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/web/OFFlowModMap.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/OFFlowModMap.java
index d79e7817c76b8dc8b2e114cdf99bf6fe73fdd9d8..f91fdedc36e0c5cefe68955e2ad27602df91cbdf 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/web/OFFlowModMap.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/web/OFFlowModMap.java
@@ -1,7 +1,6 @@
 package net.floodlightcontroller.staticflowentry.web;
 
 import java.util.Map;
-import net.floodlightcontroller.core.web.serializers.OFFlowModMapSerializer;
 
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/OFFlowModMapSerializer.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/OFFlowModMapSerializer.java
similarity index 78%
rename from src/main/java/net/floodlightcontroller/core/web/serializers/OFFlowModMapSerializer.java
rename to src/main/java/net/floodlightcontroller/staticflowentry/web/OFFlowModMapSerializer.java
index 853c9d7f8e9e170d222d77e9fb7505db0417d7b1..368716790868845ded5ab967568fc02d81d5df8e 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/OFFlowModMapSerializer.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/web/OFFlowModMapSerializer.java
@@ -1,14 +1,15 @@
-package net.floodlightcontroller.core.web.serializers;
+package net.floodlightcontroller.staticflowentry.web;
 
 import java.io.IOException;
 import java.util.Map;
 
-import net.floodlightcontroller.staticflowentry.web.OFFlowModMap;
+import net.floodlightcontroller.core.web.serializers.OFFlowModSerializer;
 
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonGenerator.Feature;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
 
@@ -29,6 +30,8 @@ public class OFFlowModMapSerializer extends JsonSerializer<OFFlowModMap> {
 	@Override
 	public void serialize(OFFlowModMap fmm, JsonGenerator jGen, SerializerProvider serializer)
 			throws IOException, JsonProcessingException {
+		
+        jGen.configure(Feature.WRITE_NUMBERS_AS_STRINGS, true); // IMHO this just looks nicer and is easier to read if everything is quoted
 
 		if (fmm == null) {
 			jGen.writeStartObject();
@@ -38,7 +41,6 @@ public class OFFlowModMapSerializer extends JsonSerializer<OFFlowModMap> {
 		}
 
 		Map<String, Map<String, OFFlowMod>> theMap = fmm.getMap();
-		OFFlowModSerializer fms = new OFFlowModSerializer();
 
 		jGen.writeStartObject();
 		if (theMap.keySet() != null) {
@@ -47,9 +49,8 @@ public class OFFlowModMapSerializer extends JsonSerializer<OFFlowModMap> {
 					jGen.writeArrayFieldStart(dpid);
 					for (String name : theMap.get(dpid).keySet()) {
 						jGen.writeStartObject();
-						jGen.writeArrayFieldStart(name);
-						fms.serialize(theMap.get(dpid).get(name), jGen, serializer);
-						jGen.writeEndArray();
+						jGen.writeFieldName(name);
+						OFFlowModSerializer.serializeFlowMod(jGen, theMap.get(dpid).get(name));
 						jGen.writeEndObject();
 					}    
 					jGen.writeEndArray();
diff --git a/src/main/java/net/floodlightcontroller/testmodule/TestModule.java b/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
index 0949bf55535891c0ce839e5c2a19a27ec529f96f..3c345ce6ab6ab0042b1818f456417f0884d6abd3 100644
--- a/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
+++ b/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
@@ -3,6 +3,7 @@ package net.floodlightcontroller.testmodule;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
@@ -11,11 +12,18 @@ import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFFlowAdd;
 import org.projectfloodlight.openflow.protocol.OFMeterBandStats;
 import org.projectfloodlight.openflow.protocol.OFMeterBandType;
+import org.projectfloodlight.openflow.protocol.OFMeterConfig;
 import org.projectfloodlight.openflow.protocol.OFMeterMod;
 import org.projectfloodlight.openflow.protocol.OFMeterModCommand;
 import org.projectfloodlight.openflow.protocol.OFOxmClass;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFSetConfig;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropWriteActions;
+import org.projectfloodlight.openflow.protocol.OFTableFeaturePropWriteSetfield;
+import org.projectfloodlight.openflow.protocol.OFTableMod;
+import org.projectfloodlight.openflow.protocol.OFTableModProp;
+import org.projectfloodlight.openflow.protocol.OFTableModPropEviction;
+import org.projectfloodlight.openflow.protocol.OFTableModPropEvictionFlag;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.protocol.action.OFAction;
 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
@@ -59,6 +67,8 @@ import org.projectfloodlight.openflow.types.VlanVid;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableList;
+
 import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.PortChangeType;
 import net.floodlightcontroller.core.internal.IOFSwitchService;
@@ -114,7 +124,36 @@ public class TestModule implements IFloodlightModule, IOFSwitchListener {
 	@Override
 	public void switchAdded(DatapathId switchId) {
 		OFFactory factory = switchService.getSwitch(switchId).getOFFactory();
-		OFFlowAdd.Builder fmb = factory.buildFlowAdd();
+		
+		/*
+		 * An attempt at meters, but they aren't supported anywhere, yet... 
+		 * OFMeterBand mb = factory.meterBands().buildDrop()
+				.setRate(1000)
+				.setBurstSize(1000)
+				.build();
+		ArrayList<OFMeterBand> mbl = new ArrayList<OFMeterBand>();
+		mbl.add(mb);
+		
+		OFMeterMod mm = factory.buildMeterMod()
+				.setMeters(mbl)
+				.setMeterId(1)
+				.setCommand(0)
+				.build(); */
+		
+		/*HashSet<OFTableModPropEvictionFlag> efs = new HashSet<OFTableModPropEvictionFlag>();
+		efs.add(OFTableModPropEvictionFlag.IMPORTANCE);
+		
+		ArrayList<OFTableModProp> tabModPropList = new ArrayList<OFTableModProp>();
+		OFTableFeaturePropWriteActions propEvic = switchService.getActiveSwitch(switchId).getOFFactory().buildTableFeaturePropWriteActions()
+				.setActionIds(actionIds)
+				.build();
+		tabModPropList.add(propEvic);
+		OFTableMod tm = switchService.getActiveSwitch(switchId).getOFFactory().buildTableMod()
+				.setProperties(pro)
+		
+		switchService.getActiveSwitch(switchId).write(mm);*/
+		
+		/*OFFlowAdd.Builder fmb = factory.buildFlowAdd();
 		List<OFAction> actions = new ArrayList<OFAction>();
         Match.Builder mb = factory.buildMatch();
         List<OFInstruction> instructions = new ArrayList<OFInstruction>();
@@ -166,7 +205,7 @@ public class TestModule implements IFloodlightModule, IOFSwitchListener {
         actions.add(factory.actions().setField(factory.oxms().arpTpa(IPv4Address.of("255.255.255.255")))); 
         fmb.setTableId(TableId.of(16)); */
         
-        /* TP, IP OPT, VLAN TESTS */  mb.setExact(MatchField.ETH_TYPE, EthType.IPv4);
+        /* TP, IP OPT, VLAN TESTS   mb.setExact(MatchField.ETH_TYPE, EthType.IPv4);
         mb.setExact(MatchField.VLAN_PCP, VlanPcp.of((byte) 1)); // might as well test these now too
         //mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(512));
         mb.setExact(MatchField.MPLS_LABEL, U32.of(32));
@@ -202,17 +241,17 @@ public class TestModule implements IFloodlightModule, IOFSwitchListener {
         actions.add(factory.actions().setField(factory.oxms().mplsTc(U8.ZERO))); */
         
         /* METADATA TEST 
-        mb.setExact(MatchField.METADATA, OFMetadata.ofRaw(1)); */
+        mb.setExact(MatchField.METADATA, OFMetadata.ofRaw(1)); 
         //fmb.setActions(actions); // this will automatically create the apply actions instruction
         applyActInstBldr.setActions(actions);
         //mtrBldr.setMeterId(1);
         instructions.add(applyActInstBldr.build());
         //instructions.add(mtrBldr.build());
         fmb.setInstructions(instructions);
-        fmb.setMatch(mb.build());
+        fmb.setMatch(mb.build()); 
 		        
 		sfps.addFlow("test-flow", fmb.build(), switchId);
-		//sfps.deleteFlow("test-flow");
+		//sfps.deleteFlow("test-flow"); */
 		
 	}