diff --git a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
index de90067ae5411bb835dcca4bff21be839c61f01f..cd4f77f917001048338bebe74d100e1bbe19d535 100644
--- a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
@@ -54,28 +54,36 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
         OFStatsType type = null;
         REQUESTTYPE rType = null;
 
-        if (statType.equals("port")) {
-            type = OFStatsType.PORT;
+        switch (statType) {
+        case OFStatsTypeStrings.PORT:
+        	type = OFStatsType.PORT;
             rType = REQUESTTYPE.OFSTATS;
-        } else if (statType.equals("queue")) {
-            type = OFStatsType.QUEUE;
+            break;
+        case OFStatsTypeStrings.QUEUE:
+        	type = OFStatsType.QUEUE;
             rType = REQUESTTYPE.OFSTATS;
-        } else if (statType.equals("flow")) {
-            type = OFStatsType.FLOW;
+            break;
+        case OFStatsTypeStrings.FLOW:
+        	type = OFStatsType.FLOW;
             rType = REQUESTTYPE.OFSTATS;
-        } else if (statType.equals("aggregate")) {
-            type = OFStatsType.AGGREGATE;
+            break;
+        case OFStatsTypeStrings.AGGREGATE:
+        	type = OFStatsType.AGGREGATE;
             rType = REQUESTTYPE.OFSTATS;
-        } else if (statType.equals("desc")) {
-            type = OFStatsType.DESC;
+            break;
+        case OFStatsTypeStrings.DESC:
+        	type = OFStatsType.DESC;
             rType = REQUESTTYPE.OFSTATS;
-        } else if (statType.equals("table")) {
-            type = OFStatsType.TABLE;
+            break;
+        case OFStatsTypeStrings.TABLE:
+        	type = OFStatsType.TABLE;
             rType = REQUESTTYPE.OFSTATS;
-        } else if (statType.equals("features")) {
+            break;
+        case OFStatsTypeStrings.FEATURES:
             rType = REQUESTTYPE.OFFEATURES;
-        } else {
-            return model;
+            break;
+        default:
+        	return model;
         }
 
         IOFSwitchService switchService =
diff --git a/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java b/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java
index a4fe5d657184b8ce479d15887227f0f725fa04b8..8c1927863da5bd2b53b7be4baf74e4796a8d55a7 100644
--- a/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java
@@ -29,6 +29,14 @@ import org.restlet.routing.Router;
  * @author readams
  */
 public class CoreWebRoutable implements RestletRoutable {
+	// define the parts of each path the user can define in the REST message at runtime
+	// access these same strings where the attributes are parsed
+	public static final String STR_SWITCH_ID = "switchId";
+	public static final String STR_STAT_TYPE = "statType";
+	public static final String STR_CTR_TITLE = "counterTitle";
+	public static final String STR_CTR_NAME = "counterName";
+	public static final String STR_LAYER = "layer";
+	
     @Override
     public String basePath() {
         return "/wm/core";
@@ -39,13 +47,13 @@ public class CoreWebRoutable implements RestletRoutable {
         Router router = new Router(context);
         router.attach("/module/all/json", ModuleLoaderResource.class);
         router.attach("/module/loaded/json", LoadedModuleLoaderResource.class);
-        router.attach("/switch/{switchId}/role/json", SwitchRoleResource.class);
-        router.attach("/switch/all/{statType}/json", AllSwitchStatisticsResource.class);
-        router.attach("/switch/{switchId}/{statType}/json", SwitchStatisticsResource.class);
+        router.attach("/switch/{" + STR_SWITCH_ID + "}/role/json", SwitchRoleResource.class);
+        router.attach("/switch/all/{" + STR_STAT_TYPE + "}/json", AllSwitchStatisticsResource.class);
+        router.attach("/switch/{" + STR_SWITCH_ID + "}/{" + STR_STAT_TYPE + "}/json", SwitchStatisticsResource.class);
         router.attach("/controller/switches/json", ControllerSwitchesResource.class);
-        router.attach("/counter/{counterTitle}/json", CounterResource.class);
-        router.attach("/counter/{switchId}/{counterName}/json", SwitchCounterResource.class);
-        router.attach("/counter/categories/{switchId}/{counterName}/{layer}/json", SwitchCounterCategoriesResource.class);
+        router.attach("/counter/{" + STR_CTR_TITLE + "}/json", CounterResource.class);
+        router.attach("/counter/{" + STR_SWITCH_ID + "}/{" + STR_CTR_NAME + "}/json", SwitchCounterResource.class);
+        router.attach("/counter/categories/{" + STR_SWITCH_ID + "}/{" + STR_CTR_NAME + "}/{" + STR_LAYER + "}/json", SwitchCounterCategoriesResource.class);
         router.attach("/memory/json", ControllerMemoryResource.class);
         router.attach("/packettrace/json", PacketTraceResource.class);
         router.attach("/storage/tables/json", StorageSourceTablesResource.class);
diff --git a/src/main/java/net/floodlightcontroller/core/web/StatsReply.java b/src/main/java/net/floodlightcontroller/core/web/StatsReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..a705fa987075a4becee5c63b353502104493c187
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/web/StatsReply.java
@@ -0,0 +1,45 @@
+package net.floodlightcontroller.core.web;
+
+
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.types.DatapathId;
+
+import net.floodlightcontroller.core.web.serializers.StatsReplySerializer;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@JsonSerialize(using=StatsReplySerializer.class)
+public class StatsReply {
+    private DatapathId datapath;
+    private Object values;
+    private OFStatsType statType;
+
+    public StatsReply() {}
+
+    public StatsReply(DatapathId dpid, Object values, OFStatsType type){
+        this.datapath = dpid;
+        this.values = values;
+        this.statType = type;
+    }
+    public void setDatapathId(DatapathId dpid){
+        this.datapath = dpid;
+    }
+    public void setValues(Object values){
+        this.values = values;
+    }
+    public void setStatType(OFStatsType type){
+        this.statType = type;
+    }
+    public DatapathId getDatapathId(){
+        return datapath;
+    }
+    public Object getValues(){
+        return values;
+    }
+    public OFStatsType getStatType(){
+        return statType;
+    }
+    
+}
+
+
diff --git a/src/main/java/net/floodlightcontroller/core/web/StatsReplySerializer.java b/src/main/java/net/floodlightcontroller/core/web/StatsReplySerializer.java
deleted file mode 100644
index d39bac142fff7d8ed9a5d82761879a7b5c290c71..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/web/StatsReplySerializer.java
+++ /dev/null
@@ -1,430 +0,0 @@
-package net.floodlightcontroller.core.web;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-import net.floodlightcontroller.util.MatchUtils;
-
-import org.projectfloodlight.openflow.protocol.OFActionType;
-import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
-import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
-import org.projectfloodlight.openflow.protocol.OFInstructionType;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsType;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.protocol.action.OFActionEnqueue;
-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.OFActionPopPbb;
-import org.projectfloodlight.openflow.protocol.action.OFActionPopVlan;
-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.OFActionSetNwDst;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
-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.action.OFActionStripVlan;
-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.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.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 com.fasterxml.jackson.core.JsonGenerationException;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-public class StatsReplySerializer extends JsonSerializer<Map<String, Object>> {
-
-	@Override
-	public void serialize(Map<String, Object> statsReply, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
-		// Map<String, Object> ==> Map<Switch-DPID-String, List<OFStatsReply>>
-		// It should be safe to cast the Object as a List of OFStatsReply's
-		String dpidStr = statsReply.keySet().iterator().next(); // there's got to be a simpler way to get the key
-		List<OFStatsReply> srList = (List<OFStatsReply>) statsReply.get(dpidStr);
-
-		for (OFStatsReply sr : srList) {
-			OFStatsType t = sr.getStatsType();
-			switch (t) {
-			case FLOW:
-				List<OFFlowStatsEntry> entries = ((OFFlowStatsReply) sr).getEntries();
-				for (OFFlowStatsEntry entry : entries) {
-					// list flow stats/info
-					jsonGenerator.writeStartObject();
-					jsonGenerator.writeStringField("switch", dpidStr);
-					jsonGenerator.writeStartObject();
-					jsonGenerator.writeStringField("version", entry.getVersion().toString()); // return the enum name
-					jsonGenerator.writeNumberField("cookie", entry.getCookie().getValue());
-					jsonGenerator.writeNumberField("table-id", entry.getTableId().getValue());
-					jsonGenerator.writeNumberField("packet-count", entry.getPacketCount().getValue());
-					jsonGenerator.writeNumberField("byte-count", entry.getByteCount().getValue());
-					jsonGenerator.writeNumberField("duration-sec", entry.getDurationSec());
-					jsonGenerator.writeNumberField("priority", entry.getPriority());
-					jsonGenerator.writeNumberField("idle-timeout-sec", entry.getIdleTimeout());
-					jsonGenerator.writeNumberField("hard-timeout-sec", entry.getHardTimeout());
-					jsonGenerator.writeNumberField("flags", entry.getFlags());
-					// list flow matches
-					jsonGenerator.writeObjectFieldStart("match"); // TODO does this create the object already?
-					jsonGenerator.writeStartObject();
-					Match m = entry.getMatch();
-					if (m.get(MatchField.IN_PORT) != null) {
-						jsonGenerator.writeNumberField("in-port", m.get(MatchField.IN_PORT).getPortNumber());
-					}
-					if (m.get(MatchField.IN_PHY_PORT) != null) {
-						jsonGenerator.writeNumberField("in-phy-port", m.get(MatchField.IN_PHY_PORT).getPortNumber());
-					}
-					if (m.get(MatchField.ARP_OP) != null) {
-						jsonGenerator.writeNumberField("arp-op", m.get(MatchField.ARP_OP).getOpcode());
-					}
-					if (m.get(MatchField.ARP_SHA) != null) {
-						jsonGenerator.writeStringField("arp-sha", m.get(MatchField.ARP_SHA).toString());
-					}
-					if (m.get(MatchField.ARP_SPA) != null) {
-						jsonGenerator.writeStringField("arp-spa", m.get(MatchField.ARP_SPA).toString());
-					}
-					if (m.get(MatchField.ARP_THA) != null) {
-						jsonGenerator.writeStringField("arp-tha", m.get(MatchField.ARP_THA).toString());
-					}
-					if (m.get(MatchField.ARP_TPA) != null) {
-						jsonGenerator.writeStringField("arp-tpa", m.get(MatchField.ARP_TPA).toString());
-					}
-					if (m.get(MatchField.ETH_TYPE) != null) {
-						jsonGenerator.writeNumberField("eth-type", m.get(MatchField.ETH_TYPE).getValue());
-					}
-					if (m.get(MatchField.ETH_SRC) != null) {
-						jsonGenerator.writeStringField("eth-src", m.get(MatchField.ETH_SRC).toString());
-					}
-					if (m.get(MatchField.ETH_DST) != null) {
-						jsonGenerator.writeStringField("eth-dst", m.get(MatchField.ETH_DST).toString());
-					}
-					if (m.get(MatchField.VLAN_VID) != null) {
-						jsonGenerator.writeNumberField("vlan-vid", m.get(MatchField.VLAN_VID).getVlan());
-					}
-					if (m.get(MatchField.VLAN_PCP) != null) {
-						jsonGenerator.writeNumberField("vlan-pcp", m.get(MatchField.VLAN_PCP).getValue()); // TODO not sure if this will format correctly
-					}
-					if (m.get(MatchField.ICMPV4_TYPE) != null) {
-						jsonGenerator.writeNumberField("icmpv4-type", m.get(MatchField.ICMPV4_TYPE).getType());
-					}
-					if (m.get(MatchField.ICMPV4_CODE) != null) {
-						jsonGenerator.writeNumberField("icmpv4-code", m.get(MatchField.ICMPV4_CODE).getCode());
-					}
-					if (m.get(MatchField.ICMPV6_TYPE) != null) {
-						jsonGenerator.writeNumberField("icmpv6-type", m.get(MatchField.ICMPV6_TYPE).getValue());
-					}
-					if (m.get(MatchField.ICMPV6_CODE) != null) {
-						jsonGenerator.writeNumberField("icmpv6-code", m.get(MatchField.ICMPV6_CODE).getValue());
-					}
-					if (m.get(MatchField.IN_PORT) != null) {
-						jsonGenerator.writeNumberField("in-port", m.get(MatchField.IN_PORT).getPortNumber());
-					}
-					if (m.get(MatchField.IP_DSCP) != null) {
-						jsonGenerator.writeNumberField("ip-dscp", m.get(MatchField.IP_DSCP).getDscpValue()); // TODO not sure if this will format correctly
-					}
-					if (m.get(MatchField.IP_ECN) != null) {
-						jsonGenerator.writeNumberField("ip-ecn", m.get(MatchField.IP_ECN).getEcnValue()); // TODO not sure if this will format correctly
-					}
-					if (m.get(MatchField.IP_PROTO) != null) {
-						jsonGenerator.writeNumberField("ip-proto", m.get(MatchField.IP_PROTO).getIpProtocolNumber());
-					}
-					if (m.get(MatchField.IPV4_SRC) != null) {
-						jsonGenerator.writeStringField("ipv4-src", m.get(MatchField.IPV4_SRC).toString());
-					}
-					if (m.get(MatchField.IPV4_DST) != null) {
-						jsonGenerator.writeStringField("ipv4-dst", m.get(MatchField.IPV4_DST).toString());
-					}
-					if (m.get(MatchField.IPV6_SRC) != null) {
-						jsonGenerator.writeStringField("ipv6-src", m.get(MatchField.IPV6_SRC).toString());
-					}
-					if (m.get(MatchField.IPV6_DST) != null) {
-						jsonGenerator.writeStringField("ipv6-dst", m.get(MatchField.IPV6_DST).toString());
-					}
-					if (m.get(MatchField.IPV6_FLABEL) != null) {
-						jsonGenerator.writeNumberField("ipv6-flow-label", m.get(MatchField.IPV6_FLABEL).getIPv6FlowLabelValue());
-					}
-					if (m.get(MatchField.IPV6_ND_SLL) != null) {
-						jsonGenerator.writeNumberField("ipv6-nd-ssl", m.get(MatchField.IPV6_ND_SLL).getLong());
-					}
-					if (m.get(MatchField.IPV6_ND_TARGET) != null) {
-						jsonGenerator.writeNumberField("ipv6-nd-target", m.get(MatchField.IPV6_ND_TARGET).getZeroCompressStart()); // TODO not sure how to format this
-					}
-					if (m.get(MatchField.IPV6_ND_TLL) != null) {
-						jsonGenerator.writeNumberField("ipv6-nd-ttl", m.get(MatchField.IPV6_ND_TLL).getLong());
-					}
-					if (m.get(MatchField.METADATA) != null) {
-						jsonGenerator.writeNumberField("metadata", m.get(MatchField.METADATA).getValue().getValue());
-					}
-					if (m.get(MatchField.MPLS_LABEL) != null) {
-						jsonGenerator.writeNumberField("mpls-label", m.get(MatchField.MPLS_LABEL).getValue());
-					}
-					if (m.get(MatchField.MPLS_TC) != null) {
-						jsonGenerator.writeNumberField("mpls-tc", m.get(MatchField.MPLS_TC).getValue());
-					}
-					if (m.get(MatchField.SCTP_SRC) != null) {
-						jsonGenerator.writeNumberField("sctp-src", m.get(MatchField.SCTP_SRC).getPort());
-					}
-					if (m.get(MatchField.SCTP_DST) != null) {
-						jsonGenerator.writeNumberField("sctp-dst", m.get(MatchField.SCTP_DST).getPort());
-					}
-					if (m.get(MatchField.TCP_SRC) != null) {
-						jsonGenerator.writeNumberField("tcp-src", m.get(MatchField.TCP_SRC).getPort());
-					}
-					if (m.get(MatchField.TCP_DST) != null) {
-						jsonGenerator.writeNumberField("tcp-dst", m.get(MatchField.TCP_DST).getPort());
-					}
-					if (m.get(MatchField.UDP_SRC) != null) {
-						jsonGenerator.writeNumberField("udp-src", m.get(MatchField.UDP_SRC).getPort());
-					}
-					if (m.get(MatchField.UDP_DST) != null) {
-						jsonGenerator.writeNumberField("udp-dst", m.get(MatchField.UDP_DST).getPort());
-					}
-					jsonGenerator.writeEndObject(); // end match
-
-					// begin actions/instructions
-					if (entry.getVersion() == OFVersion.OF_10) {
-						List<OFAction> actions = entry.getActions();
-						jsonGenerator.writeObjectFieldStart("actions");
-						jsonGenerator.writeStartObject();
-						if (actions.isEmpty()) {
-							jsonGenerator.writeString("none/drop");
-						}
-						for (OFAction a : actions) {
-							switch (a.getType()) {
-							case OUTPUT:
-								jsonGenerator.writeNumberField("output", ((OFActionOutput)a).getPort().getPortNumber());
-								break;
-							case ENQUEUE:
-								jsonGenerator.writeNumberField("enqueue", ((OFActionEnqueue)a).getPort().getPortNumber());
-								break;
-							case SET_DL_SRC:
-								jsonGenerator.writeStringField("eth-src", ((OFActionSetDlSrc)a).toString());
-								break;
-							case SET_DL_DST:
-								jsonGenerator.writeStringField("eth-dst", ((OFActionSetDlDst)a).toString());
-								break;
-							case SET_VLAN_VID:
-								jsonGenerator.writeNumberField("vlan-vid", ((OFActionSetVlanVid)a).getVlanVid().getVlan());
-								break;
-							case SET_VLAN_PCP:
-								jsonGenerator.writeNumberField("vlan-pcp", ((OFActionSetVlanPcp)a).getVlanPcp().getValue());
-								break;
-							case STRIP_VLAN:
-								jsonGenerator.writeString("strip-vlan");
-								break;
-							case SET_NW_SRC:
-								jsonGenerator.writeStringField("ipv4-src", ((OFActionSetNwSrc)a).getNwAddr().toString());
-								break;
-							case SET_NW_DST:
-								jsonGenerator.writeStringField("ipv4-dst", ((OFActionSetNwDst)a).getNwAddr().toString());
-								break;
-							case SET_TP_SRC:
-								jsonGenerator.writeNumberField("tp-src", ((OFActionSetTpSrc)a).getTpPort().getPort());
-								break;
-							case SET_TP_DST:
-								jsonGenerator.writeNumberField("tp-dst", ((OFActionSetTpDst)a).getTpPort().getPort());
-								break;
-							default:
-								// these are all the valid OF1.0 actions
-								break;
-							}
-						}
-						jsonGenerator.writeEndObject(); // end actions
-					} else {
-						// handle OF1.1+ instructions with actions within
-						List<OFInstruction> instructions = entry.getInstructions();
-						jsonGenerator.writeArrayFieldStart("instructions");
-						jsonGenerator.writeStartArray(); // array of instructions, each which have objects
-						if (instructions.isEmpty()) {
-							jsonGenerator.writeStringField("none", "drop");
-						} else {
-							for (OFInstruction i : instructions) {
-								switch (i.getType()) {
-								case CLEAR_ACTIONS:
-									jsonGenerator.writeObjectFieldStart("clear-actions");
-									break;
-								case WRITE_METADATA:
-									jsonGenerator.writeStartObject();
-									jsonGenerator.writeNumberField("write-metadata", ((OFInstructionWriteMetadata)i).getMetadata().getValue());
-									jsonGenerator.writeNumberField("mask", ((OFInstructionWriteMetadata)i).getMetadataMask().getValue());
-									break;
-								case EXPERIMENTER:
-									jsonGenerator.writeStartObject();
-									jsonGenerator.writeNumberField("experimenter", ((OFInstructionExperimenter)i).getExperimenter());
-									break;
-								case GOTO_TABLE:
-									jsonGenerator.writeStartObject();
-									jsonGenerator.writeNumberField("goto-table", ((OFInstructionGotoTable)i).getTableId().getValue());
-									break;
-								case METER:
-									jsonGenerator.writeStartObject();
-									jsonGenerator.writeNumberField("meter", ((OFInstructionMeter)i).getMeterId());
-									break;
-								case APPLY_ACTIONS:
-									jsonGenerator.writeObjectFieldStart("apply-actions");
-									serializeActions(jsonGenerator, ((OFInstructionApplyActions)i).getActions()); // side effect: jsonGenerator appended to
-									break;
-								case WRITE_ACTIONS:
-									jsonGenerator.writeObjectFieldStart("write-actions");
-									serializeActions(jsonGenerator, ((OFInstructionWriteActions)i).getActions()); // side effect: jsonGenerator appended to
-								default:
-									// shouldn't ever get here
-									break;
-								} // end switch on instruction
-								jsonGenerator.writeEndObject(); // end specific instruction
-							} // end for instructions
-						} // end not-empty instructions (else)
-					} // end process OF1.1+ actions (i.e. look through instructions)
-				} // end for each OFFlowStatsReply entry
-			} // end case for FLOW
-		} // end for each OFStatsReply
-	} // end method
-
-	public static void serializeActions(JsonGenerator jsonGenerator, List<OFAction> actions) throws IOException, JsonProcessingException {
-		jsonGenerator.writeStartObject();
-		if (actions.isEmpty()) {
-			jsonGenerator.writeStringField("none", "drop");
-		}
-		for (OFAction a : actions) { // these should only be OF1.1+ (i.e. OF1.3 supported actions, set-field with oxm's, etc)
-			switch (a.getType()) {
-			case OUTPUT:
-				jsonGenerator.writeNumberField("output", ((OFActionOutput)a).getPort().getPortNumber());
-				break;
-			case SET_QUEUE:
-				jsonGenerator.writeNumberField("queue", ((OFActionSetQueue)a).getQueueId());
-				break;
-			case GROUP:
-				jsonGenerator.writeNumberField("group", ((OFActionGroup)a).getGroup().getGroupNumber());
-				break;
-			case PUSH_VLAN:
-				jsonGenerator.writeNumberField("push-vlan", ((OFActionPushVlan)a).getEthertype().getValue());
-				break;
-			case PUSH_MPLS:
-				jsonGenerator.writeNumberField("push-mpls", ((OFActionPushMpls)a).getEthertype().getValue());
-				break;
-			case PUSH_PBB:
-				jsonGenerator.writeNumberField("push-pbb", ((OFActionPushPbb)a).getEthertype().getValue());
-				break;
-			case POP_VLAN:
-				jsonGenerator.writeString("pop-vlan");
-				break;
-			case POP_MPLS:
-				jsonGenerator.writeNumberField("pop-mpls", ((OFActionPopMpls)a).getEthertype().getValue());
-				break;
-			case POP_PBB:
-				jsonGenerator.writeString("pop-pbb");
-				break;
-			case SET_FIELD:
-				if (((OFActionSetField)a).getField() instanceof OFOxmArpOp) {
-					jsonGenerator.writeNumberField("arp-op", ((OFOxmArpOp) ((OFActionSetField) a).getField()).getValue().getOpcode());
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmArpSha) {
-					jsonGenerator.writeStringField("arp-sha", ((OFOxmArpSha) ((OFActionSetField) a).getField()).getValue().toString()); // macaddress formats string already
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmArpTha) {
-					jsonGenerator.writeStringField("arp-tha", ((OFOxmArpTha) ((OFActionSetField) a).getField()).getValue().toString());
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmArpSpa) {
-					jsonGenerator.writeStringField("arp-spa", ((OFOxmArpSpa) ((OFActionSetField) a).getField()).getValue().toString()); // ipaddress formats string already
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmArpTpa) {
-					jsonGenerator.writeStringField("arp-tpa", ((OFOxmArpTpa) ((OFActionSetField) a).getField()).getValue().toString()); 
-				} 
-				/* DATA LAYER */
-				else if (((OFActionSetField)a).getField() instanceof OFOxmEthType) {
-					jsonGenerator.writeNumberField("eth-type", ((OFOxmEthType) ((OFActionSetField) a).getField()).getValue().getValue());
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmEthSrc) {
-					jsonGenerator.writeStringField("eth-src", ((OFOxmEthSrc) ((OFActionSetField) a).getField()).getValue().toString());
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmEthDst) {
-					jsonGenerator.writeStringField("eth-dst", ((OFOxmEthDst) ((OFActionSetField) a).getField()).getValue().toString()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmVlanVid) {
-					jsonGenerator.writeNumberField("vlan-vid", ((OFOxmVlanVid) ((OFActionSetField) a).getField()).getValue().getVlan()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmVlanPcp) {
-					jsonGenerator.writeNumberField("vlan-pcp", ((OFOxmVlanPcp) ((OFActionSetField) a).getField()).getValue().getValue()); 
-				} 
-				/* ICMP */
-				else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Code) {
-					jsonGenerator.writeNumberField("icmpv4-code", ((OFOxmIcmpv4Code) ((OFActionSetField) a).getField()).getValue().getCode()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Type) {
-					jsonGenerator.writeNumberField("icmpv4-type", ((OFOxmIcmpv4Type) ((OFActionSetField) a).getField()).getValue().getType()); 
-				} 
-				/* NETWORK LAYER */
-				else if (((OFActionSetField)a).getField() instanceof OFOxmIpProto) {
-					jsonGenerator.writeNumberField("ip-proto", ((OFOxmIpProto) ((OFActionSetField) a).getField()).getValue().getIpProtocolNumber()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Src) {
-					jsonGenerator.writeStringField("ipv4-src", ((OFOxmIpv4Src) ((OFActionSetField) a).getField()).getValue().toString()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Dst) {
-					jsonGenerator.writeStringField("ipv4-dst", ((OFOxmIpv4Dst) ((OFActionSetField) a).getField()).getValue().toString()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmIpEcn) {
-					jsonGenerator.writeNumberField("ip-ecn", ((OFOxmIpEcn) ((OFActionSetField) a).getField()).getValue().getEcnValue()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmIpDscp) {
-					jsonGenerator.writeNumberField("ip-dscp", ((OFOxmIpDscp) ((OFActionSetField) a).getField()).getValue().getDscpValue()); 
-				} 
-				/* TRANSPORT LAYER, TCP, UDP, and SCTP */
-				else if (((OFActionSetField)a).getField() instanceof OFOxmTcpSrc) {
-					jsonGenerator.writeNumberField("tcp-src", ((OFOxmTcpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmTcpDst) {
-					jsonGenerator.writeNumberField("tcp-dst", ((OFOxmTcpDst) ((OFActionSetField) a).getField()).getValue().getPort()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmUdpSrc) {
-					jsonGenerator.writeNumberField("udp-src", ((OFOxmUdpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmUdpDst) {
-					jsonGenerator.writeNumberField("udp-dst", ((OFOxmUdpDst) ((OFActionSetField) a).getField()).getValue().getPort()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmSctpSrc) {
-					jsonGenerator.writeNumberField("sctp-src", ((OFOxmSctpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmSctpDst) {
-					jsonGenerator.writeNumberField("sctp-dst", ((OFOxmSctpDst) ((OFActionSetField) a).getField()).getValue().getPort()); 
-				}
-				/* MPLS */
-				else if (((OFActionSetField)a).getField() instanceof OFOxmMplsLabel) {
-					jsonGenerator.writeNumberField("mpls-label", ((OFOxmMplsLabel) ((OFActionSetField) a).getField()).getValue().getValue()); 
-				} else if (((OFActionSetField)a).getField() instanceof OFOxmMplsTc) {
-					jsonGenerator.writeNumberField("mpls-tc", ((OFOxmMplsTc) ((OFActionSetField) a).getField()).getValue().getValue()); 
-				} // MPLS_BOS not implemented in loxi
-				/* METADATA */
-				else if (((OFActionSetField)a).getField() instanceof OFOxmMetadata) {
-					jsonGenerator.writeNumberField("metadata", ((OFOxmMetadata) ((OFActionSetField) a).getField()).getValue().getValue().getValue()); 
-				} else {
-					// need to get a logger in here somehow log.error("Could not decode Set-Field action field: {}", ((OFActionSetField) a));
-				}
-			}
-		}
-	}
-}
-
diff --git a/src/main/java/net/floodlightcontroller/core/web/StatsReplyToJson.java b/src/main/java/net/floodlightcontroller/core/web/StatsReplyToJson.java
deleted file mode 100644
index d3e2f83365dcb5417926d9bce366e9e3c2172d7b..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/web/StatsReplyToJson.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package net.floodlightcontroller.core.web;
-
-import java.util.List;
-import java.util.Map;
-
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-
-@JsonSerialize(using = StatsReplySerializer.class)
-public class StatsReplyToJson {
-	private Map<String, List<OFStatsReply>> toserialize;
-	
-	StatsReplyToJson(Map<String, List<OFStatsReply>> serializeMe) {
-		toserialize = serializeMe;
-	}
-}
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
index daa78b4956aa4f17187e5c26b1d4080b9a4e30de..99b4d2d830849d948e7788188eaf5215d31e3ccf 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
@@ -1,19 +1,19 @@
 /**
-*    Copyright 2011, 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, 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.
+ **/
 
 package net.floodlightcontroller.core.web;
 
@@ -48,107 +48,125 @@ import com.google.common.util.concurrent.ListenableFuture;
  *
  */
 public class SwitchResourceBase extends ServerResource {
-    protected static Logger log = LoggerFactory.getLogger(SwitchResourceBase.class);
-
-    public enum REQUESTTYPE {
-        OFSTATS,
-        OFFEATURES
-    }
-
-    @Override
-    protected void doInit() throws ResourceException {
-        super.doInit();
-
-    }
-
-    @LogMessageDoc(level="ERROR",
-                   message="Failure retrieving statistics from switch {switch}",
-                   explanation="An error occurred while retrieving statistics" +
-                   		"from the switch",
-                   recommendation=LogMessageDoc.CHECK_SWITCH + " " +
-                   		LogMessageDoc.GENERIC_ACTION)
-    protected List<OFStatsReply> getSwitchStatistics(DatapathId switchId,
-                                                     OFStatsType statType) {
-        IOFSwitchService switchService =
-                (IOFSwitchService) getContext().getAttributes().
-                    get(IOFSwitchService.class.getCanonicalName());
-
-        IOFSwitch sw = switchService.getSwitch(switchId);
-        ListenableFuture<?> future;
-        List<OFStatsReply> values = null;
-        if (sw != null) {
-        	OFStatsRequest<?> req;
-            if (statType == OFStatsType.FLOW) {
-            	Match match = sw.getOFFactory().buildMatch().build();
-                req = sw.getOFFactory().buildFlowStatsRequest()
-                		.setMatch(match)
-                		.setOutPort(OFPort.ANY)
-                		.setTableId(TableId.ALL)
-                		.build();
-            } else if (statType == OFStatsType.AGGREGATE) {
-            	Match match = sw.getOFFactory().buildMatch().build();
-                req = sw.getOFFactory().buildAggregateStatsRequest()
-                		.setMatch(match)
-                		.setOutPort(OFPort.ANY)
-                		.setTableId(TableId.ALL)
-                		.build();
-            } else if (statType == OFStatsType.PORT) {
-                req = sw.getOFFactory().buildPortStatsRequest()
-                		.setPortNo(OFPort.ANY)
-                		.build();
-            } else if (statType == OFStatsType.QUEUE) {
-            	req = sw.getOFFactory().buildQueueStatsRequest()
-                		.setPortNo(OFPort.ANY)
-                		.setQueueId(UnsignedLong.MAX_VALUE.longValue())
-                		.build();
-            } else if (statType == OFStatsType.DESC ||
-                       statType == OFStatsType.TABLE) {
-                // pass - nothing todo besides set the type above
-            	req = sw.getOFFactory().buildDescStatsRequest()
-            			.build();
-            } else {
-            	//TODO @Ryan what to do about no matches in the if...elseif statements?
-            	req = sw.getOFFactory().buildDescStatsRequest().build();
-            }
-            try {
-                future = sw.writeStatsRequest(req);
-                values = (List<OFStatsReply>) future.get(10, TimeUnit.SECONDS);
-            } catch (Exception e) {
-                log.error("Failure retrieving statistics from switch " + sw, e);
-            }
-        }
-        return values;
-    }
-
-    protected List<OFStatsReply> getSwitchStatistics(String switchId, OFStatsType statType) {
-        return getSwitchStatistics(DatapathId.of(switchId), statType);
-    }
-
-    protected OFFeaturesReply getSwitchFeaturesReply(DatapathId switchId) {
-        IOFSwitchService switchService =
-                (IOFSwitchService) getContext().getAttributes().
-                get(IOFSwitchService.class.getCanonicalName());
-
-        IOFSwitch sw = switchService.getSwitch(switchId);
-        Future<OFFeaturesReply> future;
-        OFFeaturesReply featuresReply = null;
-        //TODO @Ryan The only thing to set in an OFFeaturesRequest is the XID. I'm not sure
-        // if it matters what I set it to. Will it have a default value of the next available?
-        OFFeaturesRequest featuresRequest = sw.getOFFactory().buildFeaturesRequest().build();
-        if (sw != null) {
-            try {
-                future = sw.writeRequest(featuresRequest);
-                featuresReply = future.get(10, TimeUnit.SECONDS);
-            } catch (Exception e) {
-                log.error("Failure getting features reply from switch" + sw, e);
-            }
-        }
-
-        return featuresReply;
-    }
-
-    protected OFFeaturesReply getSwitchFeaturesReply(String switchId) {
-        return getSwitchFeaturesReply(DatapathId.of(switchId));
-    }
+	protected static Logger log = LoggerFactory.getLogger(SwitchResourceBase.class);
+
+	public enum REQUESTTYPE {
+		OFSTATS,
+		OFFEATURES
+	}
+
+	@Override
+	protected void doInit() throws ResourceException {
+		super.doInit();
+
+	}
+
+	@SuppressWarnings("unchecked")
+	@LogMessageDoc(level="ERROR",
+	message="Failure retrieving statistics from switch {switch}",
+	explanation="An error occurred while retrieving statistics" +
+			"from the switch",
+			recommendation=LogMessageDoc.CHECK_SWITCH + " " +
+					LogMessageDoc.GENERIC_ACTION)
+	protected List<OFStatsReply> getSwitchStatistics(DatapathId switchId,
+			OFStatsType statType) {
+		IOFSwitchService switchService =
+				(IOFSwitchService) getContext().getAttributes().
+				get(IOFSwitchService.class.getCanonicalName());
+
+		IOFSwitch sw = switchService.getSwitch(switchId);
+		ListenableFuture<?> future;
+		List<OFStatsReply> values = null;
+		Match match;
+		if (sw != null) {
+			OFStatsRequest<?> req = null;
+			switch (statType) {
+			case FLOW:
+				match = sw.getOFFactory().buildMatch().build();
+				req = sw.getOFFactory().buildFlowStatsRequest()
+						.setMatch(match)
+						.setOutPort(OFPort.ANY)
+						.setTableId(TableId.ALL)
+						.build();
+				break;
+			case AGGREGATE:
+				match = sw.getOFFactory().buildMatch().build();
+				req = sw.getOFFactory().buildAggregateStatsRequest()
+						.setMatch(match)
+						.setOutPort(OFPort.ANY)
+						.setTableId(TableId.ALL)
+						.build();
+				break;
+			case PORT:
+				req = sw.getOFFactory().buildPortStatsRequest()
+				.setPortNo(OFPort.ANY)
+				.build();
+				break;
+			case QUEUE:
+				req = sw.getOFFactory().buildQueueStatsRequest()
+				.setPortNo(OFPort.ANY)
+				.setQueueId(UnsignedLong.MAX_VALUE.longValue())
+				.build();
+				break;
+			case DESC:
+			case TABLE:
+				// pass - nothing todo besides set the type above
+				req = sw.getOFFactory().buildDescStatsRequest()
+				.build();
+				break;
+			case EXPERIMENTER: //TODO @Ryan support new OF1.1+ stats types
+			case GROUP:
+			case GROUP_DESC:
+			case GROUP_FEATURES:
+			case METER:
+			case METER_CONFIG:
+			case METER_FEATURES:
+			case PORT_DESC:
+			case TABLE_FEATURES:
+			default:
+				log.error("Stats Request Type {} not implemented yet", statType.name());
+				break;
+			}
+
+			try {
+				if (req != null) {
+					future = sw.writeStatsRequest(req);
+					values = (List<OFStatsReply>) future.get(10, TimeUnit.SECONDS);
+				}
+			} catch (Exception e) {
+				log.error("Failure retrieving statistics from switch " + sw, e);
+			}
+		}
+		return values;
+	}
+
+	protected List<OFStatsReply> getSwitchStatistics(String switchId, OFStatsType statType) {
+		return getSwitchStatistics(DatapathId.of(switchId), statType);
+	}
+
+	protected OFFeaturesReply getSwitchFeaturesReply(DatapathId switchId) {
+		IOFSwitchService switchService =
+				(IOFSwitchService) getContext().getAttributes().
+				get(IOFSwitchService.class.getCanonicalName());
+
+		IOFSwitch sw = switchService.getSwitch(switchId);
+		Future<OFFeaturesReply> future;
+		OFFeaturesReply featuresReply = null;
+		OFFeaturesRequest featuresRequest = sw.getOFFactory().buildFeaturesRequest().build();
+		if (sw != null) {
+			try {
+				future = sw.writeRequest(featuresRequest);
+				featuresReply = future.get(10, TimeUnit.SECONDS);
+			} catch (Exception e) {
+				log.error("Failure getting features reply from switch" + sw, e);
+			}
+		}
+
+		return featuresReply;
+	}
+
+	protected OFFeaturesReply getSwitchFeaturesReply(String switchId) {
+		return getSwitchFeaturesReply(DatapathId.of(switchId));
+	}
 
 }
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
index 22d931fcf580e71f735f909dd8725f5c4bb4bb5d..a6e7ad5e3d1145e9eed765f3333a735506a46aad 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
@@ -1,24 +1,24 @@
 /**
-*    Copyright 2011, 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, 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.
+ **/
 
 package net.floodlightcontroller.core.web;
 
-import java.util.HashMap;
-import java.util.Map;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
+import net.floodlightcontroller.core.web.StatsReply;
 
 import org.projectfloodlight.openflow.protocol.OFStatsType;
 import org.projectfloodlight.openflow.types.DatapathId;
@@ -26,44 +26,110 @@ import org.restlet.resource.Get;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.fasterxml.jackson.annotation.JsonGetter;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize.Typing;
-
 /**
  * Return switch statistics information for specific switches
  * @author readams
  */
 public class SwitchStatisticsResource extends SwitchResourceBase {
-    protected static Logger log = 
-        LoggerFactory.getLogger(SwitchStatisticsResource.class);
+	protected static Logger log = 
+			LoggerFactory.getLogger(SwitchStatisticsResource.class);
 
-    @Get("json")
-    @JsonSerialize(using = StatsReplySerializer.class)
-    public Map<String, Object> retrieve() {
-        HashMap<String,Object> result = new HashMap<String,Object>();
-        Object values = null;
-        
-        String switchId = (String) getRequestAttributes().get("switchId");
-        String statType = (String) getRequestAttributes().get("statType");
-        
-        if (statType.equals("port")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.PORT);
-        } else if (statType.equals("queue")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.QUEUE);
-        } else if (statType.equals("flow")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.FLOW);
-        } else if (statType.equals("aggregate")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.AGGREGATE);
-        } else if (statType.equals("desc")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.DESC);
-        } else if (statType.equals("table")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.TABLE);
-        } else if (statType.equals("features")) {
-            values = getSwitchFeaturesReply(switchId);
-        }
+	@Get("json")
+	public StatsReply retrieve(){
+		StatsReply result = new StatsReply();
+		Object values = null; // set for error detection in serializer
+		String switchIdStr = (String) getRequestAttributes().get(CoreWebRoutable.STR_SWITCH_ID);
+		DatapathId switchId;
+		String statType = (String) getRequestAttributes().get(CoreWebRoutable.STR_STAT_TYPE);
 
-        result.put(switchId, values);
-        return result;
-    }
+		IOFSwitchService switchService = (IOFSwitchService) getContext().getAttributes().
+				get(IOFSwitchService.class.getCanonicalName());
+		
+		// prevent input errors and give error to user if bad switch DPID
+		try {
+			switchId = DatapathId.of(switchIdStr);
+		} catch (NumberFormatException | NullPointerException e) { // new Java 7 shorthand...reduces duplicated code in each catch 
+			switchId = DatapathId.NONE; // set for error detection in serializer
+		}
+		
+		// stop if the DPID is invalid or is not presently connected
+		if (!switchId.equals(DatapathId.NONE) && switchService.getSwitch(switchId) != null) {
+			// TODO these strings should be defined someplace. StatsReply.java?
+			
+			// at this point, the switch DPID is valid AND exists; what about the OFStatsType?
+			switch (statType) {
+			case OFStatsTypeStrings.PORT:
+				values = getSwitchStatistics(switchId, OFStatsType.PORT);
+				result.setStatType(OFStatsType.PORT);
+				break;
+			case OFStatsTypeStrings.QUEUE:
+				values = getSwitchStatistics(switchId, OFStatsType.QUEUE);
+				result.setStatType(OFStatsType.QUEUE);
+				break;
+			case OFStatsTypeStrings.FLOW:
+				values = getSwitchStatistics(switchId, OFStatsType.FLOW);
+				result.setStatType(OFStatsType.FLOW);
+				break;
+			case OFStatsTypeStrings.AGGREGATE:
+				values = getSwitchStatistics(switchId, OFStatsType.AGGREGATE);
+				result.setStatType(OFStatsType.AGGREGATE);
+				break;
+			case OFStatsTypeStrings.DESC:
+				values = getSwitchStatistics(switchId, OFStatsType.DESC);
+				result.setStatType(OFStatsType.DESC);
+				break;
+			case OFStatsTypeStrings.TABLE:
+				values = getSwitchStatistics(switchId, OFStatsType.TABLE);
+				result.setStatType(OFStatsType.TABLE);
+				break;
+			case OFStatsTypeStrings.TABLE_FEATURES:
+				values = getSwitchFeaturesReply(switchId);
+				result.setStatType(OFStatsType.TABLE_FEATURES);
+				break;
+			case OFStatsTypeStrings.EXPERIMENTER:
+				values = getSwitchFeaturesReply(switchId);
+				result.setStatType(OFStatsType.EXPERIMENTER);
+				break;
+			case OFStatsTypeStrings.PORT_DESC:
+				values = getSwitchFeaturesReply(switchId);
+				result.setStatType(OFStatsType.PORT_DESC);
+				break;
+			case OFStatsTypeStrings.GROUP:
+				values = getSwitchFeaturesReply(switchId);
+				result.setStatType(OFStatsType.GROUP);
+				break;
+			case OFStatsTypeStrings.GROUP_DESC:
+				values = getSwitchFeaturesReply(switchId);
+				result.setStatType(OFStatsType.GROUP_DESC);
+				break;
+			case OFStatsTypeStrings.GROUP_FEATURES:
+				values = getSwitchFeaturesReply(switchId);
+				result.setStatType(OFStatsType.GROUP_FEATURES);
+				break;
+			case OFStatsTypeStrings.METER:
+				values = getSwitchFeaturesReply(switchId);
+				result.setStatType(OFStatsType.METER);
+				break;
+			case OFStatsTypeStrings.METER_CONFIG:
+				values = getSwitchFeaturesReply(switchId);
+				result.setStatType(OFStatsType.METER_CONFIG);
+				break;
+			case OFStatsTypeStrings.METER_FEATURES:
+				values = getSwitchFeaturesReply(switchId);
+				result.setStatType(OFStatsType.METER_FEATURES);
+				break;
+			default:
+				log.error("Invalid or unimplemented stat request type {}", statType);
+				break;
+			}
+		} else {
+			log.error("Invalid or disconnected switch {}", switchIdStr);
+			// if there was an error, the serializer will 
+		}
+		
+		result.setDatapathId(switchId);
+		result.setValues(values); // values can only be a List<OFStatsReply> or an OFFeaturesReply
+		// if values is set to null (the default), the serializer will kick back a response to the user via the REST API
+		return result;
+	}
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.java
index f5f3aea8c93f9a5769ad3eb8aa536755cf83e802..0373e2e58bb0c96ccf75e584bb8da2e9738a8094 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.java
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.java
@@ -23,7 +23,8 @@ import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
-import org.projectfloodlight.openflow.util.HexString;
+
+import org.projectfloodlight.openflow.types.MacAddress;
 
 /**
  * Serialize a MAC as colon-separated hexadecimal
@@ -34,7 +35,7 @@ public class ByteArrayMACSerializer extends JsonSerializer<byte[]> {
     public void serialize(byte[] mac, JsonGenerator jGen,
                           SerializerProvider serializer)
                                   throws IOException, JsonProcessingException {
-        jGen.writeString(HexString.toHexString(mac));
+        jGen.writeString(MacAddress.of(mac).toString());
     }
 
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/DPIDSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/DPIDSerializer.java
index 8436577cdb75eb9e70c7c39a9faf4c55ecca5926..fd4abd4a5c2896cb22f6706be0f2317580026165 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/DPIDSerializer.java
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/DPIDSerializer.java
@@ -34,7 +34,7 @@ public class DPIDSerializer extends JsonSerializer<DatapathId> {
     public void serialize(DatapathId dpid, JsonGenerator jGen,
                           SerializerProvider serializer)
                                   throws IOException, JsonProcessingException {
-        jGen.writeString(HexString.toHexString(dpid.getLong(), 8));
+        jGen.writeString(dpid.toString());
     }
 
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/IPv4Serializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/IPv4Serializer.java
index db93b66ac46af312c37f59c36febe4357389e188..cdff9e890a8b0f1a73069a7c3b476f68719ac28c 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/IPv4Serializer.java
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/IPv4Serializer.java
@@ -19,7 +19,7 @@ package net.floodlightcontroller.core.web.serializers;
 
 import java.io.IOException;
 
-import net.floodlightcontroller.packet.IPv4;
+import org.projectfloodlight.openflow.types.IPv4Address;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -35,7 +35,7 @@ public class IPv4Serializer extends JsonSerializer<Integer> {
     public void serialize(Integer i, JsonGenerator jGen,
                           SerializerProvider serializer)
                                   throws IOException, JsonProcessingException {
-        jGen.writeString(IPv4.fromIPv4Address(i));
+        jGen.writeString(IPv4Address.of(i).toString());
     }
 
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/MACSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/MACSerializer.java
deleted file mode 100644
index c7ea09b8364fa9b6e740da82b2a3f55ec6458fb8..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/MACSerializer.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
-*    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.
-**/
-
-package net.floodlightcontroller.core.web.serializers;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import org.projectfloodlight.openflow.util.HexString;
-
-/**
- * Serialize a MAC as colon-separated hexadecimal
- */
-public class MACSerializer extends JsonSerializer<Long> {
-
-    @Override
-    public void serialize(Long dpid, JsonGenerator jGen,
-                          SerializerProvider serializer)
-                                  throws IOException, JsonProcessingException {
-        jGen.writeString(HexString.toHexString(dpid, 6));
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9766245a8e25905470715aed9ef8eff563ba75d
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java
@@ -0,0 +1,499 @@
+/**
+ *    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.
+ **/
+
+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;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+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;
+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.*;
+
+/**
+ * Serialize a DPID as colon-separated hexadecimal
+ */
+public class StatsReplySerializer extends JsonSerializer<StatsReply> {
+	@SuppressWarnings("unchecked")
+	@Override
+	public void serialize(StatsReply reply, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException {
+		// Return a nice error to user if the request we're about to serialize was bad
+		if (reply.getValues() == null) {
+			jGen.writeStartObject();
+			jGen.writeObjectFieldStart("ERROR");
+			jGen.writeStringField("1)", "Invalid DPID and/or stats/features request, or");
+			jGen.writeStringField("2)", "The switch might also be disconncted from the controller");
+			jGen.writeEndObject();
+			jGen.writeObjectFieldStart("Valid OFStatsTypes are");
+			jGen.writeStringField("1)", OFStatsTypeStrings.AGGREGATE);
+			jGen.writeStringField("2)", OFStatsTypeStrings.DESC);
+			jGen.writeStringField("3)", OFStatsTypeStrings.EXPERIMENTER);
+			jGen.writeStringField("4)", OFStatsTypeStrings.FEATURES);
+			jGen.writeStringField("5)", OFStatsTypeStrings.FLOW);
+			jGen.writeStringField("6)", OFStatsTypeStrings.GROUP);
+			jGen.writeStringField("7)", OFStatsTypeStrings.GROUP_DESC);
+			jGen.writeStringField("8)", OFStatsTypeStrings.GROUP_FEATURES);  
+			jGen.writeStringField("9)", OFStatsTypeStrings.METER);  
+			jGen.writeStringField("A)", OFStatsTypeStrings.METER_CONFIG); 
+			jGen.writeStringField("B)", OFStatsTypeStrings.PORT);
+			jGen.writeStringField("C)", OFStatsTypeStrings.PORT_DESC);
+			jGen.writeStringField("D)", OFStatsTypeStrings.QUEUE);
+			jGen.writeStringField("E)", OFStatsTypeStrings.TABLE);
+			jGen.writeStringField("F)", OFStatsTypeStrings.TABLE_FEATURES);
+			jGen.writeEndObject(); 
+			jGen.writeEndObject();
+			return;
+		}
+		
+		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());
+		switch (reply.getStatType()) {
+		case PORT:
+			// handle port
+			break;
+		case QUEUE:
+			// handle queue
+			break;
+		case FLOW:
+			// handle flow. Can safely cast to List<OFFlowStatsReply>.
+			serializeFlowReply((List<OFFlowStatsReply>) reply.getValues(), jGen);
+			break;
+		case AGGREGATE:
+			// handle aggregate
+			break;
+		case DESC:
+			// handle desc
+			break;
+		case TABLE:
+			// handle table
+			break;
+		case TABLE_FEATURES:
+			// handle features
+			break;
+			// TODO need to handle new OF1.1+ stats reply types
+		case EXPERIMENTER:
+			break;
+		case GROUP:
+			break;
+		case GROUP_DESC:
+			break;
+		case GROUP_FEATURES:
+			break;
+		case METER:
+			break;
+		case METER_CONFIG:
+			break;
+		case METER_FEATURES:
+			break;
+		case PORT_DESC:
+			break;
+		default:
+			 break;
+		}   
+		jGen.writeEndObject();
+	}
+
+	public void serializeFlowReply(List<OFFlowStatsReply> flowReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{
+		int flowCount = 0;
+		for (OFFlowStatsReply flowReply : flowReplies) { // for each flow stats reply
+			List<OFFlowStatsEntry> entries = flowReply.getEntries();
+			for (OFFlowStatsEntry entry : entries) { // for each flow
+				// list flow stats/info
+				jGen.writeObjectFieldStart("flow" + Integer.toString(flowCount++)); // need to have different object names or JSON parser might only show the last one
+				jGen.writeStringField("version", entry.getVersion().toString()); // return the enum name
+				jGen.writeNumberField("cookie", entry.getCookie().getValue());
+				jGen.writeNumberField("table_id", entry.getTableId().getValue());
+				jGen.writeNumberField("packet_count", entry.getPacketCount().getValue());
+				jGen.writeNumberField("byte_count", entry.getByteCount().getValue());
+				jGen.writeNumberField("duration_sec", entry.getDurationSec());
+				jGen.writeNumberField("priority", entry.getPriority());
+				jGen.writeNumberField("idle_timeout_sec", entry.getIdleTimeout());
+				jGen.writeNumberField("hard_timeout_sec", entry.getHardTimeout());
+				jGen.writeNumberField("flags", entry.getFlags());
+				// 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
+
+				// handle OF1.1+ instructions with actions within
+				if (entry.getVersion() == OFVersion.OF_10) {
+					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)
+				jGen.writeEndObject();
+			} // end for each OFFlowStatsReply entry
+		} // 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: //TODO @Ryan need to reference the predefined string constants for each of the actions/oxms
+				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 {
+					// 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/devicemanager/internal/Entity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
index eda51cc1d45e5d1f713bb9a301d770a962ad2fdc..6723bdd112fec3ad91436b5f377f25b0e2335d73 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
@@ -20,8 +20,9 @@ package net.floodlightcontroller.devicemanager.internal;
 import java.util.Date;
 
 import net.floodlightcontroller.core.web.serializers.IPv4Serializer;
-import net.floodlightcontroller.core.web.serializers.MACSerializer;
 import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
+import net.floodlightcontroller.core.web.serializers.MacSerializer;
+
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@@ -128,7 +129,7 @@ public class Entity implements Comparable<Entity> {
     // Getters/Setters
     // ***************
 
-    @JsonSerialize(using=MACSerializer.class)
+    @JsonSerialize(using=MacSerializer.class)
     public MacAddress getMacAddress() {
         return macAddress;
     }
diff --git a/src/main/java/net/floodlightcontroller/util/MatchUtils.java b/src/main/java/net/floodlightcontroller/util/MatchUtils.java
index 449055aeacbb4365071d5f8348f5f12595271650..6345f1038c620e4f0d976d07646a320b4162387d 100644
--- a/src/main/java/net/floodlightcontroller/util/MatchUtils.java
+++ b/src/main/java/net/floodlightcontroller/util/MatchUtils.java
@@ -48,6 +48,7 @@ public class MatchUtils {
 	 * expect the JSON string to be formatted using these strings for the applicable fields.
 	 */
 	public static final String STR_IN_PORT = "ingress_port";
+	public static final String STR_IN_PHYS_PORT = "ingress_phys_port";
 
 	public static final String STR_DL_DST = "dl_dst";
 	public static final String STR_DL_SRC = "dl_src";
@@ -56,7 +57,13 @@ public class MatchUtils {
 	public static final String STR_DL_VLAN_PCP = "dl_vpcp";
 
 	public static final String STR_NW_DST = "nw_dst";
-	public static final String STR_NW_SRC = "nw_src";
+	public static final String STR_NW_SRC = "nw_src"; // should change these to IP, since they don't apply to anything else really
+	public static final String STR_IPV6_DST = "ipv6_dst";
+	public static final String STR_IPV6_SRC = "ipv6_src";
+	public static final String STR_IPV6_FLOW_LABEL = "ipv6_flow_label";
+	public static final String STR_IPV6_ND_SSL = "ipv6_nd_ssl";
+	public static final String STR_IPV6_ND_TARGET = "ipv6_nd_target";
+	public static final String STR_IPV6_ND_TTL = "ipv6_nd_ttl";
 	public static final String STR_NW_PROTO = "nw_proto";
 	public static final String STR_NW_TOS = "nw_tos";
 	public static final String STR_NW_ECN = "nw_ecn";
@@ -73,6 +80,8 @@ public class MatchUtils {
 
 	public static final String STR_ICMP_TYPE = "icmp_type";
 	public static final String STR_ICMP_CODE = "icmp_code";
+	public static final String STR_ICMPV6_TYPE = "icmpv6_type";
+	public static final String STR_ICMPV6_CODE = "icmpv6_code";
 
 	public static final String STR_ARP_OPCODE = "arp_opcode";
 	public static final String STR_ARP_SHA = "arp_sha";
diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties
index 2aaab9fdaba5ce189f597a519d3c3066e5c84374..b9da2671aeb41291f9683458ced2acc60b3342e4 100644
--- a/src/main/resources/floodlightdefault.properties
+++ b/src/main/resources/floodlightdefault.properties
@@ -10,7 +10,7 @@ net.floodlightcontroller.debugevent.DebugEventService,\
 net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
 net.floodlightcontroller.restserver.RestApiServer,\
 net.floodlightcontroller.topology.TopologyManager,\
-net.floodlightcontroller.testmodule.TestModule,\
+net.floodlightcontroller.forwarding.Forwarding,\
 net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager,\
 net.floodlightcontroller.ui.web.StaticWebRoutable,\
 net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl