/**
  * Get the result of an Object path expression as a map.
  *
  * @param path The Object path.
  * @param keyType The type of the expected key
  * @param valueType The type of the expected value
  * @param <K> The type of the expected key
  * @param <V> The type of the expected value
  * @return The map matching the Object path. A {@link java.lang.ClassCastException} will be thrown
  *     if the object cannot be casted to the expected type.
  */
 public <K, V> Map<K, V> getMap(String path, Class<K> keyType, Class<V> valueType) {
   final Map<K, V> originalMap = get(path);
   final Map<K, V> newMap = new HashMap<K, V>();
   for (Entry<K, V> entry : originalMap.entrySet()) {
     final K key =
         entry.getKey() == null ? null : ObjectConverter.convertObjectTo(entry.getKey(), keyType);
     final V value =
         entry.getValue() == null
             ? null
             : ObjectConverter.convertObjectTo(entry.getValue(), valueType);
     newMap.put(key, value);
   }
   return Collections.unmodifiableMap(newMap);
 }
  /**
   * Get the result of a Object path expression as a java Object. E.g. given the following Object
   * document:
   *
   * <pre>
   * { "store": {
   *   "book": [
   *    { "category": "reference",
   *      "author": "Nigel Rees",
   *      "title": "Sayings of the Century",
   *      "price": 8.95
   *    },
   *    { "category": "fiction",
   *      "author": "Evelyn Waugh",
   *      "title": "Sword of Honour",
   *      "price": 12.99
   *    },
   *    { "category": "fiction",
   *      "author": "Herman Melville",
   *      "title": "Moby Dick",
   *      "isbn": "0-553-21311-3",
   *      "price": 8.99
   *    },
   *    { "category": "fiction",
   *      "author": "J. R. R. Tolkien",
   *      "title": "The Lord of the Rings",
   *      "isbn": "0-395-19395-8",
   *      "price": 22.99
   *    }
   *  ],
   *    "bicycle": {
   *      "color": "red",
   *      "price": 19.95
   *    }
   *  }
   * }
   * </pre>
   *
   * And a Java object like this:
   *
   * <p>
   *
   * <pre>
   * public class Book {
   *      private String category;
   *      private String author;
   *      private String title;
   *      private String isbn;
   *      private float price;
   *
   *      public String getCategory() {
   *         return category;
   *      }
   *
   *     public void setCategory(String category) {
   *         this.category = category;
   *     }
   *
   *    public String getAuthor() {
   *          return author;
   *     }
   *
   *    public void setAuthor(String author) {
   *         this.author = author;
   *    }
   *
   *    public String getTitle() {
   *         return title;
   *    }
   *
   *    public void setTitle(String title) {
   *        this.title = title;
   *    }
   *
   *    public String getIsbn() {
   *             return isbn;
   *    }
   *
   *    public void setIsbn(String isbn) {
   *          this.isbn = isbn;
   *    }
   *
   *    public float getPrice() {
   *        return price;
   *    }
   *
   *    public void setPrice(float price) {
   *             this.price = price;
   *   }
   * }
   * </pre>
   *
   * <p>Then
   *
   * <pre>
   * Book book = from(Object).getObject("store.book[2]", Book.class);
   * </pre>
   *
   * <p>maps the second book to a Book instance.
   *
   * @param path The path to the object to map
   * @param objectType The class type of the expected object
   * @param <T> The type of the expected object
   * @return The object
   */
  public <T> T getObject(String path, Class<T> objectType) {
    Object object = getJsonObject(path);
    if (object == null) {
      return null;
    } else if (object instanceof List || object instanceof Map) {
      // TODO Avoid double parsing
      object = new JsonBuilder(object).toString();
    } else {
      return ObjectConverter.convertObjectTo(object, objectType);
    }

    JsonPathConfig cfg = new JsonPathConfig(getJsonPathConfig());
    if (cfg.hasCustomJackson10ObjectMapperFactory()) {
      cfg = cfg.defaultParserType(JsonParserType.JACKSON_1);
    } else if (cfg.hasCustomGsonObjectMapperFactory()) {
      cfg = cfg.defaultParserType(JsonParserType.GSON);
    } else if (cfg.hasCustomJackson20ObjectMapperFactory()) {
      cfg = cfg.defaultParserType(JsonParserType.JACKSON_2);
    }

    if (!(object instanceof String)) {
      throw new IllegalStateException(
          "Internal error: Json object was not an instance of String, please report to the REST Assured mailing-list.");
    }

    return JsonObjectDeserializer.deserialize((String) object, objectType, cfg);
  }
 /**
  * Get the result of an Object path expression as a double.
  *
  * @param path The Object path.
  * @return The object matching the Object path. A {@link java.lang.ClassCastException} will be
  *     thrown if the object cannot be casted to the expected type.
  */
 public double getDouble(String path) {
   final Object value = get(path);
   if (value instanceof Double) {
     return (Double) value;
   }
   return ObjectConverter.convertObjectTo(value, Double.class);
 }
 /**
  * Get the result of an Object path expression as a list.
  *
  * @param path The Object path.
  * @param genericType The generic list type
  * @param <T> The type
  * @return The object matching the Object path. A {@link java.lang.ClassCastException} will be
  *     thrown if the object cannot be casted to the expected type.
  */
 public <T> List<T> getList(String path, Class<T> genericType) {
   final List<T> original = get(path);
   final List<T> newList = new LinkedList<T>();
   for (T t : original) {
     newList.add(ObjectConverter.convertObjectTo(t, genericType));
   }
   return Collections.unmodifiableList(newList);
 }
 /**
  * Get the result of an Object path expression as a float.
  *
  * @param path The Object path.
  * @return The object matching the Object path. A {@link java.lang.ClassCastException} will be
  *     thrown if the object cannot be casted to the expected type.
  */
 public float getFloat(String path) {
   final Object value = get(path);
   // Groovy will always return a Double for floating point values.
   if (value instanceof Double) {
     return ((Double) value).floatValue();
   } else {
     return ObjectConverter.convertObjectTo(value, Float.class);
   }
 }
 /**
  * Get the result of an Object path expression as a long.
  *
  * @param path The Object path.
  * @return The object matching the Object path. A {@link java.lang.ClassCastException} will be
  *     thrown if the object cannot be casted to the expected type.
  */
 public long getLong(String path) {
   // The type returned from Groovy depends on the input, so we need to handle different numerical
   // types.
   Object value = get(path);
   if (value instanceof Long) {
     return (Long) value;
   } else if (value instanceof Short) {
     return ((Short) value).longValue();
   } else if (value instanceof Integer) {
     return ((Integer) value).longValue();
   } else {
     return ObjectConverter.convertObjectTo(value, Long.class);
   }
 }
 /**
  * Get the result of an Object path expression as a byte.
  *
  * @param path The Object path.
  * @return The object matching the Object path. A {@link java.lang.ClassCastException} will be
  *     thrown if the object cannot be casted to the expected type.
  */
 public byte getByte(String path) {
   // The type returned from Groovy depends on the input, so we need to handle different numerical
   // types.
   Object value = get(path);
   if (value instanceof Byte) {
     return (Byte) value;
   } else if (value instanceof Long) {
     return ((Long) value).byteValue();
   } else if (value instanceof Integer) {
     return ((Integer) value).byteValue();
   } else {
     return ObjectConverter.convertObjectTo(value, Byte.class);
   }
 }
 /**
  * Get the result of an Object path expression as a string.
  *
  * @param path The Object path.
  * @return The object matching the Object path. A {@link java.lang.ClassCastException} will be
  *     thrown if the object cannot be casted to the expected type.
  */
 public String getString(String path) {
   return ObjectConverter.convertObjectTo(get(path), String.class);
 }
 /**
  * Get the result of an Object path expression as a char.
  *
  * @param path The Object path.
  * @return The object matching the Object path. A {@link java.lang.ClassCastException} will be
  *     thrown if the object cannot be casted to the expected type.
  */
 public char getChar(String path) {
   return ObjectConverter.convertObjectTo(get(path), Character.class);
 }
 /**
  * Get the result of an Object path expression as a boolean
  *
  * @param path The Object path.
  * @return The object matching the Object path. A {@link java.lang.ClassCastException} will be
  *     thrown if the object cannot be casted to the expected type.
  */
 public boolean getBoolean(String path) {
   return ObjectConverter.convertObjectTo(get(path), Boolean.class);
 }