hybrid-cache-spring-boot-starter
Used in:
components
- OverviewOverview
- VersionsVersions
- DependentsDependents
- DependenciesDependencies
<dependency>
<groupId>io.github.nwwarm</groupId>
<artifactId>hybrid-cache-spring-boot-starter</artifactId>
<version>1.0.2</version>
</dependency><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.nwwarm</groupId>
<artifactId>hybrid-cache-spring-boot-starter</artifactId>
<version>1.0.2</version>
<name>spring-redis-hybrid-cache</name>
<description>Three-tier cache library: local-only, distributed-only, or near-cache (Caffeine + Redisson)</description>
<url>https://github.com/nwwarm/spring-redis-hybrid-cache</url>
<licenses>
<license>
<name>The Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<id>nwwarm</id>
<name>Mahmoud Nawwar</name>
<email>nwwarm@gmail.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/nwwarm/spring-redis-hybrid-cache.git</connection>
<developerConnection>scm:git:ssh://github.com:nwwarm/spring-redis-hybrid-cache.git</developerConnection>
<url>https://github.com/nwwarm/spring-redis-hybrid-cache</url>
</scm>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<!-- Generate Source JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Generate Javadoc JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.12.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Sign Artifacts with GPG -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.8</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Publish to Sonatype Central -->
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.10.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<!--
chaos profile: opt in to the chaos integration suite. Pulls
in testcontainers-toxiproxy and tells Failsafe to run only
tests tagged @Tag("chaos"). Default `mvn verify` skips the
suite (the slow Toxiproxy container start dominates a vanilla
test run, and chaos tests can be flaky on contended runners
without the dedicated allowance).
Run via:
mvn -Pchaos verify
Pass criteria and per-scenario commands documented in
TESTING.md / Chaos testing.
-->
<profile>
<id>chaos</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<groups>chaos</groups>
<excludedGroups>combine.self</excludedGroups>
<argLine>-XX:+AllowRedefinitionToAddDeleteMethods</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<properties>
<java.version>17</java.version>
<springboot.version>3.5.14</springboot.version>
<caffeine.version>3.2.4</caffeine.version>
<redisson.version>4.3.1</redisson.version>
<resilience4j.version>2.4.0</resilience4j.version>
<testcontainers.version>2.0.5</testcontainers.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>${caffeine.version}</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
<version>${resilience4j.version}</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-micrometer</artifactId>
<version>${resilience4j.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!--
Toxiproxy: chaos integration suite (latency, bandwidth,
disconnect, pub/sub message-loss). § 7 / "Chaos tests" pins
the test categories; TESTING.md / Chaos testing documents the
run command. Tests are tagged @Tag("chaos") and excluded from
default `mvn verify`; opt in via `mvn -Pchaos verify`. Test
scope only.
-->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-toxiproxy</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<!--
jqwik: property-based tests catalogued against § 4 / § 5 /
§ 10 invariants (every cache invariant gets at least one
property test). § 7 / "Property-based tests" lists the
mapping; TESTING.md / Property-based testing references it.
Test scope only.
-->
<dependency>
<groupId>net.jqwik</groupId>
<artifactId>jqwik</artifactId>
<version>1.9.2</version>
<scope>test</scope>
</dependency>
<!--
BlockHound: detects blocking calls on threads marked
non-blocking. Used to enforce the async-path guarantee that
no read-path step blocks on a Netty event loop. § 10 0.5.0
+ # implementation guardrails / ## Async/reactive item 2 are
the governing decisions.
Test scope only — production code carries no Reactor dep
(guardrail item 1).
-->
<dependency>
<groupId>io.projectreactor.tools</groupId>
<artifactId>blockhound</artifactId>
<version>1.0.13.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!--
enforce-banned-dependencies: rejects the parallel-Redis
reactive stack from the runtime classpath. Pinned in
DESIGN.md / # implementation guardrails / Async/reactive
item 1 (Reactor) and item 12 (spring-boot-starter-data-
redis-reactive). The build rule is what survives a
future "dependency cleanup" PR that wouldn't read the
guardrail.
Test-scope BlockHound and reactor-test are allowed
because they only run during the test phase and are not
shipped to runtime classpaths.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>enforce-banned-dependencies</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<searchTransitive>false</searchTransitive>
<!--
Banned dependencies on direct
production scope (compile and
runtime). Test-scope variants are
intentionally allowed because
BlockHound and friends pull in
Reactor through transitive test
deps; the rule fires only on
direct compile/runtime additions.
-->
<excludes>
<exclude>org.springframework.boot:spring-boot-starter-data-redis-reactive</exclude>
<exclude>io.github.resilience4j:resilience4j-reactor</exclude>
<exclude>io.lettuce:lettuce-core</exclude>
</excludes>
<includes>
<!--
Allow Reactor only as a test
dep — BlockHound pulls it in
and the cache layer never
imports it (verified by the
`chaos.*` and `core.*` test
classes that compile without
Reactor on the production
classpath).
-->
<include>io.projectreactor:reactor-core:*:*:test</include>
</includes>
<message>
Banned by DESIGN.md / # implementation guardrails / Async/reactive.
The cache layer holds zero Reactor dependencies; Mono/Flux interop
happens in Spring's CacheInterceptor upstream.
</message>
</bannedDependencies>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<!--
Surefire arg-line: BlockHound's instrumentation needs
-XX:+AllowRedefinitionToAddDeleteMethods on JDK 13+ for
its agent to redefine classes that add new methods.
Without it, BlockHound fails to install during AsyncBlockHoundIT
(and any other test that calls BlockHound.install).
The flag is harmless on tests that don't use BlockHound.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.4</version>
<configuration>
<argLine>@{argLine} -XX:+AllowRedefinitionToAddDeleteMethods</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.5</version>
<configuration>
<argLine>@{argLine} -XX:+AllowRedefinitionToAddDeleteMethods</argLine>
<!--
Default `mvn verify` excludes JUnit-tagged
categories that gate behind opt-in profiles.
Each tag has a dedicated profile that flips the
default exclude. See `<profiles>` above.
-->
<excludedGroups>chaos,soak</excludedGroups>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<!--
PIT mutation testing, library-wide. Bar at 80% mutation
kill rate (DESIGN.md §7 / Mutation testing). Excluded
classes are trivial (records / DTOs / enum holders /
auto-config wiring whose semantics are exercised by
integration tests rather than mutation-killable unit
tests) — see DESIGN.md §7 / "Mutation testing exclusions"
for the per-class rationale.
Invoke via:
mvn org.pitest:pitest-maven:mutationCoverage
Not part of default `mvn verify` — PIT is slow and the
CI workflow runs it as a dedicated job (see
.github/workflows/ci.yml / mutation-testing).
-->
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.20.4</version>
<dependencies>
<dependency>
<groupId>org.pitest</groupId>
<artifactId>pitest-junit5-plugin</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
<configuration>
<targetClasses>
<param>io.github.nwwarm.hybridcache.*</param>
</targetClasses>
<!--
Scope to unit-test naming. PIT's TestEngine
discovery ignores Surefire's *Test.java filter
and would otherwise pick up every *IT.java that
Failsafe runs — Spring-Boot context boots,
Testcontainers Redis spin-ups, and BlockHound's
bootclasspath append (from AsyncBlockHoundIT)
pollute downstream ITs running in the same minion
JVM. Mutation testing's purpose is "do unit tests
catch logic-altering mutations" — ITs assert
observable wiring, not internal logic. Documented
in DESIGN.md §7 / "Mutation testing exclusions."
-->
<targetTests>
<param>io.github.nwwarm.hybridcache.*Test</param>
</targetTests>
<excludedClasses>
<!-- Records / DTOs: shapes verified by jackson round-trip ITs -->
<param>io.github.nwwarm.hybridcache.config.CacheProperties</param>
<param>io.github.nwwarm.hybridcache.config.CacheProperties$*</param>
<param>io.github.nwwarm.hybridcache.invalidation.InvalidationMessage</param>
<param>io.github.nwwarm.hybridcache.core.ReconciliationDecision*</param>
<param>io.github.nwwarm.hybridcache.core.LoaderRejectedException</param>
<!-- Auto-config wiring exercised by SecurityStartupIT / EndToEndWiringIT -->
<param>io.github.nwwarm.hybridcache.config.CacheConfig</param>
<!--
Framework-bound classes tested via *IT.java
against Testcontainers Redis. Their behaviour
is exercised by the Failsafe IT suite which
runs as part of `mvn verify`; PIT's coverage
minion can't run those ITs deterministically
(PIT's bytecode instrumentation pushes the
slowest IT past any reasonable coverage-phase
budget — see DESIGN.md §7 / "Mutation testing
exclusions" for the per-class rationale).
-->
<param>io.github.nwwarm.hybridcache.core.NearCache</param>
<param>io.github.nwwarm.hybridcache.core.DistributedOnlyCache</param>
<param>io.github.nwwarm.hybridcache.core.LocalOnlyCache</param>
<param>io.github.nwwarm.hybridcache.core.HybridCacheManager</param>
<param>io.github.nwwarm.hybridcache.core.RefreshExecutor</param>
<param>io.github.nwwarm.hybridcache.core.RefreshAheadCoordinator</param>
<param>io.github.nwwarm.hybridcache.core.SwrSidecar</param>
<param>io.github.nwwarm.hybridcache.core.Reconciler</param>
<param>io.github.nwwarm.hybridcache.core.ReconciliationCoordinator</param>
<!--
Caffeine Expiry callback — JitteredMaxIdleExpiry
gets called by Caffeine on every access /
expireAfterUpdate; mutations on the deadline-
arithmetic branches survive unit tests because
they never observe Caffeine's actual eviction
decision (only the value the Expiry returned).
Covered by NearCacheSwrIT / NearCacheAsyncIT
which observe the eviction outcomes.
-->
<param>io.github.nwwarm.hybridcache.core.JitteredMaxIdleExpiry</param>
<!--
Codec / log-formatter / loader-semaphore: each
is a thin adapter around an external concern
(Redisson codec resolution, log output, JDK
Semaphore). Behaviour is observable only at IT
layer (CodecRoundTripIT, the InvalidationIT
family that asserts log key hashing,
LoaderConcurrencyCapIT that exercises permit
rejection under real concurrent load).
-->
<param>io.github.nwwarm.hybridcache.core.CodecResolver</param>
<param>io.github.nwwarm.hybridcache.core.KeyLogFormatter</param>
<param>io.github.nwwarm.hybridcache.core.LoaderGate</param>
<param>io.github.nwwarm.hybridcache.invalidation.InvalidationDispatcher</param>
<param>io.github.nwwarm.hybridcache.invalidation.InvalidationListener</param>
<param>io.github.nwwarm.hybridcache.preloader.NearCachePreloader</param>
<param>io.github.nwwarm.hybridcache.preloader.PreloaderCoordinator</param>
<!--
PreloaderCoordinator nested types: anonymous
ScheduledExecutorService delegate ($1) and the
@TempDir lock-info record ($LockInfo) are
structurally tied to the coordinator and
covered by PreloaderRoundTripIT.
-->
<param>io.github.nwwarm.hybridcache.preloader.PreloaderCoordinator$*</param>
<param>io.github.nwwarm.hybridcache.metrics.HybridCacheHealthIndicator</param>
<param>io.github.nwwarm.hybridcache.probe.RedisStartupProbe</param>
</excludedClasses>
<excludedTestClasses>
<param>io.github.nwwarm.hybridcache.chaos.*</param>
</excludedTestClasses>
<mutationThreshold>80</mutationThreshold>
<coverageThreshold>80</coverageThreshold>
<timestampedReports>false</timestampedReports>
<outputFormats>
<param>HTML</param>
<param>XML</param>
</outputFormats>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.14</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<!--
Both Surefire (unit) and Failsafe (integration)
agents write to the same destFile in append mode.
The single `report` execution below then reflects
coverage from BOTH suites instead of unit only.
Without this, the headline coverage number
dramatically understates integration-test-heavy
classes (NearCache, DistributedOnlyCache,
HybridCacheManager).
-->
<destFile>${project.build.directory}/jacoco.exec</destFile>
<append>true</append>
</configuration>
</execution>
<execution>
<id>prepare-agent-integration</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/jacoco.exec</destFile>
<append>true</append>
</configuration>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/jacoco.exec</dataFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>