Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Java model classes generated from [NeTEx](https://github.com/entur/NeTEx) (Netwo

This library downloads the NeTEx XSD files from the [Entur NeTEx fork](https://github.com/entur/NeTEx) and compiles them into JAXB-annotated Java model classes at build time. The generated classes support full marshalling and unmarshalling of NeTEx XML documents, including schema validation against multiple NeTEx versions.

- **NeTEx version**: 1.16 (model generation), with legacy validation support back to 1.07
- **NeTEx version**: 1.16.1 (model generation), with legacy validation support back to 1.07
- **JAXB**: Jakarta XML Bind 4.x (Jakarta EE 9+)
- **Generated package**: `org.rutebanken.netex.model`
- **GML types package**: `net.opengis.gml._3`
Expand Down Expand Up @@ -103,7 +103,7 @@ The XSD files are downloaded from GitHub during the `generate-sources` phase and
- Property name conflict resolution
- Package mapping to `org.rutebanken.netex.model`

**Schema validation**: `NeTExValidator` supports validation against NeTEx versions 1.07 through 1.16.
**Schema validation**: `NeTExValidator` supports validation against NeTEx versions 1.07 through 1.16. A version is validated against its latest patch schema: documents declaring 1.16 are validated against the 1.16.1 schema, which is backward compatible with 1.16.

**Note on GML types**: This library generates classes under `net.opengis.gml._3` as part of the NeTEx model.

Expand Down
16 changes: 8 additions & 8 deletions bindings.xjb
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

<!-- See the script bin/version_updater.sh It updates version in schema locations-->

| <jxb:bindings schemaLocation="./src/main/resources/xsd/1.16/NeTEx_publication.xsd">
| <jxb:bindings schemaLocation="./src/main/resources/xsd/1.16.1/NeTEx_publication.xsd">
<jxb:schemaBindings>
<jxb:package name="org.rutebanken.netex.model" />
</jxb:schemaBindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_framework/netex_genericFramework/netex_organisation_version.xsd">
schemaLocation="./src/main/resources/xsd/1.16.1/netex_framework/netex_genericFramework/netex_organisation_version.xsd">
<jxb:bindings node="//xsd:element[@name = 'Status']">
<jxb:property name="StatusOrganisationGroup" />
</jxb:bindings>
Expand All @@ -30,35 +30,35 @@
</jxb:bindings>
</jxb:bindings>
<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_part_3/part3_fares/netex_salesOfferPackage_version.xsd">
schemaLocation="./src/main/resources/xsd/1.16.1/netex_part_3/part3_fares/netex_salesOfferPackage_version.xsd">
<jxb:bindings node="//xsd:element[@ref = 'ResponsibilitySetRef']">
<jxb:property name="ResponsibilitySetRefDistributionByGroup" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_part_2/part2_journeyTimes/netex_vehicleJourneyFrequency_version.xsd">
schemaLocation="./src/main/resources/xsd/1.16.1/netex_part_2/part2_journeyTimes/netex_vehicleJourneyFrequency_version.xsd">
<jxb:bindings node="//xsd:group[@name= 'HeadwayJourneyGroupGroup']/xsd:sequence/xsd:element[@name = 'Description']">
<jxb:property name="DescriptionHeadwayJourneyGroupGroup" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_part_3/part3_salesTransactions/netex_salesContract_version.xsd">
schemaLocation="./src/main/resources/xsd/1.16.1/netex_part_3/part3_salesTransactions/netex_salesContract_version.xsd">
<jxb:bindings node="//xsd:element[@name = 'Status']">
<jxb:property name="StatusPassengerContractGroup" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_part_3/part3_salesTransactions/netex_retailConsortium_version.xsd">
schemaLocation="./src/main/resources/xsd/1.16.1/netex_part_3/part3_salesTransactions/netex_retailConsortium_version.xsd">
<jxb:bindings node="//xsd:element[@name = 'Status']">
<jxb:property name="StatusRetailDeviceGroup" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_framework/netex_responsibility/netex_version_support.xsd">
schemaLocation="./src/main/resources/xsd/1.16.1/netex_framework/netex_responsibility/netex_version_support.xsd">
<jxb:bindings node="//xsd:simpleType[@name = 'VersionIdType']">
<xjc:javaType name="java.lang.String" adapter="org.rutebanken.util.VersionXmlAdapter" />
</jxb:bindings>
Expand All @@ -71,7 +71,7 @@
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_framework/netex_genericFramework/netex_zone_version.xsd">
schemaLocation="./src/main/resources/xsd/1.16.1/netex_framework/netex_genericFramework/netex_zone_version.xsd">
<jxb:bindings node="//xsd:complexType[@name = 'tariffZonesInFrame_RelStructure']/xsd:complexContent/xsd:extension[@base = 'containmentAggregationStructure']/xsd:sequence/xsd:element[@ref = 'TariffZone_']">
<jxb:property name="tariffZone" />
</jxb:bindings>
Expand Down
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@
<jdk.version>11</jdk.version>

<netexRepoName>NeTEx</netexRepoName>
<netexBranch>master</netexBranch>
<netexBranch>tags/v1.0.16.1</netexBranch>
<netexGithubUrl>https://github.com/entur/${netexRepoName}</netexGithubUrl>
<netexVersion>1.16</netexVersion>
<netexVersion>1.16.1</netexVersion>

<!-- JAXB components versions -->
<jakarta-xml-bind.version>4.0.5</jakarta-xml-bind.version>
Expand Down Expand Up @@ -285,7 +285,7 @@
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/${netexBranch}.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/${netexVersion}</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-${netexBranch}/xsd/*</ZIP_PATH_TO_EXTRACT>
<ZIP_PATH_TO_EXTRACT>NeTEx-tags-v1.0.16.1/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
<executable>./bin/netex-download-extract.sh</executable>
</configuration>
Expand Down
29 changes: 24 additions & 5 deletions src/main/java/org/rutebanken/netex/validation/NeTExValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,36 @@
v1_13 ("1.13"),
v1_14 ("1.14"),
v1_15 ("1.15"),
v1_16 ("1.16");

/**
* NeTEx 1.16, validated against the latest 1.16 patch schema. Patch releases of the schema
* are backward compatible, and documents only ever declare the minor version, so a document
* declaring 1.16 is validated against the same schema the model is generated from.
*/
v1_16 ("1.16", "1.16.1"),

Check failure on line 52 in src/main/java/org/rutebanken/netex/validation/NeTExValidator.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this constant name to match the regular expression '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.

See more on https://sonarcloud.io/project/issues?id=entur_netex-java-model&issues=AaDnpIR7EGH9SgCwIcE-&open=AaDnpIR7EGH9SgCwIcE-&pullRequest=308
/**
* @deprecated the 1.16.1 schema is what {@link #v1_16} validates against. Use {@link #v1_16}.
*/
@Deprecated
v1_16_1 ("1.16.1");

Check failure on line 57 in src/main/java/org/rutebanken/netex/validation/NeTExValidator.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this constant name to match the regular expression '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.

See more on https://sonarcloud.io/project/issues?id=entur_netex-java-model&issues=AaDnpIR7EGH9SgCwIcE_&open=AaDnpIR7EGH9SgCwIcE_&pullRequest=308

private final String version;
private final String folderName;

NetexVersion(String folderName) {
NetexVersion(String version) {
this(version, version);
}

NetexVersion(String version, String folderName) {
this.version = version;
this.folderName = folderName;
}

/**
* @return the NeTEx version, which is not always the name of the folder holding its schema.
*/
@Override
public String toString() {
return folderName;
return version;
}
}
private final Schema neTExSchema;
Expand Down Expand Up @@ -102,7 +121,7 @@
public NeTExValidator(NetexVersion version) throws IOException, SAXException {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

String resourceName = "xsd/"+ version +"/NeTEx_publication.xsd";
String resourceName = "xsd/"+ version.folderName +"/NeTEx_publication.xsd";
LOGGER.info("Loading resource: {}", resourceName);
URL resource = getClass().getClassLoader().getResource(resourceName);
if(resource == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,51 @@ void unmarshalOperatorWithBrandingRef() throws JAXBException {
assertNotNull(operator.getBrandingRef());
assertEquals("TST:Branding:1", operator.getBrandingRef().getRef());
}

@Test
void unmarshalResponsibilitySetWithAssociatedContract() throws JAXBException {

String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<PublicationDelivery xmlns=\"http://www.netex.org.uk/netex\" version=\"1.0\">\n" +
" <PublicationTimestamp>2026-09-10T10:00:00</PublicationTimestamp>\n" +
" <ParticipantRef>TST</ParticipantRef>\n" +
" <dataObjects>\n" +
" <ResourceFrame version=\"1\" id=\"TST:ResourceFrame:1\">\n" +
" <responsibilitySets>\n" +
" <ResponsibilitySet version=\"1\" id=\"TST:ResponsibilitySet:1\">\n" +
" <Name>Contracted operation</Name>\n" +
" <roles>\n" +
" <ResponsibilityRoleAssignment version=\"1\" id=\"TST:ResponsibilityRoleAssignment:1\">\n" +
" <AssociatedContract>\n" +
" <ContractRef ref=\"TST:Contract:1\" version=\"1\"/>\n" +
" </AssociatedContract>\n" +
" </ResponsibilityRoleAssignment>\n" +
" </roles>\n" +
" </ResponsibilitySet>\n" +
" </responsibilitySets>\n" +
" </ResourceFrame>\n" +
" </dataObjects>\n" +
"</PublicationDelivery>";

Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

@SuppressWarnings("unchecked")
JAXBElement<PublicationDeliveryStructure> jaxbElement = (JAXBElement<PublicationDeliveryStructure>) unmarshaller
.unmarshal(new ByteArrayInputStream(xml.getBytes()));

PublicationDeliveryStructure publicationDeliveryStructure = jaxbElement.getValue();
ResourceFrame resourceFrame = (ResourceFrame) publicationDeliveryStructure.getDataObjects().getCompositeFrameOrCommonFrame().get(0).getValue();

ResponsibilitySet responsibilitySet = resourceFrame.getResponsibilitySets().getResponsibilitySet().get(0);
assertEquals("Contracted operation", responsibilitySet.getName().getValue());

ResponsibilityRoleAssignment_VersionedChildStructure roleAssignment = responsibilitySet.getRoles().getResponsibilityRoleAssignment().get(0);

ContractRef_RelStructure associatedContract = roleAssignment.getAssociatedContract();
assertNotNull(associatedContract);
ContractRefStructure contractRef = associatedContract.getContractRef();
assertNotNull(contractRef);
assertEquals("TST:Contract:1", contractRef.getRef());
assertEquals("1", contractRef.getVersion());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.io.StringReader;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals;

class NeTExValidatorTest {

Expand Down Expand Up @@ -52,4 +53,58 @@

}

}
/**
* AssociatedContract / ContractRef on a ResponsibilityRoleAssignment was added in NeTEx 1.16.1
* (entur/NeTEx#63). 1.16 is validated against the 1.16.1 schema, so it is valid against 1.16 too.
*/
private static final String RESPONSIBILITY_SET_WITH_ASSOCIATED_CONTRACT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<PublicationDelivery xmlns=\"http://www.netex.org.uk/netex\" version=\"1.0\">\n" +
" <PublicationTimestamp>2026-09-10T10:00:00</PublicationTimestamp>\n" +
" <ParticipantRef>TST</ParticipantRef>\n" +
" <dataObjects>\n" +
" <ResourceFrame version=\"1\" id=\"TST:ResourceFrame:1\">\n" +
" <responsibilitySets>\n" +
" <ResponsibilitySet version=\"1\" id=\"TST:ResponsibilitySet:1\">\n" +
" <Name>Contracted operation</Name>\n" +
" <roles>\n" +
" <ResponsibilityRoleAssignment version=\"1\" id=\"TST:ResponsibilityRoleAssignment:1\">\n" +
" <AssociatedContract>\n" +
" <ContractRef ref=\"TST:Contract:1\" version=\"1\"/>\n" +
" </AssociatedContract>\n" +
" </ResponsibilityRoleAssignment>\n" +
" </roles>\n" +
" </ResponsibilitySet>\n" +
" </responsibilitySets>\n" +
" </ResourceFrame>\n" +
" </dataObjects>\n" +
"</PublicationDelivery>";

@Test
void latestVersionIs1_16() {
assertEquals(NeTExValidator.NetexVersion.v1_16, NeTExValidator.LATEST);
}

@Test
void version1_16IsNamed1_16() {
assertEquals("1.16", NeTExValidator.NetexVersion.v1_16.toString());
}

@Test
void validateResponsibilitySetWithAssociatedContractAgainstLatestVersion() throws IOException, SAXException {
neTExValidator.validate(new StreamSource(new StringReader(RESPONSIBILITY_SET_WITH_ASSOCIATED_CONTRACT)));
}

@Test
void validateResponsibilitySetWithAssociatedContractAgainstVersion1_16() throws IOException, SAXException {
NeTExValidator validator1_16 = NeTExValidator.getNeTExValidator(NeTExValidator.NetexVersion.v1_16);

Check warning on line 99 in src/test/java/org/rutebanken/netex/validation/NeTExValidatorTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.

See more on https://sonarcloud.io/project/issues?id=entur_netex-java-model&issues=AaDnpIVvEGH9SgCwIcFA&open=AaDnpIVvEGH9SgCwIcFA&pullRequest=308
validator1_16.validate(new StreamSource(new StringReader(RESPONSIBILITY_SET_WITH_ASSOCIATED_CONTRACT)));
}

@Test
@SuppressWarnings("deprecation")
void validateResponsibilitySetWithAssociatedContractAgainstDeprecatedVersion1_16_1() throws IOException, SAXException {
NeTExValidator validator1_16_1 = NeTExValidator.getNeTExValidator(NeTExValidator.NetexVersion.v1_16_1);

Check warning on line 106 in src/test/java/org/rutebanken/netex/validation/NeTExValidatorTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.

See more on https://sonarcloud.io/project/issues?id=entur_netex-java-model&issues=AaDnpIVvEGH9SgCwIcFB&open=AaDnpIVvEGH9SgCwIcFB&pullRequest=308
validator1_16_1.validate(new StreamSource(new StringReader(RESPONSIBILITY_SET_WITH_ASSOCIATED_CONTRACT)));
}

}
Loading