Installation

Nomos is a multi-module Maven project. Import the BOM to align versions, then depend on nomos-runtime — the small library the generated code uses at runtime, with no third-party JSON dependencies and only the Scala standard library required.

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>dev.cjfravel</groupId>
      <artifactId>nomos-bom</artifactId>
      <version>0.0.1-alpha11</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>dev.cjfravel</groupId>
    <artifactId>nomos-runtime</artifactId>
  </dependency>
</dependencies>

Add the Maven plugin

The plugin scans your templates and generates sources during the generate-sources phase.

<plugin>
  <groupId>dev.cjfravel</groupId>
  <artifactId>nomos-maven-plugin</artifactId>
  <version>0.0.1-alpha11</version>
  <executions>
    <execution>
      <phase>generate-sources</phase>
      <goals><goal>generate</goal></goals>
    </execution>
  </executions>
</plugin>

Write a template

Templates live under src/main/resources/nomos/templates/, and the base package is derived from the file's path. A template at nomos/templates/com/example/models/user.json generates into base package com.example.models.

{
  "definitions": [
    {
      "name": "User",
      "subPackage": "user",
      "template": {
        "id": "string",
        "username": { "type": "string", "minLength": 1 },
        "email": { "type": "string", "format": "email" },
        "age": { "$optional": "int" },
        "roles": ["string"]
      }
    }
  ]
}

The base package comes from the template's path, and validation targets a definition by its fully-qualified name.

Generate

mvn generate-sources

Nomos writes, into target/generated-sources/nomos by default (Maven adds it as a compile source root, so it needn't be checked in):

// Code generated by Nomos. DO NOT EDIT.
// Source: com/example/models/user.json
package com.example.models.user

case class User(
  id: String,
  username: String,
  email: String,
  age: Option[Int],
  roles: List[String]
)

object User {
  def fromJson(json: String): Either[String, User] = { ... }
  def toJson(obj: User): String = { ... }
  def validate(json: String): Either[List[ValidationError], User] = { ... }
}

Use the generated code

import com.example.models.user.User

// Validate against the embedded template, then parse
User.validate("""{"id":"1","username":"jo","email":"jo@x.com","roles":["admin"]}""") match {
  case Right(user)  => println(s"ok: ${user.email}")
  case Left(errors) => errors.foreach(e => println(e.fullMessage))
}

// Round-trip
val json = User.toJson(User("1", "jo", "jo@x.com", Some(30), List("admin")))
val back = User.fromJson(json)   // Either[String, User]

Validation needs no template file at runtime — the template is embedded in NomosFormats, so a single generated jar carries both the model and its schema.

What to read next