GoForge — Build | Test | Ship | Collaborate GoForge — Build | Test | Ship | Collaborate
Skip to documentation

GoForge / Schema tooling

Refine

Richer contracts. Ordinary schemas.

Haskell-style refinement types for OpenAPI 3, Avro, and JSON Schema. One contract for the shape of your data—and the rules between its fields.

Maven 0.4.0 · publication pending · Java 25 · MIT

contract.refineHaskell-style syntax
type Person = {
  name :: String,
  age  :: Int
}

type Child = Person
  where it.age >= 0 && it.age < 18
    @code "person.child_age_range"
    @message "Age must be at least 0 and less than 18"

Keep the domain type. State the constraint.

Use Refine from Maven

Java 25 + Maven · Configured schema project · Central publication pending

mvn dev.goforge:refine-maven-plugin:0.4.0:generate

Maven release — 0.4.0 (Central publication pending). The release has passed local verification and was submitted to Sonatype; its public artifacts are not yet available. The Maven commands below require publication to finish. Java 25 consumers can import schemas, generate contracts, and run mutation verification through Maven. No Go executable is required in the consumer build. The compiler itself is authored in GoPlus.

Refine adds executable refinement rules to data contracts. It supports native schema import and Java generation for supported OpenAPI 3, Avro, and JSON Schema constructs. Ordinary schema exports carry explanations for rules the target format cannot express. Unsupported correspondences can reject generation; this is not a claim of complete support for every construct in those standards.

One contract, richer rules

type Booking = {
  arrivalDay   :: Int,
  departureDay :: Int,
  guests       :: Int
}
  where it.departureDay > it.arrivalDay
    @code "booking.date_order"
    @message "Departure must be after arrival"
  where it.guests >= 1
    @code "booking.guest_count"
    @message "A booking must have at least one guest"

The first rule compares two fields; the second constrains one. Each where clause has its own diagnostic. Validation distinguishes valid, invalid, and indeterminate results; exhausting an evaluation budget is not a pass.

Use from Maven

Requirements: Java 25 and Maven, plus a configured Refine schema project. Add this plugin to the consumer POM:

<plugin>
  <groupId>dev.goforge</groupId>
  <artifactId>refine-maven-plugin</artifactId>
  <version>0.4.0</version>
  <executions>
    <execution>
      <goals><goal>generate</goal></goals>
    </execution>
  </executions>
</plugin>

The generate goal reads refine.project.json and versioned contracts under schemata/, then registers generated Java and resources with Maven. Consumers must also declare the dependencies required by their selected adapters and tests, and configure execution of the generated property-test entry point. Generation alone does not mean those tests ran.

The plugin resolves the Refine engine from Maven. The engine runs inside the JVM, using Chicory-compiled code and a Java interpreter for some large functions. Google Java Format runs in a Java subprocess. There is no Go process or native Refine executable in this consumer path.

The ingest goal imports a local OpenAPI, JSON Schema, or Avro spec into a native bundle. It does not fetch a remote spec automatically. See the Maven guide and project configuration for complete setup, dependencies, and supported inputs.

Supported outputs and boundaries

CapabilityCurrent scope
Native schemasImport and export supported OpenAPI 3, Avro, and JSON Schema contracts; retain native constraints in native bundles
Refinement languageHaskell-style types and predicates, named functions, records and tagged unions; supported semantics documented in the language guide
Java 25Models, validators, Jackson 3 JSON codecs, Avro binary/JSON codecs, validated construction and explicit bypass APIs
In-memory payload validationPer-clause diagnostics, exact rational values, evaluation budgets, and indeterminate outcomes
Project generationVersioned schema families, generated files with ownership checks, Maven integration, and default Java formatting
AnalysisCompatibility analysis, semantic-version guidance, and explanations of constraints omitted from ordinary schemas

Refine does not currently generate a complete Spring HTTP client, Spring MVC server, Kafka producer, or Kafka consumer. Generated codecs and models can be used in those applications, with handwritten transport and framework integration. Python, JavaScript, TypeScript, and Go model generation are not current targets.

Generated tests and mutation evidence

Generated suites report executed properties, evaluated case counts, and coverage gaps. Missing codecs do not get constant-success test stubs. Zero-case properties and exhausted generation budgets fail. Case counts are not distinct-input counts or coverage percentages.

In Maven 0.4.0, generated payload suites add top-level model-accessor checks, JSON node/depth budget checks through a plain Jackson mapper, and bounded native JSON rejection probes. Native probe expectations are determined during generation by the Go native validator; consumers execute the resulting assertions in Java. These are selected checks, not exhaustive native-schema or accessor coverage. Generic and union accessor checks remain a reported gap; authored native-invalid model examples are distinct from the generated raw-JSON probes.

Run the mutation harness from a configured consumer project:

./mvnw refine:mutate

Refine owns this harness. The consumer supplies refine.mutations.tsv and its expected suite count. Each selected production-source mutation is compiled into an isolated copy, then tested against generated properties and application JUnit tests separately. The report distinguishes kills, survivors, invalid compilations, timeouts, and infrastructure errors. A survivor or inconclusive result fails the goal. This is a bounded catalog, not exhaustive mutation coverage.

Rice’s Tax can read .mut/current to review surviving mutants. Its review ledger supplements the test results: classifying a survivor does not currently make Refine’s mutation goal pass. See the mutation guide.

Offscript is the Spring Boot/Thymeleaf consumer used to exercise this workflow against the Nager.Date OpenAPI contract. Its application transport is handwritten. Its test results are evidence for that fixture, not proof of all Refine behavior.

CLI and source

The separately tagged Go CLI v0.1.0 remains available:

go install goforge.dev/refine/cmd/refine@v0.1.0

That older CLI release requires Go 1.26 or newer and does not contain the Maven 0.4.0 improvements. The Maven artifact version and Go CLI tag are distinct.