diff --git a/CLAUDE.md b/CLAUDE.md index 75ec8a6..4d373b0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,17 +27,19 @@ mvn generate-sources **Note:** Tests run with `-Duser.timezone=Europe/Oslo` (configured in surefire plugin). +**Note:** Surefire runs tests on the module path because `module-info.java` exists. + ## Architecture ### Code Generation (bulk of the codebase) The `cxf-xjc-plugin` generates ~1,900 Java classes from XSD schemas during `generate-sources`: -- **SIRI 2.0** XSDs → `uk.org.siri.siri20.*` (plus `uk.org.ifopt.siri20`, `uk.org.acbs.siri20`, `eu.datex2.siri20`) -- **SIRI 2.1** XSDs → `uk.org.siri.siri21.*` (plus `uk.org.ifopt.siri21`, `uk.org.acbs.siri21`, `eu.datex2.siri21`) +- **SIRI 2.0** XSDs → `org.entur.siri.schema.v20.siri` (plus `.ifopt`, `.acsb`, `.datex2`) +- **SIRI 2.1** XSDs → `org.entur.siri.schema.v21.siri` (plus `.ifopt`, `.acsb`, `.datex2`, `.gml`) Generated sources land in `target/generated-sources`. JAXB binding customizations are in `src/main/resources/siri-{2.0,2.1}/xjb/jaxb-bindings.xml` — these map `xsd:dateTime`/`xsd:time` to `java.time.ZonedDateTime` and `xsd:duration` to `java.time.Duration`. -### Handwritten Code (~9 files) +### Handwritten Code (~11 files) | Package | Class | Purpose | |---------|-------|---------| @@ -47,16 +49,18 @@ Generated sources land in `target/generated-sources`. JAXB binding customization | `org.entur.siri.validator` | `SiriValidationEventHandler` | Collects validation errors | | `org.entur.siri21.util` | `SiriXml` | SIRI 2.1 XML marshalling/unmarshalling (JAXB) | | `org.entur.siri21.util` | `SiriJson` | SIRI 2.1 JSON conversion (Jackson + Jakarta XML Bind) | -| `org.rutebanken.siri20.util` | `SiriXml` | SIRI 2.0 XML marshalling/unmarshalling (legacy package) | +| `org.entur.siri20.util` | `SiriXml` | SIRI 2.0 XML marshalling/unmarshalling | +| `org.entur.siri20.util` | `SiriJson` | SIRI 2.0 JSON conversion (Jackson + Jakarta XML Bind) | | `org.entur.siri` | `UnsupportedSiriVersionException` | Exception for unsupported SIRI versions | +| (module root) | `module-info.java` | JPMS descriptor: `open module org.entur.siri` | ### Key Design Decisions - **Jakarta EE**: Uses `jakarta.xml.bind` (3.0+), not legacy `javax.xml.bind`. - **Java 11** target (source and bytecode) via `` in the compiler plugin; CI builds on JDK 25, and any JDK from 11 to 25 works locally. +- **JPMS**: `src/main/java/module-info.java` declares `open module org.entur.siri` (open because the consumer's JAXB runtime needs reflective access). When you add a generated or handwritten package, add an `exports` line for it. +- **No `NamespacePrefixMapper` in the API**: `SiriXml.toXml` takes a `Consumer` customizer. The `JAXBNamespacePrefixMapper` stub shares a package with the JAXB RI, so it cannot be used on the module path. - **JUnit 4** for tests. -- **JSON support exists only for SIRI 2.1** (`SiriJson`), not 2.0. -- **SIRI 2.0 utility lives in legacy package** `org.rutebanken.siri20.util` (historical). ### Test Data diff --git a/README.md b/README.md index 9f45435..c74afc6 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,56 @@ Source 1.0 - 1.4 http://user47094.vs.easily.co.uk/siri/ Source 2.0 -> https://www.vdv.de/siri.aspx -Also provides XML-validation through method `SiriValidator.validate`. \ No newline at end of file +Also provides XML-validation through method `SiriValidator.validate`. + +## Java modules (JPMS) + +The jar is a named module, `org.entur.siri`. It is an `open module`, because the JAXB runtime that you supply needs reflective access to the generated classes. It requires `jakarta.xml.bind` and Jackson. You must also provide a JAXB implementation, for example `com.sun.xml.bind:jaxb-impl`. + +```java +module my.app { + requires org.entur.siri; +} +``` + +## Upgrading to 3.0 + +**Breaking change: the generated packages are renamed.** +The XML namespaces and the wire format are unchanged. Update your imports: + +| Before | After | +|---|---| +| `uk.org.siri.siri20` / `siri21` | `org.entur.siri.schema.v20.siri` / `v21.siri` | +| `uk.org.ifopt.siri20` / `siri21` | `org.entur.siri.schema.v20.ifopt` / `v21.ifopt` | +| `uk.org.acbs.siri20` / `siri21` | `org.entur.siri.schema.v20.acsb` / `v21.acsb` | +| `eu.datex2.siri20.schema._2_0rc1._2_0` / `siri21...` | `org.entur.siri.schema.v20.datex2` / `v21.datex2` | +| `net.opengis.gml.siri` | `org.entur.siri.schema.v21.gml` | + + +**Breaking change: `NamespacePrefixMapper` is removed from `SiriXml`.** +The overloads `toXml(Siri, NamespacePrefixMapper)` and `toXml(Siri, NamespacePrefixMapper, OutputStream)` in `org.entur.siri21.util.SiriXml` and `org.entur.siri20.util.SiriXml` now take a `Consumer` instead. The `JAXBNamespacePrefixMapper` dependency is removed, because it shares a package with the JAXB reference implementation and cannot be used on the module path. + +Before: + +```java +SiriXml.toXml(siri, myNamespacePrefixMapper); +``` + +After: set the property of your own JAXB implementation on the marshaller. + +```java +SiriXml.toXml(siri, marshaller -> { + try { + marshaller.setProperty("org.glassfish.jaxb.namespacePrefixMapper", myNamespacePrefixMapper); + } catch (PropertyException e) { + throw new IllegalStateException(e); + } +}); +``` + +The property name depends on your JAXB implementation. Use the one that your implementation documents. If your own code imports `com.sun.xml.bind.marshaller.NamespacePrefixMapper`, add the dependency that provides it yourself. This library no longer brings it in. + +**Breaking change: the SIRI 2.0 utility package is renamed.** +`org.rutebanken.siri20.util` (`SiriXml`, `SiriJson`) is now `org.entur.siri20.util`, which matches `org.entur.siri21.util`. Update your imports. There are no deprecated forwarders in the old package. + +The module name is now explicit (`org.entur.siri`). It was derived from the jar file name (`siri.java.model`) before. diff --git a/pom.xml b/pom.xml index eb78e0a..df5e6f5 100644 --- a/pom.xml +++ b/pom.xml @@ -24,9 +24,7 @@ UTF-8 11 - 2.0.9 2.18.11 - 2.0.7 1.18.0 4.2.0 3.11.2 @@ -71,11 +69,6 @@ - - com.googlecode.jaxb-namespaceprefixmapper-interfaces - JAXBNamespacePrefixMapper - 6.1.0 - com.fasterxml.jackson.core jackson-databind @@ -90,6 +83,12 @@ com.fasterxml.jackson.module jackson-module-jakarta-xmlbind-annotations ${jackson.version} + + + jakarta.activation + jakarta.activation-api + + jakarta.xml.bind @@ -108,17 +107,6 @@ 3.0.2 test - - jakarta.activation - jakarta.activation-api - test - 2.1.0 - - - org.slf4j - slf4j-api - ${slf4j.version} - junit @@ -126,12 +114,6 @@ 4.13.2 test - - org.slf4j - slf4j-simple - ${slf4j.version} - test - diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000..4f144d3 --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,21 @@ +open module org.entur.siri { + requires transitive jakarta.xml.bind; + requires com.fasterxml.jackson.annotation; + requires com.fasterxml.jackson.databind; + requires com.fasterxml.jackson.module.jakarta.xmlbind; + + exports org.entur.siri; + exports org.entur.siri.adapter; + exports org.entur.siri.validator; + exports org.entur.siri21.util; + exports org.entur.siri20.util; + exports org.entur.siri.schema.v20.acsb; + exports org.entur.siri.schema.v20.datex2; + exports org.entur.siri.schema.v20.ifopt; + exports org.entur.siri.schema.v20.siri; + exports org.entur.siri.schema.v21.acsb; + exports org.entur.siri.schema.v21.datex2; + exports org.entur.siri.schema.v21.gml; + exports org.entur.siri.schema.v21.ifopt; + exports org.entur.siri.schema.v21.siri; +} diff --git a/src/main/java/org/entur/siri/adapter/ZonedDateTimeDateTimeXmlAdapter.java b/src/main/java/org/entur/siri/adapter/ZonedDateTimeDateTimeXmlAdapter.java new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/org/entur/siri/adapter/ZonedDateTimeTimeXmlAdapter.java b/src/main/java/org/entur/siri/adapter/ZonedDateTimeTimeXmlAdapter.java new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/org/entur/siri/adapter/ZonedDateTimeXmlAdapter.java b/src/main/java/org/entur/siri/adapter/ZonedDateTimeXmlAdapter.java new file mode 100644 index 0000000..878facd --- /dev/null +++ b/src/main/java/org/entur/siri/adapter/ZonedDateTimeXmlAdapter.java @@ -0,0 +1,22 @@ +package org.entur.siri.adapter; + +import jakarta.xml.bind.annotation.adapters.XmlAdapter; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +/** + * JAXB adapter for {@code xsd:dateTime} bound to {@link ZonedDateTime}. Written by hand so that XJC does not + * generate an adapter class into the {@code org.w3._2001.xmlschema} package, which would be a split package. + */ +public class ZonedDateTimeXmlAdapter extends XmlAdapter { + + @Override + public ZonedDateTime unmarshal(String value) { + return ZonedDateTimeAdapter.parse(value); + } + + @Override + public String marshal(ZonedDateTime value) { + return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value); + } +} diff --git a/src/main/java/org/entur/siri/adapter/ZonedTimeXmlAdapter.java b/src/main/java/org/entur/siri/adapter/ZonedTimeXmlAdapter.java new file mode 100644 index 0000000..a318f6c --- /dev/null +++ b/src/main/java/org/entur/siri/adapter/ZonedTimeXmlAdapter.java @@ -0,0 +1,22 @@ +package org.entur.siri.adapter; + +import jakarta.xml.bind.annotation.adapters.XmlAdapter; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +/** + * JAXB adapter for {@code xsd:time} bound to {@link ZonedDateTime}. Written by hand so that XJC does not + * generate an adapter class into the {@code org.w3._2001.xmlschema} package, which would be a split package. + */ +public class ZonedTimeXmlAdapter extends XmlAdapter { + + @Override + public ZonedDateTime unmarshal(String value) { + return ZonedDateTimeAdapter.parse(value); + } + + @Override + public String marshal(ZonedDateTime value) { + return DateTimeFormatter.ISO_OFFSET_TIME.format(value); + } +} diff --git a/src/main/java/org/entur/siri/validator/SiriValidator.java b/src/main/java/org/entur/siri/validator/SiriValidator.java index 42d1fc1..bece60e 100644 --- a/src/main/java/org/entur/siri/validator/SiriValidator.java +++ b/src/main/java/org/entur/siri/validator/SiriValidator.java @@ -51,10 +51,10 @@ public class SiriValidator { private static void init() throws JAXBException { if (siri20jaxbContext == null) { - siri20jaxbContext = JAXBContext.newInstance(uk.org.siri.siri20.Siri.class); + siri20jaxbContext = JAXBContext.newInstance(org.entur.siri.schema.v20.siri.Siri.class); } if (siri21jaxbContext == null) { - siri21jaxbContext = JAXBContext.newInstance(uk.org.siri.siri21.Siri.class); + siri21jaxbContext = JAXBContext.newInstance(org.entur.siri.schema.v21.siri.Siri.class); } } /** diff --git a/src/main/java/org/rutebanken/siri20/util/SiriJson.java b/src/main/java/org/entur/siri20/util/SiriJson.java similarity index 97% rename from src/main/java/org/rutebanken/siri20/util/SiriJson.java rename to src/main/java/org/entur/siri20/util/SiriJson.java index 9127181..d2b0304 100644 --- a/src/main/java/org/rutebanken/siri20/util/SiriJson.java +++ b/src/main/java/org/entur/siri20/util/SiriJson.java @@ -13,7 +13,7 @@ * limitations under the Licence. */ -package org.rutebanken.siri20.util; +package org.entur.siri20.util; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -23,7 +23,7 @@ import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.databind.util.StdDateFormat; import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector; -import uk.org.siri.siri20.Siri; +import org.entur.siri.schema.v20.siri.Siri; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/org/rutebanken/siri20/util/SiriXml.java b/src/main/java/org/entur/siri20/util/SiriXml.java similarity index 79% rename from src/main/java/org/rutebanken/siri20/util/SiriXml.java rename to src/main/java/org/entur/siri20/util/SiriXml.java index 538529f..dc54d94 100644 --- a/src/main/java/org/rutebanken/siri20/util/SiriXml.java +++ b/src/main/java/org/entur/siri20/util/SiriXml.java @@ -13,13 +13,14 @@ * limitations under the Licence. */ -package org.rutebanken.siri20.util; +package org.entur.siri20.util; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.io.StringWriter; +import java.util.function.Consumer; import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBException; @@ -29,10 +30,9 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; -import com.sun.xml.bind.marshaller.NamespacePrefixMapper; import org.entur.siri.XmlInputFactoryProvider; -import uk.org.siri.siri20.Siri; +import org.entur.siri.schema.v20.siri.Siri; public class SiriXml { @@ -73,12 +73,12 @@ public static String toXml(Siri siri) throws JAXBException { return toXml(siri, null); } - public static String toXml(Siri siri, NamespacePrefixMapper customNamespacePrefixMapper) throws JAXBException { + public static String toXml(Siri siri, Consumer marshallerCustomizer) throws JAXBException { Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); - if (customNamespacePrefixMapper != null) { - jaxbMarshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", customNamespacePrefixMapper); + if (marshallerCustomizer != null) { + marshallerCustomizer.accept(jaxbMarshaller); } StringWriter sw = new StringWriter(); jaxbMarshaller.marshal(siri, sw); @@ -86,11 +86,11 @@ public static String toXml(Siri siri, NamespacePrefixMapper customNamespacePrefi return sw.toString(); } - public static void toXml(Siri siri, NamespacePrefixMapper customNamespacePrefixMapper, OutputStream out) throws JAXBException, IOException { + public static void toXml(Siri siri, Consumer marshallerCustomizer, OutputStream out) throws JAXBException, IOException { Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); - if (customNamespacePrefixMapper != null) { - jaxbMarshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", customNamespacePrefixMapper); + if (marshallerCustomizer != null) { + marshallerCustomizer.accept(jaxbMarshaller); } jaxbMarshaller.marshal(siri, out); } diff --git a/src/main/java/org/entur/siri21/util/SiriJson.java b/src/main/java/org/entur/siri21/util/SiriJson.java index 23ff35d..eda3976 100644 --- a/src/main/java/org/entur/siri21/util/SiriJson.java +++ b/src/main/java/org/entur/siri21/util/SiriJson.java @@ -23,7 +23,7 @@ import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.databind.util.StdDateFormat; import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector; -import uk.org.siri.siri21.Siri; +import org.entur.siri.schema.v21.siri.Siri; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/org/entur/siri21/util/SiriXml.java b/src/main/java/org/entur/siri21/util/SiriXml.java index 41c3f46..92293ca 100644 --- a/src/main/java/org/entur/siri21/util/SiriXml.java +++ b/src/main/java/org/entur/siri21/util/SiriXml.java @@ -15,9 +15,8 @@ package org.entur.siri21.util; -import com.sun.xml.bind.marshaller.NamespacePrefixMapper; import org.entur.siri.XmlInputFactoryProvider; -import uk.org.siri.siri21.Siri; +import org.entur.siri.schema.v21.siri.Siri; import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBException; @@ -31,6 +30,7 @@ import java.io.OutputStream; import java.io.StringReader; import java.io.StringWriter; +import java.util.function.Consumer; public class SiriXml { @@ -71,12 +71,12 @@ public static String toXml(Siri siri) throws JAXBException { return toXml(siri, null); } - public static String toXml(Siri siri, NamespacePrefixMapper customNamespacePrefixMapper) throws JAXBException { + public static String toXml(Siri siri, Consumer marshallerCustomizer) throws JAXBException { Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); - if (customNamespacePrefixMapper != null) { - jaxbMarshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", customNamespacePrefixMapper); + if (marshallerCustomizer != null) { + marshallerCustomizer.accept(jaxbMarshaller); } StringWriter sw = new StringWriter(); jaxbMarshaller.marshal(siri, sw); @@ -84,11 +84,11 @@ public static String toXml(Siri siri, NamespacePrefixMapper customNamespacePrefi return sw.toString(); } - public static void toXml(Siri siri, NamespacePrefixMapper customNamespacePrefixMapper, OutputStream out) throws JAXBException, IOException { + public static void toXml(Siri siri, Consumer marshallerCustomizer, OutputStream out) throws JAXBException, IOException { Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); - if (customNamespacePrefixMapper != null) { - jaxbMarshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", customNamespacePrefixMapper); + if (marshallerCustomizer != null) { + marshallerCustomizer.accept(jaxbMarshaller); } jaxbMarshaller.marshal(siri, out); } diff --git a/src/main/resources/siri-2.0/xjb/jaxb-bindings.xml b/src/main/resources/siri-2.0/xjb/jaxb-bindings.xml index 4c9fa1f..c69c758 100644 --- a/src/main/resources/siri-2.0/xjb/jaxb-bindings.xml +++ b/src/main/resources/siri-2.0/xjb/jaxb-bindings.xml @@ -20,12 +20,8 @@ - - + + @@ -33,25 +29,25 @@ - + - + - + - + diff --git a/src/main/resources/siri-2.1/xjb/jaxb-bindings.xml b/src/main/resources/siri-2.1/xjb/jaxb-bindings.xml index c375d52..b549ec9 100644 --- a/src/main/resources/siri-2.1/xjb/jaxb-bindings.xml +++ b/src/main/resources/siri-2.1/xjb/jaxb-bindings.xml @@ -20,12 +20,8 @@ - - + + @@ -33,30 +29,30 @@ - + - + - + - + - + diff --git a/src/test/java/org/entur/siri/XmlInputFactoryProviderTest.java b/src/test/java/org/entur/siri/XmlInputFactoryProviderTest.java index 08d7ed0..f632ff9 100644 --- a/src/test/java/org/entur/siri/XmlInputFactoryProviderTest.java +++ b/src/test/java/org/entur/siri/XmlInputFactoryProviderTest.java @@ -42,7 +42,7 @@ public class XmlInputFactoryProviderTest { @Test(expected = Exception.class) public void testXxeBlockedSiri20() throws Exception { - org.rutebanken.siri20.util.SiriXml.parseXml(XXE_XML); + org.entur.siri20.util.SiriXml.parseXml(XXE_XML); } @Test(expected = Exception.class) diff --git a/src/test/java/org/entur/siri20/util/SiriXmlMarshallerCustomizerTest.java b/src/test/java/org/entur/siri20/util/SiriXmlMarshallerCustomizerTest.java new file mode 100644 index 0000000..f916095 --- /dev/null +++ b/src/test/java/org/entur/siri20/util/SiriXmlMarshallerCustomizerTest.java @@ -0,0 +1,92 @@ +/* + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +package org.entur.siri20.util; + +import jakarta.xml.bind.Marshaller; +import org.junit.BeforeClass; +import org.junit.Test; +import org.entur.siri.schema.v20.siri.Siri; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.entur.siri20.util.SiriXml.parseXml; +import static org.entur.siri20.util.SiriXml.toXml; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class SiriXmlMarshallerCustomizerTest { + + private static Siri siri; + + @BeforeClass + public static void init() throws Exception { + String xml = new String(Files.readAllBytes(Paths.get("src/test/resources/et.xml")), StandardCharsets.UTF_8); + siri = parseXml(xml); + } + + @Test + public void testCustomizerIsAppliedToMarshaller() throws Exception { + AtomicInteger calls = new AtomicInteger(); + + String formatted = toXml(siri, marshaller -> { + calls.incrementAndGet(); + setFormattedOutput(marshaller); + }); + + assertEquals(1, calls.get()); + assertTrue("Expected indented output", isIndented(formatted)); + } + + @Test + public void testNullCustomizerGivesSameOutputAsDefault() throws Exception { + assertEquals(toXml(siri), toXml(siri, null)); + } + + @Test + public void testCustomizerIsAppliedWhenWritingToOutputStream() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + SiriXml.toXml(siri, SiriXmlMarshallerCustomizerTest::setFormattedOutput, out); + + String formatted = new String(out.toByteArray(), StandardCharsets.UTF_8); + assertTrue("Expected indented output", isIndented(formatted)); + } + + @Test + public void testCustomizerDoesNotLeakIntoLaterCalls() throws Exception { + toXml(siri, SiriXmlMarshallerCustomizerTest::setFormattedOutput); + + assertFalse("Customizer must only affect its own marshaller", isIndented(toXml(siri))); + } + + private static boolean isIndented(String xml) { + return xml.split("\n").length > 5; + } + + private static void setFormattedOutput(Marshaller marshaller) { + try { + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} diff --git a/src/test/java/org/entur/siri21/util/MarshallingTest.java b/src/test/java/org/entur/siri21/util/MarshallingTest.java index 107c4ce..00eb8f1 100644 --- a/src/test/java/org/entur/siri21/util/MarshallingTest.java +++ b/src/test/java/org/entur/siri21/util/MarshallingTest.java @@ -17,7 +17,7 @@ import org.junit.BeforeClass; import org.junit.Test; -import uk.org.siri.siri21.Siri; +import org.entur.siri.schema.v21.siri.Siri; import java.io.IOException; import java.io.RandomAccessFile; diff --git a/src/test/java/org/entur/siri21/util/SiriJsonTest.java b/src/test/java/org/entur/siri21/util/SiriJsonTest.java index 3722a15..316d138 100644 --- a/src/test/java/org/entur/siri21/util/SiriJsonTest.java +++ b/src/test/java/org/entur/siri21/util/SiriJsonTest.java @@ -17,7 +17,7 @@ import org.junit.BeforeClass; import org.junit.Test; -import uk.org.siri.siri21.Siri; +import org.entur.siri.schema.v21.siri.Siri; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/test/java/org/entur/siri21/util/SiriXmlMarshallerCustomizerTest.java b/src/test/java/org/entur/siri21/util/SiriXmlMarshallerCustomizerTest.java new file mode 100644 index 0000000..73abcfe --- /dev/null +++ b/src/test/java/org/entur/siri21/util/SiriXmlMarshallerCustomizerTest.java @@ -0,0 +1,114 @@ + /* + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +package org.entur.siri21.util; + +import jakarta.xml.bind.Marshaller; +import org.glassfish.jaxb.runtime.marshaller.NamespacePrefixMapper; +import org.junit.BeforeClass; +import org.junit.Test; +import org.entur.siri.schema.v21.siri.Siri; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.entur.siri21.util.SiriXml.parseXml; +import static org.entur.siri21.util.SiriXml.toXml; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class SiriXmlMarshallerCustomizerTest { + + private static Siri siri; + + @BeforeClass + public static void init() throws Exception { + String xml = new String(Files.readAllBytes(Paths.get("src/test/resources/et-2_1.xml")), StandardCharsets.UTF_8); + siri = parseXml(xml); + } + + @Test + public void testCustomizerIsAppliedToMarshaller() throws Exception { + AtomicInteger calls = new AtomicInteger(); + + String formatted = toXml(siri, marshaller -> { + calls.incrementAndGet(); + setFormattedOutput(marshaller); + }); + + assertEquals(1, calls.get()); + assertTrue("Expected indented output", isIndented(formatted)); + } + + @Test + public void testJaxbRiNamespacePrefixMapperCanBeSetThroughCustomizer() throws Exception { + NamespacePrefixMapper mapper = new NamespacePrefixMapper() { + @Override + public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) { + return "http://www.siri.org.uk/siri".equals(namespaceUri) ? "siri" : suggestion; + } + }; + + String xml = toXml(siri, marshaller -> { + try { + marshaller.setProperty("org.glassfish.jaxb.namespacePrefixMapper", mapper); + } catch (Exception e) { + throw new IllegalStateException(e); + } + }); + + assertTrue("Expected siri: prefix", xml.contains(" 5; + } + + private static void setFormattedOutput(Marshaller marshaller) { + try { + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} diff --git a/src/test/java/org/entur/siri21/util/SiriXmlTest.java b/src/test/java/org/entur/siri21/util/SiriXmlTest.java index ec215d0..46c28b8 100644 --- a/src/test/java/org/entur/siri21/util/SiriXmlTest.java +++ b/src/test/java/org/entur/siri21/util/SiriXmlTest.java @@ -18,7 +18,7 @@ import org.entur.siri.validator.SiriValidator; import org.junit.BeforeClass; import org.junit.Test; -import uk.org.siri.siri21.Siri; +import org.entur.siri.schema.v21.siri.Siri; import java.io.IOException; import java.io.RandomAccessFile;