Skip to content

Commit c7a13df

Browse files
Routable points support for services-geocoding (#1522)
1 parent d112384 commit c7a13df

11 files changed

Lines changed: 611 additions & 8 deletions

File tree

services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/GeocodingService.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public interface GeocodingService {
3535
* @param language The locale in which results should be returned.
3636
* @param reverseMode Set the factors that are used to sort nearby results.
3737
* @param fuzzyMatch Set whether to allow the geocoding API to attempt exact matching or not.
38+
* @param routing Set whether to request additional metadata
39+
* about the recommended navigation destination.
3840
* @return A retrofit Call object
3941
* @since 1.0.0
4042
*/
@@ -52,7 +54,8 @@ Call<GeocodingResponse> getCall(
5254
@Query("limit") String limit,
5355
@Query("language") String language,
5456
@Query("reverseMode") String reverseMode,
55-
@Query("fuzzyMatch") Boolean fuzzyMatch);
57+
@Query("fuzzyMatch") Boolean fuzzyMatch,
58+
@Query("routing") Boolean routing);
5659

5760
/**
5861
* Constructs the html call using the information passed in through the

services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/MapboxGeocoding.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ protected Call<GeocodingResponse> initializeCall() {
9797
limit(),
9898
languages(),
9999
reverseMode(),
100-
fuzzyMatch());
100+
fuzzyMatch(),
101+
routing());
101102
}
102103

103104
private Call<List<GeocodingResponse>> getBatchCall() {
@@ -215,6 +216,9 @@ public Call<List<GeocodingResponse>> cloneBatchCall() {
215216
@Nullable
216217
abstract Boolean fuzzyMatch();
217218

219+
@Nullable
220+
abstract Boolean routing();
221+
218222
@Nullable
219223
abstract String clientAppName();
220224

@@ -560,6 +564,24 @@ public abstract Builder reverseMode(
560564
*/
561565
public abstract Builder fuzzyMatch(Boolean fuzzyMatch);
562566

567+
/**
568+
* Specify whether to request additional metadata about the recommended navigation destination
569+
* corresponding to the feature (true) or not (false, default).
570+
* Only applicable for address features.
571+
*
572+
* For example, if routing=true the response could include data about a point
573+
* on the road the feature fronts.
574+
* Response features may include an array containing one or more routable points.
575+
* Routable points cannot always be determined. Consuming applications should fall back to
576+
* using the feature's normal geometry for routing if a separate routable point
577+
* is not returned.
578+
*
579+
* @param routing optionally set whether to request
580+
* additional metadata about the recommended navigation destination
581+
* @return this builder for chaining options together
582+
*/
583+
public abstract Builder routing(Boolean routing);
584+
563585
/**
564586
* Required to call when this is being built. If no access token provided,
565587
* {@link ServicesException} will be thrown.

services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/CarmenContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
/**
1414
* Array representing a hierarchy of parents. Each parent includes id, text keys along with
15-
* (if avaliable) a wikidata, short_code, and Maki key.
15+
* (if available) a wikidata, short_code, and Maki key.
1616
*
1717
* @see <a href="https://github.com/mapbox/carmen/blob/master/carmen-geojson.md">Carmen Geojson information</a>
1818
* @see <a href="https://www.mapbox.com/api-documentation/search/#geocoding">Mapbox geocoder documentation</a>

services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/CarmenFeature.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,15 @@ public Point center() {
261261
@SerializedName("matching_place_name")
262262
public abstract String matchingPlaceName();
263263

264+
/**
265+
* An object with the routable points for the {@link CarmenFeature}.
266+
*
267+
* @return an object with the routable points for the {@link CarmenFeature}
268+
*/
269+
@Nullable
270+
@SerializedName("routable_points")
271+
public abstract RoutablePoints routablePoints();
272+
264273
/**
265274
* A string of the IETF language tag of the query's primary language.
266275
*
@@ -482,6 +491,14 @@ public abstract static class Builder {
482491
*/
483492
public abstract Builder language(@Nullable String language);
484493

494+
/**
495+
* An object with the routable points for the {@link CarmenFeature}.
496+
*
497+
* @param routablePoints an object with the routable points for the {@link CarmenFeature}
498+
* @return this builder for chaining options together
499+
*/
500+
public abstract Builder routablePoints(@Nullable RoutablePoints routablePoints);
501+
485502
/**
486503
* Build a new {@link CarmenFeature} object.
487504
*
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.mapbox.api.geocoding.v5.models;
2+
3+
import androidx.annotation.Nullable;
4+
5+
import com.google.auto.value.AutoValue;
6+
import com.google.gson.Gson;
7+
import com.google.gson.TypeAdapter;
8+
import com.google.gson.annotations.SerializedName;
9+
import com.mapbox.geojson.Point;
10+
11+
/**
12+
* Object representing {@link CarmenFeature}'s routable point.
13+
*/
14+
@AutoValue
15+
public abstract class RoutablePoint {
16+
17+
/**
18+
* A string representing the routable point name.
19+
*
20+
* @return routable point name
21+
*/
22+
@Nullable
23+
@SerializedName("name")
24+
public abstract String name();
25+
26+
/**
27+
* A {@link Point} object which represents the routable point location.
28+
*
29+
* @return a GeoJson {@link Point} which defines the routable point location
30+
*/
31+
@Nullable
32+
public Point coordinate() {
33+
final double[] coordinate = rawCoordinate();
34+
if (coordinate != null && coordinate.length == 2) {
35+
return Point.fromLngLat(coordinate[0], coordinate[1]);
36+
}
37+
return null;
38+
}
39+
40+
// No public access thus, we lessen enforcement on mutability here.
41+
@Nullable
42+
@SerializedName("coordinates")
43+
@SuppressWarnings("mutable")
44+
abstract double[] rawCoordinate();
45+
46+
/**
47+
* Convert current instance values into another Builder to quickly change one or more values.
48+
*
49+
* @return a new instance of {@link Builder}
50+
*/
51+
@SuppressWarnings("unused")
52+
public abstract Builder toBuilder();
53+
54+
/**
55+
* Gson type adapter for parsing Gson to this class.
56+
*
57+
* @param gson the built {@link Gson} object
58+
* @return the type adapter for this class
59+
*/
60+
public static TypeAdapter<RoutablePoint> typeAdapter(Gson gson) {
61+
return new AutoValue_RoutablePoint.GsonTypeAdapter(gson);
62+
}
63+
64+
/**
65+
* This builder can be used to set the values describing the {@link RoutablePoint}.
66+
*/
67+
@AutoValue.Builder
68+
@SuppressWarnings("unused")
69+
public abstract static class Builder {
70+
71+
/**
72+
* A string representing the routable point name.
73+
*
74+
* @param name routable point name
75+
* @return this builder for chaining options together
76+
*/
77+
public abstract Builder name(@Nullable String name);
78+
79+
/**
80+
* Raw coordinates (longitude and latitude, order matters)
81+
* that represent the routable point location.
82+
*
83+
* @param coordinate raw coordinates that represent the routable point location
84+
* @return this builder for chaining options together
85+
*/
86+
public abstract Builder rawCoordinate(@Nullable double[] coordinate);
87+
88+
/**
89+
* Build a new {@link RoutablePoint} object.
90+
*
91+
* @return a new {@link RoutablePoint} using the provided values in this builder
92+
*/
93+
public abstract RoutablePoint build();
94+
}
95+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.mapbox.api.geocoding.v5.models;
2+
3+
import androidx.annotation.Nullable;
4+
5+
import com.google.auto.value.AutoValue;
6+
import com.google.gson.Gson;
7+
import com.google.gson.TypeAdapter;
8+
import com.google.gson.annotations.SerializedName;
9+
10+
import java.util.List;
11+
12+
/**
13+
* An object with the routable points for the {@link CarmenFeature}.
14+
*/
15+
@AutoValue
16+
public abstract class RoutablePoints {
17+
18+
/**
19+
* A list of routable points for the {@link CarmenFeature}, or null if no points were found.
20+
*
21+
* @return a list of routable points for the {@link CarmenFeature},
22+
* or null if no points were found
23+
*/
24+
@Nullable
25+
@SerializedName("points")
26+
public abstract List<RoutablePoint> points();
27+
28+
/**
29+
* Convert current instance values into another Builder to quickly change one or more values.
30+
*
31+
* @return a new instance of {@link Builder}
32+
*/
33+
@SuppressWarnings("unused")
34+
public abstract Builder toBuilder();
35+
36+
/**
37+
* Gson type adapter for parsing Gson to this class.
38+
*
39+
* @param gson the built {@link Gson} object
40+
* @return the type adapter for this class
41+
*/
42+
public static TypeAdapter<RoutablePoints> typeAdapter(Gson gson) {
43+
return new AutoValue_RoutablePoints.GsonTypeAdapter(gson);
44+
}
45+
46+
/**
47+
* This builder can be used to set the values describing the {@link RoutablePoints}.
48+
*/
49+
@AutoValue.Builder
50+
@SuppressWarnings("unused")
51+
public abstract static class Builder {
52+
53+
/**
54+
* A list of routable points for the {@link CarmenFeature},
55+
* or null if no points were found.
56+
*
57+
* @param points a list of routable points for the {@link CarmenFeature},
58+
* or null if no points were found
59+
* @return this builder for chaining options together
60+
*/
61+
public abstract Builder points(@Nullable List<RoutablePoint> points);
62+
63+
/**
64+
* Build a new {@link RoutablePoints} object.
65+
*
66+
* @return a new {@link RoutablePoints} using the provided values in this builder
67+
*/
68+
public abstract RoutablePoints build();
69+
}
70+
}

services-geocoding/src/test/java/com/mapbox/api/geocoding/v5/MapboxGeocodingTest.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import static org.hamcrest.Matchers.startsWith;
1717
import static org.junit.Assert.assertEquals;
18+
import static org.junit.Assert.assertFalse;
1819
import static org.junit.Assert.assertNotNull;
1920
import static org.junit.Assert.assertTrue;
2021

@@ -312,6 +313,44 @@ public void fuzzyMatch_getsAddedToUrlCorrectly() {
312313
.contains("fuzzyMatch=true"));
313314
}
314315

316+
@Test
317+
public void routingSanity() throws Exception {
318+
MapboxGeocoding mapboxGeocoding = MapboxGeocoding.builder()
319+
.accessToken(ACCESS_TOKEN)
320+
.query("wahsington")
321+
.routing(true)
322+
.baseUrl(mockUrl.toString())
323+
.build();
324+
assertNotNull(mapboxGeocoding);
325+
Response<GeocodingResponse> response = mapboxGeocoding.executeCall();
326+
assertEquals(200, response.code());
327+
}
328+
329+
@Test
330+
public void routing_defaultIsNotSpecified() {
331+
MapboxGeocoding mapboxGeocoding = MapboxGeocoding.builder()
332+
.accessToken(ACCESS_TOKEN)
333+
.query("wahsington")
334+
.baseUrl(mockUrl.toString())
335+
.build();
336+
assertNotNull(mapboxGeocoding);
337+
assertFalse(mapboxGeocoding.cloneCall().request().url().toString()
338+
.contains("routing="));
339+
}
340+
341+
@Test
342+
public void routing_getsAddedToUrlCorrectly() {
343+
MapboxGeocoding mapboxGeocoding = MapboxGeocoding.builder()
344+
.accessToken(ACCESS_TOKEN)
345+
.query("wahsington")
346+
.routing(true)
347+
.baseUrl(mockUrl.toString())
348+
.build();
349+
assertNotNull(mapboxGeocoding);
350+
assertTrue(mapboxGeocoding.cloneCall().request().url().toString()
351+
.contains("routing=true"));
352+
}
353+
315354
@Test
316355
public void intersectionSearchSanity() throws IOException {
317356
MapboxGeocoding mapboxGeocoding = MapboxGeocoding.builder()
@@ -382,7 +421,7 @@ public void intersectionSearch_AutoSetGeocodingType() {
382421
}
383422

384423
@Test
385-
public void intersectionSearch_EmptyPromixity() {
424+
public void intersectionSearch_EmptyProximity() {
386425
thrown.expect(ServicesException.class);
387426
thrown.expectMessage(
388427
startsWith("Geocoding proximity must be set for intersection search."));

services-geocoding/src/test/java/com/mapbox/api/geocoding/v5/models/CarmenContextTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
public class CarmenContextTest extends GeocodingTestUtils {
2020

2121
@Test
22-
public void sanity() throws Exception {
22+
public void sanity() {
2323
CarmenContext carmenContext = CarmenContext.builder().build();
2424
assertNotNull(carmenContext);
2525
}

services-geocoding/src/test/java/com/mapbox/api/geocoding/v5/models/CarmenFeatureTest.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class CarmenFeatureTest extends GeocodingTestUtils {
3333
private static final String FORWARD_FEATURE_VALID = "forward_feature_valid.json";
3434

3535
@Test
36-
public void sanity() throws Exception {
36+
public void sanity() {
3737
CarmenFeature carmenFeature = CarmenFeature.builder()
3838
.properties(new JsonObject())
3939
.address("1234")
@@ -104,6 +104,32 @@ public void fromJson_handlesConversionCorrectly() throws Exception {
104104
assertThat(feature.center().latitude(), equalTo(38.897702));
105105
assertThat(feature.center().longitude(), equalTo(-77.036543));
106106
assertThat(feature.language(), nullValue());
107+
assertThat(feature.routablePoints(), notNullValue());
108+
}
109+
110+
@Test
111+
public void routablePoints_handlesCorrectly() throws IOException {
112+
MapboxGeocoding mapboxGeocoding = MapboxGeocoding.builder()
113+
.accessToken(ACCESS_TOKEN)
114+
.query("1600 pennsylvania ave nw")
115+
.baseUrl(mockUrl.toString())
116+
.build();
117+
GeocodingResponse response = mapboxGeocoding.executeCall().body();
118+
assertNotNull(response);
119+
120+
assertThat(response.features().size(), equalTo(5));
121+
122+
CarmenFeature feature = response.features().get(0);
123+
assertThat(feature.routablePoints(), notNullValue());
124+
assertThat(feature.routablePoints().points(), notNullValue());
125+
assertThat(feature.routablePoints().points().size(), equalTo(1));
126+
assertThat(feature.routablePoints().points().get(0).name(), equalTo("default_routable_point"));
127+
assertThat(feature.routablePoints().points().get(0).coordinate(), equalTo(Point.fromLngLat(-77.036544, 38.897703)));
128+
129+
assertThat(response.features().get(1).routablePoints(), notNullValue());
130+
assertThat(response.features().get(1).routablePoints().points(), nullValue());
131+
132+
assertThat(response.features().get(2).routablePoints(), nullValue());
107133
}
108134

109135
@Test

0 commit comments

Comments
 (0)