Skip to content

Commit 781f201

Browse files
authored
feat: Add GBFS v3.1-RC3 support (#195)
1 parent 96797ca commit 781f201

19 files changed

Lines changed: 1009 additions & 58 deletions

File tree

gbfs-validator-java/pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
</scm>
5252
<properties>
5353
<jdk.version>17</jdk.version>
54-
<gbfsGithubUrl>https://github.com/MobilityData/gbfs-json-schema/archive/refs/tags/v4.0.0.zip</gbfsGithubUrl>
55-
<schemaVersion>4.0.0</schemaVersion>
54+
<gbfsGithubUrl>https://github.com/MobilityData/gbfs-json-schema/archive/refs/tags/v4.3.0.zip</gbfsGithubUrl>
55+
<schemaVersion>4.3.0</schemaVersion>
5656

5757
<everit-json-schema.version>1.14.6</everit-json-schema.version>
5858
<slf4j.version>2.0.17</slf4j.version>
@@ -310,7 +310,7 @@
310310
<artifactId>maven-javadoc-plugin</artifactId>
311311
<version>${maven-javadoc-plugin.version}</version>
312312
<configuration>
313-
<additionalparam>-Xdoclint:none</additionalparam>
313+
<additionalOptions>-Xdoclint:none</additionalOptions>
314314
</configuration>
315315
<executions>
316316
<execution>

gbfs-validator-java/src/main/java/org/mobilitydata/gbfs/validation/validator/GbfsJsonValidator.java

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,13 @@ private record ParsedFeedContainer(
7777
"station_status",
7878
"free_bike_status",
7979
"vehicle_status",
80+
"vehicle_availability",
81+
"manifest",
8082
"system_hours",
81-
"system_alerts",
82-
"system_alerts",
8383
"system_calendar",
8484
"system_regions",
8585
"system_pricing_plans",
86+
"system_alerts",
8687
"geofencing_zones"
8788
);
8889

@@ -110,17 +111,10 @@ public ValidationResult validate(Map<String, InputStream> rawFeeds) {
110111
}
111112

112113
if (parsedContainer.jsonObject() == null) {
113-
// Parsing failed or stream read error
114-
FileValidationResult result = new FileValidationResult(
114+
FileValidationResult result = createParsingErrorResult(
115115
feedName,
116-
version.isFileRequired(feedName),
117-
true,
118-
0,
119-
version.getSchema(feedName).toString(),
120-
parsedContainer.originalContent(),
121-
null,
122-
Collections.emptyList(),
123-
parsedContainer.parsingErrors()
116+
parsedContainer,
117+
version
124118
);
125119
fileValidations.put(feedName, result);
126120
} else {
@@ -183,19 +177,10 @@ public FileValidationResult validateFile(String fileName, InputStream file) {
183177
ParsedFeedContainer parsedContainer = parseFeed(fileName, file);
184178

185179
if (parsedContainer.jsonObject() == null) {
186-
// Determine version for schema and requirement - this is tricky for a single file
187-
// For now, using default version. A more robust approach might require context.
188-
Version tempVersion = VersionFactory.createVersion(DEFAULT_VERSION);
189-
return new FileValidationResult(
180+
return createParsingErrorResult(
190181
fileName,
191-
tempVersion.isFileRequired(fileName),
192-
true, // File was provided
193-
0,
194-
tempVersion.getSchema(fileName).toString(),
195-
parsedContainer.originalContent(),
196-
null, // File specific version unknown
197-
Collections.emptyList(),
198-
parsedContainer.parsingErrors()
182+
parsedContainer,
183+
VersionFactory.createVersion(DEFAULT_VERSION)
199184
);
200185
} else {
201186
return validateFile(
@@ -350,4 +335,58 @@ private ParsedFeedContainer parseFeed(String name, InputStream raw) {
350335
);
351336
}
352337
}
338+
339+
/**
340+
* Creates a validation result for a file that could not be parsed. Parsing can fail before
341+
* the exact version for a single file is known, so this resolves the best schema version
342+
* available and still returns file metadata alongside the parse errors.
343+
*
344+
* @param feedName The GBFS feed name
345+
* @param parsedContainer The parsed container holding original content and parse errors
346+
* @param preferredVersion The initially preferred GBFS version
347+
* @return A file validation result containing parse errors and any schema metadata that could be resolved
348+
*/
349+
private FileValidationResult createParsingErrorResult(
350+
String feedName,
351+
ParsedFeedContainer parsedContainer,
352+
Version preferredVersion
353+
) {
354+
Version schemaVersion = resolveVersionForFeed(feedName, preferredVersion);
355+
boolean supportedFeed = schemaVersion.getFileNames().contains(feedName);
356+
357+
return new FileValidationResult(
358+
feedName,
359+
supportedFeed && schemaVersion.isFileRequired(feedName),
360+
true,
361+
0,
362+
supportedFeed ? schemaVersion.getSchema(feedName).toString() : null,
363+
parsedContainer.originalContent(),
364+
null,
365+
Collections.emptyList(),
366+
parsedContainer.parsingErrors()
367+
);
368+
}
369+
370+
/**
371+
* Resolves the version to use for a feed when building parse-error results. Some feed types
372+
* may not exist in the initially detected version, so this falls back to the newest version
373+
* that supports the feed in order to point the error result at a schema when possible.
374+
*
375+
* @param feedName The GBFS feed name
376+
* @param preferredVersion The initially detected or preferred GBFS version
377+
* @return The preferred version when it supports the feed, otherwise the newest version that does
378+
*/
379+
private Version resolveVersionForFeed(
380+
String feedName,
381+
Version preferredVersion
382+
) {
383+
if (preferredVersion.getFileNames().contains(feedName)) {
384+
return preferredVersion;
385+
}
386+
387+
return VersionFactory.createLatestVersionSupportingFeed(
388+
feedName,
389+
preferredVersion.getVersionString()
390+
);
391+
}
353392
}

gbfs-validator-java/src/main/java/org/mobilitydata/gbfs/validation/validator/versions/Version30.java

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class Version30 extends AbstractVersion {
3636

3737
public static final String VERSION = "3.0";
3838

39-
private static final List<String> feeds = Arrays.asList(
39+
private static final List<String> FEEDS = Arrays.asList(
4040
"gbfs",
4141
"gbfs_versions",
4242
"system_information",
@@ -51,37 +51,36 @@ public class Version30 extends AbstractVersion {
5151
"geofencing_zones"
5252
);
5353

54-
private static final Map<String, List<CustomRuleSchemaPatcher>> customRules =
55-
Map.of(
56-
"vehicle_types",
57-
List.of(new NoInvalidReferenceToPricingPlansInVehicleTypes()),
58-
"station_status",
59-
List.of(
60-
new NoInvalidReferenceToVehicleTypesInStationStatus(),
61-
new NoMissingVehicleTypesAvailableWhenVehicleTypesExists(),
62-
new NoInvalidReferenceToStation("station_information")
54+
static final Map<String, List<CustomRuleSchemaPatcher>> CUSTOM_RULES = Map.of(
55+
"vehicle_types",
56+
List.of(new NoInvalidReferenceToPricingPlansInVehicleTypes()),
57+
"station_status",
58+
List.of(
59+
new NoInvalidReferenceToVehicleTypesInStationStatus(),
60+
new NoMissingVehicleTypesAvailableWhenVehicleTypesExists(),
61+
new NoInvalidReferenceToStation("station_information")
62+
),
63+
"vehicle_status",
64+
List.of(
65+
new NoMissingOrInvalidVehicleTypeIdInVehicleStatusWhenVehicleTypesExist(
66+
"vehicle_status"
6367
),
64-
"vehicle_status",
65-
List.of(
66-
new NoMissingOrInvalidVehicleTypeIdInVehicleStatusWhenVehicleTypesExist(
67-
"vehicle_status"
68-
),
69-
new NoMissingCurrentRangeMetersInVehicleStatusForMotorizedVehicles(
70-
"vehicle_status"
71-
),
72-
new NoInvalidReferenceToPricingPlansInVehicleStatus("vehicle_status")
68+
new NoMissingCurrentRangeMetersInVehicleStatusForMotorizedVehicles(
69+
"vehicle_status"
7370
),
74-
"system_information",
75-
List.of(new NoMissingStoreUriInSystemInformation("vehicle_status")),
76-
"station_information",
77-
List.of(
78-
new NoInvalidReferenceToRegionInStationInformation(),
79-
new NoInvalidReferenceToStation("station_status")
80-
)
81-
);
71+
new NoInvalidReferenceToPricingPlansInVehicleStatus("vehicle_status")
72+
),
73+
"system_information",
74+
List.of(new NoMissingStoreUriInSystemInformation("vehicle_status")),
75+
"station_information",
76+
List.of(
77+
new NoInvalidReferenceToRegionInStationInformation(),
78+
new NoInvalidReferenceToStation("station_status")
79+
)
80+
);
8281

8382
protected Version30() {
84-
super(VERSION, feeds, customRules);
83+
super(VERSION, FEEDS, CUSTOM_RULES);
8584
}
8685

8786
@Override
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
*
3+
*
4+
* * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
5+
* * the European Commission - subsequent versions of the EUPL (the "Licence");
6+
* * You may not use this work except in compliance with the Licence.
7+
* * You may obtain a copy of the Licence at:
8+
* *
9+
* * https://joinup.ec.europa.eu/software/page/eupl
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the Licence is distributed on an "AS IS" basis,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the Licence for the specific language governing permissions and
15+
* * limitations under the Licence.
16+
*
17+
*/
18+
19+
package org.mobilitydata.gbfs.validation.validator.versions;
20+
21+
import java.util.Arrays;
22+
import java.util.List;
23+
24+
public class Version31RC3 extends AbstractVersion {
25+
26+
public static final String VERSION = "3.1-RC3";
27+
28+
private static final List<String> FEEDS = Arrays.asList(
29+
"gbfs",
30+
"gbfs_versions",
31+
"system_information",
32+
"vehicle_types",
33+
"station_information",
34+
"station_status",
35+
"vehicle_status",
36+
"manifest",
37+
"system_regions",
38+
"system_pricing_plans",
39+
"system_alerts",
40+
"geofencing_zones",
41+
"vehicle_availability"
42+
);
43+
44+
protected Version31RC3() {
45+
super(VERSION, FEEDS, Version30.CUSTOM_RULES);
46+
}
47+
48+
@Override
49+
public boolean isFileRequired(String file) {
50+
return super.isFileRequired(file) || "gbfs".equals(file);
51+
}
52+
}

gbfs-validator-java/src/main/java/org/mobilitydata/gbfs/validation/validator/versions/VersionFactory.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,21 @@
1818

1919
package org.mobilitydata.gbfs.validation.validator.versions;
2020

21+
import java.util.List;
22+
2123
public class VersionFactory {
2224

25+
private static final List<String> SUPPORTED_VERSIONS_DESC = List.of(
26+
"3.1-RC3",
27+
"3.0",
28+
"2.3",
29+
"2.2",
30+
"2.1",
31+
"2.0",
32+
"1.1",
33+
"1.0"
34+
);
35+
2336
private VersionFactory() {}
2437

2538
public static Version createVersion(String version) {
@@ -38,8 +51,22 @@ public static Version createVersion(String version) {
3851
return new Version23();
3952
case "3.0":
4053
return new Version30();
54+
case "3.1-RC3":
55+
return new Version31RC3();
4156
default:
4257
throw new UnsupportedOperationException("Version not implemented");
4358
}
4459
}
60+
61+
public static Version createLatestVersionSupportingFeed(
62+
String feedName,
63+
String fallbackVersion
64+
) {
65+
return SUPPORTED_VERSIONS_DESC
66+
.stream()
67+
.map(VersionFactory::createVersion)
68+
.filter(version -> version.getFileNames().contains(feedName))
69+
.findFirst()
70+
.orElse(createVersion(fallbackVersion));
71+
}
4572
}

0 commit comments

Comments
 (0)