This is an automated email from the ASF dual-hosted git repository.

bchapuis pushed a commit to branch armeria
in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git

commit e94b62adfa0b7889f2f0d9e2cd2af971668a9b66
Author: Bertil Chapuis <[email protected]>
AuthorDate: Sun Jan 14 23:44:09 2024 +0100

    Use armeria for all commands and remove service talk
---
 baremaps-cli/pom.xml                               |  20 ----
 .../org/apache/baremaps/cli/geocoder/Serve.java    |  60 ++++++-----
 .../java/org/apache/baremaps/cli/iploc/Serve.java  |  62 +++++++-----
 .../main/java/org/apache/baremaps/cli/map/Dev.java |  48 ++++-----
 .../java/org/apache/baremaps/cli/map/MBTiles.java  |  72 ++++++-------
 .../main/java/org/apache/baremaps/cli/map/Map.java |   3 +-
 .../java/org/apache/baremaps/cli/map/Serve.java    |  79 +++++++--------
 .../org/apache/baremaps/cli/map/StyleCommand.java  | 111 ---------------------
 baremaps-server/pom.xml                            |  44 --------
 .../baremaps/server/BaseUriRequestFilter.java      |  52 ----------
 .../apache/baremaps/server/ClassPathResource.java  |  74 --------------
 .../org/apache/baremaps/server/CorsFilter.java     |  84 ----------------
 .../apache/baremaps/server/GeocoderResource.java   |  54 +++++-----
 .../org/apache/baremaps/server/IpLocResource.java  |  73 +++++++-------
 .../org/apache/baremaps/server/SearchResource.java |  32 +++---
 .../BaseUriRequestFilterIntegrationTest.java       |  54 ----------
 .../server/ClassPathResourceIntegrationTest.java   |  53 ----------
 pom.xml                                            |  89 ++---------------
 18 files changed, 255 insertions(+), 809 deletions(-)

diff --git a/baremaps-cli/pom.xml b/baremaps-cli/pom.xml
index bb1e853a..b9ebf99b 100644
--- a/baremaps-cli/pom.xml
+++ b/baremaps-cli/pom.xml
@@ -39,26 +39,6 @@ limitations under the License.
       <groupId>info.picocli</groupId>
       <artifactId>picocli</artifactId>
     </dependency>
-    <dependency>
-      <groupId>io.servicetalk</groupId>
-      <artifactId>servicetalk-data-jackson</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.servicetalk</groupId>
-      <artifactId>servicetalk-data-jackson-jersey</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.servicetalk</groupId>
-      <artifactId>servicetalk-http-netty</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.servicetalk</groupId>
-      <artifactId>servicetalk-http-router-jersey</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.servicetalk</groupId>
-      <artifactId>servicetalk-transport-netty</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.apache.baremaps</groupId>
       <artifactId>baremaps-core</artifactId>
diff --git 
a/baremaps-cli/src/main/java/org/apache/baremaps/cli/geocoder/Serve.java 
b/baremaps-cli/src/main/java/org/apache/baremaps/cli/geocoder/Serve.java
index bdbf84cc..def8831e 100644
--- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/geocoder/Serve.java
+++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/geocoder/Serve.java
@@ -18,19 +18,21 @@
 package org.apache.baremaps.cli.geocoder;
 
 
+import static org.apache.baremaps.utils.ObjectMapperUtils.objectMapper;
 
-import io.servicetalk.http.netty.HttpServers;
-import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder;
+import com.linecorp.armeria.common.HttpHeaderNames;
+import com.linecorp.armeria.common.HttpMethod;
+import com.linecorp.armeria.server.Server;
+import com.linecorp.armeria.server.annotation.JacksonResponseConverterFunction;
+import com.linecorp.armeria.server.cors.CorsService;
+import com.linecorp.armeria.server.file.FileService;
+import com.linecorp.armeria.server.file.HttpFile;
 import java.nio.file.Path;
 import java.util.concurrent.Callable;
-import org.apache.baremaps.server.ClassPathResource;
-import org.apache.baremaps.server.CorsFilter;
 import org.apache.baremaps.server.GeocoderResource;
 import org.apache.lucene.search.SearcherFactory;
 import org.apache.lucene.search.SearcherManager;
 import org.apache.lucene.store.MMapDirectory;
-import org.glassfish.hk2.utilities.binding.AbstractBinder;
-import org.glassfish.jersey.server.ResourceConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import picocli.CommandLine.Command;
@@ -54,28 +56,38 @@ public class Serve implements Callable<Integer> {
 
   @Override
   public Integer call() throws Exception {
+
     try (
         var directory = MMapDirectory.open(indexDirectory);
         var searcherManager = new SearcherManager(directory, new 
SearcherFactory())) {
 
-      var application = new ResourceConfig()
-          .register(CorsFilter.class)
-          .register(GeocoderResource.class)
-          .register(ClassPathResource.class)
-          .register(new AbstractBinder() {
-            @Override
-            protected void configure() {
-              bind("geocoder").to(String.class).named("directory");
-              bind("index.html").to(String.class).named("index");
-              
bind(searcherManager).to(SearcherManager.class).named("searcherManager");
-            }
-          });
-
-      var httpService = new 
HttpJerseyRouterBuilder().buildBlockingStreaming(application);
-      var serverContext = 
HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService);
-
-      logger.info("Listening on {}", serverContext.listenAddress());
-      serverContext.awaitShutdown();
+      var serverBuilder = Server.builder();
+      serverBuilder.http(port);
+
+      var objectMapper = objectMapper();
+      var jsonResponseConverter = new 
JacksonResponseConverterFunction(objectMapper);
+      serverBuilder.annotatedService(new GeocoderResource(searcherManager), 
jsonResponseConverter);
+
+      var index = HttpFile.of(ClassLoader.getSystemClassLoader(), 
"/geocoder/index.html");
+      serverBuilder.service("/", index.asService());
+      serverBuilder.serviceUnder("/",
+          FileService.of(ClassLoader.getSystemClassLoader(), "/geocoder"));
+
+      serverBuilder.decorator(CorsService.builderForAnyOrigin()
+          .allowRequestMethods(HttpMethod.GET, HttpMethod.POST, 
HttpMethod.PUT, HttpMethod.DELETE,
+              HttpMethod.OPTIONS, HttpMethod.HEAD)
+          .allowRequestHeaders(HttpHeaderNames.ORIGIN, 
HttpHeaderNames.CONTENT_TYPE,
+              HttpHeaderNames.ACCEPT, HttpHeaderNames.AUTHORIZATION)
+          .allowCredentials()
+          .exposeHeaders(HttpHeaderNames.LOCATION)
+          .newDecorator());
+
+      serverBuilder.disableServerHeader();
+      serverBuilder.disableDateHeader();
+
+      var server = serverBuilder.build();
+      var future = server.start();
+      future.join();
     }
 
     return 0;
diff --git 
a/baremaps-cli/src/main/java/org/apache/baremaps/cli/iploc/Serve.java 
b/baremaps-cli/src/main/java/org/apache/baremaps/cli/iploc/Serve.java
index 4669cb04..eb2716f0 100644
--- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/iploc/Serve.java
+++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/iploc/Serve.java
@@ -18,20 +18,22 @@
 package org.apache.baremaps.cli.iploc;
 
 
-
+import static org.apache.baremaps.utils.ObjectMapperUtils.objectMapper;
+
+import com.linecorp.armeria.common.HttpHeaderNames;
+import com.linecorp.armeria.common.HttpMethod;
+import com.linecorp.armeria.server.Server;
+import com.linecorp.armeria.server.annotation.JacksonResponseConverterFunction;
+import com.linecorp.armeria.server.cors.CorsService;
+import com.linecorp.armeria.server.file.FileService;
+import com.linecorp.armeria.server.file.HttpFile;
 import com.zaxxer.hikari.HikariConfig;
 import com.zaxxer.hikari.HikariDataSource;
-import io.servicetalk.http.netty.HttpServers;
-import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder;
 import java.nio.file.Path;
 import java.util.concurrent.Callable;
 import javax.sql.DataSource;
 import org.apache.baremaps.iploc.IpLocRepository;
-import org.apache.baremaps.server.ClassPathResource;
-import org.apache.baremaps.server.CorsFilter;
 import org.apache.baremaps.server.IpLocResource;
-import org.glassfish.hk2.utilities.binding.AbstractBinder;
-import org.glassfish.jersey.server.ResourceConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import picocli.CommandLine.Command;
@@ -66,25 +68,33 @@ public class Serve implements Callable<Integer> {
 
     IpLocRepository ipLocRepository = new IpLocRepository(dataSource);
 
-    var application = new ResourceConfig()
-        .register(CorsFilter.class)
-        .register(IpLocResource.class)
-        .register(ClassPathResource.class)
-        .register(new AbstractBinder() {
-          @Override
-          protected void configure() {
-            bind("iploc").to(String.class).named("directory");
-            bind("index.html").to(String.class).named("index");
-            
bind(ipLocRepository).to(IpLocRepository.class).named("iplocRepository");
-          }
-        });
-
-    var httpService = new 
HttpJerseyRouterBuilder().buildBlockingStreaming(application);
-    var serverContext = 
HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService);
-
-    logger.info("Listening on {}", serverContext.listenAddress());
-
-    serverContext.awaitShutdown();
+    var serverBuilder = Server.builder();
+    serverBuilder.http(port);
+
+    var objectMapper = objectMapper();
+    var jsonResponseConverter = new 
JacksonResponseConverterFunction(objectMapper);
+    serverBuilder.annotatedService(new IpLocResource(ipLocRepository), 
jsonResponseConverter);
+
+    var index = HttpFile.of(ClassLoader.getSystemClassLoader(), 
"/iploc/index.html");
+    serverBuilder.service("/", index.asService());
+    serverBuilder.serviceUnder("/", 
FileService.of(ClassLoader.getSystemClassLoader(), "/iploc"));
+
+    serverBuilder.decorator(CorsService.builderForAnyOrigin()
+        .allowRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, 
HttpMethod.DELETE,
+            HttpMethod.OPTIONS, HttpMethod.HEAD)
+        .allowRequestHeaders(HttpHeaderNames.ORIGIN, 
HttpHeaderNames.CONTENT_TYPE,
+            HttpHeaderNames.ACCEPT, HttpHeaderNames.AUTHORIZATION)
+        .allowCredentials()
+        .exposeHeaders(HttpHeaderNames.LOCATION)
+        .newDecorator());
+
+    serverBuilder.disableServerHeader();
+    serverBuilder.disableDateHeader();
+
+    var server = serverBuilder.build();
+    var future = server.start();
+    future.join();
+
     return 0;
   }
 }
diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Dev.java 
b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Dev.java
index f335ab6b..03342506 100644
--- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Dev.java
+++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Dev.java
@@ -24,22 +24,23 @@ import com.linecorp.armeria.server.Server;
 import com.linecorp.armeria.server.annotation.JacksonResponseConverterFunction;
 import com.linecorp.armeria.server.cors.CorsService;
 import com.linecorp.armeria.server.file.FileService;
+import com.linecorp.armeria.server.file.HttpFile;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Supplier;
-
-import com.linecorp.armeria.server.file.HttpFile;
 import org.apache.baremaps.cli.Options;
 import org.apache.baremaps.config.ConfigReader;
-import org.apache.baremaps.server.*;
+import org.apache.baremaps.server.ChangeResource;
+import org.apache.baremaps.server.StyleResource;
+import org.apache.baremaps.server.TileResource;
+import org.apache.baremaps.server.TilesetResource;
 import org.apache.baremaps.tilestore.TileStore;
 import org.apache.baremaps.tilestore.postgres.PostgresTileStore;
 import org.apache.baremaps.utils.PostgresUtils;
 import org.apache.baremaps.vectortile.style.Style;
 import org.apache.baremaps.vectortile.tileset.Tileset;
-import org.glassfish.hk2.api.TypeLiteral;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import picocli.CommandLine.Command;
@@ -78,18 +79,20 @@ public class Dev implements Callable<Integer> {
     var tileset = objectMapper.readValue(configReader.read(this.tilesetPath), 
Tileset.class);
     var datasource = 
PostgresUtils.createDataSourceFromObject(tileset.getDatabase());
 
-    var tileStoreType = new TypeLiteral<Supplier<TileStore>>() {};
-    var tileStoreSupplier = (Supplier<TileStore>) () -> {
+    var tilesetSupplier = (Supplier<Tileset>) () -> {
       try {
-        var config = configReader.read(this.tilesetPath);
-        var tilesetObject =
-            objectMapper.readValue(config, Tileset.class);
-        return new PostgresTileStore(datasource, tilesetObject);
+        var config = configReader.read(tilesetPath);
+        return objectMapper.readValue(config, Tileset.class);
       } catch (IOException e) {
         throw new RuntimeException(e);
       }
     };
 
+    var tileStoreSupplier = (Supplier<TileStore>) () -> {
+      var tileJSON = tilesetSupplier.get();
+      return new PostgresTileStore(datasource, tileJSON);
+    };
+
     var styleSupplier = (Supplier<Style>) () -> {
       try {
         var config = configReader.read(stylePath);
@@ -99,33 +102,26 @@ public class Dev implements Callable<Integer> {
       }
     };
 
-    var tileJSONSupplier = (Supplier<Tileset>) () -> {
-      try {
-        var config = configReader.read(tilesetPath);
-        return objectMapper.readValue(config, Tileset.class);
-      } catch (IOException e) {
-        throw new RuntimeException(e);
-      }
-    };
-
     var serverBuilder = Server.builder();
     serverBuilder.http(port);
 
-    JacksonResponseConverterFunction jsonResponseConverter = new 
JacksonResponseConverterFunction(objectMapper);
-    serverBuilder.annotatedService(new ChangeResource(tilesetPath, stylePath), 
jsonResponseConverter);
+    JacksonResponseConverterFunction jsonResponseConverter =
+        new JacksonResponseConverterFunction(objectMapper);
+    serverBuilder.annotatedService(new ChangeResource(tilesetPath, stylePath),
+        jsonResponseConverter);
     serverBuilder.annotatedService(new TileResource(tileStoreSupplier), 
jsonResponseConverter);
     serverBuilder.annotatedService(new StyleResource(styleSupplier), 
jsonResponseConverter);
-    serverBuilder.annotatedService(new TilesetResource(tileJSONSupplier), 
jsonResponseConverter);
+    serverBuilder.annotatedService(new TilesetResource(tilesetSupplier), 
jsonResponseConverter);
 
     HttpFile index = HttpFile.of(ClassLoader.getSystemClassLoader(), 
"/assets/viewer.html");
     serverBuilder.service("/", index.asService());
     serverBuilder.serviceUnder("/", 
FileService.of(ClassLoader.getSystemClassLoader(), "/assets"));
 
     serverBuilder.decorator(CorsService.builderForAnyOrigin()
-          .allowRequestMethods(HttpMethod.POST, HttpMethod.GET, HttpMethod.PUT)
-          .allowRequestHeaders("Origin", "Content-Type", "Accept")
-          .newDecorator());
-    
+        .allowRequestMethods(HttpMethod.POST, HttpMethod.GET, HttpMethod.PUT)
+        .allowRequestHeaders("Origin", "Content-Type", "Accept")
+        .newDecorator());
+
     serverBuilder.disableServerHeader();
     serverBuilder.disableDateHeader();
 
diff --git 
a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/MBTiles.java 
b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/MBTiles.java
index 72e06639..487e8a0c 100644
--- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/MBTiles.java
+++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/MBTiles.java
@@ -17,14 +17,19 @@
 
 package org.apache.baremaps.cli.map;
 
-import static 
io.servicetalk.data.jackson.jersey.ServiceTalkJacksonSerializerFeature.newContextResolver;
 import static org.apache.baremaps.utils.ObjectMapperUtils.objectMapper;
 
 import com.github.benmanes.caffeine.cache.CaffeineSpec;
-import io.servicetalk.http.netty.HttpServers;
-import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder;
+import com.linecorp.armeria.common.HttpHeaderNames;
+import com.linecorp.armeria.common.HttpMethod;
+import com.linecorp.armeria.server.Server;
+import com.linecorp.armeria.server.annotation.JacksonResponseConverterFunction;
+import com.linecorp.armeria.server.cors.CorsService;
+import com.linecorp.armeria.server.file.FileService;
+import com.linecorp.armeria.server.file.HttpFile;
 import java.nio.file.Path;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
 import java.util.function.Supplier;
 import org.apache.baremaps.cli.Options;
 import org.apache.baremaps.config.ConfigReader;
@@ -35,9 +40,6 @@ import org.apache.baremaps.tilestore.mbtiles.MBTilesStore;
 import org.apache.baremaps.utils.SqliteUtils;
 import org.apache.baremaps.vectortile.style.Style;
 import org.apache.baremaps.vectortile.tilejson.TileJSON;
-import org.glassfish.hk2.api.TypeLiteral;
-import org.glassfish.hk2.utilities.binding.AbstractBinder;
-import org.glassfish.jersey.server.ResourceConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import picocli.CommandLine.Command;
@@ -77,45 +79,45 @@ public class MBTiles implements Callable<Integer> {
     var caffeineSpec = CaffeineSpec.parse(cache);
 
     var datasource = SqliteUtils.createDataSource(mbtilesPath, true);
-    var tileStoreSupplierType = new TypeLiteral<Supplier<TileStore>>() {};
     var tileStore = new MBTilesStore(datasource);
     var tileCache = new TileCache(tileStore, caffeineSpec);
     var tileStoreSupplier = (Supplier<TileStore>) () -> tileCache;
 
-    var styleSupplierType = new TypeLiteral<Supplier<Style>>() {};
     var style = objectMapper.readValue(configReader.read(stylePath), 
Style.class);
     var styleSupplier = (Supplier<Style>) () -> style;
 
-    var tileJSONSupplierType = new TypeLiteral<Supplier<TileJSON>>() {};
     var tileJSON = objectMapper.readValue(configReader.read(tileJSONPath), 
TileJSON.class);
     var tileJSONSupplier = (Supplier<TileJSON>) () -> tileJSON;
 
-    // Configure the application
-    var application =
-        new ResourceConfig()
-            .register(CorsFilter.class)
-            .register(TileResource.class)
-            .register(StyleResource.class)
-            .register(TilesetResource.class)
-            .register(ClassPathResource.class)
-            .register(newContextResolver(objectMapper))
-            .register(new AbstractBinder() {
-              @Override
-              protected void configure() {
-                bind("assets").to(String.class).named("directory");
-                bind("server.html").to(String.class).named("index");
-                bind(tileStoreSupplier).to(tileStoreSupplierType);
-                bind(styleSupplier).to(styleSupplierType);
-                bind(tileJSONSupplier).to(tileJSONSupplierType);
-              }
-            });
-
-    var httpService = new 
HttpJerseyRouterBuilder().buildBlockingStreaming(application);
-    var serverContext = 
HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService);
-
-    logger.info("Listening on {}", serverContext.listenAddress());
-
-    serverContext.awaitShutdown();
+    var serverBuilder = Server.builder();
+    serverBuilder.http(port);
+
+    JacksonResponseConverterFunction jsonResponseConverter =
+        new JacksonResponseConverterFunction(objectMapper);
+    serverBuilder.annotatedService(new TileResource(tileStoreSupplier), 
jsonResponseConverter);
+    serverBuilder.annotatedService(new StyleResource(styleSupplier), 
jsonResponseConverter);
+    serverBuilder.annotatedService(new TileJSONResource(tileJSONSupplier), 
jsonResponseConverter);
+
+    HttpFile index = HttpFile.of(ClassLoader.getSystemClassLoader(), 
"/assets/server.html");
+    serverBuilder.service("/", index.asService());
+    serverBuilder.serviceUnder("/", 
FileService.of(ClassLoader.getSystemClassLoader(), "/assets"));
+
+    serverBuilder.decorator(CorsService.builderForAnyOrigin()
+        .allowRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, 
HttpMethod.DELETE,
+            HttpMethod.OPTIONS, HttpMethod.HEAD)
+        .allowRequestHeaders(HttpHeaderNames.ORIGIN, 
HttpHeaderNames.CONTENT_TYPE,
+            HttpHeaderNames.ACCEPT, HttpHeaderNames.AUTHORIZATION)
+        .allowCredentials()
+        .exposeHeaders(HttpHeaderNames.LOCATION)
+        .newDecorator());
+
+    serverBuilder.disableServerHeader();
+    serverBuilder.disableDateHeader();
+
+    Server server = serverBuilder.build();
+    CompletableFuture<Void> future = server.start();
+    future.join();
+
     return 0;
   }
 }
diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java 
b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java
index 0f0f1a4c..fa825607 100644
--- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java
+++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java
@@ -23,8 +23,7 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
 @Command(name = "map", description = "Map commands.",
-    subcommands = {Init.class, Export.class, Serve.class, Dev.class, 
StyleCommand.class,
-        MBTiles.class},
+    subcommands = {Init.class, Export.class, Serve.class, Dev.class, 
MBTiles.class},
     sortOptions = false)
 public class Map implements Runnable {
 
diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Serve.java 
b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Serve.java
index d3163566..de2da754 100644
--- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Serve.java
+++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Serve.java
@@ -17,20 +17,25 @@
 
 package org.apache.baremaps.cli.map;
 
-import static 
io.servicetalk.data.jackson.jersey.ServiceTalkJacksonSerializerFeature.newContextResolver;
 import static org.apache.baremaps.utils.ObjectMapperUtils.objectMapper;
 
 import com.github.benmanes.caffeine.cache.CaffeineSpec;
-import io.servicetalk.http.netty.HttpServers;
-import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder;
+import com.linecorp.armeria.common.HttpHeaderNames;
+import com.linecorp.armeria.common.HttpMethod;
+import com.linecorp.armeria.server.Server;
+import com.linecorp.armeria.server.annotation.JacksonResponseConverterFunction;
+import com.linecorp.armeria.server.cors.CorsService;
+import com.linecorp.armeria.server.file.FileService;
+import com.linecorp.armeria.server.file.HttpFile;
 import java.nio.file.Path;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
 import java.util.function.Supplier;
-import javax.sql.DataSource;
 import org.apache.baremaps.cli.Options;
 import org.apache.baremaps.config.ConfigReader;
-import org.apache.baremaps.server.*;
-import org.apache.baremaps.server.CorsFilter;
+import org.apache.baremaps.server.StyleResource;
+import org.apache.baremaps.server.TileJSONResource;
+import org.apache.baremaps.server.TileResource;
 import org.apache.baremaps.tilestore.TileCache;
 import org.apache.baremaps.tilestore.TileStore;
 import org.apache.baremaps.tilestore.postgres.PostgresTileStore;
@@ -38,9 +43,6 @@ import org.apache.baremaps.utils.PostgresUtils;
 import org.apache.baremaps.vectortile.style.Style;
 import org.apache.baremaps.vectortile.tilejson.TileJSON;
 import org.apache.baremaps.vectortile.tileset.Tileset;
-import org.glassfish.hk2.api.TypeLiteral;
-import org.glassfish.hk2.utilities.binding.AbstractBinder;
-import org.glassfish.jersey.server.ResourceConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import picocli.CommandLine.Command;
@@ -83,46 +85,45 @@ public class Serve implements Callable<Integer> {
     var tileset = objectMapper.readValue(configReader.read(tilesetPath), 
Tileset.class);
     var datasource = 
PostgresUtils.createDataSourceFromObject(tileset.getDatabase());
 
-    var tileStoreSupplierType = new TypeLiteral<Supplier<TileStore>>() {};
     var tileStore = new PostgresTileStore(datasource, tileset);
     var tileCache = new TileCache(tileStore, caffeineSpec);
     var tileStoreSupplier = (Supplier<TileStore>) () -> tileCache;
 
-    var styleSupplierType = new TypeLiteral<Supplier<Style>>() {};
     var style = objectMapper.readValue(configReader.read(stylePath), 
Style.class);
     var styleSupplier = (Supplier<Style>) () -> style;
 
-    var tileJSONSupplierType = new TypeLiteral<Supplier<TileJSON>>() {};
     var tileJSON = objectMapper.readValue(configReader.read(tilesetPath), 
TileJSON.class);
     var tileJSONSupplier = (Supplier<TileJSON>) () -> tileJSON;
 
-    var application =
-        new ResourceConfig()
-            .register(CorsFilter.class)
-            .register(TileResource.class)
-            .register(StyleResource.class)
-            .register(TileJSONResource.class)
-            .register(SearchResource.class)
-            .register(ClassPathResource.class)
-            .register(newContextResolver(objectMapper))
-            .register(new AbstractBinder() {
-              @Override
-              protected void configure() {
-                bind("assets").to(String.class).named("directory");
-                bind("server.html").to(String.class).named("index");
-                bind(datasource).to(DataSource.class);
-                bind(tileStoreSupplier).to(tileStoreSupplierType);
-                bind(styleSupplier).to(styleSupplierType);
-                bind(tileJSONSupplier).to(tileJSONSupplierType);
-              }
-            });
-
-    var httpService = new 
HttpJerseyRouterBuilder().buildBlockingStreaming(application);
-    var serverContext = 
HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService);
-
-    logger.info("Listening on {}", serverContext.listenAddress());
-
-    serverContext.awaitShutdown();
+    var serverBuilder = Server.builder();
+    serverBuilder.http(port);
+
+    JacksonResponseConverterFunction jsonResponseConverter =
+        new JacksonResponseConverterFunction(objectMapper);
+    serverBuilder.annotatedService(new TileResource(tileStoreSupplier), 
jsonResponseConverter);
+    serverBuilder.annotatedService(new StyleResource(styleSupplier), 
jsonResponseConverter);
+    serverBuilder.annotatedService(new TileJSONResource(tileJSONSupplier), 
jsonResponseConverter);
+
+    HttpFile index = HttpFile.of(ClassLoader.getSystemClassLoader(), 
"/assets/server.html");
+    serverBuilder.service("/", index.asService());
+    serverBuilder.serviceUnder("/", 
FileService.of(ClassLoader.getSystemClassLoader(), "/assets"));
+
+    serverBuilder.decorator(CorsService.builderForAnyOrigin()
+        .allowRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, 
HttpMethod.DELETE,
+            HttpMethod.OPTIONS, HttpMethod.HEAD)
+        .allowRequestHeaders(HttpHeaderNames.ORIGIN, 
HttpHeaderNames.CONTENT_TYPE,
+            HttpHeaderNames.ACCEPT, HttpHeaderNames.AUTHORIZATION)
+        .allowCredentials()
+        .exposeHeaders(HttpHeaderNames.LOCATION)
+        .newDecorator());
+
+    serverBuilder.disableServerHeader();
+    serverBuilder.disableDateHeader();
+
+    Server server = serverBuilder.build();
+    CompletableFuture<Void> future = server.start();
+    future.join();
+
     return 0;
   }
 }
