1

I'm currently working on a client application written in Java, using the org.geotools library in version 33.2 (released July 17th 2025) to request Features from a WFS layer. The code below establishes the WFS equivalent of a connection to the WFS service, and successfully retrieves the Capabilities of the server, and properly detects the name of the feature (stored in this.name)

 WFSDataAccessFactory accessFactory = new WFSDataAccessFactory();
 
 try {
 URL capabilitiesUrl = WFSDataStoreFactory.createGetCapabilitiesRequest(new URI(this.serverURL).toURL(), new Version("1.1.0"));
 
 Path temporaryFile = Files.createTempDirectory("cache");
 temporaryFile.toFile().deleteOnExit();
 
 java.util.Map<String,Object> connectionParameters = new HashMap<>();
 connectionParameters.put(WFSDataStoreFactory.URL.key, capabilitiesUrl);
 connectionParameters.put(WFSDataStoreFactory.TIMEOUT.key, 60000);
 connectionParameters.put(WFSDataStoreFactory.BUFFER_SIZE.key, 1000);
 connectionParameters.put(WFSDataStoreFactory.WFS_STRATEGY.key, "mapserver");
 connectionParameters.put(WFSDataStoreFactory.PROTOCOL.key, Boolean.FALSE);
 connectionParameters.put(WFSDataStoreFactory.SCHEMA_CACHE_LOCATION.key, temporaryFile.toString());
 dataStore.getFeatureSource(this.featureName);
 WFSContentDataAccess dataAccess = (WFSContentDataAccess) accessFactory.createDataStore(connectionParameters);
 
 for (Name name : dataAccess.getNames()) {
 LOGGER.info("Found Name {}...",name.getLocalPart());
 if (this.name.equals(name.getLocalPart())) {
 this.featureName = name;
 break;
 }
 }
 
 if (this.featureName == null) {
 LOGGER.error("WFS service at {} doesn't have a feature named {}!",this.serverURL,this.name);
 }
 
 this.wfs = (FeatureSource<T, F>) dataAccess.getFeatureSource(this.featureName);
 
 FeatureType schema = dataAccess.getSchema(this.featureName); 
 geometry = schema.getGeometryDescriptor().getName();
 LOGGER.info("Found Geometry {}...",geometry.toString()); 
 } catch (IOException exception) {
 LOGGER.error("Failed to connect to WFS service at {}",this.serverURL,exception);
 } catch (URISyntaxException exception) {
 LOGGER.error("Failed to extract URL for WFS service at {}",this.serverURL,exception);
 }

The returned feature source is an instance of WFSContentComplexFeatureSource. After the above code is run, I double-checked in the specified temp folder that the Schema is properly cached. I can also located the Schema of the sought feature.

 <?xml version='1.0' encoding="UTF-8" ?>
 <schema targetNamespace="http://mapserver.gis.umn.edu/mapserver" xmlns:ms="http://mapserver.gis.umn.edu/mapserver" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml"elementFormDefault="qualified" version="0.1" >
 <import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/gml.xsd" />
 <element name="beckerich_roads" 
 type="ms:beckerich_roadsType" 
 substitutionGroup="gml:_Feature" />
 <complexType name="beckerich_roadsType">
 <complexContent>
 <extension base="gml:AbstractFeatureType">
 <sequence>
 <element name="msGeometry" type="gml:GeometryPropertyType" minOccurs="0" maxOccurs="1"/>
 <element name="full_id" minOccurs="0" type="string"/>
 <element name="osm_id" minOccurs="0" type="string"/>
 <element name="osm_type" minOccurs="0" type="string"/>
 <element name="highway" minOccurs="0" type="string"/>
 <element name="name" minOccurs="0" type="string"/>
 <element name="surface" minOccurs="0" type="string"/>
 <element name="maxspeed" minOccurs="0" type="string"/>
 <element name="ref" minOccurs="0" type="string"/>
 </sequence>
 </extension>
 </complexContent>
 </complexType>
 </schema>

All this works as expected. Next, I'm trying to submit a query to the previously retrieved FeatureSource.

 Query query = new Query(this.featureName.getLocalPart());
 query.setPropertyNames(this.geometry.getLocalPart());
 FeatureCollection<T,F> results = this.wfs.getFeatures(query)
 
 LOGGER.info("{} Features found!",results.size()); 
 
 try (FeatureIterator<F> iterator = results.features()) {
 while (iterator.hasNext()) {
 Feature feature = iterator.next();
 ... Do something with the feature ...
 }
 }

The request fails as soon as I'm trying to do something with the returned FeatureCollection.

