This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-26170-geocoder-zero-results in repository https://gitbox.apache.org/repos/asf/camel.git
commit c6ae28d7dc2e4ab8209fd811ed3b7dfc15d723ee Author: Claus Ibsen <[email protected]> AuthorDate: Mon Nov 2 23:30:57 2026 +0100 CAMEL-26170: camel-geocoder - Nominatim sets ZERO_RESULTS when it finds no place Nominatim answers [] for an address it does not find. The producer set the status OK, cut off the brackets and parsed the empty text, which failed the exchange with an IllegalArgumentException. An empty array is now ZERO_RESULTS. A latitude and longitude with no place ({"error":"Unable to geocode"}) is ZERO_RESULTS as well, and another error answer is ERROR; both were OK before. The Nominatim tests use a local HTTP server with recorded answers instead of nominatim.openstreetmap.org. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../apache/camel/catalog/components/geocoder.json | 2 +- .../camel/catalog/docs/geocoder-component.adoc | 2 + .../apache/camel/component/geocoder/geocoder.json | 2 +- .../src/main/docs/geocoder-component.adoc | 2 + .../camel/component/geocoder/GeoCoderEndpoint.java | 4 +- .../geocoder/GeoCoderNominatimProducer.java | 25 +++++-- .../geocoder/GeoCoderNominatimAddressTest.java | 11 +-- .../component/geocoder/GeoCoderNominatimTest.java | 10 +-- .../geocoder/GeoCoderNominatimTestSupport.java | 84 ++++++++++++++++++++++ .../geocoder/GeoCoderNominatimZeroResultsTest.java | 81 +++++++++++++++++++++ .../test/resources/nominatim/reverse-sevilla.json | 1 + .../nominatim/search-calle-marie-curie.json | 1 + .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 7 ++ 13 files changed, 214 insertions(+), 18 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/geocoder.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/geocoder.json index d8fd1660170a..459f1b883f46 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/geocoder.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/geocoder.json @@ -43,7 +43,7 @@ }, "bodyTypes": { "producerIn": { "carriers": [ "any" ], "description": "The body is not read: the address or the latitude and longitude come from the CamelGeoCoderAddress or CamelGeoCoderLatlng header, or else from the endpoint" }, - "producerOut": { "carriers": [ "list", "unchanged" ], "byOption": [ { "option": "type", "value": "NOMINATIM", "carriers": [ "text" ], "javaType": "java.lang.String" }, { "option": "headersOnly", "value": "true", "carriers": [ "unchanged" ] } ], "description": "With Google, the array of com.google.maps.model.GeocodingResult, empty for no results; unchanged when Google denies the request, with the status in the CamelGeoCoderStatus header. With Nominatim, its jsonv2 response as text: an [...] + "producerOut": { "carriers": [ "list", "unchanged" ], "byOption": [ { "option": "type", "value": "NOMINATIM", "carriers": [ "text" ], "javaType": "java.lang.String" }, { "option": "headersOnly", "value": "true", "carriers": [ "unchanged" ] } ], "description": "With Google, the array of com.google.maps.model.GeocodingResult, empty for no results; unchanged when Google denies the request, with the status in the CamelGeoCoderStatus header. With Nominatim, its jsonv2 response as text: an [...] }, "properties": { "address": { "index": 0, "kind": "path", "displayName": "Address", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The geo address which should be prefixed with address:" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/geocoder-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/geocoder-component.adoc index 8da79a403ab9..d59b7e832c36 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/geocoder-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/geocoder-component.adoc @@ -54,6 +54,8 @@ mode in use (`address` vs. `latlng`). Camel will deliver the body as a String with the JSON response of Nominatim (the `jsonv2` format): an array with one place for an address, and an object for a latitude and longitude. +When Nominatim finds no place (an empty array for an address, or `{"error":"Unable to geocode"}` for a latitude and longitude), +the `CamelGeoCoderStatus` header is `ZERO_RESULTS`, and when it answers with an error, the header is `ERROR`. === Body using a Google Server diff --git a/components/camel-geocoder/src/generated/resources/META-INF/org/apache/camel/component/geocoder/geocoder.json b/components/camel-geocoder/src/generated/resources/META-INF/org/apache/camel/component/geocoder/geocoder.json index d8fd1660170a..459f1b883f46 100644 --- a/components/camel-geocoder/src/generated/resources/META-INF/org/apache/camel/component/geocoder/geocoder.json +++ b/components/camel-geocoder/src/generated/resources/META-INF/org/apache/camel/component/geocoder/geocoder.json @@ -43,7 +43,7 @@ }, "bodyTypes": { "producerIn": { "carriers": [ "any" ], "description": "The body is not read: the address or the latitude and longitude come from the CamelGeoCoderAddress or CamelGeoCoderLatlng header, or else from the endpoint" }, - "producerOut": { "carriers": [ "list", "unchanged" ], "byOption": [ { "option": "type", "value": "NOMINATIM", "carriers": [ "text" ], "javaType": "java.lang.String" }, { "option": "headersOnly", "value": "true", "carriers": [ "unchanged" ] } ], "description": "With Google, the array of com.google.maps.model.GeocodingResult, empty for no results; unchanged when Google denies the request, with the status in the CamelGeoCoderStatus header. With Nominatim, its jsonv2 response as text: an [...] + "producerOut": { "carriers": [ "list", "unchanged" ], "byOption": [ { "option": "type", "value": "NOMINATIM", "carriers": [ "text" ], "javaType": "java.lang.String" }, { "option": "headersOnly", "value": "true", "carriers": [ "unchanged" ] } ], "description": "With Google, the array of com.google.maps.model.GeocodingResult, empty for no results; unchanged when Google denies the request, with the status in the CamelGeoCoderStatus header. With Nominatim, its jsonv2 response as text: an [...] }, "properties": { "address": { "index": 0, "kind": "path", "displayName": "Address", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The geo address which should be prefixed with address:" }, diff --git a/components/camel-geocoder/src/main/docs/geocoder-component.adoc b/components/camel-geocoder/src/main/docs/geocoder-component.adoc index 8da79a403ab9..d59b7e832c36 100644 --- a/components/camel-geocoder/src/main/docs/geocoder-component.adoc +++ b/components/camel-geocoder/src/main/docs/geocoder-component.adoc @@ -54,6 +54,8 @@ mode in use (`address` vs. `latlng`). Camel will deliver the body as a String with the JSON response of Nominatim (the `jsonv2` format): an array with one place for an address, and an object for a latitude and longitude. +When Nominatim finds no place (an empty array for an address, or `{"error":"Unable to geocode"}` for a latitude and longitude), +the `CamelGeoCoderStatus` header is `ZERO_RESULTS`, and when it answers with an error, the header is `ERROR`. === Body using a Google Server diff --git a/components/camel-geocoder/src/main/java/org/apache/camel/component/geocoder/GeoCoderEndpoint.java b/components/camel-geocoder/src/main/java/org/apache/camel/component/geocoder/GeoCoderEndpoint.java index a1dacf752942..c4f13de0717e 100644 --- a/components/camel-geocoder/src/main/java/org/apache/camel/component/geocoder/GeoCoderEndpoint.java +++ b/components/camel-geocoder/src/main/java/org/apache/camel/component/geocoder/GeoCoderEndpoint.java @@ -51,8 +51,8 @@ import org.apache.camel.support.DefaultEndpoint; description = "With Google, the array of com.google.maps.model.GeocodingResult, empty for" + " no results; unchanged when Google denies the request, with the status in" + " the CamelGeoCoderStatus header. With Nominatim, its jsonv2 response as text:" - + " an array of one place for an address, an object for a latitude and" - + " longitude. The first result is also in the headers")) + + " an array of one place for an address (empty for no results), an object" + + " for a latitude and longitude. The first result is also in the headers")) public class GeoCoderEndpoint extends DefaultEndpoint implements EndpointServiceLocation { @UriPath diff --git a/components/camel-geocoder/src/main/java/org/apache/camel/component/geocoder/GeoCoderNominatimProducer.java b/components/camel-geocoder/src/main/java/org/apache/camel/component/geocoder/GeoCoderNominatimProducer.java index b30ee8f23c08..af3932601e5d 100644 --- a/components/camel-geocoder/src/main/java/org/apache/camel/component/geocoder/GeoCoderNominatimProducer.java +++ b/components/camel-geocoder/src/main/java/org/apache/camel/component/geocoder/GeoCoderNominatimProducer.java @@ -129,20 +129,33 @@ public class GeoCoderNominatimProducer extends DefaultProducer { exchange.getIn().setBody(place); } + if (place != null) { + place = place.trim(); + // search answers an array, of one place as we ask for limit=1, and [] when nothing is found + if (place.startsWith("[") && place.endsWith("]")) { + place = place.substring(1, place.length() - 1).trim(); + } + } if (place == null || place.isEmpty()) { exchange.getIn().setHeader(GeoCoderConstants.STATUS, GeocoderStatus.ZERO_RESULTS); return; } - exchange.getIn().setHeader(GeoCoderConstants.STATUS, GeocoderStatus.OK); - if (place.startsWith("[") && place.endsWith("]")) { - place = place.substring(1, place.length() - 1); - } - - // additional details final Configuration conf = Configuration.defaultConfiguration().addOptions(Option.SUPPRESS_EXCEPTIONS); final DocumentContext doc = JsonPath.using(conf).parse(place); + Object error = doc.read("$['error']"); + if (error instanceof String) { + // reverse answers {"error":"Unable to geocode"} when there is no place at the latitude and longitude + exchange.getIn().setHeader(GeoCoderConstants.STATUS, GeocoderStatus.ZERO_RESULTS); + return; + } else if (error != null) { + // an error answer such as {"error":{"code":400,"message":"..."}} + exchange.getIn().setHeader(GeoCoderConstants.STATUS, GeocoderStatus.ERROR); + return; + } + exchange.getIn().setHeader(GeoCoderConstants.STATUS, GeocoderStatus.OK); + exchange.getIn().setHeader(GeoCoderConstants.ADDRESS, doc.read("$['display_name']")); // just grab the first element and its lat and lon diff --git a/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimAddressTest.java b/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimAddressTest.java index 6294366c113a..4998bf71f8e6 100644 --- a/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimAddressTest.java +++ b/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimAddressTest.java @@ -18,19 +18,21 @@ package org.apache.camel.component.geocoder; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.junit6.CamelTestSupport; import org.junit.jupiter.api.Test; -public class GeoCoderNominatimAddressTest extends CamelTestSupport { +public class GeoCoderNominatimAddressTest extends GeoCoderNominatimTestSupport { @Test public void testGeoCoder() throws Exception { + answerFromResource("search", "search-calle-marie-curie.json"); + MockEndpoint mock = getMockEndpoint("mock:result"); mock.expectedMessageCount(1); + mock.expectedHeaderReceived(GeoCoderConstants.STATUS, GeocoderStatus.OK); mock.expectedHeaderReceived(GeoCoderConstants.COUNTRY_SHORT, "ES"); mock.expectedHeaderReceived(GeoCoderConstants.REGION_NAME, "Andalucía"); + mock.expectedHeaderReceived(GeoCoderConstants.POSTAL_CODE, "41092"); - // the address header overrides the endpoint configuration template.sendBody("direct:start", "Test"); MockEndpoint.assertIsSatisfied(context); @@ -41,7 +43,8 @@ public class GeoCoderNominatimAddressTest extends CamelTestSupport { return new RouteBuilder() { public void configure() { from("direct:start").to( - "geocoder:address:calle marie curie, sevilla, sevilla?type=NOMINATIM&serverUrl=RAW(https://nominatim.openstreetmap.org)") + "geocoder:address:calle marie curie, sevilla, sevilla?type=NOMINATIM&serverUrl=RAW(" + serverUrl() + + ")") .to("log:result") .log("Location ${header.CamelGeocoderAddress} is at lat/lng: ${header.CamelGeocoderLatlng}" + " and in city ${header.CamelGeoCoderCity} in country ${header.CamelGeoCoderCountryLong}") diff --git a/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimTest.java b/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimTest.java index 3a1790fa175d..dfc749809df8 100644 --- a/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimTest.java +++ b/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimTest.java @@ -18,19 +18,21 @@ package org.apache.camel.component.geocoder; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.junit6.CamelTestSupport; import org.junit.jupiter.api.Test; -public class GeoCoderNominatimTest extends CamelTestSupport { +public class GeoCoderNominatimTest extends GeoCoderNominatimTestSupport { @Test public void testGeoCoder() throws Exception { + answerFromResource("reverse", "reverse-sevilla.json"); + MockEndpoint mock = getMockEndpoint("mock:result"); mock.expectedMessageCount(1); + mock.expectedHeaderReceived(GeoCoderConstants.STATUS, GeocoderStatus.OK); mock.expectedHeaderReceived(GeoCoderConstants.COUNTRY_SHORT, "ES"); mock.expectedHeaderReceived(GeoCoderConstants.CITY, "Sevilla"); + mock.expectedHeaderReceived(GeoCoderConstants.LATLNG, "37.38618880, -5.99255350"); - // the address header overrides the endpoint configuration template.sendBody("direct:start", "Test"); MockEndpoint.assertIsSatisfied(context); @@ -41,7 +43,7 @@ public class GeoCoderNominatimTest extends CamelTestSupport { return new RouteBuilder() { public void configure() { from("direct:start").to( - "geocoder:latlng:37.38619,-5.99255?type=NOMINATIM&serverUrl=RAW(https://nominatim.openstreetmap.org)") + "geocoder:latlng:37.38619,-5.99255?type=NOMINATIM&serverUrl=RAW(" + serverUrl() + ")") .to("log:result") .log("Location ${header.CamelGeocoderAddress} is at lat/lng: ${header.CamelGeocoderLatlng}" + " and in city ${header.CamelGeoCoderCity} in country ${header.CamelGeoCoderCountryLong}") diff --git a/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimTestSupport.java b/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimTestSupport.java new file mode 100644 index 000000000000..ed1d5c8c9235 --- /dev/null +++ b/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimTestSupport.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.geocoder; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.sun.net.httpserver.HttpServer; +import org.apache.camel.test.junit6.CamelTestSupport; + +/** + * Runs the Nominatim tests against a local HTTP server that answers the recorded responses of + * nominatim.openstreetmap.org, so the build does not depend on the public service. + */ +public abstract class GeoCoderNominatimTestSupport extends CamelTestSupport { + + private final Map<String, String> answers = new ConcurrentHashMap<>(); + private HttpServer server; + + @Override + protected void setupResources() throws Exception { + server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0); + server.createContext("/", exchange -> { + String answer = answers.get(exchange.getRequestURI().getPath()); + byte[] bytes = answer != null ? answer.getBytes(StandardCharsets.UTF_8) : new byte[0]; + exchange.getResponseHeaders().add("Content-Type", "application/json; charset=utf-8"); + exchange.sendResponseHeaders(answer != null ? 200 : 404, bytes.length > 0 ? bytes.length : -1); + try (OutputStream body = exchange.getResponseBody()) { + body.write(bytes); + } + }); + server.start(); + } + + @Override + protected void cleanupResources() throws Exception { + if (server != null) { + server.stop(0); + } + } + + /** + * The URL of the local Nominatim server, for the serverUrl option. + */ + protected String serverUrl() { + return "http://127.0.0.1:" + server.getAddress().getPort(); + } + + /** + * Sets the answer of the given operation (search or reverse). + */ + protected void answer(String operation, String json) { + answers.put("/" + operation, json); + } + + /** + * Sets the answer of the given operation (search or reverse) from a recorded response in + * src/test/resources/nominatim. + */ + protected void answerFromResource(String operation, String name) throws IOException { + try (InputStream is = getClass().getResourceAsStream("/nominatim/" + name)) { + answer(operation, new String(is.readAllBytes(), StandardCharsets.UTF_8)); + } + } +} diff --git a/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimZeroResultsTest.java b/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimZeroResultsTest.java new file mode 100644 index 000000000000..97acc619fc30 --- /dev/null +++ b/components/camel-geocoder/src/test/java/org/apache/camel/component/geocoder/GeoCoderNominatimZeroResultsTest.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.geocoder; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.jupiter.api.Test; + +public class GeoCoderNominatimZeroResultsTest extends GeoCoderNominatimTestSupport { + + @Test + public void testAddressNotFound() throws Exception { + // search answers an empty array when it finds nothing + answer("search", "[]"); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(1); + mock.expectedBodiesReceived("[]"); + mock.expectedHeaderReceived(GeoCoderConstants.STATUS, GeocoderStatus.ZERO_RESULTS); + + template.sendBody("direct:address", "Test"); + + MockEndpoint.assertIsSatisfied(context); + } + + @Test + public void testLatLngNotFound() throws Exception { + // reverse answers an error text when there is no place at the latitude and longitude, such as at sea + answer("reverse", "{\"error\":\"Unable to geocode\"}"); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(1); + mock.expectedHeaderReceived(GeoCoderConstants.STATUS, GeocoderStatus.ZERO_RESULTS); + + template.sendBody("direct:latlng", "Test"); + + MockEndpoint.assertIsSatisfied(context); + } + + @Test + public void testErrorAnswer() throws Exception { + answer("reverse", "{\"error\":{\"code\":400,\"message\":\"Parameter 'lat' must be a number.\"}}"); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(1); + mock.expectedHeaderReceived(GeoCoderConstants.STATUS, GeocoderStatus.ERROR); + + template.sendBody("direct:latlng", "Test"); + + MockEndpoint.assertIsSatisfied(context); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:address") + .to("geocoder:address:nowhere?type=NOMINATIM&serverUrl=RAW(" + serverUrl() + ")") + .to("mock:result"); + + from("direct:latlng") + .to("geocoder:latlng:0,-30?type=NOMINATIM&serverUrl=RAW(" + serverUrl() + ")") + .to("mock:result"); + } + }; + } +} diff --git a/components/camel-geocoder/src/test/resources/nominatim/reverse-sevilla.json b/components/camel-geocoder/src/test/resources/nominatim/reverse-sevilla.json new file mode 100644 index 000000000000..11a72c3d1c6a --- /dev/null +++ b/components/camel-geocoder/src/test/resources/nominatim/reverse-sevilla.json @@ -0,0 +1 @@ +{"place_id":295378929,"licence":"Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright","osm_type":"node","osm_id":3814289959,"lat":"37.3861888","lon":"-5.9925535","category":"historic","type":"memorial","place_rank":30,"importance":0.23094323434513592,"addresstype":"historic","name":"Giraldillo","display_name":"Giraldillo, Puerta de Palos, Santa Cruz, Casco Antiguo, Sevilla, Andalucía, 41004, España","address":{"historic":"Giraldillo","road":"Puerta de Palos","neighbourh [...] \ No newline at end of file diff --git a/components/camel-geocoder/src/test/resources/nominatim/search-calle-marie-curie.json b/components/camel-geocoder/src/test/resources/nominatim/search-calle-marie-curie.json new file mode 100644 index 000000000000..b0d877fe7939 --- /dev/null +++ b/components/camel-geocoder/src/test/resources/nominatim/search-calle-marie-curie.json @@ -0,0 +1 @@ +[{"place_id":295982222,"licence":"Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright","osm_type":"way","osm_id":70971075,"lat":"37.4062844","lon":"-6.0059975","category":"highway","type":"primary","place_rank":26,"importance":0.05341013427939265,"addresstype":"primary","name":"Calle Marie Curie","display_name":"Calle Marie Curie, Triana, Sevilla, Andalucía, 41092, España","address":{"road":"Calle Marie Curie","suburb":"Triana","city":"Sevilla","province":"Sevilla","ISO [...] \ No newline at end of file diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc index 10f5a47c1b89..538140b96503 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc @@ -764,6 +764,13 @@ onto the configuration of the endpoint. Before, they were, so every later query `location` already did the geolocation when its producer was created, so its `CamelWeatherLocation` header was never used. The `lat` and `lon` options of an endpoint are still used instead of the location. +=== camel-geocoder - Nominatim sets ZERO_RESULTS when it finds no place + +With `type=NOMINATIM`, an address that Nominatim does not find (it answers `[]`) now sets the `CamelGeoCoderStatus` +header to `ZERO_RESULTS`. Before, the exchange failed with an `IllegalArgumentException`. A latitude and longitude with +no place (Nominatim answers `{"error":"Unable to geocode"}`) now sets `ZERO_RESULTS` too, and another error answer of +Nominatim sets `ERROR`. Before, both set `OK` with no other headers. + === camel-gson, camel-jsonb - the unmarshal type header needs allowUnmarshallType The Gson and JSON-B data formats now use the `CamelGsonUnmarshalType` and `CamelJsonbUnmarshallType` headers to choose
