// Entity Resolver
  public InputSource resolveEntity(String publicId, String systemId) throws SAXException {

    if (er != null) {
      try {
        return er.resolveEntity(publicId, systemId);
      } catch (IOException e) {
        System.out.println("resolveEntity threw IOException!");
        return null;
      }
    } else {
      return null;
    }
  }
  /**
   * Reserved for internal use. Parses the operation response as an entity. Parses the result
   * returned in the specified stream in JSON format into a {@link TableResult} containing an entity
   * of the specified class type projected using the specified resolver.
   *
   * @param parser The <code>JsonParser</code> to read the data to parse from.
   * @param clazzType The class type <code>T</code> implementing {@link TableEntity} for the entity
   *     returned. Set to <code>null</code> to ignore the returned entity and copy only response
   *     properties into the {@link TableResult} object.
   * @param resolver An {@link EntityResolver} instance to project the entity into an instance of
   *     type <code>R</code>. Set to <code>null</code> to return the entity as an instance of the
   *     class type <code>T</code>.
   * @param options A {@link TableRequestOptions} object that specifies execution options such as
   *     retry policy and timeout settings for the operation.
   * @param opContext An {@link OperationContext} object used to track the execution of the
   *     operation.
   * @return A {@link TableResult} containing the parsed entity result of the operation.
   * @throws IOException if an error occurs while accessing the stream.
   * @throws InstantiationException if an error occurs while constructing the result.
   * @throws IllegalAccessException if an error occurs in reflection while parsing the result.
   * @throws StorageException if a storage service error occurs.
   * @throws IOException if an error occurs while accessing the stream.
   * @throws JsonParseException if an error occurs while parsing the stream.
   */
  private static <T extends TableEntity, R> TableResult parseJsonEntity(
      final JsonParser parser,
      final Class<T> clazzType,
      HashMap<String, PropertyPair> classProperties,
      final EntityResolver<R> resolver,
      final TableRequestOptions options,
      final OperationContext opContext)
      throws JsonParseException, IOException, StorageException, InstantiationException,
          IllegalAccessException {
    final TableResult res = new TableResult();

    final HashMap<String, EntityProperty> properties = new HashMap<String, EntityProperty>();

    if (!parser.hasCurrentToken()) {
      parser.nextToken();
    }

    JsonUtilities.assertIsStartObjectJsonToken(parser);

    parser.nextToken();

    // get all metadata, if present
    while (parser.getCurrentName().startsWith(ODataConstants.ODATA_PREFIX)) {
      final String name = parser.getCurrentName().substring(ODataConstants.ODATA_PREFIX.length());

      // get the value token
      parser.nextToken();

      if (name.equals(ODataConstants.ETAG)) {
        String etag = parser.getValueAsString();
        res.setEtag(etag);
      }

      // get the key token
      parser.nextToken();
    }

    if (resolver == null && clazzType == null) {
      return res;
    }

    // get object properties
    while (parser.getCurrentToken() != JsonToken.END_OBJECT) {
      String key = Constants.EMPTY_STRING;
      String val = Constants.EMPTY_STRING;
      EdmType edmType = null;

      // checks if this property is preceded by an OData property type annotation
      if (options.getTablePayloadFormat() != TablePayloadFormat.JsonNoMetadata
          && parser.getCurrentName().endsWith(ODataConstants.ODATA_TYPE_SUFFIX)) {
        parser.nextToken();
        edmType = EdmType.parse(parser.getValueAsString());

        parser.nextValue();
        key = parser.getCurrentName();
        val = parser.getValueAsString();
      } else {
        key = parser.getCurrentName();

        parser.nextToken();
        val = parser.getValueAsString();
        edmType = evaluateEdmType(parser.getCurrentToken(), parser.getValueAsString());
      }

      final EntityProperty newProp = new EntityProperty(val, edmType);
      newProp.setDateBackwardCompatibility(options.getDateBackwardCompatibility());
      properties.put(key, newProp);

      parser.nextToken();
    }

    String partitionKey = null;
    String rowKey = null;
    Date timestamp = null;
    String etag = null;

    // Remove core properties from map and set individually
    EntityProperty tempProp = properties.remove(TableConstants.PARTITION_KEY);
    if (tempProp != null) {
      partitionKey = tempProp.getValueAsString();
    }

    tempProp = properties.remove(TableConstants.ROW_KEY);
    if (tempProp != null) {
      rowKey = tempProp.getValueAsString();
    }

    tempProp = properties.remove(TableConstants.TIMESTAMP);
    if (tempProp != null) {
      tempProp.setDateBackwardCompatibility(false);
      timestamp = tempProp.getValueAsDate();

      if (res.getEtag() == null) {
        etag = getETagFromTimestamp(tempProp.getValueAsString());
        res.setEtag(etag);
      }
    }

    // do further processing for type if JsonNoMetdata by inferring type information via resolver or
    // clazzType
    if (options.getTablePayloadFormat() == TablePayloadFormat.JsonNoMetadata
        && (options.getPropertyResolver() != null || clazzType != null)) {
      if (options.getPropertyResolver() != null) {
        for (final Entry<String, EntityProperty> p : properties.entrySet()) {
          final String key = p.getKey();
          final String value = p.getValue().getValueAsString();
          EdmType edmType;

          // try to use the property resolver to get the type
          try {
            edmType =
                options.getPropertyResolver().propertyResolver(partitionKey, rowKey, key, value);
          } catch (Exception e) {
            throw new StorageException(
                StorageErrorCodeStrings.INTERNAL_ERROR,
                SR.CUSTOM_RESOLVER_THREW,
                Constants.HeaderConstants.HTTP_UNUSED_306,
                null,
                e);
          }

          // try to create a new entity property using the returned type
          try {
            final EntityProperty newProp = new EntityProperty(value, edmType);
            newProp.setDateBackwardCompatibility(options.getDateBackwardCompatibility());
            properties.put(p.getKey(), newProp);
          } catch (IllegalArgumentException e) {
            throw new StorageException(
                StorageErrorCodeStrings.INVALID_TYPE,
                String.format(SR.FAILED_TO_PARSE_PROPERTY, key, value, edmType),
                Constants.HeaderConstants.HTTP_UNUSED_306,
                null,
                e);
          }
        }
      } else if (clazzType != null) {
        if (classProperties == null) {
          classProperties = PropertyPair.generatePropertyPairs(clazzType);
        }
        for (final Entry<String, EntityProperty> p : properties.entrySet()) {
          PropertyPair propPair = classProperties.get(p.getKey());
          if (propPair != null) {
            final EntityProperty newProp =
                new EntityProperty(p.getValue().getValueAsString(), propPair.type);
            newProp.setDateBackwardCompatibility(options.getDateBackwardCompatibility());
            properties.put(p.getKey(), newProp);
          }
        }
      }
    }

    // set the result properties, now that they are appropriately parsed
    res.setProperties(properties);

    // use resolver if provided, else create entity based on clazz type
    if (resolver != null) {
      res.setResult(
          resolver.resolve(partitionKey, rowKey, timestamp, res.getProperties(), res.getEtag()));
    } else if (clazzType != null) {
      // Generate new entity and return
      final T entity = clazzType.newInstance();
      entity.setEtag(res.getEtag());

      entity.setPartitionKey(partitionKey);
      entity.setRowKey(rowKey);
      entity.setTimestamp(timestamp);

      entity.readEntity(res.getProperties(), opContext);

      res.setResult(entity);
    }

    return res;
  }