Aug 01, 2025 3:16:43 PM org.geotools.data.ows.AbstractOpenWebService internalIssueRequest
SEVERE: Failed to execute request https://mapserver.domain.org/service?PROPERTYNAME=%28msGeometry%29&TYPENAME=ms%3Abeckerich_roads&REQUEST=GetFeature&RESULTTYPE=RESULTS&OUTPUTFORMAT=text%2Fxml%3B+subtype%3Dgml%2F3.1.1&VERSION=1.1.0&SERVICE=WFS
Exception in thread "AWT-EventQueue-0" java.lang.UnsupportedOperationException
at org.geotools.data.wfs.internal.parsers.GmlGetFeatureResponseParserFactory.parser(GmlGetFeatureResponseParserFactory.java:78)
at org.geotools.data.wfs.internal.parsers.AbstractGetFeatureResponseParserFactory.createResponseImpl(AbstractGetFeatureResponseParserFactory.java:82)
at org.geotools.data.wfs.internal.parsers.AbstractWFSResponseFactory.createResponse(AbstractWFSResponseFactory.java:110)
at org.geotools.data.wfs.internal.WFSRequest.createResponse(WFSRequest.java:209)
at org.geotools.data.wfs.internal.WFSRequest.createResponse(WFSRequest.java:36)
at org.geotools.data.ows.AbstractOpenWebService.internalIssueRequest(AbstractOpenWebService.java:447)
at org.geotools.data.wfs.internal.WFSClient.internalIssueRequest(WFSClient.java:322)
at org.geotools.data.wfs.internal.WFSClient.issueComplexRequest(WFSClient.java:371)
at org.geotools.data.wfs.internal.WFSContentComplexFeatureCollection.features(WFSContentComplexFeatureCollection.java:73)
...

However, if I paste request into a browser, I'm actually getting the requested features:

<?xml version='1.0' encoding="UTF-8" ?>
 <wfs:FeatureCollection
 xmlns:ms="http://mapserver.gis.umn.edu/mapserver"
 xmlns:gml="http://www.opengis.net/gml"
 xmlns:wfs="http://www.opengis.net/wfs"
 xmlns:ogc="http://www.opengis.net/ogc"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver https://mapserver.domain.org/service?SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=ms:beckerich_roads&amp;OUTPUTFORMAT=SFE_XMLSCHEMA http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
 <gml:boundedBy>
 <gml:Envelope srsName="EPSG:2169">
 <gml:lowerCorner>83339.896453 54689.578935</gml:lowerCorner>
 <gml:upperCorner>94377.106739 65551.221427</gml:upperCorner>
 </gml:Envelope>
 </gml:boundedBy>
 <gml:featureMember>
 <ms:beckerich_roads>
 <gml:boundedBy>
 <gml:Envelope srsName="EPSG:2169">
 <gml:lowerCorner>88388.223655 56535.597859</gml:lowerCorner>
 <gml:upperCorner>88389.234600 56553.900902</gml:upperCorner>
 </gml:Envelope>
 </gml:boundedBy>
 <ms:msGeometry>
 <gml:LineString srsName="EPSG:2169">
 <gml:posList srsDimension="2">88389.234600 56553.900902 88388.233812 56543.543192 88388.223655 56535.597859 </gml:posList>
 </gml:LineString>
 </ms:msGeometry>
 </ms:beckerich_roads>

Looking into the source code of the GmlGetFeatureResponseParserFactory it seems that it's only capable of handling SimpleFeatures. I've explicitly added the gt-complex library, thinking that maybe that's allowing the retrieval of complex features, but it doesn't. So my question, is there a way or a config to let the FeatureSource know how to process complex features?

Vince
20.5k16 gold badges49 silver badges65 bronze badges
asked Aug 1 at 13:32

2 Answers 2

0

From a quick google and from a very old memory I found this PR which was merged in 2015. I think you will need to add the gt-app-schema module, there's some fairly comprehensive documentation to help you get started. As far as I recall you use it to replace your WFS store.

answered Aug 1 at 15:46
2
  • Hi Ian, first of thank you for getting back to me. I already hade the gt-app-schema module added, however, thanks to your link I realized that I had to replace the WFSDataAccessFactory with the AppSchemaDataAccessFactory, respectively my WFSContentDataAccess instance by AppSchemaDataAccess. The only part I still haven't figured out is what to use as the URL for the AppSchemaDataAccess connection parameters. I tried saving the XML returned by the DescribeFeatureType request, however, this doesn't seem correct. Commented Aug 4 at 12:53
  • Just for your information, the server I'm submitting the requests to is a MapServer, not a GeoServer instance. Commented Aug 4 at 13:06
0

I returned to my initial issue after some time, and I finally figured out the missing pieces. The missing part in my previous attempts was the GET_CAPABILITIES_URL parameter, which I had to add as a literal, because it wasn't available as a key. I realized this while debugging. As soon as I added this parameter, the retrieval of complex features worked as expected. Hope this helps if somebody else stumbles over this issue.

 URL capabilitiesUrl = WFSDataStoreFactory.createGetCapabilitiesRequest(new URI(this.serverURL).toURL(), new Version("1.1.0"));
 
 java.util.Map<String,Object> connectionParameters = new HashMap<>();
 connectionParameters.put("WFSDataStoreFactory:GET_CAPABILITIES_URL", capabilitiesUrl);
 connectionParameters.put(AppSchemaDataAccessFactory.DBTYPE.key, "app-schema");
 
 DataAccess<FeatureType, Feature> dataAccess = DataAccessFinder.getDataStore(connectionParameters);
 
 for (Name name : dataAccess.getNames()) {
 LOGGER.info("Found Name {}...",name.getLocalPart());
 if (this.name.equals(name.getLocalPart())) {
 this.featureName = name;
 break;
 }
 }
 
 if (this.featureName == null) {
 LOGGER.error("WFS service at {} doesn't have a feature named {}!",this.serverURL,this.name);
 }
 
 this.wfs = (FeatureSource<T, F>) dataAccess.getFeatureSource(this.featureName);
 
 FeatureType schema = dataAccess.getSchema(this.featureName); 
 geometry = schema.getGeometryDescriptor().getName();
answered Sep 4 at 10:33

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.