@VPoint. Three pieces cooperate: the annotation processor generates schema-bearing aggregate classes at compile time, the varianz-agent intercepts annotated methods at class-load time, and RegistryBinding connects the process to the registry. The Gradle plugin wires all three.
Canonical imports
io.varianz.annotations.VPoint (missing the vpoint package), io.varianz.sdk.VPoint, and similar guesses do not exist.
Defining VPoints
- Always set an explicit
name. Omitted names derive from package/class/method names and break under refactoring. - Any class and method visibility works — the agent rewrites bytecode, so
private/final/synchronizedmethods are fine. (One limit: for private inner classes, the generated aggregate can’t expose direct typed invocation; stages by name still work.) - Plain beans and public-field DTOs are introspected automatically — fields from getters or public fields, constructors matched by type compatibility (static factories like
Quote.of(...)included). No@Structneeded for typical types. Field names convert camelCase → snake_case in CEL (basePrice→base_price). - For gRPC handlers, extract business logic into a plain-typed
@VPointmethod — keepStreamObserverout of schemas. See the pattern.
PricingServiceVPoints aggregate in the same package, wrapping the method with stage execution and embedding the VPD schema.
How interception works
The agent transforms each@VPoint method at class load: the original body is cloned to <method>$varianzDirect (keeping line tables, so breakpoints still land in your source), and the method itself becomes a dispatch stub into the stage chain. Calling the method normally routes through the pipeline — no bind()-proxy calls needed:
@VPoint methods run their original bodies. The Gradle/Maven plugins attach the agent for test and run tasks; production launchers must attach it explicitly:
Connecting to the registry
CallRegistryBinding.init() early — before your server starts serving — then bind() each service instance to register its VPDs:
@PostConstruct. Session propagation uses the pull-based @VarianzId @Function(global = true) pattern — the full setup is in Propagate sessions.
Control annotations
Aggregate.bind(service) returning a typed proxy exists for advanced cases (test harnesses, programmatic stage composition) — normal code doesn’t need it.
Disabling interception
In order of preference: don’t attach the agent (Gradleweave.set(false), Maven -Dvarianz.skipAgent=true); disable at runtime with -Dvarianz.proc.weave=false; or opt out one method with @VPoint(wrapped = false).
Maven
--enable-native-access=io.varianz.native_loader to the <argLine>. To disable interception for a build, pass -Dvarianz.skipAgent=true.
Native access (Java 22+)
The SDK loads its Rust runtime viaSystem.load, a restricted method under JEP 472. All Varianz JNI loading funnels through the io.varianz.native_loader module, so one flag covers the SDK:
Test/JavaExec on Java 22+; Maven and hand-rolled launchers add it to their JVM args. Prefer this targeted grant over ALL-UNNAMED.
Troubleshooting
@VPointmethods not intercepted — almost always the agent isn’t attached; look for the[varianz] Varianz agent not attachedwarning. Checkweave(Gradle) or theprepare-agentexecution +@{varianz.agentArgs}(Maven). For custom launchers, verify with-Dvarianz.proc.debug=true(the agent logs its transformer registration).NoClassDefFoundErrorfor a...VPointsclass at first call — the annotation processor didn’t run at compile time, so the aggregate doesn’t exist. With Gradle,compileJavashould logNote: [Varianz] Generated adapters....System.loadwarnings on Java 24+ — the JVM fork is missing the native-access flag; see above.
