io.github.dinamo541.corefx.util

Validator

Singleton final null-safe statelesssin estado

A general-purpose validation suite with two complementary families: predicate validators that never throw (returning false for input that can't satisfy a rule), and contract validators (require*) that enforce a precondition and throw a descriptive exception when violated. Una suite de validación de propósito general con dos familias complementarias: validadores de predicado que nunca lanzan (devolviendo false ante entrada que no puede satisfacer una regla), y validadores de contrato (require*) que imponen una precondición y lanzan una excepción descriptiva cuando se viola.

Two families, two intentionsDos familias, dos intenciones

  • Predicates (isBlank, isEmail, isInRange, …) — fully null-safe, composable in UI bindings, guard clauses and business logic. They answer "is this valid?" without side effects.Predicados (isBlank, isEmail, isInRange, …) — totalmente null-safe, componibles en bindings de UI, cláusulas de guarda y lógica de negocio. Responden "¿esto es válido?" sin efectos secundarios.
  • Contracts (requireNotBlank, requireInRange, …) — enforce a precondition and return the value when valid, throwing otherwise. They answer "this must be valid — fail loudly if not."Contratos (requireNotBlank, requireInRange, …) — imponen una precondición y devuelven el valor cuando es válido, lanzando excepción en caso contrario. Responden "esto debe ser válido — falla ruidosamente si no lo es."
⚙️
Built for safety & speedHecho para seguridad y velocidad

Every regex is a pre-compiled, immutable Pattern written in linear (non-backtracking) form, so even hostile input can't trigger catastrophic backtracking. All methods are stateless and thread-safe.Cada regex es un Pattern inmutable y precompilado, escrito en forma lineal (sin backtracking), así que ni la entrada hostil puede provocar backtracking catastrófico. Todos los métodos son sin estado y thread-safe.

Quick startInicio rápido

Validator v = Validator.getInstance();

// Predicates — never throw:
if (v.isBlank(name))        { /* show "required" */ }
if (!v.isEmail(email))      { /* show "bad e-mail" */ }
if (v.isInRange(age, 18, 120)) { /* ok */ }

// Contracts — throw on violation, return the value on success:
String n = v.requireNotBlank(name, "name");
int qty  = (int) v.requireInRange(quantity, 1, 99, "quantity");

Null & presence predicatesPredicados de null y presencia

MethodMétodoReturns true when…Devuelve true cuando…
isNull(Object) / isNotNull(Object)the reference is / isn't null.la referencia es / no es null.
isEmpty(String) / isNotEmpty(String)the string is null-or-empty / has ≥ 1 char.la cadena es null-o-vacía / tiene ≥ 1 carácter.
isBlank(String) / isNotBlank(String)the string is null/empty/whitespace / has a non-whitespace char.la cadena es null/vacía/espacios / tiene un carácter no en blanco.

Length predicatesPredicados de longitud

MethodMétodoChecks (on the trimmed length)Comprueba (sobre la longitud recortada)
hasMinLength(s, min)length ≥ min (false if null).longitud ≥ min (false si null).
hasMaxLength(s, max)length ≤ max (false if null).longitud ≤ max (false si null).
hasLengthBetween(s, min, max)length within [min, max] (false if null).longitud dentro de [min, max] (false si null).

Text / format predicatesPredicados de texto / formato

MethodMétodoMatchesCoincide con
isNumeric(s)digits only (non-negative integer), trimmed.solo dígitos (entero no negativo), recortado.
isInteger(s)optionally signed integer, trimmed.entero con signo opcional, recortado.
isDecimal(s)optionally signed decimal, trimmed.decimal con signo opcional, recortado.
isAlphabetic(s)Unicode letters only.solo letras Unicode.
isAlphabeticWithSpaces(s)letters with single spaces between words (no leading/trailing/double spaces).letras con espacios simples entre palabras (sin espacios al inicio/final/dobles).
isAlphanumeric(s)Unicode letters and digits.letras y dígitos Unicode.
isEmail(s)a pragmatic, RFC-ish e-mail (trimmed, linear-time).un e-mail pragmático, estilo RFC (recortado, tiempo lineal).
matches(s, String regex)full match; returns false (never throws) on null args or invalid regex.coincidencia completa; devuelve false (nunca lanza) ante args null o regex inválida.
matches(s, Pattern)full match against a pre-compiled pattern.coincidencia completa contra un patrón precompilado.

Numeric range & signRango numérico y signo

MethodMétodoNotesNotas
isInRange(long value, long min, long max)Inclusive; bounds auto-normalized (order doesn't matter).Inclusivo; los límites se normalizan automáticamente (el orden no importa).
isInRange(double value, double min, double max)Inclusive, normalized; NaN is never in range.Inclusivo, normalizado; NaN nunca está en rango.
isPositive(Number) · isNegative(Number) · isNonNegative(Number)Strict > 0, strict < 0, ≥ 0; false for null.Estricto > 0, estricto < 0, ≥ 0; false para null.

Collection / map / array predicatesPredicados de colección / mapa / array

Overloaded isEmpty / isNotEmpty for Collection<?>, Map<?,?> and Object[] — all null-safe (a null container counts as empty).Sobrecargas de isEmpty / isNotEmpty para Collection<?>, Map<?,?> y Object[] — todas null-safe (un contenedor null cuenta como vacío).

Contract validators (throwing)Validadores de contrato (lanzan)

<T> T requireNonNull(T value, String message)

Returns value or throws NullPointerException(message).Devuelve value o lanza NullPointerException(message).

String requireNotBlank(String value, String name)

Returns the original (untrimmed) value, or throws IllegalArgumentException ("name cannot be null or blank").Devuelve el valor original (sin recortar), o lanza IllegalArgumentException ("name cannot be null or blank").

long requireInRange(long value, long min, long max, String name)

Returns value if within [min, max] (normalized), else throws IllegalArgumentException with a message naming the value and bounds.Devuelve value si está dentro de [min, max] (normalizado), de lo contrario lanza IllegalArgumentException con un mensaje que nombra el valor y los límites.

double requireInRange(double value, double min, double max, String name)

Same for doubles; NaN is never in range and always fails.Igual para doubles; NaN nunca está en rango y siempre falla.

🤝
Pairs naturally with AnswerCombina de forma natural con Answer

Validate with predicates, then report with Answer:Valida con predicados y luego reporta con Answer:

if (!v.isEmail(email)) return Answer.failure("Please enter a valid e-mail");
return Answer.success("Account created").with("userId", id);
⚠️
Predicate vs. contract — pick on intentPredicado vs. contrato — elige por intención

Use predicates for user-facing validation where you'll render a friendly message; use contracts at API boundaries where invalid input is a programming error that should fail fast. Don't wrap require* in a try/catch for normal UI validation — that's what the predicates are for.Usa predicados para validación de cara al usuario donde mostrarás un mensaje amable; usa contratos en los límites de la API donde la entrada inválida es un error de programación que debe fallar rápido. No envuelvas require* en un try/catch para la validación normal de UI — para eso están los predicados.

RecommendationsRecomendaciones

Combine with Format: the formatter restricts keystrokes; the validator confirms the final value (range, e-mail, length).Combina con Format: el formateador restringe las pulsaciones; el validador confirma el valor final (rango, e-mail, longitud).

Lean on null-safety — pass possibly-null fields straight to predicates without guarding; they handle null for you.Apóyate en el null-safety — pasa campos posiblemente null directamente a los predicados sin proteger; ellos manejan null por ti.