diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesActivity.java
index 2183bf4401a..9d36ea141d6 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesActivity.java
@@ -9,6 +9,7 @@
 import android.util.Log;
 import android.view.MenuItem;
 
+import com.google.gson.JsonElement;
 import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
 import com.mapbox.mapboxsdk.geometry.LatLng;
 import com.mapbox.mapboxsdk.maps.MapView;
@@ -18,6 +19,7 @@
 import com.mapbox.services.commons.geojson.Feature;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * Demo's query rendered features
@@ -54,7 +56,12 @@ public void onMapClick(@NonNull LatLng point) {
 
                         for (Feature feature : features) {
                             if (feature != null) {
-                                Log.i(TAG, String.format("Got feature %s", feature.getId()));
+                                Log.i(TAG, String.format("Got feature %s. With %s properties", feature.getId(), feature.getProperties() != null ? feature.getProperties().entrySet().size() : "<null>"));
+                                if (feature.getProperties() != null) {
+                                    for (Map.Entry<String, JsonElement> entry : feature.getProperties().entrySet()) {
+                                        Log.i(TAG, String.format("Prop %s - %s", entry.getKey(), entry.getValue()));
+                                    }
+                                }
                             } else {
                                 Log.i(TAG, "Got NULL feature %s");
                             }
@@ -63,7 +70,7 @@ public void onMapClick(@NonNull LatLng point) {
                 });
 
                 //Little taste of home
-                mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.0907, 5.1214), 12));
+                mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.0907, 5.1214), 16));
             }
         });
     }
diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp
index 9a570d37174..ceda4859582 100644
--- a/platform/android/src/conversion/constant.hpp
+++ b/platform/android/src/conversion/constant.hpp
@@ -32,6 +32,27 @@ struct Converter<jni::jobject*, float> {
     }
 };
 
+template <>
+struct Converter<jni::jobject*, double> {
+    Result<jni::jobject*> operator()(jni::JNIEnv& env, const double& value) const {
+        static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Double")).release();
+        static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(D)V");
+        return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)};
+    }
+};
+
+/**
+ * All integrals. java is limited to 64 bit signed, so...
+ */
+template<typename T>
+struct Converter<jni::jobject*, T, typename std::enable_if<std::is_integral<T>::value>::type> {
+    Result<jni::jobject*> operator()(jni::JNIEnv& env, const T& value) const {
+        static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Long")).release();
+        static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(J)V");
+        return {&jni::NewObject(env, *javaClass, *constructor, (jlong) value)};
+    }
+};
+
 template <>
 struct Converter<jni::jobject*, std::string> {
     Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::string& value) const {
diff --git a/platform/android/src/conversion/conversion.hpp b/platform/android/src/conversion/conversion.hpp
index ea8a31bcf29..1277f3f67e0 100644
--- a/platform/android/src/conversion/conversion.hpp
+++ b/platform/android/src/conversion/conversion.hpp
@@ -37,7 +37,7 @@ class Result : private variant<T, Error> {
     }
 };
 
-template <class T, class V>
+template <class T, class V, class Enable = void>
 struct Converter;
 
 template <class T, typename V, class...Args>
