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

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


The following commit(s) were added to refs/heads/main by this push:
     new fc64ee17 Fix some issues detected by sonar (#873)
fc64ee17 is described below

commit fc64ee1745737bfd9ac4a27c01fe0f1bdee9f2fb
Author: Bertil Chapuis <[email protected]>
AuthorDate: Thu Jun 13 11:36:22 2024 +0200

    Fix some issues detected by sonar (#873)
    
    * Improve visibility and isolation in pmtiles
    
    * Format code with spotless
    
    * throw dedicated exceptions
    
    * Remove unused methods
    
    * Remove duplicate code
    
    * Add default to switch statements
    
    * Fix boxed boolean checks
    
    * Suppress warnings
    
    * implement equals and hashCode in adapters
    
    * Use unary operator instead of function
    
    * Use parametrized types
    
    * Add private constructors
    
    * Improve use of instanceof
    
    * Cleanup test
    
    * Merge cases in switch statements
    
    * Merge if statements
    
    * Use records instead of classes
    
    * Use final when appropriate
    
    * Improve use of Optional
    
    * Format test assertions
---
 .../org/apache/baremaps/database/DiffService.java  |  11 +-
 .../database/function/ChangeElementsImporter.java  |   6 +-
 .../database/function/CopyChangeImporter.java      |  66 ++++-----
 .../database/function/PutChangeImporter.java       |  63 ++++-----
 .../database/postgres/HeaderRepository.java        |  45 ++++---
 .../database/postgres/RelationRepository.java      |  12 +-
 .../storage/flatgeobuf/FlatGeoBufDataTable.java    |   2 +-
 .../shapefile/internal/CommonByteReader.java       |  11 +-
 .../shapefile/internal/ShapefileByteReader.java    |   1 +
 .../shapefile/internal/ShapefileReader.java        |   3 +-
 .../baremaps/tilestore/pmtiles/PMTilesStore.java   |   4 +-
 .../tilestore/postgres/PostgresTileStore.java      |   2 +-
 .../org/apache/baremaps/utils/PostgresUtils.java   |  17 ---
 .../workflow/tasks/ImportDaylightFeatures.java     |  61 +++------
 .../workflow/tasks/ImportDaylightTranslations.java |  65 ++++-----
 .../baremaps/workflow/tasks/ImportOsmPbf.java      |   7 +-
 .../baremaps/workflow/tasks/UpdateOsmDatabase.java |  15 ++-
 .../org/apache/baremaps/config/TileSetTest.java    |   8 +-
 .../database/postgres/HeaderRepositoryTest.java    |  14 +-
 .../workflow/tasks/ImportUpdateSampleTest.java     |  12 +-
 .../baremaps/data/algorithm/ExternalMergeSort.java |   2 +-
 .../baremaps/data/collection/AppendOnlyLog.java    |  15 +--
 .../baremaps/data/collection/DataConversions.java  |  40 ++++++
 .../apache/baremaps/data/collection/DataList.java  |   4 +-
 .../data/collection/MemoryAlignedDataMap.java      |  12 +-
 .../data/storage/DataTableGeometryMapper.java      |   4 +-
 .../baremaps/data/storage/DataTableMapper.java     |   3 +-
 .../apache/baremaps/data/type/BooleanDataType.java |   4 +-
 .../data/type/GeometryCollectionDataType.java      |   2 +-
 .../org/apache/baremaps/data/type/RowDataType.java |   2 +-
 .../org/apache/baremaps/data/util/FileUtils.java   |   4 +
 .../baremaps/data/sort/ExternalMergeSortTest.java  |  12 +-
 .../baremaps/data/type/DataTypeProvider.java       |   2 -
 .../data/GeoParquetGroupRecordConverter.java       |   2 +-
 .../geoparquet/data/GeoParquetMaterializer.java    |   2 +-
 .../geoparquet/hadoop/GeoParquetWriter.java        |  12 +-
 .../baremaps/maplibre/expression/Expressions.java  |   3 +-
 .../maplibre/vectortile/VectorTileEncoder.java     |  24 ++--
 .../maplibre/expression/ExpressionsTest.java       |  51 ++++---
 .../vectortile/VectorTileFunctionsTest.java        |   1 -
 .../maplibre/vectortile/VectorTileViewer.java      |   5 +-
 .../function/ChangeEntitiesHandler.java            |   2 +-
 .../function/ProjectionTransformer.java            |   4 +-
 .../function/RelationMultiPolygonBuilder.java      |  16 +--
 .../apache/baremaps/openstreetmap/model/Bound.java |  91 +------------
 .../baremaps/openstreetmap/model/Change.java       |  42 +-----
 .../baremaps/openstreetmap/model/Header.java       | 110 +--------------
 .../baremaps/openstreetmap/model/Member.java       |  96 +------------
 .../apache/baremaps/openstreetmap/model/State.java |  34 +----
 .../apache/baremaps/openstreetmap/model/User.java  |  54 +-------
 .../baremaps/openstreetmap/state/StateReader.java  |  98 ++++++++------
 .../openstreetmap/stream/ConsumerUtils.java        |   4 +-
 .../baremaps/openstreetmap/utils/CRSUtils.java     |   4 +
 .../openstreetmap/xml/XmlChangeSpliterator.java    |  30 +++--
 .../openstreetmap/xml/XmlEntitySpliterator.java    |   4 +-
 .../baremaps/openstreetmap/OsmSampleTest.java      |  14 +-
 .../apache/baremaps/openstreetmap/OsmTestData.java |  14 +-
 .../openstreetmap/state/StateReaderTest.java       |   2 +-
 .../stream/BatchedSpliteratorTest.java             |   4 +-
 .../xml/XmlChangeSpliteratorTest.java              |   2 +-
 .../org/apache/baremaps/pmtiles/Compression.java   |   2 +-
 .../java/org/apache/baremaps/pmtiles/Entry.java    |   2 +-
 .../java/org/apache/baremaps/pmtiles/Header.java   |   2 +-
 .../org/apache/baremaps/pmtiles/PMTilesReader.java |   8 +-
 .../pmtiles/{PMTiles.java => PMTilesUtils.java}    |  42 +++---
 .../org/apache/baremaps/pmtiles/PMTilesWriter.java |  28 ++--
 .../java/org/apache/baremaps/pmtiles/TileType.java |   2 +-
 .../{PMTilesTest.java => PMTilesUtilsTest.java}    | 148 ++++++++++-----------
 68 files changed, 561 insertions(+), 929 deletions(-)

diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/database/DiffService.java 
b/baremaps-core/src/main/java/org/apache/baremaps/database/DiffService.java
index 07a7b890..4a042a2a 100644
--- a/baremaps-core/src/main/java/org/apache/baremaps/database/DiffService.java
+++ b/baremaps-core/src/main/java/org/apache/baremaps/database/DiffService.java
@@ -55,6 +55,7 @@ public class DiffService implements Callable<List<TileCoord>> 
{
   private final int srid;
   private final int zoom;
 
+  @SuppressWarnings("squid:S107")
   public DiffService(
       Map<Long, Coordinate> coordinateMap,
       Map<Long, List<Long>> referenceMap,
@@ -79,8 +80,8 @@ public class DiffService implements Callable<List<TileCoord>> 
{
     logger.info("Importing changes");
 
     var header = headerRepository.selectLatest();
-    var replicationUrl = header.getReplicationUrl();
-    var sequenceNumber = header.getReplicationSequenceNumber() + 1;
+    var replicationUrl = header.replicationUrl();
+    var sequenceNumber = header.replicationSequenceNumber() + 1;
     var changeUrl = resolve(replicationUrl, sequenceNumber, "osc.gz");
 
     var projectionTransformer = new ProjectionTransformer(srid, 4326);
@@ -100,7 +101,7 @@ public class DiffService implements 
Callable<List<TileCoord>> {
   }
 
   private Stream<Geometry> geometriesForChange(Change change) {
-    switch (change.getType()) {
+    switch (change.type()) {
       case CREATE:
         return geometriesForNextVersion(change);
       case DELETE:
@@ -114,7 +115,7 @@ public class DiffService implements 
Callable<List<TileCoord>> {
   }
 
   private Stream<Geometry> geometriesForPreviousVersion(Change change) {
-    return 
change.getEntities().stream().map(this::geometriesForPreviousVersion)
+    return change.entities().stream().map(this::geometriesForPreviousVersion)
         .flatMap(Optional::stream);
   }
 
@@ -138,7 +139,7 @@ public class DiffService implements 
Callable<List<TileCoord>> {
   }
 
   private Stream<Geometry> geometriesForNextVersion(Change change) {
-    return change.getEntities().stream()
+    return change.entities().stream()
         .map(consumeThenReturn(new EntityGeometryBuilder(coordinateMap, 
referenceMap)))
         .flatMap(new EntityToGeometryMapper().andThen(Optional::stream));
   }
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/database/function/ChangeElementsImporter.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/database/function/ChangeElementsImporter.java
index 200a8bfe..01cc8af1 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/database/function/ChangeElementsImporter.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/database/function/ChangeElementsImporter.java
@@ -49,14 +49,14 @@ public class ChangeElementsImporter<T extends Element> 
implements Consumer<Chang
   /** {@inheritDoc} */
   @Override
   public void accept(Change change) {
-    switch (change.getType()) {
+    switch (change.type()) {
       case CREATE, MODIFY -> put(change);
       case DELETE -> delete(change);
     }
   }
 
   private void put(Change change) {
-    var nodes = change.getEntities().stream()
+    var nodes = change.entities().stream()
         .filter(type::isInstance)
         .map(type::cast)
         .toList();
@@ -70,7 +70,7 @@ public class ChangeElementsImporter<T extends Element> 
implements Consumer<Chang
   }
 
   private void delete(Change change) {
-    var nodes = change.getEntities().stream()
+    var nodes = change.entities().stream()
         .filter(type::isInstance)
         .map(type::cast)
         .map(Element::getId)
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/database/function/CopyChangeImporter.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/database/function/CopyChangeImporter.java
index 9e8676ec..47586b95 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/database/function/CopyChangeImporter.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/database/function/CopyChangeImporter.java
@@ -18,13 +18,11 @@
 package org.apache.baremaps.database.function;
 
 
+import java.util.List;
 import java.util.function.Consumer;
 import org.apache.baremaps.database.postgres.Repository;
 import org.apache.baremaps.database.postgres.RepositoryException;
-import org.apache.baremaps.openstreetmap.model.Change;
-import org.apache.baremaps.openstreetmap.model.Node;
-import org.apache.baremaps.openstreetmap.model.Relation;
-import org.apache.baremaps.openstreetmap.model.Way;
+import org.apache.baremaps.openstreetmap.model.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,57 +54,49 @@ public class CopyChangeImporter implements Consumer<Change> 
{
   /** {@inheritDoc} */
   @Override
   public void accept(Change change) {
-    var nodes = change.getEntities().stream()
+    var nodes = change.entities().stream()
         .filter(entity -> entity instanceof Node)
         .map(entity -> (Node) entity)
         .toList();
-    var nodeIds = nodes.stream().map(Node::getId).toList();
-    var ways = change.getEntities().stream()
+    var ways = change.entities().stream()
         .filter(entity -> entity instanceof Way)
         .map(entity -> (Way) entity)
         .toList();
-    var wayIds = ways.stream().map(Way::getId).toList();
-    var relations = change.getEntities().stream()
+    var relations = change.entities().stream()
         .filter(entity -> entity instanceof Relation)
         .map(entity -> (Relation) entity)
         .toList();
-    var relationIds = relations.stream().map(Relation::getId).toList();
     try {
-      switch (change.getType()) {
+      switch (change.type()) {
         case CREATE, MODIFY -> {
-          if (!nodes.isEmpty()) {
-            logger.trace("Creating {} nodes", nodes.size());
-            nodeRepository.delete(nodeIds);
-            nodeRepository.copy(nodes);
-          }
-          if (!ways.isEmpty()) {
-            logger.trace("Creating {} ways", ways.size());
-            wayRepository.delete(wayIds);
-            wayRepository.copy(ways);
-          }
-          if (!relations.isEmpty()) {
-            logger.trace("Creating {} relations", relations.size());
-            relationRepository.delete(relationIds);
-            relationRepository.copy(relations);
-          }
+          copy(nodeRepository, nodes);
+          copy(wayRepository, ways);
+          copy(relationRepository, relations);
         }
         case DELETE -> {
-          if (!nodes.isEmpty()) {
-            logger.trace("Deleting {} nodes", nodes.size());
-            nodeRepository.delete(nodeIds);
-          }
-          if (!ways.isEmpty()) {
-            logger.trace("Deleting {} ways", ways.size());
-            wayRepository.delete(wayIds);
-          }
-          if (!relations.isEmpty()) {
-            logger.trace("Deleting {} relations", relations.size());
-            relationRepository.delete(relationIds);
-          }
+          delete(nodeRepository, nodes);
+          delete(wayRepository, ways);
+          delete(relationRepository, relations);
         }
       }
     } catch (RepositoryException e) {
       logger.error("Error while saving changes", e);
     }
   }
+
+  private <T extends Element> void copy(Repository<Long, T> repository, 
List<T> entities)
+      throws RepositoryException {
+    if (!entities.isEmpty()) {
+      delete(repository, entities);
+      repository.copy(entities);
+    }
+  }
+
+  private <T extends Element> void delete(Repository<Long, T> repository, 
List<T> entities)
+      throws RepositoryException {
+    List<Long> ids = entities.stream().map(Element::getId).toList();
+    if (!ids.isEmpty()) {
+      repository.delete(ids);
+    }
+  }
 }
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/database/function/PutChangeImporter.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/database/function/PutChangeImporter.java
index 1bb76e8b..4d1e24b6 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/database/function/PutChangeImporter.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/database/function/PutChangeImporter.java
@@ -19,13 +19,11 @@ package org.apache.baremaps.database.function;
 
 
 
+import java.util.List;
 import java.util.function.Consumer;
 import org.apache.baremaps.database.postgres.Repository;
 import org.apache.baremaps.database.postgres.RepositoryException;
-import org.apache.baremaps.openstreetmap.model.Change;
-import org.apache.baremaps.openstreetmap.model.Node;
-import org.apache.baremaps.openstreetmap.model.Relation;
-import org.apache.baremaps.openstreetmap.model.Way;
+import org.apache.baremaps.openstreetmap.model.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -57,54 +55,49 @@ public class PutChangeImporter implements Consumer<Change> {
   /** {@inheritDoc} */
   @Override
   public void accept(Change change) {
-    var nodes = change.getEntities().stream()
+    var nodes = change.entities().stream()
         .filter(entity -> entity instanceof Node)
         .map(entity -> (Node) entity)
         .toList();
-    var nodeIds = nodes.stream().map(Node::getId).toList();
-    var ways = change.getEntities().stream()
+    var ways = change.entities().stream()
         .filter(entity -> entity instanceof Way)
         .map(entity -> (Way) entity)
         .toList();
-    var wayIds = ways.stream().map(Way::getId).toList();
-    var relations = change.getEntities().stream()
+    var relations = change.entities().stream()
         .filter(entity -> entity instanceof Relation)
         .map(entity -> (Relation) entity)
         .toList();
-    var relationIds = relations.stream().map(Relation::getId).toList();
     try {
-      switch (change.getType()) {
+      switch (change.type()) {
         case CREATE, MODIFY -> {
-          if (!nodes.isEmpty()) {
-            logger.trace("Creating {} nodes", nodes.size());
-            nodeRepository.put(nodes);
-          }
-          if (!ways.isEmpty()) {
-            logger.trace("Creating {} ways", ways.size());
-            wayRepository.put(ways);
-          }
-          if (!relations.isEmpty()) {
-            logger.trace("Creating {} relations", relations.size());
-            relationRepository.put(relations);
-          }
+          put(nodeRepository, nodes);
+          put(wayRepository, ways);
+          put(relationRepository, relations);
         }
         case DELETE -> {
-          if (!nodes.isEmpty()) {
-            logger.trace("Deleting {} nodes", nodes.size());
-            nodeRepository.delete(nodeIds);
-          }
-          if (!ways.isEmpty()) {
-            logger.trace("Deleting {} ways", ways.size());
-            wayRepository.delete(wayIds);
-          }
-          if (!relations.isEmpty()) {
-            logger.trace("Deleting {} relations", relations.size());
-            relationRepository.delete(relationIds);
-          }
+          delete(nodeRepository, nodes);
+          delete(wayRepository, ways);
+          delete(relationRepository, relations);
         }
       }
     } catch (RepositoryException e) {
       logger.error("Error while saving changes", e);
     }
   }
+
+  private <T extends Element> void put(Repository<Long, T> repository, List<T> 
entities)
+      throws RepositoryException {
+    if (!entities.isEmpty()) {
+      repository.put(entities);
+    }
+  }
+
+  private <T extends Element> void delete(Repository<Long, T> repository, 
List<T> entities)
+      throws RepositoryException {
+    List<Long> ids = entities.stream().map(Element::getId).toList();
+    if (!ids.isEmpty()) {
+      repository.delete(ids);
+    }
+  }
+
 }
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/database/postgres/HeaderRepository.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/database/postgres/HeaderRepository.java
index c4c665c9..d2dcfac1 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/database/postgres/HeaderRepository.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/database/postgres/HeaderRepository.java
@@ -64,9 +64,15 @@ public class HeaderRepository implements Repository<Long, 
Header> {
    * @param dataSource
    */
   public HeaderRepository(DataSource dataSource) {
-    this(dataSource, "public", "osm_headers", "replication_sequence_number",
+    this(
+        dataSource,
+        "public",
+        "osm_headers",
+        "replication_sequence_number",
         "replication_timestamp",
-        "replication_url", "source", "writing_program");
+        "replication_url",
+        "source",
+        "writing_program");
   }
 
   /**
@@ -81,9 +87,16 @@ public class HeaderRepository implements Repository<Long, 
Header> {
    * @param sourceColumn
    * @param writingProgramColumn
    */
-  public HeaderRepository(DataSource dataSource, String schema, String table,
-      String replicationSequenceNumberColumn, String 
replicationTimestampColumn,
-      String replicationUrlColumn, String sourceColumn, String 
writingProgramColumn) {
+  @SuppressWarnings("squid:S107")
+  public HeaderRepository(
+      DataSource dataSource,
+      String schema,
+      String table,
+      String replicationSequenceNumberColumn,
+      String replicationTimestampColumn,
+      String replicationUrlColumn,
+      String sourceColumn,
+      String writingProgramColumn) {
     var fullTableName = String.format("%1$s.%2$s", schema, table);
     this.dataSource = dataSource;
     this.createTable = String.format("""
@@ -219,7 +232,7 @@ public class HeaderRepository implements Repository<Long, 
Header> {
         Map<Long, Header> values = new HashMap<>();
         while (result.next()) {
           Header value = getValue(result);
-          values.put(value.getReplicationSequenceNumber(), value);
+          values.put(value.replicationSequenceNumber(), value);
         }
         return keys.stream().map(values::get).toList();
       }
@@ -302,11 +315,11 @@ public class HeaderRepository implements Repository<Long, 
Header> {
         writer.writeHeader();
         for (Header value : values) {
           writer.startRow(5);
-          writer.writeLong(value.getReplicationSequenceNumber());
-          writer.writeLocalDateTime(value.getReplicationTimestamp());
-          writer.write(value.getReplicationUrl());
-          writer.write(value.getSource());
-          writer.write(value.getWritingProgram());
+          writer.writeLong(value.replicationSequenceNumber());
+          writer.writeLocalDateTime(value.replicationTimestamp());
+          writer.write(value.replicationUrl());
+          writer.write(value.source());
+          writer.write(value.writingProgram());
         }
       }
     } catch (IOException | SQLException e) {
@@ -325,10 +338,10 @@ public class HeaderRepository implements Repository<Long, 
Header> {
   }
 
   private void setValue(PreparedStatement statement, Header value) throws 
SQLException {
-    statement.setObject(1, value.getReplicationSequenceNumber());
-    statement.setObject(2, value.getReplicationTimestamp());
-    statement.setObject(3, value.getReplicationUrl());
-    statement.setObject(4, value.getSource());
-    statement.setObject(5, value.getWritingProgram());
+    statement.setObject(1, value.replicationSequenceNumber());
+    statement.setObject(2, value.replicationTimestamp());
+    statement.setObject(3, value.replicationUrl());
+    statement.setObject(4, value.source());
+    statement.setObject(5, value.writingProgram());
   }
 }
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/database/postgres/RelationRepository.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/database/postgres/RelationRepository.java
index 6a0a9622..a37f02b8 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/database/postgres/RelationRepository.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/database/postgres/RelationRepository.java
@@ -315,11 +315,11 @@ public class RelationRepository implements 
Repository<Long, Relation> {
           writer.writeLong(value.getInfo().getChangeset());
           writer.writeJsonb(JsonbMapper.toJson(value.getTags()));
           writer.writeLongList(
-              value.getMembers().stream().map(Member::getRef).toList());
-          
writer.writeIntegerList(value.getMembers().stream().map(Member::getType)
+              value.getMembers().stream().map(Member::ref).toList());
+          writer.writeIntegerList(value.getMembers().stream().map(Member::type)
               .map(MemberType::ordinal).toList());
           writer
-              
.write(value.getMembers().stream().map(Member::getRole).toList());
+              .write(value.getMembers().stream().map(Member::role).toList());
           writer.writeGeometry(value.getGeometry());
         }
       }
@@ -355,12 +355,12 @@ public class RelationRepository implements 
Repository<Long, Relation> {
     statement.setObject(4, value.getInfo().getTimestamp());
     statement.setObject(5, value.getInfo().getChangeset());
     statement.setObject(6, JsonbMapper.toJson(value.getTags()));
-    Object[] refs = value.getMembers().stream().map(Member::getRef).toArray();
+    Object[] refs = value.getMembers().stream().map(Member::ref).toArray();
     statement.setObject(7, statement.getConnection().createArrayOf("bigint", 
refs));
     Object[] types =
-        
value.getMembers().stream().map(Member::getType).map(MemberType::ordinal).toArray();
+        
value.getMembers().stream().map(Member::type).map(MemberType::ordinal).toArray();
     statement.setObject(8, statement.getConnection().createArrayOf("int", 
types));
-    Object[] roles = 
value.getMembers().stream().map(Member::getRole).toArray();
+    Object[] roles = value.getMembers().stream().map(Member::role).toArray();
     statement.setObject(9, statement.getConnection().createArrayOf("varchar", 
roles));
     statement.setBytes(10, GeometryUtils.serialize(value.getGeometry()));
   }
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/storage/flatgeobuf/FlatGeoBufDataTable.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/storage/flatgeobuf/FlatGeoBufDataTable.java
index e3dd4815..1132f8b8 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/storage/flatgeobuf/FlatGeoBufDataTable.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/storage/flatgeobuf/FlatGeoBufDataTable.java
@@ -46,7 +46,7 @@ public class FlatGeoBufDataTable implements DataTable {
 
   private final Path file;
 
-  private DataSchema schema;
+  private final DataSchema schema;
 
   /**
    * Constructs a table from a flatgeobuf file (used for reading).
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/CommonByteReader.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/CommonByteReader.java
index 3084ca8a..a0db24c9 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/CommonByteReader.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/CommonByteReader.java
@@ -32,16 +32,16 @@ import java.util.Objects;
 public abstract class CommonByteReader implements AutoCloseable {
 
   /** The File. */
-  private File file;
+  private final File file;
 
   /** Input Stream on the DBF. */
-  private FileInputStream fis;
+  private final FileInputStream fis;
 
   /** File channel on the file. */
-  private FileChannel fc;
+  private final FileChannel fc;
 
   /** Buffer reader. */
-  private MappedByteBuffer byteBuffer;
+  private final MappedByteBuffer byteBuffer;
 
   /** Indicates if the byte buffer is closed. */
   private boolean isClosed = false;
@@ -56,8 +56,7 @@ public abstract class CommonByteReader implements 
AutoCloseable {
     this.file = f;
     this.fis = new FileInputStream(this.file);
     this.fc = this.fis.getChannel();
-    int fsize = (int) this.fc.size();
-    this.byteBuffer = this.fc.map(FileChannel.MapMode.READ_ONLY, 0, fsize);
+    this.byteBuffer = this.fc.map(FileChannel.MapMode.READ_ONLY, 0, 
this.fc.size());
   }
 
   /**
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/ShapefileByteReader.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/ShapefileByteReader.java
index 86cc3ccd..aac85dcf 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/ShapefileByteReader.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/ShapefileByteReader.java
@@ -214,6 +214,7 @@ public class ShapefileByteReader extends CommonByteReader {
         try {
           databaseReader.close();
         } catch (IOException e) {
+          // Ignore
         }
       }
     }
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/ShapefileReader.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/ShapefileReader.java
index 6d41aa7b..a55de8a0 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/ShapefileReader.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/ShapefileReader.java
@@ -190,8 +190,9 @@ public class ShapefileReader {
    * this is also automatically done when executing a query on it, by findAll.
    */
   public void loadDescriptors() throws IOException {
-    // Doing a simple query will init the internal descriptors.
+
     try (ShapefileInputStream is = read()) {
+      // Doing a read is sufficient to initialize the internal descriptors.
     }
   }
 }
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/tilestore/pmtiles/PMTilesStore.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/tilestore/pmtiles/PMTilesStore.java
index 1ef2b472..b17b12ba 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/tilestore/pmtiles/PMTilesStore.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/tilestore/pmtiles/PMTilesStore.java
@@ -33,7 +33,7 @@ public class PMTilesStore implements TileStore {
 
   private final PMTilesWriter writer;
 
-  public PMTilesStore(Path path, Tileset tileset) {
+  public PMTilesStore(Path path, Tileset tileset) throws TileStoreException {
     try {
       var metadata = new HashMap<String, Object>();
       metadata.put("name", tileset.getName());
@@ -62,7 +62,7 @@ public class PMTilesStore implements TileStore {
       writer.setMaxZoom(tileset.getMaxzoom());
 
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      throw new TileStoreException(e);
     }
   }
 
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/tilestore/postgres/PostgresTileStore.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/tilestore/postgres/PostgresTileStore.java
index fe72fbd4..ba9f3586 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/tilestore/postgres/PostgresTileStore.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/tilestore/postgres/PostgresTileStore.java
@@ -60,7 +60,7 @@ public class PostgresTileStore implements TileStore {
   /**
    * A cache of queries.
    */
-  private Map<Integer, Query> cache = new ConcurrentHashMap<>();
+  private final Map<Integer, Query> cache = new ConcurrentHashMap<>();
 
   /**
    * A record that holds the sql of a prepared statement and the number of 
parameters.
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/utils/PostgresUtils.java 
b/baremaps-core/src/main/java/org/apache/baremaps/utils/PostgresUtils.java
index 32da3bf8..7b41740a 100644
--- a/baremaps-core/src/main/java/org/apache/baremaps/utils/PostgresUtils.java
+++ b/baremaps-core/src/main/java/org/apache/baremaps/utils/PostgresUtils.java
@@ -164,23 +164,6 @@ public final class PostgresUtils {
     return new HikariDataSource(config);
   }
 
-  /**
-   * Appends the multi-queries parameter to the given JDBC URL.
-   *
-   * @param jdbcUrl the JDBC URL
-   * @return the JDBC URL with the multi-queries parameter
-   */
-  private static String withAllowMultiQueriesParameter(String jdbcUrl) {
-    if (jdbcUrl == null || jdbcUrl.isEmpty()) {
-      return jdbcUrl;
-    }
-    if (jdbcUrl.contains("?")) {
-      return jdbcUrl + "&allowMultiQueries=true";
-    } else {
-      return jdbcUrl + "?allowMultiQueries=true";
-    }
-  }
-
   /**
    * Executes the queries contained in a resource file.
    *
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportDaylightFeatures.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportDaylightFeatures.java
index c5a1050b..8ff7b3ea 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportDaylightFeatures.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportDaylightFeatures.java
@@ -24,9 +24,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.StringJoiner;
-import org.apache.baremaps.database.postgres.NodeRepository;
-import org.apache.baremaps.database.postgres.RelationRepository;
-import org.apache.baremaps.database.postgres.WayRepository;
+import org.apache.baremaps.database.postgres.*;
+import org.apache.baremaps.openstreetmap.model.Element;
 import org.apache.baremaps.workflow.Task;
 import org.apache.baremaps.workflow.WorkflowContext;
 import org.slf4j.Logger;
@@ -55,7 +54,7 @@ public class ImportDaylightFeatures implements Task {
    * Constructs an {@code ImportDaylightFeatures}.
    */
   public ImportDaylightFeatures() {
-
+    // Default constructor
   }
 
   /**
@@ -75,11 +74,11 @@ public class ImportDaylightFeatures implements Task {
   @Override
   public void execute(WorkflowContext context) throws Exception {
     var datasource = context.getDataSource(database);
-
-    // Initialize the repositories
     var nodeRepository = new NodeRepository(datasource);
     var wayRepository = new WayRepository(datasource);
     var relationRepository = new RelationRepository(datasource);
+
+    // Initialize the repositories
     nodeRepository.create();
     wayRepository.create();
     relationRepository.create();
@@ -90,40 +89,24 @@ public class ImportDaylightFeatures implements Task {
     List<Feature> features = objectMapper.readValue(file.toFile(), javaType);
     for (var feature : features) {
       switch (feature.type()) {
-        case "node" -> {
-          var node = nodeRepository.get(feature.id());
-          if (node != null) {
-            var tags = new HashMap<>(feature.tags());
-            if (node.getTags() != null) {
-              tags.putAll(node.getTags());
-            }
-            node.setTags(tags);
-            nodeRepository.put(node);
-          }
-        }
-        case "way" -> {
-          var way = wayRepository.get(feature.id());
-          if (way != null) {
-            var tags = new HashMap<>(feature.tags());
-            if (way.getTags() != null) {
-              tags.putAll(way.getTags());
-            }
-            way.setTags(tags);
-            wayRepository.put(way);
-          }
-        }
-        case "relation" -> {
-          var relation = relationRepository.get(feature.id());
-          if (relation != null) {
-            var tags = new HashMap<>(feature.tags());
-            if (relation.getTags() != null) {
-              tags.putAll(relation.getTags());
-            }
-            relation.setTags(tags);
-            relationRepository.put(relation);
-          }
-        }
+        case "node" -> save(feature, nodeRepository);
+        case "way" -> save(feature, wayRepository);
+        case "relation" -> save(feature, relationRepository);
+        default -> logger.warn("Unknown type: {}", feature.type());
+      }
+    }
+  }
+
+  private <T extends Element> void save(Feature feature, Repository<Long, T> 
repository)
+      throws RepositoryException {
+    var entity = repository.get(feature.id());
+    if (entity != null) {
+      var tags = new HashMap<>(feature.tags());
+      if (entity.getTags() != null) {
+        tags.putAll(entity.getTags());
       }
+      entity.setTags(tags);
+      repository.put(entity);
     }
   }
 
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportDaylightTranslations.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportDaylightTranslations.java
index 3cb44997..b99e073d 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportDaylightTranslations.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportDaylightTranslations.java
@@ -20,11 +20,11 @@ package org.apache.baremaps.workflow.tasks;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.HashMap;
+import java.util.List;
 import java.util.StringJoiner;
 import java.util.stream.Collectors;
-import org.apache.baremaps.database.postgres.NodeRepository;
-import org.apache.baremaps.database.postgres.RelationRepository;
-import org.apache.baremaps.database.postgres.WayRepository;
+import org.apache.baremaps.database.postgres.*;
+import org.apache.baremaps.openstreetmap.model.Element;
 import org.apache.baremaps.workflow.Task;
 import org.apache.baremaps.workflow.WorkflowContext;
 import org.slf4j.Logger;
@@ -86,11 +86,11 @@ public class ImportDaylightTranslations implements Task {
   @Override
   public void execute(WorkflowContext context) throws Exception {
     var datasource = context.getDataSource(database);
-
-    // Initialize the repositories
     var nodeRepository = new NodeRepository(datasource);
     var wayRepository = new WayRepository(datasource);
     var relationRepository = new RelationRepository(datasource);
+
+    // Initialize the repositories
     nodeRepository.create();
     wayRepository.create();
     relationRepository.create();
@@ -99,46 +99,31 @@ public class ImportDaylightTranslations implements Task {
     try (var lines = Files.lines(file)) {
       var entries = 
lines.map(Line::parse).collect(Collectors.groupingBy(Line::group));
       for (var entry : entries.entrySet()) {
-        var group = entry.getKey();
-        switch (group.type()) {
-          case "node" -> {
-            var node = nodeRepository.get(group.id());
-            if (node != null) {
-              var tags = new HashMap<>(node.getTags());
-              for (var line : entry.getValue()) {
-                tags.put(line.attributeKey(), line.attributeValue());
-              }
-              node.setTags(tags);
-              nodeRepository.put(node);
-            }
-          }
-          case "way" -> {
-            var way = wayRepository.get(group.id());
-            if (way != null) {
-              var tags = new HashMap<>(way.getTags());
-              for (var line : entry.getValue()) {
-                tags.put(line.attributeKey(), line.attributeValue());
-              }
-              way.setTags(tags);
-              wayRepository.put(way);
-            }
-          }
-          case "relation" -> {
-            var relation = relationRepository.get(group.id());
-            if (relation != null) {
-              var tags = new HashMap<>(relation.getTags());
-              for (var line : entry.getValue()) {
-                tags.put(line.attributeKey(), line.attributeValue());
-              }
-              relation.setTags(tags);
-              relationRepository.put(relation);
-            }
-          }
+        var key = entry.getKey();
+        var value = entry.getValue();
+        switch (entry.getKey().type()) {
+          case "node" -> save(key, value, nodeRepository);
+          case "way" -> save(key, value, wayRepository);
+          case "relation" -> save(key, value, relationRepository);
+          default -> logger.warn("Unknown type: {}", key.type());
         }
       }
     }
   }
 
+  private <T extends Element> void save(Group group, List<Line> lines,
+      Repository<Long, T> repository) throws RepositoryException {
+    var entity = repository.get(group.id());
+    if (entity != null) {
+      var tags = new HashMap<>(entity.getTags());
+      for (var line : lines) {
+        tags.put(line.attributeKey(), line.attributeValue());
+      }
+      entity.setTags(tags);
+      repository.put(entity);
+    }
+  }
+
   /**
    * {@inheritDoc}
    */
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportOsmPbf.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportOsmPbf.java
index cf3809b6..01762d10 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportOsmPbf.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/ImportOsmPbf.java
@@ -17,6 +17,8 @@
 
 package org.apache.baremaps.workflow.tasks;
 
+import static java.lang.Boolean.TRUE;
+
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -81,7 +83,7 @@ public class ImportOsmPbf implements Task {
     var wayRepository = new WayRepository(datasource);
     var relationRepository = new RelationRepository(datasource);
 
-    if (replaceExisting) {
+    if (TRUE.equals(replaceExisting)) {
       // Drop the existing tables
       headerRepository.drop();
       nodeRepository.drop();
@@ -122,7 +124,8 @@ public class ImportOsmPbf implements Task {
    * @param databaseSrid the database SRID
    * @throws IOException
    */
-  public static void execute(
+  @SuppressWarnings("squid:S107")
+  static void execute(
       Path path,
       Map<Long, Coordinate> coordinateMap,
       Map<Long, List<Long>> referenceMap,
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/UpdateOsmDatabase.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/UpdateOsmDatabase.java
index 52d847fb..f4170dab 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/UpdateOsmDatabase.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/UpdateOsmDatabase.java
@@ -102,7 +102,8 @@ public class UpdateOsmDatabase implements Task {
    * @param databaseSrid the SRID
    * @throws Exception if something went wrong
    */
-  public static void execute(
+  @SuppressWarnings("squid:S107")
+  static void execute(
       Map<Long, Coordinate> coordinateMap,
       Map<Long, List<Long>> referenceMap,
       HeaderRepository headerRepository,
@@ -117,19 +118,19 @@ public class UpdateOsmDatabase implements Task {
 
     // If the replicationUrl is not provided, use the one from the latest 
header.
     if (replicationUrl == null) {
-      replicationUrl = header.getReplicationUrl();
+      replicationUrl = header.replicationUrl();
     }
 
     // Get the sequence number of the latest header
     var stateReader = new StateReader(replicationUrl, true);
-    var sequenceNumber = header.getReplicationSequenceNumber();
+    var sequenceNumber = header.replicationSequenceNumber();
 
     // If the replicationTimestamp is not provided, guess it from the 
replication timestamp.
     if (sequenceNumber <= 0) {
-      var replicationTimestamp = header.getReplicationTimestamp();
+      var replicationTimestamp = header.replicationTimestamp();
       var state = stateReader.getStateFromTimestamp(replicationTimestamp);
       if (state.isPresent()) {
-        sequenceNumber = state.get().getSequenceNumber();
+        sequenceNumber = state.get().sequenceNumber();
       }
     }
 
@@ -173,8 +174,8 @@ public class UpdateOsmDatabase implements Task {
     var stateUrl = stateReader.getUrl(replicationUrl, nextSequenceNumber, 
"state.txt");
     try (var stateInputStream = new 
BufferedInputStream(stateUrl.openStream())) {
       var state = new StateReader().read(stateInputStream);
-      headerRepository.put(new Header(state.getSequenceNumber(), 
state.getTimestamp(),
-          header.getReplicationUrl(), header.getSource(), 
header.getWritingProgram()));
+      headerRepository.put(new Header(state.sequenceNumber(), 
state.timestamp(),
+          header.replicationUrl(), header.source(), header.writingProgram()));
     }
   }
 
diff --git 
a/baremaps-core/src/test/java/org/apache/baremaps/config/TileSetTest.java 
b/baremaps-core/src/test/java/org/apache/baremaps/config/TileSetTest.java
index 2679084e..fefd185a 100644
--- a/baremaps-core/src/test/java/org/apache/baremaps/config/TileSetTest.java
+++ b/baremaps-core/src/test/java/org/apache/baremaps/config/TileSetTest.java
@@ -31,10 +31,10 @@ import org.junit.Test;
 
 public class TileSetTest {
 
-  private String tilesetFile = "/tilesets/tileset.json";
-  private String tilejsonFile = "/tilesets/tilejson.json";
-  private ObjectMapper objectMapper = ObjectMapperUtils.objectMapper();
-  ConfigReader configReader = new ConfigReader();
+  final String tilesetFile = "/tilesets/tileset.json";
+  final String tilejsonFile = "/tilesets/tilejson.json";
+  final ObjectMapper objectMapper = ObjectMapperUtils.objectMapper();
+  final ConfigReader configReader = new ConfigReader();
 
   private File resourceFile(String path) {
     return new File(TileSetTest.class.getResource(path).getFile());
diff --git 
a/baremaps-core/src/test/java/org/apache/baremaps/database/postgres/HeaderRepositoryTest.java
 
b/baremaps-core/src/test/java/org/apache/baremaps/database/postgres/HeaderRepositoryTest.java
index 3897b5f5..7a1b4a4a 100644
--- 
a/baremaps-core/src/test/java/org/apache/baremaps/database/postgres/HeaderRepositoryTest.java
+++ 
b/baremaps-core/src/test/java/org/apache/baremaps/database/postgres/HeaderRepositoryTest.java
@@ -60,7 +60,7 @@ class HeaderRepositoryTest extends PostgresRepositoryTest {
   @Tag("integration")
   void insert() throws RepositoryException {
     headerRepository.put(HEADER_0);
-    assertEquals(HEADER_0, 
headerRepository.get(HEADER_0.getReplicationSequenceNumber()));
+    assertEquals(HEADER_0, 
headerRepository.get(HEADER_0.replicationSequenceNumber()));
   }
 
   @Test
@@ -69,15 +69,15 @@ class HeaderRepositoryTest extends PostgresRepositoryTest {
     List<Header> headers = Arrays.asList(HEADER_0, HEADER_1, HEADER_2);
     headerRepository.put(headers);
     assertIterableEquals(headers, headerRepository.get(
-        headers.stream().map(Header::getReplicationSequenceNumber).toList()));
+        headers.stream().map(Header::replicationSequenceNumber).toList()));
   }
 
   @Test
   @Tag("integration")
   void delete() throws RepositoryException {
     headerRepository.put(HEADER_0);
-    headerRepository.delete(HEADER_0.getReplicationSequenceNumber());
-    assertNull(headerRepository.get(HEADER_0.getReplicationSequenceNumber()));
+    headerRepository.delete(HEADER_0.replicationSequenceNumber());
+    assertNull(headerRepository.get(HEADER_0.replicationSequenceNumber()));
   }
 
   @Test
@@ -86,9 +86,9 @@ class HeaderRepositoryTest extends PostgresRepositoryTest {
     List<Header> headers = Arrays.asList(HEADER_0, HEADER_1, HEADER_2);
     headerRepository.put(headers);
     headerRepository.delete(
-        headers.stream().map(Header::getReplicationSequenceNumber).toList());
+        headers.stream().map(Header::replicationSequenceNumber).toList());
     assertIterableEquals(Arrays.asList(null, null, null), headerRepository.get(
-        headers.stream().map(Header::getReplicationSequenceNumber).toList()));
+        headers.stream().map(Header::replicationSequenceNumber).toList()));
   }
 
   @Test
@@ -97,6 +97,6 @@ class HeaderRepositoryTest extends PostgresRepositoryTest {
     List<Header> headers = Arrays.asList(HEADER_0, HEADER_1, HEADER_2);
     headerRepository.copy(headers);
     assertIterableEquals(headers, headerRepository.get(
-        headers.stream().map(Header::getReplicationSequenceNumber).toList()));
+        headers.stream().map(Header::replicationSequenceNumber).toList()));
   }
 }
diff --git 
a/baremaps-core/src/test/java/org/apache/baremaps/workflow/tasks/ImportUpdateSampleTest.java
 
b/baremaps-core/src/test/java/org/apache/baremaps/workflow/tasks/ImportUpdateSampleTest.java
index 0942ebf7..d91627d3 100644
--- 
a/baremaps-core/src/test/java/org/apache/baremaps/workflow/tasks/ImportUpdateSampleTest.java
+++ 
b/baremaps-core/src/test/java/org/apache/baremaps/workflow/tasks/ImportUpdateSampleTest.java
@@ -67,14 +67,14 @@ class ImportUpdateSampleTest extends PostgresRepositoryTest 
{
     // Import the sample data
     ImportOsmPbf.execute(TestFiles.SAMPLE_OSM_PBF, coordinateMap, 
referenceMap, headerRepository,
         nodeRepository, wayRepository, relationRepository, srid);
-    assertEquals(0, 
headerRepository.selectLatest().getReplicationSequenceNumber());
+    assertEquals(0, 
headerRepository.selectLatest().replicationSequenceNumber());
 
     // Import the state file
     try (var stateInput = Files.newInputStream(TestFiles.SAMPLE_STATE_TXT)) {
       var state = new StateReader().read(stateInput);
-      headerRepository.put(new Header(state.getSequenceNumber(), 
state.getTimestamp(),
+      headerRepository.put(new Header(state.sequenceNumber(), 
state.timestamp(),
           "file:///" + TestFiles.SAMPLE_DIR, "", ""));
-      assertEquals(1, 
headerRepository.selectLatest().getReplicationSequenceNumber());
+      assertEquals(1, 
headerRepository.selectLatest().replicationSequenceNumber());
     }
     assertGeometryEquals(NODE_POINT_1, nodeRepository.get(1L).getGeometry(), 
100);
     assertGeometryEquals(WAY_LINESTRING_4, 
wayRepository.get(4L).getGeometry(), 100);
@@ -89,7 +89,7 @@ class ImportUpdateSampleTest extends PostgresRepositoryTest {
     // Add elements to the database
     UpdateOsmDatabase.execute(coordinateMap, referenceMap, headerRepository, 
nodeRepository,
         wayRepository, relationRepository, srid, null);
-    assertEquals(2, 
headerRepository.selectLatest().getReplicationSequenceNumber());
+    assertEquals(2, 
headerRepository.selectLatest().replicationSequenceNumber());
 
     assertGeometryEquals(NODE_POINT_37, nodeRepository.get(37L).getGeometry(), 
100);
     assertGeometryEquals(WAY_LINESTRING_40, 
wayRepository.get(40L).getGeometry(), 100);
@@ -100,7 +100,7 @@ class ImportUpdateSampleTest extends PostgresRepositoryTest 
{
     // Modify elements in the database
     UpdateOsmDatabase.execute(coordinateMap, referenceMap, headerRepository, 
nodeRepository,
         wayRepository, relationRepository, srid, null);
-    assertEquals(3, 
headerRepository.selectLatest().getReplicationSequenceNumber());
+    assertEquals(3, 
headerRepository.selectLatest().replicationSequenceNumber());
     assertGeometryEquals(NODE_POINT_1_MODIFIED, 
nodeRepository.get(1L).getGeometry(), 100);
     assertGeometryEquals(WAY_LINESTRING_4_MODIFIED, 
wayRepository.get(4L).getGeometry(), 100);
     assertGeometryEquals(WAY_POLYGON_9_MODIFIED, 
wayRepository.get(9L).getGeometry(), 100);
@@ -112,7 +112,7 @@ class ImportUpdateSampleTest extends PostgresRepositoryTest 
{
     // Delete elements from the database
     UpdateOsmDatabase.execute(coordinateMap, referenceMap, headerRepository, 
nodeRepository,
         wayRepository, relationRepository, srid, null);
-    assertEquals(4, 
headerRepository.selectLatest().getReplicationSequenceNumber());
+    assertEquals(4, 
headerRepository.selectLatest().replicationSequenceNumber());
     assertNull(nodeRepository.get(1L));
     assertNull(nodeRepository.get(4L));
     assertNull(nodeRepository.get(9L));
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/algorithm/ExternalMergeSort.java
 
b/baremaps-data/src/main/java/org/apache/baremaps/data/algorithm/ExternalMergeSort.java
index 1e520979..76bcd32b 100644
--- 
a/baremaps-data/src/main/java/org/apache/baremaps/data/algorithm/ExternalMergeSort.java
+++ 
b/baremaps-data/src/main/java/org/apache/baremaps/data/algorithm/ExternalMergeSort.java
@@ -209,7 +209,7 @@ public class ExternalMergeSort {
    */
   static final class DataStack<T> implements AutoCloseable {
 
-    private DataList<T> list;
+    private final DataList<T> list;
 
     private Long index = 0l;
 
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/collection/AppendOnlyLog.java
 
b/baremaps-data/src/main/java/org/apache/baremaps/data/collection/AppendOnlyLog.java
index 23e1777f..fbb54998 100644
--- 
a/baremaps-data/src/main/java/org/apache/baremaps/data/collection/AppendOnlyLog.java
+++ 
b/baremaps-data/src/main/java/org/apache/baremaps/data/collection/AppendOnlyLog.java
@@ -44,7 +44,7 @@ public class AppendOnlyLog<E> implements DataCollection<E> {
   private long offset;
   private long size;
 
-  private Lock lock = new ReentrantLock();
+  private final Lock lock = new ReentrantLock();
 
   /**
    * Constructs an {@link AppendOnlyLog}.
@@ -143,7 +143,6 @@ public class AppendOnlyLog<E> implements DataCollection<E> {
    */
   @Override
   public AppendOnlyLogIterator iterator() {
-    final long size = size();
     return new AppendOnlyLogIterator(size);
   }
 
@@ -180,21 +179,21 @@ public class AppendOnlyLog<E> implements 
DataCollection<E> {
 
       ByteBuffer segment = memory.segment((int) segmentIndex);
 
-      int size;
+      int valueSize;
       try {
-        size = dataType.size(segment, (int) segmentOffset);
+        valueSize = dataType.size(segment, (int) segmentOffset);
       } catch (IndexOutOfBoundsException e) {
-        size = 0;
+        valueSize = 0;
       }
 
-      if (segmentOffset + size > segmentSize || size == 0) {
+      if (segmentOffset + valueSize > segmentSize || valueSize == 0) {
         segmentIndex = segmentIndex + 1;
         segmentOffset = 0;
         position = segmentIndex * segmentSize;
         segment = memory.segment((int) segmentIndex);
-        size = dataType.size(segment, (int) segmentOffset);
+        valueSize = dataType.size(segment, (int) segmentOffset);
       }
-      position += size;
+      position += valueSize;
       index++;
 
       return dataType.read(segment, (int) segmentOffset);
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/collection/DataConversions.java
 
b/baremaps-data/src/main/java/org/apache/baremaps/data/collection/DataConversions.java
index 4a315fb2..dd327e31 100644
--- 
a/baremaps-data/src/main/java/org/apache/baremaps/data/collection/DataConversions.java
+++ 
b/baremaps-data/src/main/java/org/apache/baremaps/data/collection/DataConversions.java
@@ -196,6 +196,16 @@ public class DataConversions {
     public int size() {
       return size;
     }
+
+    @Override
+    public boolean equals(Object object) {
+      return list.equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+      return list.hashCode();
+    }
   }
 
   private static class DataListAdapter<E> implements DataList<E> {
@@ -231,6 +241,16 @@ public class DataConversions {
     public E get(long index) {
       return list.get((int) index);
     }
+
+    @Override
+    public boolean equals(Object object) {
+      return list.equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+      return list.hashCode();
+    }
   }
 
   private static class MapAdapter<K, V> extends AbstractMap<K, V> {
@@ -262,6 +282,16 @@ public class DataConversions {
         }
       };
     }
+
+    @Override
+    public boolean equals(Object object) {
+      return map.equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+      return map.hashCode();
+    }
   }
 
   private static class DataMapAdapter<K, V> implements DataMap<K, V> {
@@ -316,6 +346,16 @@ public class DataConversions {
     public Iterator<Entry<K, V>> entryIterator() {
       return map.entrySet().iterator();
     }
+
+    @Override
+    public boolean equals(Object object) {
+      return map.equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+      return map.hashCode();
+    }
   }
 
 }
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/collection/DataList.java 
b/baremaps-data/src/main/java/org/apache/baremaps/data/collection/DataList.java
index d4b4bd7d..de711d10 100644
--- 
a/baremaps-data/src/main/java/org/apache/baremaps/data/collection/DataList.java
+++ 
b/baremaps-data/src/main/java/org/apache/baremaps/data/collection/DataList.java
@@ -67,9 +67,9 @@ public interface DataList<E> extends DataCollection<E> {
   default Iterator<E> iterator() {
     return new Iterator<>() {
 
-      private long index = 0;
+      private final long size = size();
 
-      private long size = size();
+      private long index = 0;
 
       @Override
       public boolean hasNext() {
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/collection/MemoryAlignedDataMap.java
 
b/baremaps-data/src/main/java/org/apache/baremaps/data/collection/MemoryAlignedDataMap.java
index e6f2f9f9..3e521acc 100644
--- 
a/baremaps-data/src/main/java/org/apache/baremaps/data/collection/MemoryAlignedDataMap.java
+++ 
b/baremaps-data/src/main/java/org/apache/baremaps/data/collection/MemoryAlignedDataMap.java
@@ -129,9 +129,9 @@ public class MemoryAlignedDataMap<E> implements 
DataMap<Long, E> {
   public Iterator<Long> keyIterator() {
     return new Iterator<>() {
 
-      private long index = 0;
+      private final long size = size();
 
-      private long size = size();
+      private long index = 0;
 
       @Override
       public boolean hasNext() {
@@ -153,9 +153,9 @@ public class MemoryAlignedDataMap<E> implements 
DataMap<Long, E> {
   public Iterator<E> valueIterator() {
     return new Iterator<>() {
 
-      private long index = 0;
+      private final long size = size();
 
-      private long size = size();
+      private long index = 0;
 
       @Override
       public boolean hasNext() {
@@ -176,9 +176,9 @@ public class MemoryAlignedDataMap<E> implements 
DataMap<Long, E> {
   public Iterator<Entry<Long, E>> entryIterator() {
     return new Iterator<>() {
 
-      private long index = 0;
+      private final long size = size();
 
-      private long size = size();
+      private long index = 0;
 
       @Override
       public boolean hasNext() {
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/storage/DataTableGeometryMapper.java
 
b/baremaps-data/src/main/java/org/apache/baremaps/data/storage/DataTableGeometryMapper.java
index 09110fcf..8f6ee5d5 100644
--- 
a/baremaps-data/src/main/java/org/apache/baremaps/data/storage/DataTableGeometryMapper.java
+++ 
b/baremaps-data/src/main/java/org/apache/baremaps/data/storage/DataTableGeometryMapper.java
@@ -17,14 +17,14 @@
 
 package org.apache.baremaps.data.storage;
 
-import java.util.function.Function;
+import java.util.function.UnaryOperator;
 import org.locationtech.jts.geom.Geometry;
 import org.locationtech.jts.geom.util.GeometryTransformer;
 
 /**
  * A decorator for a {@link DataTable} that applies a geometry transformation 
to each row.
  */
-public class DataTableGeometryMapper implements Function<DataRow, DataRow> {
+public class DataTableGeometryMapper implements UnaryOperator<DataRow> {
 
   private final DataTable table;
 
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/storage/DataTableMapper.java
 
b/baremaps-data/src/main/java/org/apache/baremaps/data/storage/DataTableMapper.java
index e496060b..9186eac2 100644
--- 
a/baremaps-data/src/main/java/org/apache/baremaps/data/storage/DataTableMapper.java
+++ 
b/baremaps-data/src/main/java/org/apache/baremaps/data/storage/DataTableMapper.java
@@ -20,6 +20,7 @@ package org.apache.baremaps.data.storage;
 
 import java.util.Iterator;
 import java.util.function.Function;
+import java.util.function.UnaryOperator;
 
 /**
  * A decorator for a {@link DataTable} that applies a transformation to each 
row.
@@ -36,7 +37,7 @@ public class DataTableMapper implements DataTable {
    * @param table the table
    * @param mapper the mapper
    */
-  public DataTableMapper(DataTable table, Function<DataRow, DataRow> mapper) {
+  public DataTableMapper(DataTable table, UnaryOperator<DataRow> mapper) {
     this.table = table;
     this.transformer = mapper;
   }
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/type/BooleanDataType.java
 
b/baremaps-data/src/main/java/org/apache/baremaps/data/type/BooleanDataType.java
index feb04b67..5758aad5 100644
--- 
a/baremaps-data/src/main/java/org/apache/baremaps/data/type/BooleanDataType.java
+++ 
b/baremaps-data/src/main/java/org/apache/baremaps/data/type/BooleanDataType.java
@@ -19,6 +19,8 @@ package org.apache.baremaps.data.type;
 
 
 
+import static java.lang.Boolean.TRUE;
+
 import java.nio.ByteBuffer;
 
 /** A {@link DataType} for reading and writing bytes in {@link ByteBuffer}s. */
@@ -32,7 +34,7 @@ public class BooleanDataType extends 
MemoryAlignedDataType<Boolean> {
   /** {@inheritDoc} */
   @Override
   public void write(final ByteBuffer buffer, final int position, final Boolean 
value) {
-    buffer.put(position, value ? (byte) 1 : (byte) 0);
+    buffer.put(position, TRUE.equals(value) ? (byte) 1 : (byte) 0);
   }
 
   /** {@inheritDoc} */
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/type/GeometryCollectionDataType.java
 
b/baremaps-data/src/main/java/org/apache/baremaps/data/type/GeometryCollectionDataType.java
index 451e4ce1..768a27b6 100644
--- 
a/baremaps-data/src/main/java/org/apache/baremaps/data/type/GeometryCollectionDataType.java
+++ 
b/baremaps-data/src/main/java/org/apache/baremaps/data/type/GeometryCollectionDataType.java
@@ -30,7 +30,7 @@ public class GeometryCollectionDataType implements 
DataType<GeometryCollection>
 
   private final GeometryFactory geometryFactory;
 
-  private GeometryDataType geometryDataType;
+  private final GeometryDataType geometryDataType;
 
   /**
    * Constructs a {@code GeometryCollectionDataType} with a default {@code 
GeometryFactory}.
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/type/RowDataType.java 
b/baremaps-data/src/main/java/org/apache/baremaps/data/type/RowDataType.java
index 1236e530..243ec7ee 100644
--- a/baremaps-data/src/main/java/org/apache/baremaps/data/type/RowDataType.java
+++ b/baremaps-data/src/main/java/org/apache/baremaps/data/type/RowDataType.java
@@ -96,7 +96,7 @@ public class RowDataType implements DataType<DataRow> {
   public DataRow read(final ByteBuffer buffer, final int position) {
     int p = position + Integer.BYTES;
     var columns = rowType.columns();
-    var values = new ArrayList();
+    var values = new ArrayList<>();
     for (DataColumn column : columns) {
       var columnType = column.type();
       var dataType = types.get(columnType);
diff --git 
a/baremaps-data/src/main/java/org/apache/baremaps/data/util/FileUtils.java 
b/baremaps-data/src/main/java/org/apache/baremaps/data/util/FileUtils.java
index d730816e..8fc7469f 100644
--- a/baremaps-data/src/main/java/org/apache/baremaps/data/util/FileUtils.java
+++ b/baremaps-data/src/main/java/org/apache/baremaps/data/util/FileUtils.java
@@ -28,6 +28,10 @@ import java.util.stream.Stream;
 
 public class FileUtils {
 
+  private FileUtils() {
+    // Prevent instantiation
+  }
+
   public static void deleteRecursively(Path path) throws IOException {
     try (Stream<Path> files = Files.walk(path)) {
       
files.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
diff --git 
a/baremaps-data/src/test/java/org/apache/baremaps/data/sort/ExternalMergeSortTest.java
 
b/baremaps-data/src/test/java/org/apache/baremaps/data/sort/ExternalMergeSortTest.java
index 5ee07c44..87b8ff34 100644
--- 
a/baremaps-data/src/test/java/org/apache/baremaps/data/sort/ExternalMergeSortTest.java
+++ 
b/baremaps-data/src/test/java/org/apache/baremaps/data/sort/ExternalMergeSortTest.java
@@ -39,16 +39,20 @@ import org.junit.jupiter.api.Test;
 
 class ExternalMergeSortTest {
 
-  List<String> strings = List.of("a", "b", "k", "c", "d", "a", "i", "j", "e", 
"e", "h", "f", "g");
-  List<String> stringsAsc = 
strings.stream().sorted(Comparator.naturalOrder()).toList();
-  List<String> stringsDsc = 
strings.stream().sorted(Comparator.reverseOrder()).toList();;
-  List<String> stringsDistinct = stringsAsc.stream().distinct().toList();
+  List<String> strings;
+  List<String> stringsAsc;
+  List<String> stringsDsc;
+  List<String> stringsDistinct;
   Supplier<DataList<String>> supplier;
   DataList<String> input;
   DataList<String> output;
 
   @BeforeEach
   void before() {
+    strings = List.of("a", "b", "k", "c", "d", "a", "i", "j", "e", "e", "h", 
"f", "g");
+    stringsAsc = strings.stream().sorted(Comparator.naturalOrder()).toList();
+    stringsDsc = strings.stream().sorted(Comparator.reverseOrder()).toList();
+    stringsDistinct = stringsAsc.stream().distinct().toList();
     supplier = () -> new IndexedDataList<>(
         new MemoryAlignedDataList<>(new LongDataType(), new OnHeapMemory()),
         new AppendOnlyLog<>(new StringDataType(), new OnHeapMemory()));
diff --git 
a/baremaps-data/src/test/java/org/apache/baremaps/data/type/DataTypeProvider.java
 
b/baremaps-data/src/test/java/org/apache/baremaps/data/type/DataTypeProvider.java
index eb0ec04d..b95f0369 100644
--- 
a/baremaps-data/src/test/java/org/apache/baremaps/data/type/DataTypeProvider.java
+++ 
b/baremaps-data/src/test/java/org/apache/baremaps/data/type/DataTypeProvider.java
@@ -24,8 +24,6 @@ import java.util.stream.Stream;
 import org.apache.baremaps.data.storage.*;
 import org.apache.baremaps.data.storage.DataColumn.Cardinality;
 import org.apache.baremaps.data.storage.DataColumn.Type;
-import org.apache.baremaps.data.storage.DataSchema;
-import org.apache.baremaps.data.storage.DataSchemaImpl;
 import org.junit.jupiter.params.provider.Arguments;
 import org.locationtech.jts.geom.*;
 
diff --git 
a/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/data/GeoParquetGroupRecordConverter.java
 
b/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/data/GeoParquetGroupRecordConverter.java
index ad1b1d2d..01cfc871 100644
--- 
a/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/data/GeoParquetGroupRecordConverter.java
+++ 
b/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/data/GeoParquetGroupRecordConverter.java
@@ -40,7 +40,7 @@ public class GeoParquetGroupRecordConverter extends 
RecordMaterializer<GeoParque
 
   private final GeoParquetGroupFactory groupFactory;
 
-  private GeoParquetGroupConverter root;
+  private final GeoParquetGroupConverter root;
 
   public GeoParquetGroupRecordConverter(MessageType schema, GeoParquetMetadata 
metadata) {
     this.groupFactory = new GeoParquetGroupFactory(schema, metadata);
diff --git 
a/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/data/GeoParquetMaterializer.java
 
b/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/data/GeoParquetMaterializer.java
index a01ba90f..a8cc46a0 100644
--- 
a/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/data/GeoParquetMaterializer.java
+++ 
b/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/data/GeoParquetMaterializer.java
@@ -25,7 +25,7 @@ public class GeoParquetMaterializer extends 
RecordMaterializer<GeoParquetGroupIm
 
   private final GeoParquetGroupFactory groupFactory;
 
-  private GeoParquetGroupConverter root;
+  private final GeoParquetGroupConverter root;
 
   public GeoParquetMaterializer(MessageType schema, GeoParquetMetadata 
metadata) {
     this.groupFactory = new GeoParquetGroupFactory(schema, metadata);
diff --git 
a/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/hadoop/GeoParquetWriter.java
 
b/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/hadoop/GeoParquetWriter.java
index 41d2c8fe..4395d5e6 100644
--- 
a/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/hadoop/GeoParquetWriter.java
+++ 
b/baremaps-geoparquet/src/main/java/org/apache/baremaps/geoparquet/hadoop/GeoParquetWriter.java
@@ -70,13 +70,17 @@ public class GeoParquetWriter extends 
ParquetWriter<GeoParquetGroupImpl> {
    * @param conf The Configuration to use.
    * @throws IOException
    */
-  GeoParquetWriter(Path file, WriteSupport<GeoParquetGroupImpl> writeSupport,
+  @SuppressWarnings("squid:S107")
+  GeoParquetWriter(
+      Path file,
+      WriteSupport<GeoParquetGroupImpl> writeSupport,
       CompressionCodecName compressionCodecName,
-      int blockSize, int pageSize, boolean enableDictionary,
+      int blockSize,
+      int pageSize,
+      boolean enableDictionary,
       boolean enableValidation,
       ParquetProperties.WriterVersion writerVersion,
-      Configuration conf)
-      throws IOException {
+      Configuration conf) throws IOException {
     super(file, writeSupport, compressionCodecName, blockSize, pageSize,
         pageSize, enableDictionary, enableValidation, writerVersion, conf);
   }
diff --git 
a/baremaps-maplibre/src/main/java/org/apache/baremaps/maplibre/expression/Expressions.java
 
b/baremaps-maplibre/src/main/java/org/apache/baremaps/maplibre/expression/Expressions.java
index 72eae357..a3ce8b4c 100644
--- 
a/baremaps-maplibre/src/main/java/org/apache/baremaps/maplibre/expression/Expressions.java
+++ 
b/baremaps-maplibre/src/main/java/org/apache/baremaps/maplibre/expression/Expressions.java
@@ -19,7 +19,6 @@ package org.apache.baremaps.maplibre.expression;
 
 
 
-import com.fasterxml.jackson.core.JacksonException;
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.Version;
@@ -452,7 +451,7 @@ public interface Expressions {
 
     @Override
     public Expression deserialize(JsonParser jsonParser,
-        DeserializationContext deserializationContext) throws IOException, 
JacksonException {
+        DeserializationContext deserializationContext) throws IOException {
       JsonNode node = jsonParser.getCodec().readTree(jsonParser);
       return deserializeJsonNode(node);
     }
diff --git 
a/baremaps-maplibre/src/main/java/org/apache/baremaps/maplibre/vectortile/VectorTileEncoder.java
 
b/baremaps-maplibre/src/main/java/org/apache/baremaps/maplibre/vectortile/VectorTileEncoder.java
index 8af06bbe..8a883f59 100644
--- 
a/baremaps-maplibre/src/main/java/org/apache/baremaps/maplibre/vectortile/VectorTileEncoder.java
+++ 
b/baremaps-maplibre/src/main/java/org/apache/baremaps/maplibre/vectortile/VectorTileEncoder.java
@@ -183,18 +183,18 @@ public class VectorTileEncoder {
    * @param encoding The consumer of commands and parameters.
    */
   protected void encodeGeometry(Geometry geometry, Consumer<Integer> encoding) 
{
-    if (geometry instanceof Point) {
-      encodePoint((Point) geometry, encoding);
-    } else if (geometry instanceof MultiPoint) {
-      encodeMultiPoint((MultiPoint) geometry, encoding);
-    } else if (geometry instanceof LineString) {
-      encodeLineString((LineString) geometry, encoding);
-    } else if (geometry instanceof MultiLineString) {
-      encodeMultiLineString((MultiLineString) geometry, encoding);
-    } else if (geometry instanceof Polygon) {
-      encodePolygon((Polygon) geometry, encoding);
-    } else if (geometry instanceof MultiPolygon) {
-      encodeMultiPolygon((MultiPolygon) geometry, encoding);
+    if (geometry instanceof Point point) {
+      encodePoint(point, encoding);
+    } else if (geometry instanceof MultiPoint multiPoint) {
+      encodeMultiPoint(multiPoint, encoding);
+    } else if (geometry instanceof LineString lineString) {
+      encodeLineString(lineString, encoding);
+    } else if (geometry instanceof MultiLineString multiLineString) {
+      encodeMultiLineString(multiLineString, encoding);
+    } else if (geometry instanceof Polygon polygon) {
+      encodePolygon(polygon, encoding);
+    } else if (geometry instanceof MultiPolygon multiPolygon) {
+      encodeMultiPolygon(multiPolygon, encoding);
     } else if (geometry instanceof GeometryCollection) {
       throw new UnsupportedOperationException("GeometryCollection not 
supported");
     }
diff --git 
a/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/expression/ExpressionsTest.java
 
b/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/expression/ExpressionsTest.java
index 721fc167..e9b91263 100644
--- 
a/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/expression/ExpressionsTest.java
+++ 
b/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/expression/ExpressionsTest.java
@@ -28,17 +28,14 @@ import org.junit.jupiter.api.Test;
 
 class ExpressionsTest {
 
-  record Property(String name, Object value) {
-  }
-
   @Test
-  public void literal() throws IOException {
+  void literal() {
     assertEquals(1, new Literal(1).evaluate(null));
     assertEquals("value", new Literal("value").evaluate(null));
   }
 
   @Test
-  public void at() throws IOException {
+  void at() {
     var literal = new Literal(List.of(0, 1, 2));
     assertEquals(0, new At(0, literal).evaluate(null));
     assertEquals(1, new At(1, literal).evaluate(null));
@@ -48,21 +45,21 @@ class ExpressionsTest {
   }
 
   @Test
-  public void get() throws IOException {
+  void get() {
     assertEquals("value",
         new Get("key").evaluate(new Feature(0L, Map.of("key", "value"), 
null)));
     assertEquals(null, new Get("key").evaluate(new Feature(0L, Map.of(), 
null)));
   }
 
   @Test
-  public void has() throws IOException {
+  void has() {
     assertEquals(true,
         new Has("key").evaluate(new Feature(0L, Map.of("key", "value"), 
null)));
     assertEquals(false, new Has("key").evaluate(new Feature(0L, Map.of(), 
null)));
   }
 
   @Test
-  public void inList() throws IOException {
+  void inList() {
     var literal = new Literal(List.of(0, 1, 2));
     assertEquals(true, new In(0, literal).evaluate(null));
     assertEquals(true, new In(1, literal).evaluate(null));
@@ -71,7 +68,7 @@ class ExpressionsTest {
   }
 
   @Test
-  public void inString() throws IOException {
+  void inString() {
     var literal = new Literal("foobar");
     assertEquals(true, new In("foo", literal).evaluate(null));
     assertEquals(true, new In("bar", literal).evaluate(null));
@@ -79,7 +76,7 @@ class ExpressionsTest {
   }
 
   @Test
-  public void indexOfList() throws IOException {
+  void indexOfList() {
     var literal = new Literal(List.of(0, 1, 2));
     assertEquals(0, new IndexOf(0, literal).evaluate(null));
     assertEquals(1, new IndexOf(1, literal).evaluate(null));
@@ -88,7 +85,7 @@ class ExpressionsTest {
   }
 
   @Test
-  public void indexOfString() throws IOException {
+  void indexOfString() {
     var literal = new Literal("foobar");
     assertEquals(0, new IndexOf("foo", literal).evaluate(null));
     assertEquals(3, new IndexOf("bar", literal).evaluate(null));
@@ -96,25 +93,25 @@ class ExpressionsTest {
   }
 
   @Test
-  public void lengthList() throws IOException {
+  void lengthList() {
     var literal = new Literal(List.of(0, 1, 2));
     assertEquals(3, new Length(literal).evaluate(null));
   }
 
   @Test
-  public void lengthString() throws IOException {
+  void lengthString() {
     var literal = new Literal("foo");
     assertEquals(3, new Length(literal).evaluate(null));
   }
 
   @Test
-  public void lengthNull() throws IOException {
+  void lengthNull() {
     var literal = new Literal(null);
     assertEquals(-1, new Length(literal).evaluate(null));
   }
 
   @Test
-  public void slice() throws IOException {
+  void slice() {
     var literal = new Literal("foobar");
     assertEquals("foobar", new Slice(literal, new Literal(0)).evaluate(null));
     assertEquals("bar", new Slice(literal, new Literal(3)).evaluate(null));
@@ -123,53 +120,53 @@ class ExpressionsTest {
   }
 
   @Test
-  public void not() throws IOException {
+  void not() throws IOException {
     assertEquals(true, Expressions.read("[\"!\", false]").evaluate(null));
     assertEquals(false, Expressions.read("[\"!\", true]").evaluate(null));
   }
 
   @Test
-  public void notEqual() throws IOException {
+  void notEqual() throws IOException {
     assertEquals(true, Expressions.read("[\"!=\", 1, 2]").evaluate(null));
     assertEquals(false, Expressions.read("[\"!=\", 1, 1]").evaluate(null));
   }
 
   @Test
-  public void less() throws IOException {
+  void less() throws IOException {
     assertEquals(true, Expressions.read("[\"<\", 1, 2]").evaluate(null));
     assertEquals(false, Expressions.read("[\"<\", 1, 1]").evaluate(null));
     assertEquals(false, Expressions.read("[\"<\", 1, 0]").evaluate(null));
   }
 
   @Test
-  public void lessOrEqual() throws IOException {
+  void lessOrEqual() throws IOException {
     assertEquals(true, Expressions.read("[\"<=\", 1, 2]").evaluate(null));
     assertEquals(true, Expressions.read("[\"<=\", 1, 1]").evaluate(null));
     assertEquals(false, Expressions.read("[\"<=\", 1, 0]").evaluate(null));
   }
 
   @Test
-  public void equal() throws IOException {
+  void equal() throws IOException {
     assertEquals(true, Expressions.read("[\"==\", 1, 1]").evaluate(null));
     assertEquals(false, Expressions.read("[\"==\", 1, 2]").evaluate(null));
   }
 
   @Test
-  public void greater() throws IOException {
+  void greater() throws IOException {
     assertEquals(true, Expressions.read("[\">\", 1, 0]").evaluate(null));
     assertEquals(false, Expressions.read("[\">\", 1, 1]").evaluate(null));
     assertEquals(false, Expressions.read("[\">\", 1, 2]").evaluate(null));
   }
 
   @Test
-  public void greaterOrEqual() throws IOException {
+  void greaterOrEqual() throws IOException {
     assertEquals(true, Expressions.read("[\">=\", 1, 0]").evaluate(null));
     assertEquals(true, Expressions.read("[\">=\", 1, 1]").evaluate(null));
     assertEquals(false, Expressions.read("[\">=\", 1, 2]").evaluate(null));
   }
 
   @Test
-  public void all() throws IOException {
+  void all() {
     assertEquals(true, new All(List.of(new Literal(true), new 
Literal(true))).evaluate(null));
     assertEquals(false, new All(List.of(new Literal(true), new 
Literal(false))).evaluate(null));
     assertEquals(false, new All(List.of(new Literal(false), new 
Literal(false))).evaluate(null));
@@ -177,7 +174,7 @@ class ExpressionsTest {
   }
 
   @Test
-  public void any() throws IOException {
+  void any() {
     assertEquals(true, new Any(List.of(new Literal(true), new 
Literal(true))).evaluate(null));
     assertEquals(true, new Any(List.of(new Literal(true), new 
Literal(false))).evaluate(null));
     assertEquals(false, new Any(List.of(new Literal(false), new 
Literal(false))).evaluate(null));
@@ -185,7 +182,7 @@ class ExpressionsTest {
   }
 
   @Test
-  public void caseExpression() throws IOException {
+  void caseExpression() {
     assertEquals("a",
         new Case(new Literal(true), new Literal("a"), new 
Literal("b")).evaluate(null));
     assertEquals("b",
@@ -193,7 +190,7 @@ class ExpressionsTest {
   }
 
   @Test
-  public void coalesce() {
+  void coalesce() {
     assertEquals("a", new Coalesce(List.of(new Literal(null), new 
Literal("a"), new Literal("b")))
         .evaluate(null));
     assertEquals("b", new Coalesce(List.of(new Literal(null), new 
Literal("b"), new Literal("a")))
@@ -203,7 +200,7 @@ class ExpressionsTest {
   }
 
   @Test
-  public void match() throws IOException {
+  void match() throws IOException {
     assertEquals("foo", Expressions
         .read("[\"match\", \"foo\", \"foo\", \"foo\", \"bar\", \"bar\", 
\"baz\"]").evaluate(null));
     assertEquals("bar", Expressions
diff --git 
a/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/vectortile/VectorTileFunctionsTest.java
 
b/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/vectortile/VectorTileFunctionsTest.java
index 07f153d5..f93718e6 100644
--- 
a/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/vectortile/VectorTileFunctionsTest.java
+++ 
b/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/vectortile/VectorTileFunctionsTest.java
@@ -21,7 +21,6 @@ import static org.junit.jupiter.api.Assertions.*;
 
 import org.junit.jupiter.api.Test;
 import org.locationtech.jts.geom.*;
-import org.locationtech.jts.geom.Polygon;
 
 class VectorTileFunctionsTest {
 
diff --git 
a/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/vectortile/VectorTileViewer.java
 
b/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/vectortile/VectorTileViewer.java
index a7310553..ac7e3eaa 100644
--- 
a/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/vectortile/VectorTileViewer.java
+++ 
b/baremaps-maplibre/src/test/java/org/apache/baremaps/maplibre/vectortile/VectorTileViewer.java
@@ -73,10 +73,7 @@ public class VectorTileViewer {
         case "Polygon":
           paintPolygon(graphics, (Polygon) geometry, extent);
           break;
-        case "MultiPoint":
-        case "MultiLineString":
-        case "MultiPolygon":
-        case "GeometryCollection":
+        case "MultiPoint", "MultiLineString", "MultiPolygon", 
"GeometryCollection":
           paintGeometryCollection(graphics, (GeometryCollection) geometry, 
extent);
           break;
         default:
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/ChangeEntitiesHandler.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/ChangeEntitiesHandler.java
index d500cd85..8b92a113 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/ChangeEntitiesHandler.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/ChangeEntitiesHandler.java
@@ -41,6 +41,6 @@ public class ChangeEntitiesHandler implements 
Consumer<Change> {
   /** {@inheritDoc} */
   @Override
   public void accept(Change change) {
-    change.getEntities().forEach(consumer);
+    change.entities().forEach(consumer);
   }
 }
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/ProjectionTransformer.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/ProjectionTransformer.java
index 42e506ac..b7b82d0b 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/ProjectionTransformer.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/ProjectionTransformer.java
@@ -42,9 +42,9 @@ public class ProjectionTransformer extends 
GeometryTransformer {
 
   private final CoordinateTransform transform;
 
-  private ProjCoordinate min;
+  private final ProjCoordinate min;
 
-  private ProjCoordinate max;
+  private final ProjCoordinate max;
 
   /**
    * Creates a transformer that reprojects geometries with the provided SRIDs.
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/RelationMultiPolygonBuilder.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/RelationMultiPolygonBuilder.java
index 73a674f5..e406d592 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/RelationMultiPolygonBuilder.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/function/RelationMultiPolygonBuilder.java
@@ -88,8 +88,8 @@ public class RelationMultiPolygonBuilder implements 
Consumer<Entity> {
     var innerMembers = new ArrayList<Member>();
     var otherMembers = new ArrayList<Member>();
     for (var member : relation.getMembers()) {
-      if (MemberType.WAY.equals(member.getType())) {
-        switch (member.getRole()) {
+      if (MemberType.WAY.equals(member.type())) {
+        switch (member.role()) {
           case "outer" -> outerMembers.add(member);
           case "inner" -> innerMembers.add(member);
           default -> otherMembers.add(member);
@@ -192,12 +192,10 @@ public class RelationMultiPolygonBuilder implements 
Consumer<Entity> {
 
     // Merge the lines to build the polygons
     for (Object geometry : lineMerger.getMergedLineStrings()) {
-      if (geometry instanceof LineString lineString) {
-        if (lineString.isClosed()) {
-          var polygon =
-              
GeometryUtils.GEOMETRY_FACTORY_WGS84.createPolygon(lineString.getCoordinates());
-          repairPolygon(polygon, polygons);
-        }
+      if (geometry instanceof LineString lineString && lineString.isClosed()) {
+        var polygon =
+            
GeometryUtils.GEOMETRY_FACTORY_WGS84.createPolygon(lineString.getCoordinates());
+        repairPolygon(polygon, polygons);
       }
     }
 
@@ -205,7 +203,7 @@ public class RelationMultiPolygonBuilder implements 
Consumer<Entity> {
   }
 
   private LineString createLineString(Member member) {
-    List<Long> refs = referenceMap.get(member.getRef());
+    List<Long> refs = referenceMap.get(member.ref());
 
     // Build the coordinate list and remove duplicates.
     List<Coordinate> list = new ArrayList<>();
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Bound.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Bound.java
index b30d5a4b..fc798f52 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Bound.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Bound.java
@@ -18,96 +18,7 @@
 package org.apache.baremaps.openstreetmap.model;
 
 
-
-import java.util.Objects;
-import java.util.StringJoiner;
-
 /** Represents the bounds of an OpenStreetMap dataset. */
-public final class Bound implements Entity {
-
-  private final double maxLat;
-
-  private final double maxLon;
-
-  private final double minLat;
-
-  private final double minLon;
-
-  /**
-   * Consturcts a {@code Bound} with the specified limits.
-   *
-   * @param maxLat the max latitude
-   * @param maxLon the max longitude
-   * @param minLat the min latitude
-   * @param minLon the max longitude
-   */
-  public Bound(double maxLat, double maxLon, double minLat, double minLon) {
-    this.maxLat = maxLat;
-    this.maxLon = maxLon;
-    this.minLat = minLat;
-    this.minLon = minLon;
-  }
-
-  /**
-   * Returns the max latitude.
-   *
-   * @return the max latitude
-   */
-  public double getMaxLat() {
-    return maxLat;
-  }
-
-  /**
-   * Returns the max longitude.
-   *
-   * @return the max longitude
-   */
-  public double getMaxLon() {
-    return maxLon;
-  }
-
-  /**
-   * Returns the min latitude.
-   *
-   * @return the min latitude
-   */
-  public double getMinLat() {
-    return minLat;
-  }
-
-  /**
-   * Returns the min longitude.
-   *
-   * @return the min longitude
-   */
-  public double getMinLon() {
-    return minLon;
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (!(o instanceof Bound)) {
-      return false;
-    }
-    Bound bound = (Bound) o;
-    return Double.compare(bound.maxLat, maxLat) == 0 && 
Double.compare(bound.maxLon, maxLon) == 0
-        && Double.compare(bound.minLat, minLat) == 0 && 
Double.compare(bound.minLon, minLon) == 0;
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public int hashCode() {
-    return Objects.hash(maxLat, maxLon, minLat, minLon);
-  }
+public record Bound(double maxLat, double maxLon, double minLat, double 
minLon) implements Entity {
 
-  /** {@inheritDoc} */
-  @Override
-  public String toString() {
-    return new StringJoiner(", ", Bound.class.getSimpleName() + "[", 
"]").add("maxLat=" + maxLat)
-        .add("maxLon=" + maxLon).add("minLat=" + minLat).add("minLon=" + 
minLon).toString();
-  }
 }
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Change.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Change.java
index 43d1bce1..868df68e 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Change.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Change.java
@@ -20,10 +20,9 @@ package org.apache.baremaps.openstreetmap.model;
 
 
 import java.util.List;
-import java.util.StringJoiner;
 
 /** Represents a change in an OpenStreetMap dataset. */
-public final class Change {
+public record Change(ChangeType type, List<Entity> entities) {
 
   public enum ChangeType {
     DELETE,
@@ -31,43 +30,4 @@ public final class Change {
     MODIFY
   }
 
-  private final ChangeType type;
-
-  private final List<Entity> entities;
-
-  /**
-   * Constructs an OpenStreetMap change.
-   *
-   * @param type the type of the change
-   * @param entities the entities affected by the change
-   */
-  public Change(ChangeType type, List<Entity> entities) {
-    this.type = type;
-    this.entities = entities;
-  }
-
-  /**
-   * Returns the type of the change.
-   *
-   * @return the type of the change
-   */
-  public ChangeType getType() {
-    return type;
-  }
-
-  /**
-   * Returns the entities affected by the change.
-   *
-   * @return the entities affected by the change
-   */
-  public List<Entity> getEntities() {
-    return entities;
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public String toString() {
-    return new StringJoiner(", ", Change.class.getSimpleName() + "[", 
"]").add("type=" + type)
-        .add("elements=" + entities).toString();
-  }
 }
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Header.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Header.java
index 36277e0b..cf692df3 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Header.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Header.java
@@ -20,111 +20,13 @@ package org.apache.baremaps.openstreetmap.model;
 
 
 import java.time.LocalDateTime;
-import java.util.Objects;
-import java.util.StringJoiner;
 
 /** Represents a header entity in an OpenStreetMap dataset. */
-public final class Header implements Entity {
+public record Header(
+    Long replicationSequenceNumber,
+    LocalDateTime replicationTimestamp,
+    String replicationUrl,
+    String source,
+    String writingProgram) implements Entity {
 
-  private final Long replicationSequenceNumber;
-  private final LocalDateTime replicationTimestamp;
-  private final String replicationUrl;
-  private final String source;
-  private final String writingProgram;
-
-  /**
-   * Constructs an OpenStreetMap {@code Header} based on the specified 
parameters.
-   *
-   * @param replicationSequenceNumber the replication sequence number
-   * @param replicationTimestamp the replication timestamp
-   * @param replicationUrl the replication url
-   * @param source the source
-   * @param writingProgram the writing program
-   */
-  public Header(Long replicationSequenceNumber, LocalDateTime 
replicationTimestamp,
-      String replicationUrl, String source, String writingProgram) {
-    this.replicationTimestamp = replicationTimestamp;
-    this.replicationSequenceNumber = replicationSequenceNumber;
-    this.replicationUrl = replicationUrl;
-    this.source = source;
-    this.writingProgram = writingProgram;
-  }
-
-  /**
-   * Returns the replication timestamp.
-   *
-   * @return the replication timestamp
-   */
-  public LocalDateTime getReplicationTimestamp() {
-    return replicationTimestamp;
-  }
-
-  /**
-   * Returns the replication sequence number.
-   *
-   * @return the replication sequence number
-   */
-  public Long getReplicationSequenceNumber() {
-    return replicationSequenceNumber;
-  }
-
-  /**
-   * Returns the replication url.
-   *
-   * @return the replication url
-   */
-  public String getReplicationUrl() {
-    return replicationUrl;
-  }
-
-  /**
-   * Returns the source.
-   *
-   * @return the source
-   */
-  public String getSource() {
-    return source;
-  }
-
-  /**
-   * Returns the writing program.
-   *
-   * @return the writing program
-   */
-  public String getWritingProgram() {
-    return writingProgram;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (!(o instanceof Header)) {
-      return false;
-    }
-    Header header = (Header) o;
-    return Objects.equals(replicationTimestamp, header.replicationTimestamp)
-        && Objects.equals(replicationSequenceNumber, 
header.replicationSequenceNumber)
-        && Objects.equals(replicationUrl, header.replicationUrl)
-        && Objects.equals(source, header.source)
-        && Objects.equals(writingProgram, header.writingProgram);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public int hashCode() {
-    return Objects.hash(replicationTimestamp, replicationSequenceNumber, 
replicationUrl, source,
-        writingProgram);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public String toString() {
-    return new StringJoiner(", ", Header.class.getSimpleName() + "[", "]")
-        .add("replicationTimestamp=" + replicationTimestamp)
-        .add("replicationSequenceNumber=" + replicationSequenceNumber)
-        .add("replicationUrl='" + replicationUrl + "'").add("source='" + 
source + "'")
-        .add("writingProgram='" + writingProgram + "'").toString();
-  }
 }
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Member.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Member.java
index a3b572ac..1f73d4d2 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Member.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/Member.java
@@ -17,13 +17,10 @@
 
 package org.apache.baremaps.openstreetmap.model;
 
-import static com.google.common.base.Preconditions.checkNotNull;
 
-import com.google.common.base.Objects;
-import java.util.StringJoiner;
 
 /** Represents a member of a relation in an OpenStreetMap dataset. */
-public final class Member {
+public record Member(long ref, MemberType type, String role) {
 
   public enum MemberType {
     NODE,
@@ -31,91 +28,12 @@ public final class Member {
     RELATION;
 
     public static MemberType forNumber(int value) {
-      switch (value) {
-        case 0:
-          return NODE;
-        case 1:
-          return WAY;
-        case 2:
-          return RELATION;
-        default:
-          throw new IllegalArgumentException();
-      }
+      return switch (value) {
+        case 0 -> NODE;
+        case 1 -> WAY;
+        case 2 -> RELATION;
+        default -> throw new IllegalArgumentException();
+      };
     }
   }
-
-  private final long ref;
-
-  private final MemberType type;
-
-  private final String role;
-
-  /**
-   * Constructs a {@code Member} of an OpenStreetMap relation.
-   *
-   * @param ref the relation id
-   * @param type the member type
-   * @param role the member role
-   */
-  public Member(long ref, MemberType type, String role) {
-    checkNotNull(type);
-    checkNotNull(role);
-    this.ref = ref;
-    this.type = type;
-    this.role = role;
-  }
-
-  /**
-   * Returns the relation id.
-   *
-   * @return the relation id
-   */
-  public long getRef() {
-    return ref;
-  }
-
-  /**
-   * Returns the member type.
-   *
-   * @return the member type
-   */
-  public MemberType getType() {
-    return type;
-  }
-
-  /**
-   * Returns the member role.
-   *
-   * @return the member role
-   */
-  public String getRole() {
-    return role;
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    Member member = (Member) o;
-    return ref == member.ref && Objects.equal(type, member.type)
-        && Objects.equal(role, member.role);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public int hashCode() {
-    return Objects.hashCode(ref, type, role);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public String toString() {
-    return new StringJoiner(", ", Member.class.getSimpleName() + "[", 
"]").add("ref=" + ref)
-        .add("type='" + type.name() + "'").add("role='" + role + 
"'").toString();
-  }
 }
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/State.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/State.java
index 79f4c406..3795825f 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/State.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/State.java
@@ -22,38 +22,6 @@ package org.apache.baremaps.openstreetmap.model;
 import java.time.LocalDateTime;
 
 /** Represents the state of an OpenStreetMap dataset, enabling its 
replication. */
-public final class State {
+public record State(long sequenceNumber, LocalDateTime timestamp) {
 
-  private final long sequenceNumber;
-
-  private final LocalDateTime timestamp;
-
-  /**
-   * Constructs an OpenStreetMap {@code State} with the specified parameters.
-   *
-   * @param sequenceNumber the sequence number
-   * @param timestamp the timestamp
-   */
-  public State(long sequenceNumber, LocalDateTime timestamp) {
-    this.sequenceNumber = sequenceNumber;
-    this.timestamp = timestamp;
-  }
-
-  /**
-   * Returns the sequence number.
-   *
-   * @return the sequence number
-   */
-  public long getSequenceNumber() {
-    return sequenceNumber;
-  }
-
-  /**
-   * Returns the timestamp.
-   *
-   * @return the timestamp
-   */
-  public LocalDateTime getTimestamp() {
-    return timestamp;
-  }
 }
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/User.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/User.java
index 1c6b1036..734af1af 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/User.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/model/User.java
@@ -19,61 +19,9 @@ package org.apache.baremaps.openstreetmap.model;
 
 
 
-import com.google.common.base.Objects;
-
 /** Represents the author of an objet in an OpenStreetMap dataset. */
-public final class User {
+public record User(int id, String name) {
 
   public static final User NO_USER = new User(-1, "");
 
-  private final int id;
-  private final String name;
-
-  /**
-   * Constructs an OpenStreetMap {@code User} with the specified parameters.
-   *
-   * @param id the id
-   * @param name the name
-   */
-  public User(int id, String name) {
-    this.id = id;
-    this.name = name;
-  }
-
-  /**
-   * Returns the id.
-   *
-   * @return the id
-   */
-  public int getId() {
-    return id;
-  }
-
-  /**
-   * Returns the name.
-   *
-   * @return the name
-   */
-  public String getName() {
-    return name;
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    User user = (User) o;
-    return id == user.id && Objects.equal(name, user.name);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public int hashCode() {
-    return Objects.hashCode(id, name);
-  }
 }
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/state/StateReader.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/state/StateReader.java
index d9e84dd5..85ab571a 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/state/StateReader.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/state/StateReader.java
@@ -109,75 +109,75 @@ public class StateReader implements Reader<State> {
    * @param timestamp the timestamp
    * @return the state
    */
-  @SuppressWarnings("squid:S3776")
+  @SuppressWarnings({"squid:S3776", "squid:S6541"})
   public Optional<State> getStateFromTimestamp(LocalDateTime timestamp) {
-    var upper = getState(Optional.empty());
+    var upper = getLatestState();
     if (upper.isEmpty()) {
       return Optional.empty();
     }
-    if (timestamp.isAfter(upper.get().getTimestamp()) || 
upper.get().getSequenceNumber() <= 0) {
+    if (timestamp.isAfter(upper.get().timestamp()) || 
upper.get().sequenceNumber() <= 0) {
       return upper;
     }
     var lower = Optional.<State>empty();
-    var lowerId = Optional.of(0L);
+    var lowerId = 0L;
     while (lower.isEmpty()) {
-      lower = getState(lowerId);
-      if (lower.isPresent() && lower.get().getTimestamp().isAfter(timestamp)) {
-        if (lower.get().getSequenceNumber() == 0
-            || lower.get().getSequenceNumber() + 1 >= 
upper.get().getSequenceNumber()) {
+      lower = getLatestState(lowerId);
+      if (lower.isPresent() && lower.get().timestamp().isAfter(timestamp)) {
+        if (lower.get().sequenceNumber() == 0
+            || lower.get().sequenceNumber() + 1 >= 
upper.get().sequenceNumber()) {
           return lower;
         }
         upper = lower;
         lower = Optional.empty();
-        lowerId = Optional.of(0L);
+        lowerId = 0L;
       }
       if (lower.isEmpty()) {
-        var newId = (lowerId.get() + upper.get().getSequenceNumber()) / 2;
-        if (newId <= lowerId.get()) {
+        var newId = (lowerId + upper.get().sequenceNumber()) / 2;
+        if (newId <= lowerId) {
           return upper;
         }
-        lowerId = Optional.of(newId);
+        lowerId = newId;
       }
     }
     long baseSplitId;
     while (true) {
       if (balancedSearch) {
-        baseSplitId = ((lower.get().getSequenceNumber() + 
upper.get().getSequenceNumber()) / 2);
+        baseSplitId = ((lower.get().sequenceNumber() + 
upper.get().sequenceNumber()) / 2);
       } else {
-        var tsInt = upper.get().getTimestamp().toEpochSecond(ZoneOffset.UTC)
-            - lower.get().getTimestamp().toEpochSecond(ZoneOffset.UTC);
-        var seqInt = upper.get().getSequenceNumber() - 
lower.get().getSequenceNumber();
-        var goal = timestamp.getSecond() - 
lower.get().getTimestamp().getSecond();
+        var tsInt = upper.get().timestamp().toEpochSecond(ZoneOffset.UTC)
+            - lower.get().timestamp().toEpochSecond(ZoneOffset.UTC);
+        var seqInt = upper.get().sequenceNumber() - 
lower.get().sequenceNumber();
+        var goal = timestamp.getSecond() - lower.get().timestamp().getSecond();
         baseSplitId =
-            lower.get().getSequenceNumber() + (long) Math.ceil((double) (goal 
* seqInt) / tsInt);
-        if (baseSplitId >= upper.get().getSequenceNumber()) {
-          baseSplitId = upper.get().getSequenceNumber() - 1;
+            lower.get().sequenceNumber() + (long) Math.ceil((double) (goal * 
seqInt) / tsInt);
+        if (baseSplitId >= upper.get().sequenceNumber()) {
+          baseSplitId = upper.get().sequenceNumber() - 1;
         }
       }
-      var split = getState(Optional.of(baseSplitId));
+      var split = getLatestState(baseSplitId);
       if (split.isEmpty()) {
         var splitId = baseSplitId - 1;
-        while (split.isEmpty() && splitId > lower.get().getSequenceNumber()) {
-          split = getState(Optional.of(splitId));
+        while (split.isEmpty() && splitId > lower.get().sequenceNumber()) {
+          split = getLatestState(splitId);
           splitId--;
         }
       }
       if (split.isEmpty()) {
         var splitId = baseSplitId + 1;
-        while (split.isEmpty() && splitId < upper.get().getSequenceNumber()) {
-          split = getState(Optional.of(splitId));
+        while (split.isEmpty() && splitId < upper.get().sequenceNumber()) {
+          split = getLatestState(splitId);
           splitId++;
         }
       }
       if (split.isEmpty()) {
         return lower;
       }
-      if (split.get().getTimestamp().isBefore(timestamp)) {
+      if (split.get().timestamp().isBefore(timestamp)) {
         lower = split;
       } else {
         upper = split;
       }
-      if (lower.get().getSequenceNumber() + 1 >= 
upper.get().getSequenceNumber()) {
+      if (lower.get().sequenceNumber() + 1 >= upper.get().sequenceNumber()) {
         return lower;
       }
     }
@@ -189,7 +189,7 @@ public class StateReader implements Reader<State> {
    * @param sequenceNumber the sequence number
    * @return the state
    */
-  public Optional<State> getState(Optional<Long> sequenceNumber) {
+  public Optional<State> getLatestState(long sequenceNumber) {
     for (int i = 0; i < retries + 1; i++) {
       try (var inputStream = getStateUrl(sequenceNumber).openStream()) {
         var state = new StateReader().read(inputStream);
@@ -201,6 +201,21 @@ public class StateReader implements Reader<State> {
     return Optional.empty();
   }
 
+  /**
+   * Get the latest state.
+   *
+   * @return the state
+   */
+  public Optional<State> getLatestState() {
+    try (var inputStream = getStateUrl().openStream()) {
+      var state = new StateReader().read(inputStream);
+      return Optional.of(state);
+    } catch (Exception e) {
+      logger.error("Error while reading state file", e);
+    }
+    return Optional.empty();
+  }
+
   /**
    * Get the URL of the state file corresponding to the given sequence number.
    *
@@ -208,17 +223,22 @@ public class StateReader implements Reader<State> {
    * @return the URL
    * @throws MalformedURLException if the URL is malformed
    */
-  public URL getStateUrl(Optional<Long> sequenceNumber) throws 
MalformedURLException {
-    if (sequenceNumber.isPresent()) {
-
-      var s = String.format("%09d", sequenceNumber.get());
-      var uri =
-          String.format("%s/%s/%s/%s.%s", replicationUrl, s.substring(0, 3), 
s.substring(3, 6),
-              s.substring(6, 9), "state.txt");
-      return URI.create(uri).toURL();
-    } else {
-      return new URL(replicationUrl + "/state.txt");
-    }
+  public URL getStateUrl(long sequenceNumber) throws MalformedURLException {
+    var s = String.format("%09d", sequenceNumber);
+    var uri =
+        String.format("%s/%s/%s/%s.%s", replicationUrl, s.substring(0, 3), 
s.substring(3, 6),
+            s.substring(6, 9), "state.txt");
+    return URI.create(uri).toURL();
+  }
+
+  /**
+   * Get the URL of the latest state file.
+   *
+   * @return the URL
+   * @throws MalformedURLException if the URL is malformed
+   */
+  public URL getStateUrl() throws MalformedURLException {
+    return new URL(replicationUrl + "/state.txt");
   }
 
   /**
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/stream/ConsumerUtils.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/stream/ConsumerUtils.java
index 45afc0c7..5fe5f804 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/stream/ConsumerUtils.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/stream/ConsumerUtils.java
@@ -20,7 +20,7 @@ package org.apache.baremaps.openstreetmap.stream;
 
 
 import java.util.function.Consumer;
-import java.util.function.Function;
+import java.util.function.UnaryOperator;
 
 /** Utility methods for dealing with consumers. */
 public class ConsumerUtils {
@@ -46,7 +46,7 @@ public class ConsumerUtils {
    * @param <T> the type
    * @return the function
    */
-  public static <T> Function<T, T> consumeThenReturn(Consumer<T> consumer) {
+  public static <T> UnaryOperator<T> consumeThenReturn(Consumer<T> consumer) {
     return t -> {
       consumer.accept(t);
       return t;
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/utils/CRSUtils.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/utils/CRSUtils.java
index 5e9eae27..1645ebf4 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/utils/CRSUtils.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/utils/CRSUtils.java
@@ -35,6 +35,10 @@ import org.locationtech.proj4j.CoordinateReferenceSystem;
  */
 public class CRSUtils {
 
+  private CRSUtils() {
+    // prevent instantiation
+  }
+
   private static final CRSFactory CRS_FACTORY = new CRSFactory();
 
   private static final CoordinateReferenceSystem WGS_84 =
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlChangeSpliterator.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlChangeSpliterator.java
index 0850d722..1f26ae34 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlChangeSpliterator.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlChangeSpliterator.java
@@ -122,21 +122,23 @@ public class XmlChangeSpliterator implements 
Spliterator<Change> {
   }
 
   private Change readChange() throws XMLStreamException {
-    switch (reader.getLocalName()) {
-      case ELEMENT_NAME_CREATE:
-      case ELEMENT_NAME_DELETE:
-      case ELEMENT_NAME_MODIFY:
-        Change.ChangeType type = 
Change.ChangeType.valueOf(reader.getLocalName().toUpperCase());
-        List<Entity> elements = new ArrayList<>();
-        reader.nextTag();
-        while (reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
-          elements.add(readElement());
-          reader.nextTag();
-        }
-        return new Change(type, elements);
-      default:
-        throw new StreamException("Unexpected XML element: " + 
reader.getLocalName());
+    if (!isChangeElement(reader.getLocalName())) {
+      throw new StreamException("Unexpected XML element: " + 
reader.getLocalName());
+    }
+    Change.ChangeType type = 
Change.ChangeType.valueOf(reader.getLocalName().toUpperCase());
+    List<Entity> elements = new ArrayList<>();
+    reader.nextTag();
+    while (reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
+      elements.add(readElement());
+      reader.nextTag();
     }
+    return new Change(type, elements);
+  }
+
+  private boolean isChangeElement(String elementName) {
+    return ELEMENT_NAME_CREATE.equals(elementName)
+        || ELEMENT_NAME_DELETE.equals(elementName)
+        || ELEMENT_NAME_MODIFY.equals(elementName);
   }
 
   private Element readElement() throws XMLStreamException {
diff --git 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlEntitySpliterator.java
 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlEntitySpliterator.java
index c431f3b3..3787f4af 100644
--- 
a/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlEntitySpliterator.java
+++ 
b/baremaps-openstreetmap/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlEntitySpliterator.java
@@ -134,8 +134,7 @@ public class XmlEntitySpliterator implements 
Spliterator<Entity> {
       case ELEMENT_NAME_OSM:
         consumer.accept(readHeader());
         return;
-      case ELEMENT_NAME_BOUND:
-      case ELEMENT_NAME_BOUNDS:
+      case ELEMENT_NAME_BOUND, ELEMENT_NAME_BOUNDS:
         consumer.accept(readBounds());
         return;
       case ELEMENT_NAME_NODE:
@@ -149,7 +148,6 @@ public class XmlEntitySpliterator implements 
Spliterator<Entity> {
         return;
       default:
         readUnknownElement();
-        return;
     }
   }
 
diff --git 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/OsmSampleTest.java
 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/OsmSampleTest.java
index e5d02780..4236377c 100644
--- 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/OsmSampleTest.java
+++ 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/OsmSampleTest.java
@@ -44,8 +44,8 @@ class OsmSampleTest {
   void sampleStateTxt() throws IOException {
     try (InputStream inputStream = 
Files.newInputStream(TestFiles.SAMPLE_STATE_TXT)) {
       State state = new StateReader().read(inputStream);
-      Assertions.assertEquals(1, state.getSequenceNumber());
-      Assertions.assertEquals(LocalDateTime.parse("2000-01-01T00:00:00"), 
state.getTimestamp());
+      Assertions.assertEquals(1, state.sequenceNumber());
+      Assertions.assertEquals(LocalDateTime.parse("2000-01-01T00:00:00"), 
state.timestamp());
     }
   }
 
@@ -75,14 +75,14 @@ class OsmSampleTest {
     stream.forEach(entity -> {
       if (entity instanceof Header header) {
         Assertions.assertNotNull(header);
-        Assertions.assertEquals("osmium/1.16.0", header.getWritingProgram());
+        Assertions.assertEquals("osmium/1.16.0", header.writingProgram());
         headers.incrementAndGet();
       } else if (entity instanceof Bound bound) {
         Assertions.assertNotNull(bound);
-        Assertions.assertEquals(0.0, bound.getMinLat(), 0.000001);
-        Assertions.assertEquals(0.0, bound.getMinLon(), 0.000001);
-        Assertions.assertEquals(20.0, bound.getMaxLat(), 0.000001);
-        Assertions.assertEquals(20.0, bound.getMaxLon(), 0.000001);
+        Assertions.assertEquals(0.0, bound.minLat(), 0.000001);
+        Assertions.assertEquals(0.0, bound.minLon(), 0.000001);
+        Assertions.assertEquals(20.0, bound.maxLat(), 0.000001);
+        Assertions.assertEquals(20.0, bound.maxLon(), 0.000001);
         bounds.incrementAndGet();
       } else if (entity instanceof Node node) {
         Assertions.assertNotNull(node);
diff --git 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/OsmTestData.java
 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/OsmTestData.java
index 949fd296..c1d9ce9b 100644
--- 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/OsmTestData.java
+++ 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/OsmTestData.java
@@ -45,10 +45,10 @@ import 
org.testcontainers.shaded.com.fasterxml.jackson.databind.JsonNode;
 import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
 
 
-public class OsmTestData {
+class OsmTestData {
 
   @TestFactory
-  public Stream<DynamicTest> runTests() throws IOException {
+  Stream<DynamicTest> runTests() throws IOException {
     var directory = resolve("osm-testdata");
     try (var files = Files.walk(directory)) {
       return files.filter(f -> f.endsWith("test.json"))
@@ -61,7 +61,7 @@ public class OsmTestData {
   }
 
   @NotNull
-  private Stream<DynamicTest> createDynamicTest(OsmTest osmTest) {
+  Stream<DynamicTest> createDynamicTest(OsmTest osmTest) {
     String displayNameFormat = "%s (%s): %s";
     var xmlDisplayName =
         String.format(displayNameFormat, osmTest.getId(), "xml", 
osmTest.getDescription());
@@ -81,7 +81,7 @@ public class OsmTestData {
         .build();
   }
 
-  public void runTest(OsmTest osmTest, Stream<Entity> entities) {
+  void runTest(OsmTest osmTest, Stream<Entity> entities) {
     var elements = entities
         .filter(e -> e instanceof Element)
         .map(e -> (Element) e)
@@ -127,7 +127,7 @@ public class OsmTestData {
     }
   }
 
-  private class OsmTest implements Comparable<OsmTest> {
+  static class OsmTest implements Comparable<OsmTest> {
 
     private static final ObjectMapper objectMapper =
         new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
@@ -264,9 +264,9 @@ public class OsmTestData {
   /**
    * A transformer that rounds the coordinates of a geometry to a given 
precision.
    */
-  public static class RoundingTransformer extends GeometryTransformer {
+  static class RoundingTransformer extends GeometryTransformer {
 
-    private int precision;
+    private final int precision;
 
     /**
      * Constructs a transformer that rounds the coordinates of a geometry to a 
given precision.
diff --git 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/state/StateReaderTest.java
 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/state/StateReaderTest.java
index 683dc0fb..b06de0f1 100644
--- 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/state/StateReaderTest.java
+++ 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/state/StateReaderTest.java
@@ -26,7 +26,7 @@ import org.junit.jupiter.api.Test;
 class StateReaderTest {
 
   @Test
-  @Ignore
+  @Ignore("Disabled because of the dependency on the internet")
   void getStateFromTimestamp() {
     var reader = new StateReader();
     var state = 
reader.getStateFromTimestamp(LocalDateTime.now().minusDays(10));
diff --git 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/stream/BatchedSpliteratorTest.java
 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/stream/BatchedSpliteratorTest.java
index 351a0c8b..f09d051e 100644
--- 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/stream/BatchedSpliteratorTest.java
+++ 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/stream/BatchedSpliteratorTest.java
@@ -60,7 +60,7 @@ class BatchedSpliteratorTest {
   }
 
   @Test
-  void tryAdvance() throws Exception {
+  void tryAdvance() {
     for (int i = 0; i < spliteratorSize; i++) {
       assertTrue(spliterator.tryAdvance(block -> {
       }));
@@ -70,7 +70,7 @@ class BatchedSpliteratorTest {
   }
 
   @Test
-  void forEachRemaining() throws Exception {
+  void forEachRemaining() {
     AccumulatingConsumer<Integer> accumulator = new AccumulatingConsumer<>();
     spliterator.forEachRemaining(accumulator);
     assertEquals(accumulator.values().size(), spliteratorSize);
diff --git 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/xml/XmlChangeSpliteratorTest.java
 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/xml/XmlChangeSpliteratorTest.java
index e048be87..4da9f767 100644
--- 
a/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/xml/XmlChangeSpliteratorTest.java
+++ 
b/baremaps-openstreetmap/src/test/java/org/apache/baremaps/openstreetmap/xml/XmlChangeSpliteratorTest.java
@@ -53,7 +53,7 @@ class XmlChangeSpliteratorTest {
       spliterator.forEachRemaining(accumulator);
       assertEquals(accumulator.values().size(), 5);
       assertEquals(accumulator.values().stream()
-          .flatMap(change -> change.getEntities().stream())
+          .flatMap(change -> change.entities().stream())
           .toList().size(), 36);
     }
   }
diff --git 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Compression.java 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Compression.java
index f2891b27..9976367c 100644
--- 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Compression.java
+++ 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Compression.java
@@ -21,7 +21,7 @@ import java.io.*;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.GZIPOutputStream;
 
-enum Compression {
+public enum Compression {
   UNKNOWN,
   NONE,
   GZIP,
diff --git 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Entry.java 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Entry.java
index 27823192..882b8697 100644
--- a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Entry.java
+++ b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Entry.java
@@ -17,7 +17,7 @@
 
 package org.apache.baremaps.pmtiles;
 
-class Entry {
+public class Entry {
   private long tileId;
   private long offset;
   private long length;
diff --git 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Header.java 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Header.java
index 143934d1..2ad0b74d 100644
--- a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Header.java
+++ b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/Header.java
@@ -19,7 +19,7 @@ package org.apache.baremaps.pmtiles;
 
 import java.util.Objects;
 
-class Header {
+public class Header {
 
   private int specVersion;
   private long rootDirectoryOffset;
diff --git 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesReader.java 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesReader.java
index 55ff4c8d..27d8f91b 100644
--- 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesReader.java
+++ 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesReader.java
@@ -41,7 +41,7 @@ public class PMTilesReader {
   public Header getHeader() {
     if (header == null) {
       try (var inputStream = new 
LittleEndianDataInputStream(Files.newInputStream(path))) {
-        header = PMTiles.deserializeHeader(inputStream);
+        header = PMTilesUtils.deserializeHeader(inputStream);
       } catch (IOException e) {
         throw new RuntimeException(e);
       }
@@ -66,7 +66,7 @@ public class PMTilesReader {
       }
       try (var decompressed =
           new 
LittleEndianDataInputStream(header.getInternalCompression().decompress(input))) 
{
-        return PMTiles.deserializeEntries(decompressed);
+        return PMTilesUtils.deserializeEntries(decompressed);
       }
     } catch (IOException e) {
       throw new RuntimeException(e);
@@ -74,10 +74,10 @@ public class PMTilesReader {
   }
 
   public ByteBuffer getTile(int z, long x, long y) {
-    var tileId = PMTiles.zxyToTileId(z, x, y);
+    var tileId = PMTilesUtils.zxyToTileId(z, x, y);
     var header = getHeader();
     var entries = getRootDirectory();
-    var entry = PMTiles.findTile(entries, tileId);
+    var entry = PMTilesUtils.findTile(entries, tileId);
 
     if (entry == null) {
       return null;
diff --git 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTiles.java 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesUtils.java
similarity index 91%
rename from 
baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTiles.java
rename to 
baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesUtils.java
index fa872e3c..85c61574 100644
--- a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTiles.java
+++ 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesUtils.java
@@ -27,13 +27,19 @@ import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.List;
 
-public class PMTiles {
+class PMTilesUtils {
 
-  public static long toNum(long low, long high) {
+  private static final int HEADER_SIZE_BYTES = 127;
+
+  private PMTilesUtils() {
+    // Prevent instantiation
+  }
+
+  static long toNum(long low, long high) {
     return high * 0x100000000L + low;
   }
 
-  public static long readVarIntRemainder(InputStream input, long l)
+  static long readVarIntRemainder(InputStream input, long l)
       throws IOException {
     long h, b;
     b = input.read() & 0xff;
@@ -69,7 +75,7 @@ public class PMTiles {
     throw new RuntimeException("Expected varint not more than 10 bytes");
   }
 
-  public static int writeVarInt(OutputStream output, long value)
+  static int writeVarInt(OutputStream output, long value)
       throws IOException {
     int n = 1;
     while (value >= 0x80) {
@@ -81,7 +87,7 @@ public class PMTiles {
     return n;
   }
 
-  public static long readVarInt(InputStream input) throws IOException {
+  static long readVarInt(InputStream input) throws IOException {
     long val, b;
     b = input.read() & 0xff;
     val = b & 0x7f;
@@ -107,7 +113,7 @@ public class PMTiles {
     return readVarIntRemainder(input, val);
   }
 
-  public static void rotate(long n, long[] xy, long rx, long ry) {
+  static void rotate(long n, long[] xy, long rx, long ry) {
     if (ry == 0) {
       if (rx == 1) {
         xy[0] = n - 1 - xy[0];
@@ -119,7 +125,7 @@ public class PMTiles {
     }
   }
 
-  public static long[] idOnLevel(int z, long pos) {
+  static long[] idOnLevel(int z, long pos) {
     long n = LongMath.pow(2, z);
     long rx, ry, t = pos;
     long[] xy = new long[] {0, 0};
@@ -136,14 +142,14 @@ public class PMTiles {
     return new long[] {z, xy[0], xy[1]};
   }
 
-  private static long[] tzValues = new long[] {
+  private static final long[] tzValues = new long[] {
       0, 1, 5, 21, 85, 341, 1365, 5461, 21845, 87381, 349525, 1398101, 5592405,
       22369621, 89478485, 357913941, 1431655765, 5726623061L, 22906492245L,
       91625968981L, 366503875925L, 1466015503701L, 5864062014805L, 
23456248059221L,
       93824992236885L, 375299968947541L, 1501199875790165L,
   };
 
-  public static long zxyToTileId(int z, long x, long y) {
+  static long zxyToTileId(int z, long x, long y) {
     if (z > 26) {
       throw new RuntimeException("Tile zoom level exceeds max safe number 
limit (26)");
     }
@@ -167,7 +173,7 @@ public class PMTiles {
     return acc + d;
   }
 
-  public static long[] tileIdToZxy(long i) {
+  static long[] tileIdToZxy(long i) {
     long acc = 0;
     for (int z = 0; z < 27; z++) {
       long numTiles = (0x1L << z) * (0x1L << z);
@@ -179,9 +185,7 @@ public class PMTiles {
     throw new RuntimeException("Tile zoom level exceeds max safe number limit 
(26)");
   }
 
-  private static final int HEADER_SIZE_BYTES = 127;
-
-  public static Header deserializeHeader(InputStream input) throws IOException 
{
+  static Header deserializeHeader(InputStream input) throws IOException {
     byte[] bytes = new byte[HEADER_SIZE_BYTES];
     var num = input.read(bytes);
     if (num != HEADER_SIZE_BYTES) {
@@ -217,7 +221,7 @@ public class PMTiles {
         (double) buffer.getInt() / 10000000);
   }
 
-  public static byte[] serializeHeader(Header header) {
+  static byte[] serializeHeader(Header header) {
     var buffer = 
ByteBuffer.allocate(HEADER_SIZE_BYTES).order(ByteOrder.LITTLE_ENDIAN);
     buffer.put((byte) 0x50);
     buffer.put((byte) 0x4D);
@@ -255,7 +259,7 @@ public class PMTiles {
     return buffer.array();
   }
 
-  public static void serializeEntries(OutputStream output, List<Entry> entries)
+  static void serializeEntries(OutputStream output, List<Entry> entries)
       throws IOException {
     var buffer = ByteBuffer.allocate(entries.size() * 48);
     writeVarInt(output, entries.size());
@@ -283,7 +287,7 @@ public class PMTiles {
     output.write(buffer.array(), 0, buffer.limit());
   }
 
-  public static List<Entry> deserializeEntries(InputStream buffer)
+  static List<Entry> deserializeEntries(InputStream buffer)
       throws IOException {
     long numEntries = readVarInt(buffer);
     List<Entry> entries = new ArrayList<>((int) numEntries);
@@ -315,7 +319,7 @@ public class PMTiles {
     return entries;
   }
 
-  public static Entry findTile(List<Entry> entries, long tileId) {
+  static Entry findTile(List<Entry> entries, long tileId) {
     int m = 0;
     int n = entries.size() - 1;
     while (m <= n) {
@@ -342,7 +346,7 @@ public class PMTiles {
     return null;
   }
 
-  public static Directories buildRootLeaves(List<Entry> entries, int leafSize,
+  static Directories buildRootLeaves(List<Entry> entries, int leafSize,
       Compression compression) throws IOException {
     var rootEntries = new ArrayList<Entry>();
     var numLeaves = 0;
@@ -379,7 +383,7 @@ public class PMTiles {
     return new Directories(rootBytes, leavesBytes, numLeaves);
   }
 
-  public static Directories optimizeDirectories(List<Entry> entries, int 
targetRootLength,
+  static Directories optimizeDirectories(List<Entry> entries, int 
targetRootLength,
       Compression compression)
       throws IOException {
     if (entries.size() < 16384) {
diff --git 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesWriter.java 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesWriter.java
index a6e1e940..2e90d579 100644
--- 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesWriter.java
+++ 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/PMTilesWriter.java
@@ -28,19 +28,19 @@ import java.util.*;
 
 public class PMTilesWriter {
 
-  private Compression compression = Compression.GZIP;
+  private final Compression compression;
 
-  private Path path;
+  private final Path path;
 
-  private Map<String, Object> metadata = new HashMap<>();
+  private final List<Entry> entries;
 
-  private List<Entry> entries;
+  private final Map<Long, Long> tileHashToOffset;
 
-  private Map<Long, Long> tileHashToOffset;
+  private final Path tilePath;
 
-  private Long lastTileHash = null;
+  private Map<String, Object> metadata = new HashMap<>();
 
-  private Path tilePath;
+  private Long lastTileHash = null;
 
   private boolean clustered = true;
 
@@ -63,11 +63,13 @@ public class PMTilesWriter {
   private double centerLon = 0;
 
   public PMTilesWriter(Path path) throws IOException {
-    this(path, new ArrayList<>(), new HashMap<>());
+    this(path, new ArrayList<>(), new HashMap<>(), Compression.GZIP);
   }
 
-  public PMTilesWriter(Path path, List<Entry> entries, Map<Long, Long> 
tileHashToOffset)
+  public PMTilesWriter(Path path, List<Entry> entries, Map<Long, Long> 
tileHashToOffset,
+      Compression compression)
       throws IOException {
+    this.compression = compression;
     this.path = path;
     this.entries = entries;
     this.tileHashToOffset = tileHashToOffset;
@@ -80,12 +82,12 @@ public class PMTilesWriter {
 
   public void setTile(int z, int x, int y, byte[] bytes) throws IOException {
     // Write the tile
-    var tileId = PMTiles.zxyToTileId(z, x, y);
+    var tileId = PMTilesUtils.zxyToTileId(z, x, y);
     var tileLength = bytes.length;
     Long tileHash = Hashing.farmHashFingerprint64().hashBytes(bytes).asLong();
 
     // If the tile is not greater than the last one, the index is not clustered
-    if (entries.size() > 0 && tileId < entries.get(entries.size() - 
1).getTileId()) {
+    if (!entries.isEmpty() && tileId < entries.get(entries.size() - 
1).getTileId()) {
       clustered = false;
     }
 
@@ -155,7 +157,7 @@ public class PMTilesWriter {
       entries.sort(Comparator.comparingLong(Entry::getTileId));
     }
 
-    var directories = PMTiles.optimizeDirectories(entries, 16247, compression);
+    var directories = PMTilesUtils.optimizeDirectories(entries, 16247, 
compression);
 
     byte[] metadataBytes;
     try (var metadataOutput = new ByteArrayOutputStream()) {
@@ -204,7 +206,7 @@ public class PMTilesWriter {
     header.setCenterLon(centerLon);
 
     try (var output = new FileOutputStream(path.toFile())) {
-      output.write(PMTiles.serializeHeader(header));
+      output.write(PMTilesUtils.serializeHeader(header));
       output.write(directories.getRoot());
       output.write(metadataBytes);
       output.write(directories.getLeaves());
diff --git 
a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/TileType.java 
b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/TileType.java
index 001db982..6888470f 100644
--- a/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/TileType.java
+++ b/baremaps-pmtiles/src/main/java/org/apache/baremaps/pmtiles/TileType.java
@@ -17,7 +17,7 @@
 
 package org.apache.baremaps.pmtiles;
 
-enum TileType {
+public enum TileType {
   UNKNOWN,
   MVT,
   PNG,
diff --git 
a/baremaps-pmtiles/src/test/java/org/apache/baremaps/pmtiles/PMTilesTest.java 
b/baremaps-pmtiles/src/test/java/org/apache/baremaps/pmtiles/PMTilesUtilsTest.java
similarity index 56%
rename from 
baremaps-pmtiles/src/test/java/org/apache/baremaps/pmtiles/PMTilesTest.java
rename to 
baremaps-pmtiles/src/test/java/org/apache/baremaps/pmtiles/PMTilesUtilsTest.java
index 5bb38642..dca694f8 100644
--- 
a/baremaps-pmtiles/src/test/java/org/apache/baremaps/pmtiles/PMTilesTest.java
+++ 
b/baremaps-pmtiles/src/test/java/org/apache/baremaps/pmtiles/PMTilesUtilsTest.java
@@ -32,7 +32,7 @@ import java.util.Random;
 import org.apache.baremaps.testing.TestFiles;
 import org.junit.jupiter.api.Test;
 
-class PMTilesTest {
+class PMTilesUtilsTest {
 
   @Test
   void decodeVarInt() throws IOException {
@@ -41,53 +41,53 @@ class PMTilesTest {
         (byte) 127, (byte) 0xe5,
         (byte) 0x8e, (byte) 0x26
     }));
-    assertEquals(PMTiles.readVarInt(b), 0);
-    assertEquals(PMTiles.readVarInt(b), 1);
-    assertEquals(PMTiles.readVarInt(b), 127);
-    assertEquals(PMTiles.readVarInt(b), 624485);
+    assertEquals(0, PMTilesUtils.readVarInt(b));
+    assertEquals(1, PMTilesUtils.readVarInt(b));
+    assertEquals(127, PMTilesUtils.readVarInt(b));
+    assertEquals(624485, PMTilesUtils.readVarInt(b));
     b = new LittleEndianDataInputStream(new ByteArrayInputStream(new byte[] {
         (byte) 0xff, (byte) 0xff,
         (byte) 0xff, (byte) 0xff,
         (byte) 0xff, (byte) 0xff,
         (byte) 0xff, (byte) 0x0f,
     }));
-    assertEquals(PMTiles.readVarInt(b), 9007199254740991L);
+    assertEquals(9007199254740991L, PMTilesUtils.readVarInt(b));
   }
 
   @Test
   void encodeVarInt() throws IOException {
     for (long i = 0; i < 1000; i++) {
       var array = new ByteArrayOutputStream();
-      PMTiles.writeVarInt(array, i);
+      PMTilesUtils.writeVarInt(array, i);
       var input = new LittleEndianDataInputStream(new 
ByteArrayInputStream(array.toByteArray()));
-      assertEquals(i, PMTiles.readVarInt(input));
+      assertEquals(i, PMTilesUtils.readVarInt(input));
     }
     for (long i = Long.MAX_VALUE - 1000; i < Long.MAX_VALUE; i++) {
       var array = new ByteArrayOutputStream();
-      PMTiles.writeVarInt(array, i);
+      PMTilesUtils.writeVarInt(array, i);
       var input = new LittleEndianDataInputStream(new 
ByteArrayInputStream(array.toByteArray()));
-      assertEquals(i, PMTiles.readVarInt(input));
+      assertEquals(i, PMTilesUtils.readVarInt(input));
     }
   }
 
   @Test
   void zxyToTileId() {
-    assertEquals(PMTiles.zxyToTileId(0, 0, 0), 0);
-    assertEquals(PMTiles.zxyToTileId(1, 0, 0), 1);
-    assertEquals(PMTiles.zxyToTileId(1, 0, 1), 2);
-    assertEquals(PMTiles.zxyToTileId(1, 1, 1), 3);
-    assertEquals(PMTiles.zxyToTileId(1, 1, 0), 4);
-    assertEquals(PMTiles.zxyToTileId(2, 0, 0), 5);
+    assertEquals(0, PMTilesUtils.zxyToTileId(0, 0, 0));
+    assertEquals(1, PMTilesUtils.zxyToTileId(1, 0, 0));
+    assertEquals(2, PMTilesUtils.zxyToTileId(1, 0, 1));
+    assertEquals(3, PMTilesUtils.zxyToTileId(1, 1, 1));
+    assertEquals(4, PMTilesUtils.zxyToTileId(1, 1, 0));
+    assertEquals(5, PMTilesUtils.zxyToTileId(2, 0, 0));
   }
 
   @Test
   void tileIdToZxy() {
-    assertArrayEquals(PMTiles.tileIdToZxy(0), new long[] {0, 0, 0});
-    assertArrayEquals(PMTiles.tileIdToZxy(1), new long[] {1, 0, 0});
-    assertArrayEquals(PMTiles.tileIdToZxy(2), new long[] {1, 0, 1});
-    assertArrayEquals(PMTiles.tileIdToZxy(3), new long[] {1, 1, 1});
-    assertArrayEquals(PMTiles.tileIdToZxy(4), new long[] {1, 1, 0});
-    assertArrayEquals(PMTiles.tileIdToZxy(5), new long[] {2, 0, 0});
+    assertArrayEquals(new long[] {0, 0, 0}, PMTilesUtils.tileIdToZxy(0));
+    assertArrayEquals(new long[] {1, 0, 0}, PMTilesUtils.tileIdToZxy(1));
+    assertArrayEquals(new long[] {1, 0, 1}, PMTilesUtils.tileIdToZxy(2));
+    assertArrayEquals(new long[] {1, 1, 1}, PMTilesUtils.tileIdToZxy(3));
+    assertArrayEquals(new long[] {1, 1, 0}, PMTilesUtils.tileIdToZxy(4));
+    assertArrayEquals(new long[] {2, 0, 0}, PMTilesUtils.tileIdToZxy(5));
   }
 
   @Test
@@ -95,7 +95,7 @@ class PMTilesTest {
     for (int z = 0; z < 9; z++) {
       for (long x = 0; x < 1 << z; x++) {
         for (long y = 0; y < 1 << z; y++) {
-          var result = PMTiles.tileIdToZxy(PMTiles.zxyToTileId(z, x, y));
+          var result = PMTilesUtils.tileIdToZxy(PMTilesUtils.zxyToTileId(z, x, 
y));
           if (result[0] != z || result[1] != x || result[2] != y) {
             fail("roundtrip failed");
           }
@@ -108,22 +108,22 @@ class PMTilesTest {
   void tileExtremes() {
     for (var z = 0; z < 27; z++) {
       var dim = LongMath.pow(2, z) - 1;
-      var tl = PMTiles.tileIdToZxy(PMTiles.zxyToTileId(z, 0, 0));
+      var tl = PMTilesUtils.tileIdToZxy(PMTilesUtils.zxyToTileId(z, 0, 0));
       assertArrayEquals(new long[] {z, 0, 0}, tl);
-      var tr = PMTiles.tileIdToZxy(PMTiles.zxyToTileId(z, dim, 0));
+      var tr = PMTilesUtils.tileIdToZxy(PMTilesUtils.zxyToTileId(z, dim, 0));
       assertArrayEquals(new long[] {z, dim, 0}, tr);
-      var bl = PMTiles.tileIdToZxy(PMTiles.zxyToTileId(z, 0, dim));
+      var bl = PMTilesUtils.tileIdToZxy(PMTilesUtils.zxyToTileId(z, 0, dim));
       assertArrayEquals(new long[] {z, 0, dim}, bl);
-      var br = PMTiles.tileIdToZxy(PMTiles.zxyToTileId(z, dim, dim));
+      var br = PMTilesUtils.tileIdToZxy(PMTilesUtils.zxyToTileId(z, dim, dim));
       assertArrayEquals(new long[] {z, dim, dim}, br);
     }
   }
 
   @Test
   void invalidTiles() {
-    assertThrows(RuntimeException.class, () -> 
PMTiles.tileIdToZxy(9007199254740991L));
-    assertThrows(RuntimeException.class, () -> PMTiles.zxyToTileId(27, 0, 0));
-    assertThrows(RuntimeException.class, () -> PMTiles.zxyToTileId(0, 1, 1));
+    assertThrows(RuntimeException.class, () -> 
PMTilesUtils.tileIdToZxy(9007199254740991L));
+    assertThrows(RuntimeException.class, () -> PMTilesUtils.zxyToTileId(27, 0, 
0));
+    assertThrows(RuntimeException.class, () -> PMTilesUtils.zxyToTileId(0, 1, 
1));
   }
 
   @Test
@@ -131,28 +131,28 @@ class PMTilesTest {
     var file = 
TestFiles.resolve("baremaps-testing/data/pmtiles/test_fixture_1.pmtiles");
     try (var channel = FileChannel.open(file)) {
       var input = new 
LittleEndianDataInputStream(Channels.newInputStream(channel));
-      var header = PMTiles.deserializeHeader(input);
-      assertEquals(header.getRootDirectoryOffset(), 127);
-      assertEquals(header.getRootDirectoryLength(), 25);
-      assertEquals(header.getJsonMetadataOffset(), 152);
-      assertEquals(header.getJsonMetadataLength(), 247);
-      assertEquals(header.getLeafDirectoryOffset(), 0);
-      assertEquals(header.getLeafDirectoryLength(), 0);
-      assertEquals(header.getTileDataOffset(), 399);
-      assertEquals(header.getTileDataLength(), 69);
-      assertEquals(header.getNumAddressedTiles(), 1);
-      assertEquals(header.getNumTileEntries(), 1);
-      assertEquals(header.getNumTileContents(), 1);
+      var header = PMTilesUtils.deserializeHeader(input);
+      assertEquals(127, header.getRootDirectoryOffset());
+      assertEquals(25, header.getRootDirectoryLength());
+      assertEquals(152, header.getJsonMetadataOffset());
+      assertEquals(247, header.getJsonMetadataLength());
+      assertEquals(0, header.getLeafDirectoryOffset());
+      assertEquals(0, header.getLeafDirectoryLength());
+      assertEquals(399, header.getTileDataOffset());
+      assertEquals(69, header.getTileDataLength());
+      assertEquals(1, header.getNumAddressedTiles());
+      assertEquals(1, header.getNumTileEntries());
+      assertEquals(1, header.getNumTileContents());
       assertFalse(header.isClustered());
-      assertEquals(header.getInternalCompression(), Compression.GZIP);
-      assertEquals(header.getTileCompression(), Compression.GZIP);
-      assertEquals(header.getTileType(), TileType.MVT);
-      assertEquals(header.getMinZoom(), 0);
-      assertEquals(header.getMaxZoom(), 0);
-      assertEquals(header.getMinLon(), 0);
-      assertEquals(header.getMinLat(), 0);
-      assertEquals(Math.round(header.getMaxLon()), 1);
-      assertEquals(Math.round(header.getMaxLat()), 1);
+      assertEquals(Compression.GZIP, header.getInternalCompression());
+      assertEquals(Compression.GZIP, header.getTileCompression());
+      assertEquals(TileType.MVT, header.getTileType());
+      assertEquals(0, header.getMinZoom());
+      assertEquals(0, header.getMaxZoom());
+      assertEquals(0, header.getMinLon());
+      assertEquals(0, header.getMinLat());
+      assertEquals(1, Math.round(header.getMaxLon()));
+      assertEquals(1, Math.round(header.getMaxLat()));
     }
   }
 
@@ -187,10 +187,10 @@ class PMTilesTest {
         0);
 
     var array = new ByteArrayOutputStream();
-    array.write(PMTiles.serializeHeader(header));
+    array.write(PMTilesUtils.serializeHeader(header));
 
     var input = new LittleEndianDataInputStream(new 
ByteArrayInputStream(array.toByteArray()));
-    var header2 = PMTiles.deserializeHeader(input);
+    var header2 = PMTilesUtils.deserializeHeader(input);
 
     assertEquals(header, header2);
   }
@@ -198,7 +198,7 @@ class PMTilesTest {
   @Test
   void searchForMissingEntry() {
     var entries = new ArrayList<Entry>();
-    assertEquals(PMTiles.findTile(entries, 101), null);
+    assertNull(PMTilesUtils.findTile(entries, 101));
   }
 
   @Test
@@ -206,7 +206,7 @@ class PMTilesTest {
     var entry = new Entry(100, 1, 1, 1);
     var entries = new ArrayList<Entry>();
     entries.add(entry);
-    assertEquals(PMTiles.findTile(entries, 100), entry);
+    assertEquals(entry, PMTilesUtils.findTile(entries, 100));
   }
 
   @Test
@@ -215,47 +215,47 @@ class PMTilesTest {
     var entries = new ArrayList<Entry>();
     entries.add(entry);
     entries.add(new Entry(5, 5, 1, 2));
-    assertEquals(PMTiles.findTile(entries, 4), entry);
+    assertEquals(entry, PMTilesUtils.findTile(entries, 4));
   }
 
   @Test
   void searchWithMultipleTileEntries() {
     var entries = new ArrayList<Entry>();
     entries.add(new Entry(100, 1, 1, 2));
-    var entry = PMTiles.findTile(entries, 101);
-    assertEquals(entry.getOffset(), 1);
-    assertEquals(entry.getLength(), 1);
+    var entry = PMTilesUtils.findTile(entries, 101);
+    assertEquals(1, entry.getOffset());
+    assertEquals(1, entry.getLength());
 
     entries = new ArrayList<Entry>();
     entries.add(new Entry(100, 1, 1, 1));
     entries.add(new Entry(150, 2, 2, 2));
-    entry = PMTiles.findTile(entries, 151);
-    assertEquals(entry.getOffset(), 2);
-    assertEquals(entry.getLength(), 2);
+    entry = PMTilesUtils.findTile(entries, 151);
+    assertEquals(2, entry.getOffset());
+    assertEquals(2, entry.getLength());
 
     entries = new ArrayList<>();
     entries.add(new Entry(50, 1, 1, 2));
     entries.add(new Entry(100, 2, 2, 1));
     entries.add(new Entry(150, 3, 3, 1));
-    entry = PMTiles.findTile(entries, 51);
-    assertEquals(entry.getOffset(), 1);
-    assertEquals(entry.getLength(), 1);
+    entry = PMTilesUtils.findTile(entries, 51);
+    assertEquals(1, entry.getOffset());
+    assertEquals(1, entry.getLength());
   }
 
   @Test
   void leafSearch() {
     var entries = new ArrayList<Entry>();
     entries.add(new Entry(100, 1, 1, 0));
-    var entry = PMTiles.findTile(entries, 150);
-    assertEquals(entry.getOffset(), 1);
-    assertEquals(entry.getLength(), 1);
+    var entry = PMTilesUtils.findTile(entries, 150);
+    assertEquals(1, entry.getOffset());
+    assertEquals(1, entry.getLength());
   }
 
   @Test
   void buildRootLeaves() throws IOException {
     var entries = List.of(new Entry(100, 1, 1, 0));
-    var directories = PMTiles.buildRootLeaves(entries, 1, Compression.NONE);
-    assertEquals(directories.getNumLeaves(), 1);
+    var directories = PMTilesUtils.buildRootLeaves(entries, 1, 
Compression.NONE);
+    assertEquals(1, directories.getNumLeaves());
 
   }
 
@@ -264,7 +264,7 @@ class PMTilesTest {
     var random = new Random(3857);
     var entries = new ArrayList<Entry>();
     entries.add(new Entry(0, 0, 100, 1));
-    var directories = PMTiles.optimizeDirectories(entries, 100, 
Compression.NONE);
+    var directories = PMTilesUtils.optimizeDirectories(entries, 100, 
Compression.NONE);
     assertFalse(directories.getLeaves().length > 0);
     assertEquals(0, directories.getNumLeaves());
 
@@ -275,9 +275,9 @@ class PMTilesTest {
       entries.add(new Entry(i, offset, randTileSize, 1));
       offset += randTileSize;
     }
-    directories = PMTiles.optimizeDirectories(entries, 1024, Compression.NONE);
+    directories = PMTilesUtils.optimizeDirectories(entries, 1024, 
Compression.NONE);
     assertFalse(directories.getRoot().length > 1024);
-    assertFalse(directories.getNumLeaves() == 0);
-    assertFalse(directories.getLeaves().length == 0);
+    assertNotEquals(0, directories.getNumLeaves());
+    assertNotEquals(0, directories.getLeaves().length);
   }
 }


Reply via email to