diff --git 
a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/StyleCommand.java 
b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/StyleCommand.java
deleted file mode 100644
index e77f6425..00000000
--- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/StyleCommand.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.baremaps.cli.map;
-
-import static 
io.servicetalk.data.jackson.jersey.ServiceTalkJacksonSerializerFeature.newContextResolver;
-import static org.apache.baremaps.utils.ObjectMapperUtils.objectMapper;
-
-import io.servicetalk.http.netty.HttpServers;
-import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder;
-import java.io.IOException;
-import java.net.URL;
-import java.nio.file.Path;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.function.Supplier;
-import org.apache.baremaps.cli.Options;
-import org.apache.baremaps.config.ConfigReader;
-import org.apache.baremaps.server.*;
-import org.apache.baremaps.vectortile.style.Style;
-import org.apache.baremaps.vectortile.style.StyleSource;
-import org.glassfish.hk2.api.TypeLiteral;
-import org.glassfish.hk2.utilities.binding.AbstractBinder;
-import org.glassfish.jersey.server.ResourceConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import picocli.CommandLine.Command;
-import picocli.CommandLine.Mixin;
-import picocli.CommandLine.Option;
-
-@Command(name = "style",
-    description = "Start a development server with live reload for editing 
styles. Overrides the style sources.")
-public class StyleCommand implements Callable<Integer> {
-
-  private static final Logger logger = 
LoggerFactory.getLogger(StyleCommand.class);
-
-  @Mixin
-  private Options options;
-
-  @Option(names = {"--tiles"}, paramLabel = "TILES", description = "The tiles 
url.",
-      required = true)
-  private URL tilesUrl;
-
-  @Option(names = {"--style"}, paramLabel = "STYLE", description = "The style 
file.",
-      required = true)
-  private Path stylePath;
-
-  @Option(names = {"--host"}, paramLabel = "HOST", description = "The host of 
the server.")
-  private String host = "localhost";
-
-  @Option(names = {"--port"}, paramLabel = "PORT", description = "The port of 
the server.")
-  private int port = 9000;
-
-  @Override
-  public Integer call() throws Exception {
-    var configReader = new ConfigReader();
-    var objectMapper = objectMapper();
-
-    var styleSupplierType = new TypeLiteral<Supplier<Style>>() {};
-    var styleSupplier = (Supplier<Style>) () -> {
-      try {
-        var config = configReader.read(stylePath);
-        var object = objectMapper.readValue(config, Style.class);
-        var styleSource = new StyleSource("vector", tilesUrl.toString());
-        object.setSources(Map.of("baremaps", styleSource));
-        return object;
-      } catch (IOException e) {
-        throw new RuntimeException(e);
-      }
-    };
-
-    var application = new ResourceConfig()
-        .register(CorsFilter.class)
-        .register(ChangeResource.class)
-        .register(StyleResource.class)
-        .register(ChangeResource.class)
-        .register(ClassPathResource.class)
-        .register(newContextResolver(objectMapper))
-        .register(new AbstractBinder() {
-          @Override
-          protected void configure() {
-            bind("assets").to(String.class).named("directory");
-            bind("viewer.html").to(String.class).named("index");
-            bind(stylePath).to(Path.class).named("style");
-            bind(styleSupplier).to(styleSupplierType);
-          }
-        });
-
-    var httpService = new 
HttpJerseyRouterBuilder().buildBlockingStreaming(application);
-    var serverContext = 
HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService);
-
-    logger.info("Listening on {}", serverContext.listenAddress());
-    serverContext.awaitShutdown();
-
-    return 0;
-  }
-}
diff --git a/baremaps-server/pom.xml b/baremaps-server/pom.xml
index 8ebd29dd..263d28d3 100644
--- a/baremaps-server/pom.xml
+++ b/baremaps-server/pom.xml
@@ -34,54 +34,10 @@ limitations under the License.
       <groupId>com.linecorp.armeria</groupId>
       <artifactId>armeria-reactor3</artifactId>
     </dependency>
-    <dependency>
-      <groupId>io.servicetalk</groupId>
-      <artifactId>servicetalk-http-api</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.servicetalk</groupId>
-      <artifactId>servicetalk-transport-api</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>jakarta.ws.rs</groupId>
-      <artifactId>jakarta.ws.rs-api</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.apache.baremaps</groupId>
       <artifactId>baremaps-core</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.glassfish.jersey.inject</groupId>
-      <artifactId>jersey-hk2</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.glassfish.jersey.media</groupId>
-      <artifactId>jersey-media-json-jackson</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.glassfish.jersey.media</groupId>
-      <artifactId>jersey-media-multipart</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.glassfish.jersey.media</groupId>
-      <artifactId>jersey-media-sse</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.glassfish.jersey.test-framework</groupId>
-      <artifactId>jersey-test-framework-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.glassfish.jersey.test-framework</groupId>
-      <artifactId>jersey-test-framework-util</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.glassfish.jersey.test-framework.providers</groupId>
-      <artifactId>jersey-test-framework-provider-inmemory</artifactId>
-      <scope>test</scope>
-    </dependency>
   </dependencies>
 
 </project>
diff --git 
a/baremaps-server/src/main/java/org/apache/baremaps/server/BaseUriRequestFilter.java
 
b/baremaps-server/src/main/java/org/apache/baremaps/server/BaseUriRequestFilter.java
deleted file mode 100644
index 4e88a968..00000000
--- 
a/baremaps-server/src/main/java/org/apache/baremaps/server/BaseUriRequestFilter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.baremaps.server;
-
-
-
-import javax.inject.Singleton;
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerRequestFilter;
-import javax.ws.rs.container.PreMatching;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.ext.Provider;
-
-/**
- * A filter that sets the base URI of the request.
- */
-@Provider
-@PreMatching
-@Singleton
-public class BaseUriRequestFilter implements ContainerRequestFilter {
-
-  @Override
-  public void filter(ContainerRequestContext requestContext) {
-    var baseUri = UriBuilder.fromUri(requestContext.getUriInfo().getBaseUri());
-    var headers = requestContext.getHeaders();
-    if (headers.get("X-Forwarded-Proto") != null) {
-      baseUri.scheme(headers.getFirst("X-Forwarded-Proto"));
-    }
-    if (headers.get("X-Forwarded-Host") != null) {
-      baseUri.host(headers.getFirst("X-Forwarded-Host"));
-    }
-    if (headers.get("X-Forwarded-Port") != null) {
-      baseUri.port(Integer.parseInt(headers.getFirst("X-Forwarded-Port")));
-    }
-    requestContext.setRequestUri(baseUri.build(), 
requestContext.getUriInfo().getRequestUri());
-  }
-}
diff --git 
a/baremaps-server/src/main/java/org/apache/baremaps/server/ClassPathResource.java
 
b/baremaps-server/src/main/java/org/apache/baremaps/server/ClassPathResource.java
deleted file mode 100644
index f1d0dbaf..00000000
--- 
a/baremaps-server/src/main/java/org/apache/baremaps/server/ClassPathResource.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.baremaps.server;
-
-import java.io.IOException;
-import java.io.InputStream;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.core.Response;
-
-/**
- * Serves static resources from the class path.
- */
-@Singleton
-@Path("/")
-public class ClassPathResource {
-
-  private final String directory;
-
-  private final String index;
-
-  /**
-   * Constructs a {@code ClassPathResources}.
-   *
-   * @param directory the directory
-   * @param index the index
-   */
-  @Inject
-  public ClassPathResource(
-      @Named("directory") String directory,
-      @Named("index") String index) {
-    this.directory = directory;
-    this.index = index;
-  }
-
-  /**
-   * Serves a static resource from the class path.
-   *
-   * @param path the path
-   * @return the response
-   */
-  @GET
-  @Path("{path:.*}")
-  public Response get(@PathParam("path") String path) {
-    if (path.isEmpty() || path.endsWith("/")) {
-      path += index;
-    }
-    path = String.format("%s/%s", directory, path);
-    try (InputStream inputStream = 
getClass().getClassLoader().getResourceAsStream(path)) {
-      return Response.ok().entity(inputStream.readAllBytes()).build();
-    } catch (NullPointerException | IOException e) {
-      return Response.status(404).build();
-    }
-  }
-}
diff --git 
a/baremaps-server/src/main/java/org/apache/baremaps/server/CorsFilter.java 
b/baremaps-server/src/main/java/org/apache/baremaps/server/CorsFilter.java
deleted file mode 100644
index 60e42147..00000000
--- a/baremaps-server/src/main/java/org/apache/baremaps/server/CorsFilter.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.baremaps.server;
-
-
-
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerRequestFilter;
-import javax.ws.rs.container.ContainerResponseContext;
-import javax.ws.rs.container.ContainerResponseFilter;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.Provider;
-
-/**
- * A filter that adds CORS headers to requests.
- */
-@Provider
-public class CorsFilter implements ContainerRequestFilter, 
ContainerResponseFilter {
-
-  private final String ACCESS_CONTROL_ALLOW_ORIGIN = 
"Access-Control-Allow-Origin";
-  private final String ACCESS_CONTROL_ALLOW_CREDENTIALS = 
"Access-Control-Allow-Credentials";
-  private final String ACCESS_CONTROL_ALLOW_METHODS = 
"Access-Control-Allow-Methods";
-  private final String ACCESS_CONTROL_ALLOW_HEADERS = 
"Access-Control-Allow-Headers";
-  private final String ACCESS_CONTROL_EXPOSE_HEADERS = 
"Access-Control-Expose-Headers";
-  private final String ORIGIN = "Origin";
-  private final String VARY = "Vary";
-
-  @Override
-  public void filter(ContainerRequestContext requestContext) {
-    var origin = requestContext.getHeaderString(ORIGIN);
-    if (origin == null) {
-      return;
-    }
-    if (requestContext.getMethod().equalsIgnoreCase("OPTIONS")) {
-      preflight(origin, requestContext);
-    }
-  }
-
-  @Override
-  public void filter(ContainerRequestContext requestContext,
-      ContainerResponseContext responseContext) {
-    var origin = requestContext.getHeaderString(ORIGIN);
-    if (origin == null || 
requestContext.getMethod().equalsIgnoreCase("OPTIONS")
-        || requestContext.getProperty("cors.failure") != null) {
-      return;
-    }
-    responseContext.getHeaders().putSingle(ACCESS_CONTROL_ALLOW_ORIGIN, 
origin);
-    responseContext.getHeaders().putSingle(ACCESS_CONTROL_ALLOW_METHODS,
-        "GET, POST, PUT, DELETE, OPTIONS, HEAD");
-    responseContext.getHeaders().putSingle(ACCESS_CONTROL_ALLOW_HEADERS,
-        "origin, content-type, accept, authorization");
-    responseContext.getHeaders().putSingle(ACCESS_CONTROL_ALLOW_CREDENTIALS, 
"true");
-    responseContext.getHeaders().putSingle(ACCESS_CONTROL_EXPOSE_HEADERS, 
"Location");
-    responseContext.getHeaders().putSingle(VARY, ORIGIN);
-  }
-
-  private void preflight(String origin, ContainerRequestContext 
requestContext) {
-    // Respond with a 204 no content since we are returning an empty response 
with just the header
-    // for preflight
-    var builder = Response.noContent();
-    builder.header(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
-    builder.header(VARY, ORIGIN);
-    builder.header(ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT, DELETE, 
OPTIONS, HEAD");
-    builder.header(ACCESS_CONTROL_ALLOW_HEADERS, "origin, content-type, 
accept, authorization");
-    builder.header(ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
-    builder.header(ACCESS_CONTROL_EXPOSE_HEADERS, "Location");
-    requestContext.abortWith(builder.build());
-  }
-}
diff --git 
a/baremaps-server/src/main/java/org/apache/baremaps/server/GeocoderResource.java
 
b/baremaps-server/src/main/java/org/apache/baremaps/server/GeocoderResource.java
index 901a055e..14ca3840 100644
--- 
a/baremaps-server/src/main/java/org/apache/baremaps/server/GeocoderResource.java
+++ 
b/baremaps-server/src/main/java/org/apache/baremaps/server/GeocoderResource.java
@@ -17,23 +17,22 @@
 
 package org.apache.baremaps.server;
 
-import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
-import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static com.google.common.net.HttpHeaders.*;
+import static io.netty.handler.codec.http.HttpHeaders.Values.APPLICATION_JSON;
 
+import com.linecorp.armeria.common.HttpResponse;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.ResponseHeaders;
+import com.linecorp.armeria.server.annotation.Default;
+import com.linecorp.armeria.server.annotation.Get;
+import com.linecorp.armeria.server.annotation.Param;
+import com.linecorp.armeria.server.annotation.ProducesJson;
 import java.io.IOException;
 import java.text.ParseException;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
 import org.apache.baremaps.geocoder.GeonamesQueryBuilder;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.ScoreDoc;
@@ -44,8 +43,6 @@ import org.slf4j.LoggerFactory;
 /**
  * A resource that provides access to the geocoder.
  */
-@Singleton
[email protected]("/")
 public class GeocoderResource {
 
   private static final Logger logger = 
LoggerFactory.getLogger(GeocoderResource.class);
@@ -53,27 +50,23 @@ public class GeocoderResource {
   record GeocoderResponse(List<GeocoderResult> results) {
   }
 
-
   record GeocoderResult(float score, Map<String, Object> data) {
   }
 
-
   private final SearcherManager searcherManager;
 
-  @Inject
   public GeocoderResource(SearcherManager searcherManager) {
     this.searcherManager = searcherManager;
   }
 
-  @GET
-  @javax.ws.rs.Path("/api/geocoder")
-  public Response searchLocations(
-      @QueryParam("queryText") String queryText,
-      @QueryParam("countryCode") @DefaultValue("") String countryCode,
-      @QueryParam("limit") @DefaultValue("10") int limit) {
+  @Get("/api/geocoder")
+  @ProducesJson
+  public HttpResponse searchLocations(
+      @Param("queryText") String queryText,
+      @Param("countryCode") @Default("") String countryCode,
+      @Param("limit") @Default("10") int limit) {
     if (queryText == null) {
-      throw new 
WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
-          .entity("The queryText parameter is mandatory").build());
+      return HttpResponse.of(HttpStatus.BAD_REQUEST);
     }
     try {
       IndexSearcher searcher = searcherManager.acquire();
@@ -91,20 +84,25 @@ public class GeocoderResource {
         var result = searcher.search(query, limit);
         var results =
             Arrays.stream(result.scoreDocs).map(scoreDoc -> asResult(searcher, 
scoreDoc)).toList();
-        return 
Response.status(Response.Status.OK).header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
-            .header(CONTENT_TYPE, APPLICATION_JSON).entity(new 
GeocoderResponse(results)).build();
+
+        var headers = ResponseHeaders.builder(200)
+            .add(CONTENT_TYPE, APPLICATION_JSON)
+            .add(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
+            .build();
+
+        return HttpResponse.ofJson(headers, new GeocoderResponse(results));
       } catch (IllegalArgumentException e) {
         logger.warn("Illegal input while processing request", e);
-        return Response.status(Response.Status.BAD_REQUEST).build();
+        return HttpResponse.of(HttpStatus.BAD_REQUEST);
       } catch (IOException | ParseException e) {
         logger.error("Error while processing request", e);
-        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+        return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
       } finally {
         searcherManager.release(searcher);
       }
     } catch (IOException e) {
       logger.error("Error while processing request", e);
-      return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+      return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
     }
   }
 
diff --git 
a/baremaps-server/src/main/java/org/apache/baremaps/server/IpLocResource.java 
b/baremaps-server/src/main/java/org/apache/baremaps/server/IpLocResource.java
index 621d98db..4d22dd6a 100644
--- 
a/baremaps-server/src/main/java/org/apache/baremaps/server/IpLocResource.java
+++ 
b/baremaps-server/src/main/java/org/apache/baremaps/server/IpLocResource.java
@@ -18,19 +18,17 @@
 package org.apache.baremaps.server;
 
 import static com.google.common.net.HttpHeaders.*;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static io.netty.handler.codec.http.HttpHeaders.Values.APPLICATION_JSON;
 
 import com.google.common.net.InetAddresses;
-import io.servicetalk.http.api.StreamingHttpRequest;
-import io.servicetalk.transport.api.ConnectionContext;
+import com.linecorp.armeria.common.*;
+import com.linecorp.armeria.server.ServiceRequestContext;
+import com.linecorp.armeria.server.annotation.Get;
+import com.linecorp.armeria.server.annotation.Param;
+import com.linecorp.armeria.server.annotation.ProducesJson;
 import java.net.InetSocketAddress;
 import java.util.List;
 import java.util.Optional;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.ws.rs.GET;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.*;
 import org.apache.baremaps.iploc.IpLocObject;
 import org.apache.baremaps.iploc.IpLocRepository;
 import org.slf4j.Logger;
@@ -39,15 +37,12 @@ import org.slf4j.LoggerFactory;
 /**
  * A resource that provides access to the IP location database.
  */
-@Singleton
[email protected]("/")
 public class IpLocResource {
 
   private static final Logger logger = 
LoggerFactory.getLogger(IpLocResource.class);
 
   private final IpLocRepository ipLocRepository;
 
-  @Inject
   public IpLocResource(IpLocRepository ipLocRepository) {
     this.ipLocRepository = ipLocRepository;
   }
@@ -55,52 +50,56 @@ public class IpLocResource {
   public record IP(String ip) {
   }
 
-  @GET
-  @javax.ws.rs.Path("/api/ip")
-  public Response ip(
-      @Context ConnectionContext context,
-      @Context StreamingHttpRequest request,
-      @QueryParam("ip") String ip) {
+  @Get("/api/ip")
+  @ProducesJson
+  public HttpResponse ip(
+      ServiceRequestContext context,
+      HttpHeaders requestHeaders,
+      @Param("ip") String ip) {
     try {
       var address = InetAddresses.forString(
           Optional.ofNullable((CharSequence) ip)
-              .or(() -> 
Optional.ofNullable(request.headers().get("X-Forwarded-For")))
-              .or(() -> 
Optional.ofNullable(request.headers().get("X-Real-IP")))
-              .orElse(((InetSocketAddress) 
context.remoteAddress()).getAddress().getHostAddress())
+              .or(() -> 
Optional.ofNullable(requestHeaders.get("X-Forwarded-For")))
+              .or(() -> Optional.ofNullable(requestHeaders.get("X-Real-IP")))
+              .orElse(context.remoteAddress().getAddress().getHostAddress())
               .toString().split(",")[0].trim());
-      return Response.status(200) // lgtm [java/xss]
-          .header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
-          .header(CONTENT_TYPE, APPLICATION_JSON)
-          .entity(new IP(address.toString())).build();
+
+      var responseHeaders = ResponseHeaders.builder(200)
+          .add(CONTENT_TYPE, APPLICATION_JSON)
+          .add(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
+          .build();
+
+      return HttpResponse.ofJson(responseHeaders, new IP(address.toString()));
     } catch (IllegalArgumentException e) {
       logger.error("Error while processing request", e);
-      return Response.serverError().build();
+      return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
     }
   }
 
-  @GET
-  @javax.ws.rs.Path("/api/iploc")
+  @Get("/api/iploc")
+  @ProducesJson
   public Response iploc(
-      @Context ConnectionContext context,
-      @Context StreamingHttpRequest request,
-      @QueryParam("ip") String ip) {
+      ServiceRequestContext context,
+      HttpHeaders requestHeaders,
+      @Param("ip") String ip) {
     try {
       var address = InetAddresses.forString(
           Optional.ofNullable((CharSequence) ip)
-              .or(() -> 
Optional.ofNullable(request.headers().get("X-Forwarded-For")))
-              .or(() -> 
Optional.ofNullable(request.headers().get("X-Real-IP")))
+              .or(() -> 
Optional.ofNullable(requestHeaders.get("X-Forwarded-For")))
+              .or(() -> Optional.ofNullable(requestHeaders.get("X-Real-IP")))
               .orElse(((InetSocketAddress) 
context.remoteAddress()).getAddress().getHostAddress())
               .toString().split(",")[0].trim());
       List<IpLocObject> inetnumLocations = 
ipLocRepository.findByInetAddress(address);
       List<InetnumLocationDto> inetnumLocationDtos =
           inetnumLocations.stream().map(InetnumLocationDto::new).toList();
-      return Response.status(200) // lgtm [java/xss]
-          .header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
-          .header(CONTENT_TYPE, APPLICATION_JSON)
-          .entity(inetnumLocationDtos).build();
+      var responseHeaders = ResponseHeaders.builder(200)
+          .add(CONTENT_TYPE, APPLICATION_JSON)
+          .add(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
+          .build();
+      return HttpResponse.ofJson(responseHeaders, inetnumLocationDtos);
     } catch (IllegalArgumentException e) {
       logger.error("Error while processing request", e);
-      return Response.serverError().build();
+      return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
     }
   }
 
diff --git 
a/baremaps-server/src/main/java/org/apache/baremaps/server/SearchResource.java 
b/baremaps-server/src/main/java/org/apache/baremaps/server/SearchResource.java
index 5b6eaaac..d7dc7002 100644
--- 
a/baremaps-server/src/main/java/org/apache/baremaps/server/SearchResource.java
+++ 
b/baremaps-server/src/main/java/org/apache/baremaps/server/SearchResource.java
@@ -20,26 +20,22 @@ package org.apache.baremaps.server;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.linecorp.armeria.common.HttpResponse;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.server.annotation.Default;
+import com.linecorp.armeria.server.annotation.Get;
+import com.linecorp.armeria.server.annotation.Param;
+import com.linecorp.armeria.server.annotation.ProducesJson;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
-import javax.inject.Inject;
-import javax.inject.Singleton;
 import javax.sql.DataSource;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * A resource that searches for entities in the database.
  */
-@Singleton
[email protected]("/")
 public class SearchResource {
 
   private static final Logger logger = 
LoggerFactory.getLogger(SearchResource.class);
@@ -55,7 +51,6 @@ public class SearchResource {
 
   private final DataSource dataSource;
 
-  @Inject
   public SearchResource(DataSource dataSource) {
     this.dataSource = dataSource;
   }
@@ -66,12 +61,11 @@ public class SearchResource {
   record SearchResult(long id, JsonNode tags, String wkt, double score) {
   }
 
-  @GET
-  @javax.ws.rs.Path("/api/search")
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response search(
-      @QueryParam("query") String queryText,
-      @QueryParam("limit") @DefaultValue("10") int limit) {
+  @Get("/api/search")
+  @ProducesJson
+  public HttpResponse search(
+      @Param("query") String queryText,
+      @Param("limit") @Default("10") int limit) {
     try (var connection = dataSource.getConnection();
         var statement = connection.prepareStatement(SEARCH_QUERY)) {
       statement.setString(1, queryText);
@@ -88,10 +82,10 @@ public class SearchResource {
         }
       }
       var response = new SearchResponse(list);
-      return Response.status(Response.Status.OK).entity(response).build();
+      return HttpResponse.ofJson(response);
     } catch (SQLException | JsonProcessingException e) {
       logger.error("Error while searching", e);
-      return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+      return HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
     }
   }
 }
diff --git 
a/baremaps-server/src/test/java/org/apache/baremaps/server/BaseUriRequestFilterIntegrationTest.java
 
b/baremaps-server/src/test/java/org/apache/baremaps/server/BaseUriRequestFilterIntegrationTest.java
deleted file mode 100644
index 9071d3c6..00000000
--- 
a/baremaps-server/src/test/java/org/apache/baremaps/server/BaseUriRequestFilterIntegrationTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.baremaps.server;
-
-import static org.junit.Assert.assertEquals;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.UriInfo;
-import org.glassfish.jersey.server.ResourceConfig;
-import org.glassfish.jersey.test.JerseyTest;
-import org.glassfish.jersey.test.TestProperties;
-import org.junit.Test;
-
-public class BaseUriRequestFilterIntegrationTest extends JerseyTest {
-
-  @Path("")
-  public static class BaseUriService {
-    @GET
-    public String getBaseUri(@Context UriInfo uriInfo) {
-      return uriInfo.getBaseUri().toString();
-    }
-  }
-
-  @Override
-  protected ResourceConfig configure() {
-    enable(TestProperties.LOG_TRAFFIC);
-    enable(TestProperties.DUMP_ENTITY);
-    return new ResourceConfig().registerClasses(BaseUriRequestFilter.class, 
BaseUriService.class);
-  }
-
-  @Test
-  public void testBaseUri() {
-    String baseUriStr = target().path("").request().header("X-Forwarded-Host", 
"test.com")
-        .header("X-Forwarded-Proto", "https").header("X-Forwarded-Port", 
"443").get(String.class);
-    assertEquals("https://test.com:443/";, baseUriStr);
-  }
-}
diff --git 
a/baremaps-server/src/test/java/org/apache/baremaps/server/ClassPathResourceIntegrationTest.java
 
b/baremaps-server/src/test/java/org/apache/baremaps/server/ClassPathResourceIntegrationTest.java
deleted file mode 100644
index 300bc0dc..00000000
--- 
a/baremaps-server/src/test/java/org/apache/baremaps/server/ClassPathResourceIntegrationTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.baremaps.server;
-
-import static org.junit.Assert.assertTrue;
-
-import org.glassfish.jersey.internal.inject.AbstractBinder;
-import org.glassfish.jersey.server.ResourceConfig;
-import org.glassfish.jersey.test.JerseyTest;
-import org.glassfish.jersey.test.TestProperties;
-import org.junit.Test;
-
-public class ClassPathResourceIntegrationTest extends JerseyTest {
-
-  @Override
-  protected ResourceConfig configure() {
-    enable(TestProperties.LOG_TRAFFIC);
-    enable(TestProperties.DUMP_ENTITY);
-    return new ResourceConfig()
-        .register(ClassPathResource.class)
-        .register(new AbstractBinder() {
-          @Override
-          protected void configure() {
-            bind("assets").to(String.class).named("directory");
-            bind("viewer.html").to(String.class).named("index");
-          }
-        });
-  }
-
-  @Test
-  public void testAssetsDirectory() {
-    
assertTrue(target().path("").request().get(String.class).contains("<title>Baremaps</title>"));
-    assertTrue(target().path("viewer.html").request().get(String.class)
-        .contains("<title>Baremaps</title>"));
-    assertTrue(target().path("server.html").request().get(String.class)
-        .contains("<title>Baremaps</title>"));
-  }
-}
diff --git a/pom.xml b/pom.xml
index 2aa0e735..19fca361 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,7 +79,6 @@ limitations under the License.
     <sonar.moduleKey>${project.groupId}:${project.artifactId}</sonar.moduleKey>
     <sonar.organization>apache</sonar.organization>
     <sonar.projectKey>apache_baremaps</sonar.projectKey>
-    <version.lib.annotation-api>1.3.2</version.lib.annotation-api>
     <version.lib.armeria>1.26.4</version.lib.armeria>
     <version.lib.awaitability>4.2.0</version.lib.awaitability>
     <version.lib.awssdk>2.21.5</version.lib.awssdk>
@@ -92,28 +91,24 @@ limitations under the License.
     <version.lib.graalvm>23.0.2</version.lib.graalvm>
     <version.lib.guava>32.1.3-jre</version.lib.guava>
     <version.lib.hikari>5.0.1</version.lib.hikari>
-    <version.lib.hk2>2.6.1</version.lib.hk2>
     <version.lib.ipresource>1.52</version.lib.ipresource>
     <version.lib.jackson>2.13.0</version.lib.jackson>
-    <version.lib.jakarta>2.1.6</version.lib.jakarta>
-    <version.lib.jersey>2.37</version.lib.jersey>
     <version.lib.jmh>1.35</version.lib.jmh>
     <version.lib.jts>1.19.0</version.lib.jts>
     <version.lib.junit>5.10.0</version.lib.junit>
     <version.lib.junit-vintage>5.10.0</version.lib.junit-vintage>
     <version.lib.log4j>3.0.0-alpha1</version.lib.log4j>
+    <version.lib.lucene>9.4.2</version.lib.lucene>
+    <version.lib.lucene-spatial>9.4.2</version.lib.lucene-spatial>
     <version.lib.pgbulkinsert>8.1.2</version.lib.pgbulkinsert>
     <version.lib.picocli>4.7.5</version.lib.picocli>
     <version.lib.postgresql>42.6.0</version.lib.postgresql>
     <version.lib.proj4j>1.3.0</version.lib.proj4j>
     <version.lib.protobuf>3.21.6</version.lib.protobuf>
     <version.lib.roaringbitmap>1.0.0</version.lib.roaringbitmap>
-    <version.lib.servicetalk>0.42.38</version.lib.servicetalk>
     <version.lib.slf4j>2.0.9</version.lib.slf4j>
     <version.lib.sqlite>3.43.2.1</version.lib.sqlite>
     <version.lib.testcontainers>1.19.1</version.lib.testcontainers>
-    <version.lucene>9.4.2</version.lucene>
-    <version.lucene-spatial>9.4.2</version.lucene-spatial>
     
<version.plugin.jacoco-maven-plugin>0.8.11</version.plugin.jacoco-maven-plugin>
     <version.plugin.jib-maven-plugin>3.0.0</version.plugin.jib-maven-plugin>
     
<version.plugin.maven-compiler-plugin>3.10.1</version.plugin.maven-compiler-plugin>
@@ -206,56 +201,11 @@ limitations under the License.
         <artifactId>picocli</artifactId>
         <version>${version.lib.picocli}</version>
       </dependency>
-      <dependency>
-        <groupId>io.servicetalk</groupId>
-        <artifactId>servicetalk-data-jackson</artifactId>
-        <version>${version.lib.servicetalk}</version>
-      </dependency>
-      <dependency>
-        <groupId>io.servicetalk</groupId>
-        <artifactId>servicetalk-data-jackson-jersey</artifactId>
-        <version>${version.lib.servicetalk}</version>
-      </dependency>
-      <dependency>
-        <groupId>io.servicetalk</groupId>
-        <artifactId>servicetalk-http-api</artifactId>
-        <version>${version.lib.servicetalk}</version>
-      </dependency>
-      <dependency>
-        <groupId>io.servicetalk</groupId>
-        <artifactId>servicetalk-http-netty</artifactId>
-        <version>${version.lib.servicetalk}</version>
-      </dependency>
-      <dependency>
-        <groupId>io.servicetalk</groupId>
-        <artifactId>servicetalk-http-router-jersey</artifactId>
-        <version>${version.lib.servicetalk}</version>
-      </dependency>
-      <dependency>
-        <groupId>io.servicetalk</groupId>
-        <artifactId>servicetalk-http-router-predicate</artifactId>
-        <version>${version.lib.servicetalk}</version>
-      </dependency>
-      <dependency>
-        <groupId>io.servicetalk</groupId>
-        <artifactId>servicetalk-transport-api</artifactId>
-        <version>${version.lib.servicetalk}</version>
-      </dependency>
-      <dependency>
-        <groupId>io.servicetalk</groupId>
-        <artifactId>servicetalk-transport-netty</artifactId>
-        <version>${version.lib.servicetalk}</version>
-      </dependency>
       <dependency>
         <groupId>it.unimi.dsi</groupId>
         <artifactId>fastutil</artifactId>
         <version>${version.lib.fastutil}</version>
       </dependency>
-      <dependency>
-        <groupId>jakarta.ws.rs</groupId>
-        <artifactId>jakarta.ws.rs-api</artifactId>
-        <version>${version.lib.jakarta}</version>
-      </dependency>
       <dependency>
         <groupId>mil.nga.geopackage</groupId>
         <artifactId>geopackage</artifactId>
@@ -321,32 +271,32 @@ limitations under the License.
       <dependency>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-analyzers-common</artifactId>
-        <version>${version.lucene}</version>
+        <version>${version.lib.lucene}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-core</artifactId>
-        <version>${version.lucene}</version>
+        <version>${version.lib.lucene}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-expressions</artifactId>
-        <version>${version.lucene}</version>
+        <version>${version.lib.lucene}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-queryparser</artifactId>
-        <version>${version.lucene}</version>
+        <version>${version.lib.lucene}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-replicator</artifactId>
-        <version>${version.lucene}</version>
+        <version>${version.lib.lucene}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-spatial-extras</artifactId>
-        <version>${version.lucene}</version>
+        <version>${version.lib.lucene}</version>
       </dependency>
       <dependency>
         <groupId>org.awaitility</groupId>
@@ -354,29 +304,6 @@ limitations under the License.
         <version>${version.lib.awaitability}</version>
         <scope>test</scope>
       </dependency>
-      <dependency>
-        <groupId>org.glassfish.hk2</groupId>
-        <artifactId>hk2-api</artifactId>
-        <version>${version.lib.hk2}</version>
-      </dependency>
-      <dependency>
-        <groupId>org.glassfish.hk2</groupId>
-        <artifactId>hk2-locator</artifactId>
-        <version>${version.lib.hk2}</version>
-      </dependency>
-      <dependency>
-        <groupId>org.glassfish.jersey</groupId>
-        <artifactId>jersey-bom</artifactId>
-        <version>${version.lib.jersey}</version>
-        <type>pom</type>
-        <scope>import</scope>
-      </dependency>
-      <dependency>
-        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
-        <artifactId>jersey-test-framework-provider-inmemory</artifactId>
-        <version>${version.lib.jersey}</version>
-        <scope>test</scope>
-      </dependency>
       <dependency>
         <groupId>org.graalvm.js</groupId>
         <artifactId>js</artifactId>

Reply via email to