diff --git a/platform/android/src/geometry/conversion/feature.hpp b/platform/android/src/geometry/conversion/feature.hpp
index c91be1637d5..7f57a1ffb7e 100644
--- a/platform/android/src/geometry/conversion/feature.hpp
+++ b/platform/android/src/geometry/conversion/feature.hpp
@@ -18,6 +18,9 @@ namespace mbgl {
 namespace android {
 namespace conversion {
 
+/**
+ * Turn feature identifier into std::string
+ */
 class FeatureIdVisitor {
 public:
 
@@ -30,6 +33,112 @@ class FeatureIdVisitor {
         return i;
     }
 
+    std::string operator()(const std::nullptr_t&) const {
+        return "";
+    }
+
+};
+
+/**
+ * Turn properties into Java GSON JsonObject's
+ */
+class PropertyValueEvaluator {
+public:
+    jni::JNIEnv& env;
+
+    /**
+     * null
+     */
+    jni::jobject* operator()(const mapbox::geometry::null_value_t &) const {
+        return (jni::jobject*) nullptr;
+    }
+
+    /**
+     * Boolean primitive
+     */
+    jni::jobject* operator()(const bool& value) const {
+        static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release();
+        static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Z)V");;
+        return &jni::NewObject(env, *javaClass, *constructor, *convert<jni::jobject*, bool>(env, value));
+    }
+
+    /**
+     * String primitive
+     */
+    jni::jobject* operator()(const std::string& value) const {
+        static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release();
+        static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/String;)V");;
+        return &jni::NewObject(env, *javaClass, *constructor, *convert<jni::jobject*, std::string>(env, value));
+    }
+
+    /**
+     * Number primitives
+     */
+    template <class Number>
+    jni::jobject* operator()(const Number& value) const {
+        static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release();
+        static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Number;)V");
+        return &jni::NewObject(env, *javaClass, *constructor, *convert<jni::jobject*, Number>(env, value));
+    }
+
+
+    /**
+     * Json Array
+     */
+    jni::jobject* operator()(const std::vector<mbgl::Value> &values) const {
+        static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonArray")).release();
+        static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");;
+        static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Lcom/google/gson/JsonElement;)V");
+
+        //Create json array
+        jni::jobject* jarray = &jni::NewObject(env, *javaClass, *constructor);
+
+        //Add values
+        for (const auto &v : values) {
+            jni::CallMethod<void>(env, jarray, *add, mbgl::Value::visit(v, *this));
+        }
+
+        return jarray;
+    }
+
+    /**
+     * Json Object
+     */
+    jni::jobject* operator()(const std::unordered_map<std::string, mbgl::Value> &value) const {
+        static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release();
+        static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");;
+        static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V");
+
+        //Create json object
+        jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor);
+
+        //Add items
+        for (auto &item : value) {
+            jni::CallMethod<void>(env, jsonObject, *add, *convert<jni::jobject*, std::string>(env, item.first), mbgl::Value::visit(item.second, *this));
+        }
+
+        return jsonObject;
+    }
+};
+
+template <>
+struct Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>> {
+    Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::unordered_map<std::string, mbgl::Value>& value) const {
+        static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release();
+        static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");;
+        static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V");
+
+        //Create json object
+        jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor);
+
+        //Add items
+        PropertyValueEvaluator evaluator {env};
+        for (auto &item : value) {
+            jni::CallMethod<void>(env, jsonObject, *add, *convert<jni::jobject*, std::string>(env, item.first), mbgl::Value::visit(item.second, evaluator));
+        }
+
+        return {jsonObject};
+    }
 };
 
 
@@ -39,13 +148,16 @@ struct Converter<jni::jobject*, mbgl::Feature> {
         static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Feature")).release();
         static jni::jmethodID* fromGeometry = &jni::GetStaticMethodID(env, *javaClass, "fromGeometry", "(Lcom/mapbox/services/commons/geojson/Geometry;Lcom/google/gson/JsonObject;Ljava/lang/String;)Lcom/mapbox/services/commons/geojson/Feature;");
 
-        //Get Id
+        //Convert Id
         FeatureIdVisitor idEvaluator;
         std::string id = (value.id) ? mapbox::geometry::identifier::visit(value.id.value(), idEvaluator) : "";
         Result<jni::jobject*> jid = convert<jni::jobject*>(env, id);
 
+        //Convert properties
+        Result<jni::jobject*> properties = convert<jni::jobject*>(env, value.properties);
+
         /**, TODO: converted geometry**/
-        return {reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometry, (jni::jobject*) nullptr, (jni::jobject*) nullptr, *jid))};
+        return {reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometry, (jni::jobject*) nullptr, *properties, *jid))};
     }
 };