Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions blackbox-test/src/test/java/example/avaje/notblank/ANotBlank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package example.avaje.notblank;

import io.avaje.validation.constraints.NotBlank;
import jakarta.validation.Valid;

@Valid
public record ANotBlank(
@NotBlank
String basic,
@NotBlank(max = 4)
String withMax,

@NotBlank(max = 4, message = "NotBlank n max 4")
String withCustom
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package example.avaje.notblank;

import io.avaje.validation.ConstraintViolation;
import io.avaje.validation.ConstraintViolationException;
import io.avaje.validation.Validator;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Locale;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

class ANotBlankTest {

final Validator validator = Validator.builder().addLocales(Locale.GERMAN).build();

@Test
void valid() {
var value = new ANotBlank("ok", "ok", "ok");
validator.validate(value);
}

@Test
void inValidNull() {
var value = new ANotBlank(null, null, null);
try {
validator.validate(value);
fail("not get here");
} catch (ConstraintViolationException e) {
assertThat(e.violations()).hasSize(3);
}
}

@Test
void invalidBlank() {
var violation = one(new ANotBlank("", "ok", "ok"));
assertThat(violation.message()).isEqualTo("must not be blank");

var violation1 = one(new ANotBlank("ok", " ", "ok"));
assertThat(violation1.message()).isEqualTo("must not be blank");

var violation2 = one(new ANotBlank("ok", "ok", "\t"));
assertThat(violation2.message()).isEqualTo("NotBlank n max 4");
}

@Test
void invalidMax() {
var violation = one(new ANotBlank("ok", "NotValid", "ok"));
assertThat(violation.message()).isEqualTo("maximum length 4 exceeded");

var violation1 = one(new ANotBlank("ok", "ok", "NotValid"));
assertThat(violation1.message()).isEqualTo("NotBlank n max 4");
}

@Test
void invalidAsDE() {
var violation = one(new ANotBlank(" ", "ok", "ok"), Locale.GERMAN);
assertThat(violation.message()).isEqualTo("darf nicht leer sein");
}

@Test
void invalidWithMaxDE() {
var violation = one(new ANotBlank("ok", "NotValid", "ok"), Locale.GERMAN);
assertThat(violation.message()).isEqualTo("Länge muss zwischen 1 und 4 sein");
}

@Test
void invalidCustomMessageDE() {
var violation = one(new ANotBlank("ok", "ok", "NotValid"), Locale.GERMAN);
assertThat(violation.message()).isEqualTo("NotBlank n max 4");
}

ConstraintViolation one(Object any) {
return one(any, Locale.ENGLISH);
}

ConstraintViolation one(Object any, Locale locale) {
try {
validator.validate(any, locale);
fail("not expected");
return null;
} catch (ConstraintViolationException e) {
var violations = new ArrayList<>(e.violations());
assertThat(violations).hasSize(1);
return violations.get(0);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
@Repeatable(List.class)
public @interface NotBlank {

/** Set the maximum length. By default this is 0 meaning unlimited. */
int max() default 0;

String message() default "{avaje.NotBlank.message}";

Class<?>[] groups() default {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ interface AdapterCreateRequest {

Message message();

Message message(String key);
Message message(String key, Object... extraKeyValues);

String targetType();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,14 @@ public ValidationContext.Message message() {
}

@Override
public ValidationContext.Message message(String messageKey) {
public ValidationContext.Message message(String messageKey, Object... extraKeyValues) {
Map<String, Object> newAttributes = new HashMap<>(attributes);
newAttributes.put("message", messageKey);
if (extraKeyValues != null) {
for (int i = 0; i < extraKeyValues.length; i += 2) {
newAttributes.put(String.valueOf(extraKeyValues[i]), extraKeyValues[i + 1]);
}
}
return ctx.message(newAttributes);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package io.avaje.validation.core.adapters;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.function.Predicate;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -99,7 +96,7 @@ private static boolean useLength(AdapterCreateRequest request) {

@Override
public boolean validate(Object value, ValidationRequest req, String propertyName) {
if (!checkGroups(groups, req) || value == null) {
if (value == null || !checkGroups(groups, req)) {
return true;
}

Expand Down Expand Up @@ -132,15 +129,47 @@ public boolean validate(Object value, ValidationRequest req, String propertyName
}
}

private static final class NotBlankAdapter extends AbstractConstraintAdapter<CharSequence> {
private static final class NotBlankAdapter implements ValidationAdapter<CharSequence> {

private final ValidationContext.Message message;
private final ValidationContext.Message maxLengthMessage;
private final Set<Class<?>> groups;
private final int maxLength;

NotBlankAdapter(AdapterCreateRequest request) {
super(request);
this.groups = request.groups();
this.message = request.message();
this.maxLength = maxLength(request);
if (maxLength > 0 && standardMessage(request)) {
maxLengthMessage = request.message("{avaje.Length.max.message}", "min", 1);
} else {
maxLengthMessage = null;
}
}

private static int maxLength(AdapterCreateRequest request) {
final Integer max = (Integer) request.attribute("max");
return Objects.requireNonNullElse(max, 0);
}

private static boolean standardMessage(AdapterCreateRequest request) {
return "{avaje.NotBlank.message}".equals(request.attribute("message"));
}

@Override
public boolean isValid(CharSequence cs) {
return (cs != null) && !isBlank(cs);
public boolean validate(CharSequence value, ValidationRequest req, String propertyName) {
if (!checkGroups(groups, req)) {
return true;
}
if (value == null || isBlank(value)) {
req.addViolation(message, propertyName);
return false;
}
if (maxLength > 0 && value.length() > maxLength) {
req.addViolation(maxLengthMessage != null ? maxLengthMessage : message, propertyName);
return false;
}
return true;
}

static boolean isBlank(final CharSequence cs) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
## Intentionally blank
avaje.Length.max.message = maximum length {max} exceeded
avaje.Size.max.message = maximum size {max} exceeded