Spring Boot Native Wire starter
Spring Boot 4.1 and JDK 25 Lockwell Native Wire starter with TLS, streaming, Object Lock, and metrics.
com.lockwell:lockwell-spring-boot-starter 0.2.2 is the opt-in, JDK 25-first client for LNW/1. It is a separate
artifact compiled with --release 25; the existing com.lockwell:lockwell-sdk remains Java 21 bytecode and continues
to provide the S3, HTTP-native JSON, Admin, and kit clients. The starter sends deterministic binary frames only—never
HTTP, JSON, or XML—and never falls back to another surface.
Install
<dependency>
<groupId>com.lockwell</groupId>
<artifactId>lockwell-spring-boot-starter</artifactId>
<version>0.2.2</version>
</dependency>This coordinate is source-shipped and consumer-tested in the repository; use your approved internal or GitHub Packages mirror and pin the artifact/checksums. The starter is tested with Spring Boot 4.1.1 and an external compatibility consumer under Spring Boot 4.0.7.
Configuration
Enable the starter explicitly and keep secrets in environment-backed configuration:
lockwell.native-wire.enabled=true
lockwell.native-wire.host=lockwell.internal.example
lockwell.native-wire.port=9444
lockwell.native-wire.access-key-id=${LOCKWELL_ACCESS_KEY_ID}
lockwell.native-wire.secret-key=${LOCKWELL_SECRET_KEY}
lockwell.native-wire.tls.ca-certificate=/run/secrets/lockwell-ca.pem
# Base64(SHA-256(SubjectPublicKeyInfo)); supplements PKIX + hostname verification.
lockwell.native-wire.tls.spki-sha256-pins[0]=${LOCKWELL_SPKI_PIN}
# Required together for an optional/required-mTLS listener.
lockwell.native-wire.tls.client-key-store=/run/secrets/lockwell-client.p12
lockwell.native-wire.tls.client-key-store-password=${LOCKWELL_CLIENT_KEYSTORE_PASSWORD}Public properties include host, port, accessKeyId, secretKey, poolSize (1–128, default 4),
connectTimeout (10 seconds), readTimeout (2 minutes), acquireTimeout (10 seconds), and nested TLS CA, SPKI pin,
PKCS#12 identity, and explicit loopback-plaintext test settings. TLS 1.3 and hostname verification are enforced for
non-loopback use. toString() and diagnostics redact secret and keystore password material.
Spring auto-configuration creates lifecycle-managed LockwellNativeWireClient, a virtual-thread
LockwellNativeWireAsyncClient, and LockwellNativeWireHealthIndicator when lockwell.native-wire.enabled=true.
The health check performs authenticated readiness, including the server metadata-authority/quorum guard. Disable the
property to roll back without changing stored objects.
Java API and streaming
The client exposes capabilities/readiness, bucket CRUD/versioning, object PUT/GET/HEAD/DELETE, ranges, ordered duplicate
user metadata, checksums, conditions, list/pagination/copy, versions/delete markers, multipart create/upload/list/
complete/abort, tags, retention, legal hold, batch delete, bucket CORS, webhook notifications, and signed GET/PUT
capabilities. ObjectLockWrite carries optional retention and legal-hold state on the initial PUT; the server rechecks
Object Lock scopes and commits the state atomically with the new version. Governance bypass is not supported.
Use getObject(request, OutputStream) for direct streaming or withObject(request, handler) for a bounded 64 KiB
backpressured pipe. The callback must consume the stream before returning; closing or abandoning it cancels and invalidates
the underlying connection. TransferProgressListener reports bytes. RequestOptions carries a deadline and validated
traceparent.
For serializable application work, the virtual-thread async client returns CompletableFuture values. The connection
pool remains the concurrency bound; an application-supplied executor remains application-owned and is not closed by the
client.
Auth, retry, and telemetry
The client performs HELLO/WELCOME and a fresh access-key timestamp/nonce proof for each connection. Only an
AUTH_ERROR with exact RATE_LIMITED, retryable=true, and a bounded hint may reopen a fresh socket and regenerate
credentials/proof before the caller deadline. AUTH_REPLAY, scope/tenant denials, malformed hints, and application
operations are never retried implicitly. A streaming write needs a new body, idempotency key, and body-binding checksum
for an explicit caller retry.
Micrometer meters use bounded labels only:
| Meter | Labels / meaning |
|---|---|
lockwell.native.wire.requests | result=success, result=failure, or result=cancelled |
lockwell.native.wire.request.duration | request timer |
lockwell.native.wire.connections | aggregate active connections |
lockwell.native.wire.bytes | direction=inbound or direction=outbound; header + metadata + payload + CRC after a successful write/validated read |
Tracing accepts a TraceparentProvider; diagnostics and errors are redacted. Webhook signing secrets are returned once;
configure a credential-free HTTPS URL and HMAC headers rather than putting a token in a query string.
Capability boundary
SSE-C is deliberately not advertised by this starter: critical SSE-C fields are rejected and same-named user metadata is still user-owned, so metadata cannot manufacture internal encryption state. Use the S3 client for genuine SSE-C. The Admin capability is a separate unimplemented authentication surface. Browser, edge, and static runtimes are not starter targets.
TangibleShift-shaped example
The public consumer fixture under
java-spring-boot-starter/consumer-tests/maven
uses company-scoped keys and exercises immutable conditional writes, ranges, copy/list, multipart resume/abort,
versions, batch delete, CORS, webhook configuration, retention/legal hold, and signed reads. A service can keep the
same shape without copying private application code:
import com.lockwell.sdk.springwire.LockwellNativeWireClient;
import com.lockwell.sdk.springwire.NativeWireTypes;
import java.io.InputStream;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Service;
@Service
final class ArtifactStore {
private final LockwellNativeWireClient lockwell;
ArtifactStore(LockwellNativeWireClient lockwell) {
this.lockwell = lockwell;
}
void write(String company, InputStream body, long length) {
var request = new NativeWireTypes.PutObjectRequest(
company + "-artifacts", "immutable/report.pdf", length,
"application/pdf", List.of(), Optional.empty(), Optional.empty(), false,
Optional.empty(), Optional.empty(),
Optional.of(NativeWireTypes.ObjectLockWrite.retention(
NativeWireTypes.RetentionMode.COMPLIANCE, Instant.now().plus(30, ChronoUnit.DAYS))),
NativeWireTypes.RequestOptions.defaults());
lockwell.putObject(request, body);
}
}Adapt the bucket naming, authorization, and retention policy to your tenant model; do not put access-key secrets in the
service source. The exact record constructors may evolve with the starter contract, so compile against the pinned
artifact and consult NativeWireTypes in source.
Verification and rollback
Run the starter's Maven tests and external Maven/Gradle consumers with JDK 25 before changing a claim. The cross-language
fixture proves byte compatibility with the Go server, comma/equals/reserved-name metadata round trips, and that native
wire metadata cannot trigger SSE-C. Disable lockwell.native-wire.enabled, drain clients, and restore the existing
explicit S3 or HTTP-native JSON selection to roll back; no object migration is performed.
See LNW architecture, the wire reference, and the source README for the full protocol, evidence, and compatibility ledger.
Java HTTP-native compatibility client
Production notes for the Java LockwellNativeClient, including bearer-token management, safe native retries, Retry-After handling, request timeouts, and TangibleShift ERP-style integration defaults.
Java SDK
The first-party Lockwell SDK for the JVM, with a JDK 25 native binary LNW/1 data plane and explicit S3, HTTP/JSON, and JSON Admin compatibility surfaces.