Skip to content

[Detail Bug] Apple Maps: Place lookup API call fails due to incorrect response deserialization #69

@detail-app

Description

@detail-app

Detail Bug Report

https://app.detail.dev/org_befd6425-a158-4e24-9d4d-1e5c08769515/bugs/bug_4b0dc27e-1a85-46f5-8317-afad12054f54

Summary

  • Context: The AppleMapsGateway interface defines methods for interacting with the Apple Maps Server API, including looking up a single place by its identifier.
  • Bug: In the HttpAppleMapsGateway implementation, the lookupPlace method attempts to deserialize the API response directly into a Place record. However, the Apple Maps Server API always returns a PlaceResults object (which contains a results array) even for single-place lookups.
  • Actual vs. expected: The code expects a Place object at the top level of the JSON response, but receives a PlaceResults object; this causes a ValueInstantiationException (or NullPointerException) because the required fields of the Place record are missing from the top-level JSON.
  • Impact: The lookupPlace method 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions