Skip to content

Commit 1b52e1f

Browse files
authored
Spring 7 and Jackson 3 update (#1467)
1 parent a87e5a4 commit 1b52e1f

25 files changed

Lines changed: 436 additions & 258 deletions

File tree

geowebcache/core/pom.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,18 @@
145145
</dependency>
146146

147147
<dependency>
148-
<groupId>com.fasterxml.jackson.core</groupId>
148+
<groupId>tools.jackson.core</groupId>
149149
<artifactId>jackson-databind</artifactId>
150+
<version>3.0.2</version>
150151
</dependency>
151152
<dependency>
152153
<groupId>com.fasterxml.jackson.core</groupId>
153154
<artifactId>jackson-annotations</artifactId>
154155
</dependency>
155156
<dependency>
156-
<groupId>com.fasterxml.jackson.core</groupId>
157+
<groupId>tools.jackson.core</groupId>
157158
<artifactId>jackson-core</artifactId>
159+
<version>3.0.2</version>
158160
</dependency>
159161
<dependency>
160162
<groupId>org.apache.httpcomponents.client5</groupId>

geowebcache/core/src/main/java/org/geowebcache/config/XMLFileResourceProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
import org.geowebcache.storage.DefaultStorageFinder;
3333
import org.geowebcache.util.ApplicationContextProvider;
3434
import org.geowebcache.util.GWCVars;
35+
import org.jspecify.annotations.NonNull;
3536
import org.springframework.context.ApplicationContext;
36-
import org.springframework.lang.NonNull;
3737
import org.springframework.web.context.WebApplicationContext;
3838

3939
/** Default implementation of ConfigurationResourceProvider that uses the file system. */

geowebcache/diskquota/jdbc/src/main/java/org/geowebcache/diskquota/jdbc/JDBCQuotaStore.java

Lines changed: 172 additions & 208 deletions
Large diffs are not rendered by default.

geowebcache/mbtiles/src/main/java/org/geowebcache/mbtiles/layer/MBTilesInfo.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
import static org.geotools.mbtiles.MBTilesFile.SPHERICAL_MERCATOR;
1717
import static org.geotools.mbtiles.MBTilesFile.WORLD_ENVELOPE;
1818

19-
import com.fasterxml.jackson.core.JsonProcessingException;
20-
import com.fasterxml.jackson.core.type.TypeReference;
21-
import com.fasterxml.jackson.databind.ObjectMapper;
2219
import java.io.IOException;
2320
import java.util.List;
2421
import java.util.logging.Level;
@@ -35,6 +32,9 @@
3532
import org.geowebcache.grid.BoundingBox;
3633
import org.geowebcache.layer.meta.TileJSON;
3734
import org.geowebcache.layer.meta.VectorLayerMetadata;
35+
import tools.jackson.core.JacksonException;
36+
import tools.jackson.core.type.TypeReference;
37+
import tools.jackson.databind.ObjectMapper;
3838

3939
/** Info Object storing basic MBTiles Cached info */
4040
public class MBTilesInfo {
@@ -146,15 +146,20 @@ public void decorateTileJSON(TileJSON tileJSON) {
146146
int index = -1;
147147
if (json != null && ((index = json.indexOf("[")) > 0)) {
148148
// skip the "vector_layers initial part and go straight to the array
149-
json = json.substring(index, json.length() - 1).trim();
150-
ObjectMapper mapper = new ObjectMapper();
151-
List<VectorLayerMetadata> layers = null;
152-
try {
153-
layers = mapper.readValue(json, new TypeReference<>() {});
154-
} catch (JsonProcessingException e) {
155-
throw new IllegalArgumentException("Exception occurred while parsing the layers metadata. " + e);
149+
// Find the closing bracket for the array
150+
int endIndex = json.indexOf("]", index);
151+
if (endIndex > 0) {
152+
json = json.substring(index, endIndex + 1).trim();
153+
ObjectMapper mapper = new ObjectMapper();
154+
List<VectorLayerMetadata> layers = null;
155+
try {
156+
layers = mapper.readValue(json, new TypeReference<>() {});
157+
} catch (JacksonException e) {
158+
throw new IllegalArgumentException(
159+
"Exception occurred while parsing the layers metadata. " + e);
160+
}
161+
tileJSON.setLayers(layers);
156162
}
157-
tileJSON.setLayers(layers);
158163
}
159164
}
160165
}

geowebcache/pom.xml

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@
5353

5454
<properties>
5555
<gt.version>35-SNAPSHOT</gt.version>
56-
<spring.version>6.2.12</spring.version>
57-
<spring.security.version>6.5.5</spring.security.version>
56+
<spring.version>7.0.2</spring.version>
57+
<spring.security.version>7.0.2</spring.security.version>
5858
<xstream.version>1.4.21</xstream.version>
5959
<commons-codec.version>1.18.0</commons-codec.version>
6060
<commons-fileupload.version>2.0.0-M4</commons-fileupload.version>
@@ -254,7 +254,6 @@
254254
<artifactId>joda-time</artifactId>
255255
<version>${joda-time.version}</version>
256256
</dependency>
257-
258257
<!-- Jackson dependencies managed by platform-dependencies BOM -->
259258
<dependency>
260259
<!-- used for tests that require environment variables -->
@@ -264,13 +263,6 @@
264263
<scope>test</scope>
265264
</dependency>
266265

267-
<!-- to be moved to GeoTools once it's upgraded to httpclient 5.x -->
268-
<dependency>
269-
<groupId>org.apache.httpcomponents.client5</groupId>
270-
<artifactId>httpclient5</artifactId>
271-
<version>5.4.4</version>
272-
</dependency>
273-
274266
</dependencies>
275267
</dependencyManagement>
276268

@@ -336,7 +328,7 @@
336328
<plugins>
337329
<plugin>
338330
<artifactId>maven-failsafe-plugin</artifactId>
339-
<version>3.5.3</version>
331+
<version>3.5.4</version>
340332
<executions>
341333
<execution>
342334
<goals>
@@ -387,7 +379,7 @@
387379

388380
<plugin>
389381
<artifactId>maven-surefire-plugin</artifactId>
390-
<version>3.5.3</version>
382+
<version>3.5.4</version>
391383
</plugin>
392384

393385
<plugin>

geowebcache/rest/pom.xml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@
2929
<groupId>com.google.guava</groupId>
3030
<artifactId>guava</artifactId>
3131
</dependency>
32-
<dependency>
33-
<groupId>jakarta.servlet</groupId>
34-
<artifactId>jakarta.servlet-api</artifactId>
35-
</dependency>
3632

3733
<!-- test dependencies -->
3834
<dependency>

geowebcache/rest/src/main/java/org/geowebcache/rest/controller/SeedController.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,22 @@ public class SeedController {
6262

6363
/** GET method for querying running GWC tasks */
6464
@RequestMapping(
65-
value = "/seed.json",
65+
value = "/seed",
6666
method = RequestMethod.GET,
6767
produces = {MediaType.APPLICATION_JSON_VALUE})
6868
public ResponseEntity<?> doGet(HttpServletRequest req) {
6969
return seedService.getRunningTasks(req);
7070
}
7171

72+
/** GET method for querying running GWC tasks with path extension */
73+
@RequestMapping(
74+
value = "/seed.json",
75+
method = RequestMethod.GET,
76+
produces = {MediaType.APPLICATION_JSON_VALUE})
77+
public ResponseEntity<?> doGetJson(HttpServletRequest req) {
78+
return seedService.getRunningTasks(req);
79+
}
80+
7281
/** GET method for querying running tasks for the provided layer */
7382
@RequestMapping(
7483
value = "/seed/{layer:.+}.json",
@@ -106,7 +115,7 @@ public ResponseEntity doPost(HttpServletRequest request) {
106115
}
107116

108117
/**
109-
* POST method for Seeding and Truncating
118+
* POST method for Seeding and Truncating via form submission
110119
*
111120
* @param params Query parameters, including urlencoded form values
112121
*/
@@ -133,6 +142,7 @@ public ResponseEntity<?> doPost(
133142
}
134143
}
135144

145+
/** POST method for JSON seeding/truncating with path extension. */
136146
@RequestMapping(value = "/seed/{layer}.json", method = RequestMethod.POST)
137147
public ResponseEntity<?> seedOrTruncateWithJsonPayload(
138148
HttpServletRequest request, InputStream inputStream, @PathVariable(name = "layer") String layerName) {
@@ -142,6 +152,7 @@ public ResponseEntity<?> seedOrTruncateWithJsonPayload(
142152
return seedService.doSeeding(request, layerName, extension, body);
143153
}
144154

155+
/** POST method for XML seeding/truncating with path extension. */
145156
@RequestMapping(value = "/seed/{layer}.xml", method = RequestMethod.POST)
146157
public ResponseEntity<?> seedOrTruncateWithXmlPayload(
147158
HttpServletRequest request, InputStream inputStream, @PathVariable(name = "layer") String layerName) {
@@ -151,6 +162,32 @@ public ResponseEntity<?> seedOrTruncateWithXmlPayload(
151162
return seedService.doSeeding(request, layerName, extension, body);
152163
}
153164

165+
/** POST method for JSON seeding/truncating without path extension. */
166+
@RequestMapping(
167+
value = "/seed/{layer:[^.]+}",
168+
method = RequestMethod.POST,
169+
consumes = {MediaType.APPLICATION_JSON_VALUE})
170+
public ResponseEntity<?> seedOrTruncateJson(
171+
HttpServletRequest request, InputStream inputStream, @PathVariable(name = "layer") String layerName) {
172+
173+
String body = readBody(inputStream);
174+
String extension = "json";
175+
return seedService.doSeeding(request, layerName, extension, body);
176+
}
177+
178+
/** POST method for XML seeding/truncating without path extension. */
179+
@RequestMapping(
180+
value = "/seed/{layer:[^.]+}",
181+
method = RequestMethod.POST,
182+
consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE})
183+
public ResponseEntity<?> seedOrTruncateXml(
184+
HttpServletRequest request, InputStream inputStream, @PathVariable(name = "layer") String layerName) {
185+
186+
String body = readBody(inputStream);
187+
String extension = "xml";
188+
return seedService.doSeeding(request, layerName, extension, body);
189+
}
190+
154191
private String readBody(InputStream inputStream) {
155192
return new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining("\n"));
156193
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
3+
* Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
4+
* later version.
5+
*
6+
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
7+
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8+
*
9+
* <p>You should have received a copy of the GNU Lesser General Public License along with this program. If not, see
10+
* <http://www.gnu.org/licenses/>.
11+
*
12+
* @author Cécile Vuilleumier, Camptocamp, Copyright 2026
13+
*/
14+
package org.geowebcache.rest.filter;
15+
16+
import jakarta.servlet.Filter;
17+
import jakarta.servlet.FilterChain;
18+
import jakarta.servlet.ServletException;
19+
import jakarta.servlet.ServletRequest;
20+
import jakarta.servlet.ServletResponse;
21+
import jakarta.servlet.http.HttpServletRequest;
22+
import jakarta.servlet.http.HttpServletRequestWrapper;
23+
import java.io.IOException;
24+
import java.util.regex.Matcher;
25+
import java.util.regex.Pattern;
26+
27+
/**
28+
* Servlet filter for GeoWebCache
29+
*
30+
* <p>Extracts the path suffix (extension) and stores it for content negotiation. Removes the extension from the path
31+
* for path mapping.
32+
*/
33+
public class SuffixStripFilter implements Filter {
34+
35+
private static final Pattern EXTENSION_PATTERN = Pattern.compile("^(.*?)\\.(json|xml)$");
36+
37+
public static final String FORMAT_ATTRIBUTE = "gwc.formatExtension";
38+
39+
@Override
40+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
41+
throws IOException, ServletException {
42+
43+
if (request instanceof HttpServletRequest httpRequest) {
44+
String requestURI = httpRequest.getRequestURI();
45+
Matcher matcher = EXTENSION_PATTERN.matcher(requestURI);
46+
47+
if (matcher.matches()) {
48+
String pathWithoutExtension = matcher.group(1);
49+
String extension = matcher.group(2);
50+
51+
// Wrap the request to return modified paths
52+
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(httpRequest) {
53+
@Override
54+
public String getRequestURI() {
55+
return pathWithoutExtension;
56+
}
57+
58+
@Override
59+
public StringBuffer getRequestURL() {
60+
StringBuffer url =
61+
new StringBuffer(super.getRequestURL().toString());
62+
int extIndex = url.lastIndexOf("." + extension);
63+
if (extIndex > 0) {
64+
url.delete(extIndex, url.length());
65+
}
66+
return url;
67+
}
68+
69+
@Override
70+
public String getServletPath() {
71+
String servletPath = super.getServletPath();
72+
return servletPath.replaceFirst("\\." + extension + "$", "");
73+
}
74+
};
75+
76+
// Store extension for content negotiation
77+
wrapper.setAttribute(FORMAT_ATTRIBUTE, extension);
78+
79+
chain.doFilter(wrapper, response);
80+
return;
81+
}
82+
}
83+
84+
// No extension found, pass through unchanged
85+
chain.doFilter(request, response);
86+
}
87+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
3+
* Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
4+
* later version.
5+
*
6+
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
7+
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8+
*
9+
* <p>You should have received a copy of the GNU Lesser General Public License along with this program. If not, see
10+
* <http://www.gnu.org/licenses/>.
11+
*
12+
* @author Cécile Vuilleumier, Camptocamp, Copyright 2026
13+
*/
14+
package org.geowebcache.rest.negotiation;
15+
16+
import jakarta.servlet.http.HttpServletRequest;
17+
import java.util.Collections;
18+
import java.util.List;
19+
import org.springframework.http.MediaType;
20+
import org.springframework.web.accept.ContentNegotiationStrategy;
21+
import org.springframework.web.context.request.NativeWebRequest;
22+
23+
/**
24+
* Spring ContentNegotiationStrategy for GeoWebCache
25+
*
26+
* <p>Reads the media type stored by {@link org.geowebcache.rest.filter.SuffixStripFilter}
27+
*/
28+
public class SuffixContentNegotiationStrategy implements ContentNegotiationStrategy {
29+
30+
List<MediaType> MEDIA_TYPE_ALL_LIST = Collections.singletonList(MediaType.ALL);
31+
32+
public static final String FORMAT_ATTRIBUTE = "gwc.formatExtension";
33+
34+
@Override
35+
public List<MediaType> resolveMediaTypes(NativeWebRequest request) {
36+
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
37+
if (servletRequest == null) {
38+
return MEDIA_TYPE_ALL_LIST;
39+
}
40+
// Check if filter stored the extension
41+
String extension = (String) servletRequest.getAttribute(FORMAT_ATTRIBUTE);
42+
43+
if (extension != null) {
44+
if ("json".equals(extension)) {
45+
return Collections.singletonList(MediaType.APPLICATION_JSON);
46+
} else if ("xml".equals(extension)) {
47+
return Collections.singletonList(MediaType.APPLICATION_XML);
48+
}
49+
}
50+
return MEDIA_TYPE_ALL_LIST;
51+
}
52+
}

geowebcache/rest/src/test/java/org/geowebcache/rest/bounds/BoundsControllerTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.test.web.servlet.MockMvc;
3939
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
4040

41+
@SuppressWarnings("deprecation")
4142
@RunWith(SpringJUnit4ClassRunner.class)
4243
@ContextConfiguration({"file*:/webapp/WEB-INF/web.xml", "file*:/webapp/WEB-INF/geowebcache-servlet.xml"})
4344
public class BoundsControllerTest {

0 commit comments

Comments
 (0)