Java Refined

March 30, 2026 · View on GitHub

CI License Maven Central Coverage Mutation

Move validation into the type system. Zero runtime dependencies. Java 8+.

Why

Validated wrapper types are not a new idea — but existing JVM tools only give you the pattern, not the types themselves.

ToolWhat it providesPre-built types
Jakarta Bean ValidationAnnotations (@NotNull, @Min) — checked only when validate() is called0
VAVRValidation<E,A> monad — great error accumulation, but the validated value is still just Integer0
Arrow-ktSmart-constructor pattern via Exact<A,B> — ~10 lines of boilerplate per type0
Kotlin value classLanguage feature — you write everything yourself, Kotlin-only0

java-refined ships 123+ ready-to-use types. PositiveInt, NonBlankString, EmailString — import and go. Zero dependencies. Java 8+.

Before

public void createUser(String name, int age, List<String> roles) {
    if (name == null || name.trim().isEmpty()) {
        throw new IllegalArgumentException("name must not be blank");
    }
    if (age <= 0) {
        throw new IllegalArgumentException("age must be positive");
    }
    if (roles == null || roles.isEmpty()) {
        throw new IllegalArgumentException("roles must not be empty");
    }
    // business logic ...
}

After

public void createUser(NonBlankString name, PositiveInt age, NonEmptyList<String> roles) {
    // no validation needed — the types guarantee it
}

Types replace scattered if-checks. Invalid data cannot even reach your method.

Quick Start

// Trusted data — just unwrap
PositiveInt confirmedAge = PositiveInt.unsafeOf(18);

// Untrusted input — safe fallback
PositiveInt safeAge = PositiveInt.ofOrElse(userInput, 1);
// Branch on success/failure
EmailString.of(email).fold(
    error -> badRequest(error.message()),
    valid -> ok(register(valid))
);

Kotlin Support

Optional module with Kotlin-idiomatic extensions:

import io.github.junggikim.refined.kotlin.*

val name = "Ada".toNonBlankStringOrThrow()
val tags = listOf("java", "fp").toNonEmptyListOrThrow()
// Safe fallback
val safeAge = PositiveInt.ofOrElse(input, 1)
// Kotlin-idiomatic nullable
val age = PositiveInt.of(input).getOrNull() ?: PositiveInt.unsafeOf(1)
// Convert to kotlin.Result
val result: Result<PositiveInt> = PositiveInt.of(input).toResult()

API

All refined wrappers follow the same pattern:

  • of(value) — returns Validation<Violation, T>, never throws
  • unsafeOf(value) — throws RefinementException on invalid input
  • ofOrElse(value, default) — returns validated instance or falls back to default
  • ofStream(stream) — collection wrappers only

Collection refined types implement JDK interfaces directly — NonEmptyList<T> is a List<T>, NonEmptyMap<K,V> is a Map<K,V>. No unwrapping needed.

For AI-Assisted Development

Method signatures are contracts that AI agents cannot ignore.

When your API accepts PositiveInt instead of int, code generators and AI assistants are forced to provide validated values — no scattered if-checks to forget or duplicate.

Installation

"I can just implement this myself. Why add a dependency?"

Totally fair! Copy the source into your project — it's MIT licensed. But if it saved you some time... give me a ⭐ 🥺

Published to Maven Central. Kotlin/JVM users can optionally add java-refined-kotlin for extension functions (adds kotlin-stdlib dependency).

Gradle Kotlin DSL

dependencies {
    implementation("io.github.junggikim:java-refined:1.1.0")

    // optional: Kotlin extensions
    // implementation("io.github.junggikim:java-refined-kotlin:1.1.0")
}

Maven

<dependency>
  <groupId>io.github.junggikim</groupId>
  <artifactId>java-refined</artifactId>
  <version>1.1.0</version>
</dependency>

Supported Types

CategoryExamplesCount
NumericPositiveInt, NegativeLong, NonZeroDouble, ZeroToOneFloat46
CharacterDigitChar, LetterChar, UpperCaseChar7
StringNonBlankString, EmailString, UuidString, Ipv4String, JwtString48
CollectionNonEmptyList, NonEmptySet, NonEmptyMap, NonEmptyDeque, NonEmptyNavigableMap, ...10
ControlOption, Either, Try, Ior, Validated5
PredicatesGreaterThan, LengthBetween, MatchesRegex, AllOf, ForAllElements55+

Full list: docs/type-matrix.md

Docs

Contributing

CONTRIBUTING.md · CODE_OF_CONDUCT.md · SECURITY.md

License

MIT. See LICENSE.