-
Notifications
You must be signed in to change notification settings - Fork 0
[Detail Bug] Apple Maps: Place lookup API call fails due to incorrect response deserialization #69
Description
Detail Bug Report
Summary
- Context: The
AppleMapsGatewayinterface defines methods for interacting with the Apple Maps Server API, including looking up a single place by its identifier. - Bug: In the
HttpAppleMapsGatewayimplementation, thelookupPlacemethod attempts to deserialize the API response directly into aPlacerecord. However, the Apple Maps Server API always returns aPlaceResultsobject (which contains aresultsarray) even for single-place lookups. - Actual vs. expected: The code expects a
Placeobject at the top level of the JSON response, but receives aPlaceResultsobject; this causes aValueInstantiationException(orNullPointerException) because the required fields of thePlacerecord are missing from the top-level JSON. - Impact: The
lookupPlacemethod is completely non-functional and will fail whenever it is called against the live Apple Maps Server API.
Code with Bug
@Override
public Place lookupPlace(String placeId, String language) {
Objects.requireNonNull(placeId, "placeId");
String resolvedLanguage = Objects.requireNonNull(language, "language");
String queryString = "";
if (!resolvedLanguage.isBlank()) {
queryString = QUERY_PREFIX + PARAMETER_LANGUAGE + "=" + resolvedLanguage;
}
return invokeApi("place", URI.create(API_SERVER + PLACE_PATH + "/" + placeId + queryString), Place.class); // <-- BUG 🔴 Cannot deserialize PlaceResults JSON into Place record
}Explanation
Apple’s Place Lookup endpoint (GET /v1/place/{id}) returns a PlaceResults wrapper object containing a results array of Place objects. lookupPlace currently requests Place.class from invokeApi, so Jackson attempts to construct a Place from the top-level JSON and fails because required Place fields (e.g., name) are nested under results[0].
Codebase Inconsistency
Other HttpAppleMapsGateway methods that return places (e.g., geocode and reverseGeocode) correctly deserialize into PlaceResults.class, indicating lookupPlace is inconsistent with the expected API response shape.
Recommended Fix
Deserialize the response as PlaceResults and return the first result (or throw if empty).
@Override
public Place lookupPlace(String placeId, String language) {
Objects.requireNonNull(placeId, "placeId");
String resolvedLanguage = Objects.requireNonNull(language, "language");
String queryString = "";
if (!resolvedLanguage.isBlank()) {
queryString = QUERY_PREFIX + PARAMETER_LANGUAGE + "=" + resolvedLanguage;
}
PlaceResults response = invokeApi("place", URI.create(API_SERVER + PLACE_PATH + "/" + placeId + queryString), PlaceResults.class); // <-- FIX 🟢
return response.results().stream().findFirst().orElseThrow(() -> new AppleMapsClientException("place", new RuntimeException("Place not found"))); // <-- FIX 🟢
}History
This bug was introduced in commit 6787139. The original change added the HttpAppleMapsGateway adapter, but it incorrectly attempted to deserialize the singular /v1/place/{id} response directly into a Place record instead of the PlaceResults wrapper returned by the Apple Maps API.