@Override
    public Host decode(ObjectNode json, CodecContext context) {
        if (json == null || !json.isObject()) {
            return null;
        }

        MacAddress mac = MacAddress.valueOf(nullIsIllegal(
                json.get(MAC), MAC + MISSING_MEMBER_MESSAGE).asText());
        VlanId vlanId = VlanId.vlanId(nullIsIllegal(
                json.get(VLAN), VLAN + MISSING_MEMBER_MESSAGE).asText());
        HostId id = HostId.hostId(mac, vlanId);

        ArrayNode locationNodes = nullIsIllegal(
                (ArrayNode) json.get(HOST_LOCATIONS), HOST_LOCATIONS + MISSING_MEMBER_MESSAGE);
        Set<HostLocation> hostLocations =
                context.codec(HostLocation.class).decode(locationNodes, context)
                .stream().collect(Collectors.toSet());

        ArrayNode ipNodes = nullIsIllegal(
                (ArrayNode) json.get(IP_ADDRESSES), IP_ADDRESSES + MISSING_MEMBER_MESSAGE);
        Set<IpAddress> ips = new HashSet<>();
        ipNodes.forEach(ipNode -> {
            ips.add(IpAddress.valueOf(ipNode.asText()));
        });

        // check optional fields
        JsonNode innerVlanIdNode = json.get(INNER_VLAN);
        VlanId innerVlanId = (null == innerVlanIdNode) ? VlanId.NONE :
                VlanId.vlanId(innerVlanIdNode.asText());
        JsonNode outerTpidNode = json.get(OUTER_TPID);
        EthType outerTpid = (null == outerTpidNode) ? EthType.EtherType.UNKNOWN.ethType() :
                EthType.EtherType.lookup((short) (Integer.decode(outerTpidNode.asText()) & 0xFFFF)).ethType();
        JsonNode configuredNode = json.get(IS_CONFIGURED);
        boolean configured = (null == configuredNode) ? false : configuredNode.asBoolean();
        JsonNode suspendedNode = json.get(IS_SUSPENDED);
        boolean suspended = (null == suspendedNode) ? false : suspendedNode.asBoolean();

        ArrayNode auxLocationNodes = (ArrayNode) json.get(AUX_LOCATIONS);
        Set<HostLocation> auxHostLocations = (null == auxLocationNodes) ? null :
                context.codec(HostLocation.class).decode(auxLocationNodes, context)
                        .stream().collect(Collectors.toSet());

        Annotations annotations = extractAnnotations(json, context);

        return new DefaultHost(ProviderId.NONE, id, mac, vlanId,
                               hostLocations, auxHostLocations, ips, innerVlanId,
                               outerTpid, configured, suspended, annotations);
    }
@Test
    public void testDecode() throws IOException {
        InputStream jsonStream = HostCodec.class.getResourceAsStream(JSON_FILE);
        JsonNode jsonString = context.mapper().readTree(jsonStream);

        Host expected = hostCodec.decode((ObjectNode) jsonString, context);
        assertEquals(expected, HOST);
    }