From 7135c00ff4a66a9fc3989d3d0ccf91f4b02a7540 Mon Sep 17 00:00:00 2001 From: Gabriel Roldan Date: Tue, 12 Dec 2023 13:03:12 -0300 Subject: [PATCH] Add simple JSON encoder Make `application/json` output format serve simple JSON instead of GeoJSON. ```json { "numberMatched":16, "numberReturned":2, "records":[ { "@id":"1", "city":" Trento", "number":140, "year":2002 }, { "@id":"10", "city":" Barcelona", "number":914, "year":2010 } ], "links":[ { "href":"http://localhost:8080/ogcapi/collections/locations/items?f=json&offset=0&limit=2", "rel":"self", "type":"application/json", "title":"This document" }, { "href":"http://localhost:8080/ogcapi/collections/locations/items?f=json&offset=2&limit=2", "rel":"next", "type":"application/json", "title":"Next page" }, { "href":"http://localhost:8080/ogcapi/collections/locations/items?offset=0&limit=2&f=geojson", "rel":"alternate", "type":"application/geo+json", "title":"This document as GeoJSON" }, { "href":"http://localhost:8080/ogcapi/collections/locations/items?offset=0&limit=2&f=shapefile", "rel":"alternate", "type":"application/x-shapefile", "title":"This document as Esri Shapefile" }, { "href":"http://localhost:8080/ogcapi/collections/locations/items?offset=0&limit=2&f=csv", "rel":"alternate", "type":"text/csv;charset=UTF-8", "title":"This document as Comma Separated Values" }, { "href":"http://localhost:8080/ogcapi/collections/locations/items?offset=0&limit=2&f=ooxml", "rel":"alternate", "type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "title":"This document as Excel 2007 / OOXML" } ] } ``` --- .../api/ApiAutoConfiguration.java | 7 + ...FeatureCollectionHttpMessageConverter.java | 102 ++++++++++ .../http/codec/json/SimpleJsonModule.java | 135 +++++++++++++ .../resources/ogc-features/1.0.1/api.yaml | 102 ++++++---- ...va => AbstractCollectionsApiImplTest.java} | 2 +- .../server/impl/CollectionsApiIT.java | 181 ++++++++++++++++++ ...ava => CollectionsApiImplPostgisTest.java} | 4 +- .../server/impl/CollectionsApiImplTest.java | 2 +- 8 files changed, 492 insertions(+), 43 deletions(-) create mode 100644 src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/http/codec/json/SimpleJsonFeatureCollectionHttpMessageConverter.java create mode 100644 src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/http/codec/json/SimpleJsonModule.java rename src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/{AbstractCollectionsApiImplIT.java => AbstractCollectionsApiImplTest.java} (99%) create mode 100644 src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiIT.java rename src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/{CollectionsApiImplPostgisIT.java => CollectionsApiImplPostgisTest.java} (98%) diff --git a/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/autoconfigure/api/ApiAutoConfiguration.java b/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/autoconfigure/api/ApiAutoConfiguration.java index 48de325..a2d12d0 100644 --- a/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/autoconfigure/api/ApiAutoConfiguration.java +++ b/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/autoconfigure/api/ApiAutoConfiguration.java @@ -17,6 +17,7 @@ import com.camptocamp.opendata.ogc.features.autoconfigure.geotools.SampleDataBackendAutoConfiguration; import com.camptocamp.opendata.ogc.features.http.codec.MimeTypes; import com.camptocamp.opendata.ogc.features.http.codec.csv.CsvFeatureCollectionHttpMessageConverter; +import com.camptocamp.opendata.ogc.features.http.codec.json.SimpleJsonFeatureCollectionHttpMessageConverter; import com.camptocamp.opendata.ogc.features.http.codec.shp.ShapefileFeatureCollectionHttpMessageConverter; import com.camptocamp.opendata.ogc.features.http.codec.xls.Excel2007FeatureCollectionHttpMessageConverter; import com.camptocamp.opendata.ogc.features.repository.CollectionRepository; @@ -68,11 +69,17 @@ CollectionsApiController collectionsApiController(CollectionsApiDelegate delegat */ @Override public void configureMessageConverters(List> converters) { + converters.add(simpleJsonFeatureCollectionHttpMessageConverter()); converters.add(csvFeatureCollectionHttpMessageConverter()); converters.add(shapefileFeatureCollectionHttpMessageConverter()); converters.add(excel2007FeatureCollectionHttpMessageConverter()); } + @Bean + SimpleJsonFeatureCollectionHttpMessageConverter simpleJsonFeatureCollectionHttpMessageConverter() { + return new SimpleJsonFeatureCollectionHttpMessageConverter(); + } + @Bean Excel2007FeatureCollectionHttpMessageConverter excel2007FeatureCollectionHttpMessageConverter() { return new Excel2007FeatureCollectionHttpMessageConverter(); diff --git a/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/http/codec/json/SimpleJsonFeatureCollectionHttpMessageConverter.java b/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/http/codec/json/SimpleJsonFeatureCollectionHttpMessageConverter.java new file mode 100644 index 0000000..6b65ec0 --- /dev/null +++ b/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/http/codec/json/SimpleJsonFeatureCollectionHttpMessageConverter.java @@ -0,0 +1,102 @@ +package com.camptocamp.opendata.ogc.features.http.codec.json; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Type; + +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.AbstractGenericHttpMessageConverter; +import org.springframework.http.converter.HttpMessageNotWritableException; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.util.MimeType; + +import com.camptocamp.opendata.model.GeodataRecord; +import com.camptocamp.opendata.ogc.features.http.codec.MimeTypes; +import com.camptocamp.opendata.ogc.features.model.FeatureCollection; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Simpler, geometry-less, JSON encoder for {@link FeatureCollection} and + * {@link GeodataRecord}. + * + *

+ * Sample output: + * + *

+ * 
+ * {
+ *     "numberMatched":16,
+ *     "numberReturned":2,
+ *     "records":[
+ *         {
+ *             "@id":"1",
+ *             "city":" Trento",
+ *            "number":140,
+ *             "year":2002
+ *         },
+ *         ...
+ *      ],
+ *      "links":[
+ *          {
+ *              "href":"http://localhost:8080/ogcapi/collections/locations/items?f=json&offset=0&limit=2",
+ *              "rel":"self",
+ *              "type":"application/json",
+ *              "title":"This document"
+ *          },
+ *          ...
+ *      ]
+ * }                  
+ * 
+ * 
+ * + */ +public class SimpleJsonFeatureCollectionHttpMessageConverter + extends AbstractGenericHttpMessageConverter { + + private static final MimeType MIME_TYPE = MimeTypes.JSON.getMimeType(); + private static final MediaType MEDIA_TYPE = new MediaType(MIME_TYPE); + + private ObjectMapper mapper; + + public SimpleJsonFeatureCollectionHttpMessageConverter() { + super(MEDIA_TYPE); + mapper = new ObjectMapper(); + Jackson2ObjectMapperBuilder.json().configure(mapper); + mapper.registerModule(new SimpleJsonModule()); + } + + /** + * {@inheritDoc} + */ + protected @Override boolean supports(Class clazz) { + return FeatureCollection.class.isAssignableFrom(clazz); + } + + /** + * {@inheritDoc} + */ + protected @Override MediaType getDefaultContentType(FeatureCollection message) { + return MEDIA_TYPE; + } + + protected @Override void writeInternal(FeatureCollection message, Type type, HttpOutputMessage outputMessage) + throws IOException, HttpMessageNotWritableException { + + OutputStream body = outputMessage.getBody(); + mapper.writeValue(body, message); + body.flush(); + } + + protected @Override FeatureCollection readInternal(Class clazz, + HttpInputMessage inputMessage) { + throw new UnsupportedOperationException(); + } + + @Override + public FeatureCollection read(Type type, Class contextClass, HttpInputMessage inputMessage) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/http/codec/json/SimpleJsonModule.java b/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/http/codec/json/SimpleJsonModule.java new file mode 100644 index 0000000..0a7db10 --- /dev/null +++ b/src/services/ogc-features/src/main/java/com/camptocamp/opendata/ogc/features/http/codec/json/SimpleJsonModule.java @@ -0,0 +1,135 @@ +package com.camptocamp.opendata.ogc.features.http.codec.json; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.List; + +import com.camptocamp.opendata.model.GeodataRecord; +import com.camptocamp.opendata.model.GeometryProperty; +import com.camptocamp.opendata.model.SimpleProperty; +import com.camptocamp.opendata.ogc.features.model.FeatureCollection; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.core.type.WritableTypeId; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.jsontype.TypeSerializer; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +@SuppressWarnings("serial") +class SimpleJsonModule extends SimpleModule { + + private static final Version VERSION = new Version(1, 0, 0, null, null, null); + + public SimpleJsonModule() { + super(SimpleJsonModule.class.getSimpleName(), VERSION); + + addSerializer(new FeatureCollectionSerializer()); + addSerializer(new GeodataRecordSerializer()); + } + + static class FeatureCollectionSerializer extends StdSerializer { + + protected FeatureCollectionSerializer() { + super(FeatureCollection.class); + } + + @Override + public void serializeWithType(FeatureCollection collection, JsonGenerator gen, SerializerProvider serializers, + TypeSerializer typeSer) throws IOException { + + WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen, typeSer.typeId(collection, JsonToken.START_OBJECT)); + + serializeContent(collection, gen); + + typeSer.writeTypeSuffix(gen, typeIdDef); + } + + @Override + public void serialize(FeatureCollection collection, JsonGenerator generator, SerializerProvider serializers) + throws IOException { + + if (collection == null) { + generator.writeNull(); + return; + } + generator.writeStartObject(); + serializeContent(collection, generator); + generator.writeEndObject(); + } + + private void serializeContent(FeatureCollection collection, JsonGenerator generator) throws IOException { + generator.writeNumberField("numberMatched", collection.getNumberMatched()); + generator.writeNumberField("numberReturned", collection.getNumberReturned()); + + generator.writeFieldName("records"); + generator.writeStartArray(); + collection.getFeatures().forEach(rec -> write(rec, generator)); + generator.writeEndArray(); + + generator.writeFieldName("links"); + generator.writeStartArray(); + collection.getLinks().forEach(link -> write(link, generator)); + generator.writeEndArray(); + } + + private void write(Object obj, JsonGenerator generator) { + try { + generator.writeObject(obj); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + } + + static class GeodataRecordSerializer extends StdSerializer { + + public GeodataRecordSerializer() { + super(GeodataRecord.class); + } + + @Override + public void serializeWithType(GeodataRecord rec, JsonGenerator gen, SerializerProvider serializers, + TypeSerializer typeSer) throws IOException { + + WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen, typeSer.typeId(rec, JsonToken.START_OBJECT)); + + serializeContent(rec, gen); + + typeSer.writeTypeSuffix(gen, typeIdDef); + } + + @Override + public void serialize(GeodataRecord rec, JsonGenerator generator, SerializerProvider serializers) + throws IOException { + + if (rec == null) { + generator.writeNull(); + return; + } + generator.writeStartObject(); + serializeContent(rec, generator); + generator.writeEndObject(); + } + + private void serializeContent(GeodataRecord rec, JsonGenerator generator) throws IOException { + if (null != rec.getId()) { + generator.writeStringField("@id", rec.getId()); + } + writeProperties(generator, rec.getProperties()); + } + + private void writeProperties(JsonGenerator generator, List> properties) + throws IOException { + for (SimpleProperty p : properties) { + if (!(p instanceof GeometryProperty)) { + generator.writeObjectField(p.getName(), p.getValue()); + } + } + } + + } + +} diff --git a/src/services/ogc-features/src/main/resources/ogc-features/1.0.1/api.yaml b/src/services/ogc-features/src/main/resources/ogc-features/1.0.1/api.yaml index 51ae612..543ab82 100644 --- a/src/services/ogc-features/src/main/resources/ogc-features/1.0.1/api.yaml +++ b/src/services/ogc-features/src/main/resources/ogc-features/1.0.1/api.yaml @@ -549,6 +549,66 @@ components: $ref: "#/components/schemas/numberMatched" numberReturned: $ref: "#/components/schemas/numberReturned" + example: + { + "type":"FeatureCollection", + "numberMatched":16, + "numberReturned":2, + "features":[ + { + "type":"Feature", + "@typeName":"locations", + "@id":"1", + "geometry":{"type":"Point","@name":"geom","@srs":"EPSG:4326","coordinates":[11.116667,46.066667]}, + "properties":{"city":" Trento","number":140,"year":2002} + }, + { + "type":"Feature", + "@typeName":"locations", + "@id":"10", + "geometry":{"type":"Point","@name":"geom","@srs":"EPSG:4326","coordinates":[2.183333,41.383333]}, + "properties":{"city":" Barcelona","number":914,"year":2010} + } + ], + "links":[ + { + "href":"http://localhost:/ogcapi/collections/locations/items?f=geojson&offset=0&limit=2", + "rel":"self", + "type":"application/geo+json", + "title":"This document" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?f=geojson&offset=2&limit=2", + "rel":"next", + "type":"application/geo+json", + "title":"Next page" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=json", + "rel":"alternate", + "type":"application/json", + "title":"This document as JSON" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=shapefile", + "rel":"alternate", + "type":"application/x-shapefile", + "title":"This document as Esri Shapefile" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=csv", + "rel":"alternate", + "type":"text/csv;charset=UTF-8", + "title":"This document as Comma Separated Values" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=ooxml", + "rel":"alternate", + "type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "title":"This document as Excel 2007 / OOXML" + } + ] + } featureGeoJSON: type: object required: @@ -968,48 +1028,12 @@ components: returned features (`numberMatched` and `numberReturned`) as well as links to support paging (link relation `next`). content: + application/json: + schema: + $ref: '#/components/schemas/featureCollectionGeoJSON' application/geo+json: schema: $ref: '#/components/schemas/featureCollectionGeoJSON' - example: - type: FeatureCollection - links: - - href: 'http://data.example.com/collections/buildings/items.json' - rel: self - type: application/geo+json - title: this document - - href: 'http://data.example.com/collections/buildings/items.html' - rel: alternate - type: text/html - title: this document as HTML - - href: 'http://data.example.com/collections/buildings/items.json&offset=10&limit=2' - rel: next - type: application/geo+json - title: next page - timeStamp: '2018-04-03T14:52:23Z' - numberMatched: 123 - numberReturned: 2 - features: - - type: Feature - id: '123' - geometry: - type: Polygon - coordinates: - - ... - properties: - function: residential - floors: '2' - lastUpdate: '2015-08-01T12:34:56Z' - - type: Feature - id: '132' - geometry: - type: Polygon - coordinates: - - ... - properties: - function: public use - floors: '10' - lastUpdate: '2013-12-03T10:15:37Z' 'text/csv': schema: type: string diff --git a/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/AbstractCollectionsApiImplIT.java b/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/AbstractCollectionsApiImplTest.java similarity index 99% rename from src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/AbstractCollectionsApiImplIT.java rename to src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/AbstractCollectionsApiImplTest.java index fb1d74a..76116ab 100644 --- a/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/AbstractCollectionsApiImplIT.java +++ b/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/AbstractCollectionsApiImplTest.java @@ -35,7 +35,7 @@ import lombok.Cleanup; -public abstract class AbstractCollectionsApiImplIT { +public abstract class AbstractCollectionsApiImplTest { protected @Autowired CollectionsApiImpl collectionsApi; diff --git a/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiIT.java b/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiIT.java new file mode 100644 index 0000000..b8495e1 --- /dev/null +++ b/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiIT.java @@ -0,0 +1,181 @@ +package com.camptocamp.opendata.ogc.features.server.impl; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; + +import org.json.JSONException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; + +import com.camptocamp.opendata.ogc.features.app.OgcFeaturesApp; +import com.camptocamp.opendata.ogc.features.http.codec.MimeTypes; + +@SpringBootTest(classes = OgcFeaturesApp.class, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("sample-data") +class CollectionsApiIT { + + private TestRestTemplate restTemplate; + + private @LocalServerPort int port; + + private String itemsUrlTemplate; + + @BeforeEach + void setup() { + restTemplate = new TestRestTemplate(); + itemsUrlTemplate = "http://localhost:%d/ogcapi/collections/{collection}/items?f={f}".formatted(port); + } + + @Test + void testGetItems_geojson() throws JSONException { + final String url = itemsUrlTemplate + "&offset=0&limit=2"; + Map urlVariables = Map.of("collection", "locations", "f", "geojson"); + ResponseEntity response = restTemplate.getForEntity(url, String.class, urlVariables); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.parseMediaType("application/geo+json")); + String expected = """ + { + "type":"FeatureCollection", + "numberMatched":16, + "numberReturned":2, + "features":[ + { + "type":"Feature", + "@typeName":"locations", + "@id":"1", + "geometry":{"type":"Point","@name":"geom","@srs":"EPSG:4326","coordinates":[11.116667,46.066667]}, + "properties":{"city":" Trento","number":140,"year":2002} + }, + { + "type":"Feature", + "@typeName":"locations", + "@id":"10", + "geometry":{"type":"Point","@name":"geom","@srs":"EPSG:4326","coordinates":[2.183333,41.383333]}, + "properties":{"city":" Barcelona","number":914,"year":2010} + } + ], + "links":[ + { + "href":"http://localhost:/ogcapi/collections/locations/items?f=geojson&offset=0&limit=2", + "rel":"self", + "type":"application/geo+json", + "title":"This document" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?f=geojson&offset=2&limit=2", + "rel":"next", + "type":"application/geo+json", + "title":"Next page" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=json", + "rel":"alternate", + "type":"application/json", + "title":"This document as JSON" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=shapefile", + "rel":"alternate", + "type":"application/x-shapefile", + "title":"This document as Esri Shapefile" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=csv", + "rel":"alternate", + "type":"text/csv;charset=UTF-8", + "title":"This document as Comma Separated Values" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=ooxml", + "rel":"alternate", + "type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "title":"This document as Excel 2007 / OOXML" + } + ] + } + """ + .replaceAll("", String.valueOf(port)); + + JSONAssert.assertEquals(expected, response.getBody(), false); + } + + @Test + void testGetItems_simplejson() throws JSONException { + final String url = itemsUrlTemplate + "&offset=0&limit=2"; + Map urlVariables = Map.of("collection", "locations", "f", "json"); + ResponseEntity response = restTemplate.getForEntity(url, String.class, urlVariables); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.parseMediaType("application/json")); + String expected = """ + { + "numberMatched":16, + "numberReturned":2, + "records":[ + { + "@id":"1", + "city":" Trento", + "number":140, + "year":2002 + }, + { + "@id":"10", + "city":" Barcelona", + "number":914, + "year":2010 + } + ], + "links":[ + { + "href":"http://localhost:/ogcapi/collections/locations/items?f=json&offset=0&limit=2", + "rel":"self", + "type":"application/json", + "title":"This document" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?f=json&offset=2&limit=2", + "rel":"next", + "type":"application/json", + "title":"Next page" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=geojson", + "rel":"alternate", + "type":"application/geo+json", + "title":"This document as GeoJSON" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=shapefile", + "rel":"alternate", + "type":"application/x-shapefile", + "title":"This document as Esri Shapefile" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=csv", + "rel":"alternate", + "type":"text/csv;charset=UTF-8", + "title":"This document as Comma Separated Values" + }, + { + "href":"http://localhost:/ogcapi/collections/locations/items?offset=0&limit=2&f=ooxml", + "rel":"alternate", + "type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "title":"This document as Excel 2007 / OOXML" + } + ] + } + """ + .replaceAll("", String.valueOf(port)); + + JSONAssert.assertEquals(expected, response.getBody(), false); + } +} diff --git a/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplPostgisIT.java b/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplPostgisTest.java similarity index 98% rename from src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplPostgisIT.java rename to src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplPostgisTest.java index c3f0eb3..cb742c3 100644 --- a/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplPostgisIT.java +++ b/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplPostgisTest.java @@ -48,7 +48,7 @@ @ActiveProfiles("postgis") @Testcontainers @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -class CollectionsApiImplPostgisIT extends AbstractCollectionsApiImplIT { +class CollectionsApiImplPostgisTest extends AbstractCollectionsApiImplTest { public static JdbcDatabaseContainer postgis; @@ -87,7 +87,7 @@ protected Comparator fidComparator() { } private static String copyInitScript(Path tmpdir) throws IOException { - URL resource = CollectionsApiImplPostgisIT.class.getResource("/test-data/postgis/opendataindex.sql"); + URL resource = CollectionsApiImplPostgisTest.class.getResource("/test-data/postgis/opendataindex.sql"); assertThat(resource).isNotNull(); Path target = tmpdir.resolve("pg-sample-data.sql"); diff --git a/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplTest.java b/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplTest.java index 7004a2d..ec66c49 100644 --- a/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplTest.java +++ b/src/services/ogc-features/src/test/java/com/camptocamp/opendata/ogc/features/server/impl/CollectionsApiImplTest.java @@ -17,7 +17,7 @@ @SpringBootTest(classes = OgcFeaturesApp.class) @ActiveProfiles("sample-data") -class CollectionsApiImplTest extends AbstractCollectionsApiImplIT { +class CollectionsApiImplTest extends AbstractCollectionsApiImplTest { @Override protected Comparator fidComparator() {