@@ -167,12 +167,17 @@ public List<LoadedFile> load(String discoveryURIString, Authentication auth)
167167 JSONObject discoveryFileJson = new JSONObject (
168168 new JSONTokener (new ByteArrayInputStream (discoveryFileBytes ))
169169 );
170- String version = discoveryFileJson .getString ("version" );
170+ // Default to version 1.0 if no version field is present (as in GBFS v1.0)
171+ String version = discoveryFileJson .optString ("version" , "1.0" );
171172
172173 List <LoadedFile > loadedFiles = new ArrayList <>();
174+ // Normalize discovery file name to "gbfs" (without extension) for validator compatibility
175+ String discoveryFileName = discoveryLoadedFile
176+ .fileName ()
177+ .replaceFirst ("\\ .json$" , "" );
173178 loadedFiles .add (
174179 new LoadedFile (
175- discoveryLoadedFile . fileName () ,
180+ discoveryFileName ,
176181 discoveryLoadedFile .url (),
177182 new ByteArrayInputStream (discoveryFileBytes ),
178183 discoveryLoadedFile .language (),
@@ -200,35 +205,40 @@ private List<LoadedFile> getV3Files(
200205 ) {
201206 List <LoadedFile > loadedFeedFiles = new ArrayList <>();
202207
203- List <CompletableFuture <LoadedFile >> futures = discoveryFileJson
204- .getJSONObject ("data" )
205- .getJSONArray ("feeds" )
206- .toList ()
207- .stream ()
208- .map (feed -> {
209- @ SuppressWarnings ("unchecked" )
210- Map <String , Object > feedMap = (Map <String , Object >) feed ;
211- String url = (String ) feedMap .get ("url" );
212- String name = (String ) feedMap .get ("name" );
213-
214- return CompletableFuture .supplyAsync (
215- () -> {
216- LoadedFile loadedFile = loadFile (URI .create (url ), auth );
217- return new LoadedFile (
218- name ,
219- url ,
220- loadedFile .fileContents (),
221- loadedFile .language (),
222- loadedFile .loaderErrors ()
223- );
224- },
225- executorService
226- );
227- })
228- .toList ();
229- loadedFeedFiles .addAll (
230- futures .stream ().map (CompletableFuture ::join ).toList ()
231- );
208+ try {
209+ List <CompletableFuture <LoadedFile >> futures = discoveryFileJson
210+ .getJSONObject ("data" )
211+ .getJSONArray ("feeds" )
212+ .toList ()
213+ .stream ()
214+ .map (feed -> {
215+ @ SuppressWarnings ("unchecked" )
216+ Map <String , Object > feedMap = (Map <String , Object >) feed ;
217+ String url = (String ) feedMap .get ("url" );
218+ String name = (String ) feedMap .get ("name" );
219+
220+ return CompletableFuture .supplyAsync (
221+ () -> {
222+ LoadedFile loadedFile = loadFile (URI .create (url ), auth );
223+ return new LoadedFile (
224+ name ,
225+ url ,
226+ loadedFile .fileContents (),
227+ loadedFile .language (),
228+ loadedFile .loaderErrors ()
229+ );
230+ },
231+ executorService
232+ );
233+ })
234+ .toList ();
235+ loadedFeedFiles .addAll (
236+ futures .stream ().map (CompletableFuture ::join ).toList ()
237+ );
238+ } catch (Exception e ) {
239+ // If we can't parse the discovery file structure, return empty list
240+ // so the discovery file itself can be validated and report proper errors
241+ }
232242
233243 return loadedFeedFiles ;
234244 }
@@ -241,42 +251,47 @@ private List<LoadedFile> getPreV3Files(
241251 List <LoadedFile > loadedFeedFiles = new ArrayList <>();
242252 List <CompletableFuture <LoadedFile >> futures = new ArrayList <>();
243253
244- discoveryFileJson
245- .getJSONObject ("data" )
246- .keys ()
247- .forEachRemaining (languageKey -> {
248- discoveryFileJson
249- .getJSONObject ("data" )
250- .getJSONObject (languageKey )
251- .getJSONArray ("feeds" )
252- .toList ()
253- .forEach (feed -> {
254- @ SuppressWarnings ("unchecked" )
255- Map <String , Object > feedMap = (Map <String , Object >) feed ;
256- String url = (String ) feedMap .get ("url" );
257- String name = (String ) feedMap .get ("name" );
258-
259- futures .add (
260- CompletableFuture .supplyAsync (
261- () -> {
262- LoadedFile loadedFile = loadFile (URI .create (url ), auth );
263- return new LoadedFile (
264- name ,
265- url ,
266- loadedFile .fileContents (),
267- languageKey ,
268- loadedFile .loaderErrors ()
269- );
270- },
271- executorService
272- )
273- );
274- });
275- });
276-
277- loadedFeedFiles .addAll (
278- futures .stream ().map (CompletableFuture ::join ).toList ()
279- );
254+ try {
255+ discoveryFileJson
256+ .getJSONObject ("data" )
257+ .keys ()
258+ .forEachRemaining (languageKey -> {
259+ discoveryFileJson
260+ .getJSONObject ("data" )
261+ .getJSONObject (languageKey )
262+ .getJSONArray ("feeds" )
263+ .toList ()
264+ .forEach (feed -> {
265+ @ SuppressWarnings ("unchecked" )
266+ Map <String , Object > feedMap = (Map <String , Object >) feed ;
267+ String url = (String ) feedMap .get ("url" );
268+ String name = (String ) feedMap .get ("name" );
269+
270+ futures .add (
271+ CompletableFuture .supplyAsync (
272+ () -> {
273+ LoadedFile loadedFile = loadFile (URI .create (url ), auth );
274+ return new LoadedFile (
275+ name ,
276+ url ,
277+ loadedFile .fileContents (),
278+ languageKey ,
279+ loadedFile .loaderErrors ()
280+ );
281+ },
282+ executorService
283+ )
284+ );
285+ });
286+ });
287+
288+ loadedFeedFiles .addAll (
289+ futures .stream ().map (CompletableFuture ::join ).toList ()
290+ );
291+ } catch (Exception e ) {
292+ // If we can't parse the discovery file structure, return empty list
293+ // so the discovery file itself can be validated and report proper errors
294+ }
280295
281296 return loadedFeedFiles ;
282297 }
0 commit comments