Skip to content

Commit

Permalink
Save attribute validatedPath in MessageInterpolatorContext
Browse files Browse the repository at this point in the history
Fixed #265
  • Loading branch information
altro3 committed Nov 11, 2024
1 parent a555d96 commit abafc40
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
* @param <R> The root bean type
*/
@Internal
final class DefaultConstraintValidatorContext<R> implements ConstraintValidatorContext {
public final class DefaultConstraintValidatorContext<R> implements ConstraintValidatorContext {

private static final Map<Class<?>, List<Class<?>>> GROUP_SEQUENCES = new ConcurrentHashMap<>();
private static final List<Class<?>> DEFAULT_GROUPS = Collections.singletonList(Default.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@

import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.validation.validator.messages.DefaultMessageInterpolatorContext;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.ElementKind;
import jakarta.validation.MessageInterpolator;
import jakarta.validation.Path;
import jakarta.validation.ValidationException;
import jakarta.validation.metadata.ConstraintDescriptor;

/**
* The default implementation {@link ConstraintValidatorContext.ConstraintViolationBuilder}.
Expand Down Expand Up @@ -122,22 +121,11 @@ public ConstraintValidatorContext addConstraintViolation() {
null,
null,
messageTemplate,
messageInterpolator.interpolate(messageTemplate, new MessageInterpolator.Context() {
@Override
public ConstraintDescriptor<?> getConstraintDescriptor() {
return constraintValidatorContext.constraint;
}

@Override
public Object getValidatedValue() {
return null;
}

@Override
public <T> T unwrap(Class<T> type) {
throw new ValidationException("Not supported!");
}
}),
messageInterpolator.interpolate(messageTemplate, new DefaultMessageInterpolatorContext(
constraintValidatorContext,
constraintValidatorContext.constraint,
null
)),
validationPath.iterator().hasNext() ? validationPath : new ValidationPath(constraintValidatorContext.getCurrentPath()),
constraintValidatorContext.constraint,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import io.micronaut.validation.validator.constraints.InternalConstraintValidatorFactory;
import io.micronaut.validation.validator.extractors.ValueExtractorDefinition;
import io.micronaut.validation.validator.extractors.ValueExtractorRegistry;
import io.micronaut.validation.validator.messages.DefaultMessageInterpolatorContext;
import jakarta.inject.Singleton;
import jakarta.validation.ClockProvider;
import jakarta.validation.Constraint;
Expand Down Expand Up @@ -1472,22 +1473,7 @@ private <R> DefaultConstraintViolation<R> createConstraintViolation(DefaultConst
Object elementValue,
ConstraintDescriptor<Annotation> constraint) {
final String messageTemplate = buildMessageTemplate(context, constraint);
final String message = messageInterpolator.interpolate(messageTemplate, new MessageInterpolator.Context() {
@Override
public ConstraintDescriptor<?> getConstraintDescriptor() {
return constraint;
}

@Override
public Object getValidatedValue() {
return elementValue;
}

@Override
public <T> T unwrap(Class<T> type) {
throw new ValidationException("Not supported!");
}
});
final String message = messageInterpolator.interpolate(messageTemplate, new DefaultMessageInterpolatorContext(context, constraint, elementValue));

return new DefaultConstraintViolation<>(
context.getRootBean(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
* The default error messages.
Expand All @@ -49,8 +48,8 @@ private String interpolate(@NonNull String template, @NonNull MessageSource.Mess
ArgumentUtils.requireNonNull("template", template);
ArgumentUtils.requireNonNull("context", context);

StringBuilder messageBuilder = new StringBuilder();
StringBuilder variableBuilder = new StringBuilder();
var messageBuilder = new StringBuilder();
var variableBuilder = new StringBuilder();
StringBuilder builder = messageBuilder;
boolean isVariable = false;
for (int i = 0; i < template.length(); i++) {
Expand Down Expand Up @@ -108,8 +107,11 @@ public String interpolate(String messageTemplate, Context context) {

@Override
public String interpolate(String messageTemplate, Context context, Locale locale) {
Map<String, Object> attributes = new HashMap<>(context.getConstraintDescriptor().getAttributes());
var attributes = new HashMap<>(context.getConstraintDescriptor().getAttributes());
attributes.put("validatedValue", context.getValidatedValue());
if (context instanceof DefaultMessageInterpolatorContext interpolatorContext) {
attributes.put("validatedPath", interpolatorContext.getValidatorContext().getCurrentPath());
}
return interpolate(messageTemplate, MessageSource.MessageContext.of(locale, attributes));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.validation.validator.messages;

import io.micronaut.core.annotation.Nullable;
import io.micronaut.validation.validator.DefaultConstraintValidatorContext;
import jakarta.validation.MessageInterpolator;
import jakarta.validation.ValidationException;
import jakarta.validation.metadata.ConstraintDescriptor;

import java.lang.annotation.Annotation;

public class DefaultMessageInterpolatorContext implements MessageInterpolator.Context {

private final DefaultConstraintValidatorContext<?> validatorContext;
private final ConstraintDescriptor<Annotation> constraintDescriptor;
@Nullable
private final Object validatedValue;

public DefaultMessageInterpolatorContext(
DefaultConstraintValidatorContext<?> validatorContext,
ConstraintDescriptor<Annotation> constraintDescriptor,
@Nullable Object validatedValue
) {
this.validatorContext = validatorContext;
this.constraintDescriptor = constraintDescriptor;
this.validatedValue = validatedValue;
}

public DefaultConstraintValidatorContext<?> getValidatorContext() {
return validatorContext;
}

@Override
public ConstraintDescriptor<?> getConstraintDescriptor() {
return constraintDescriptor;
}

@Override
public Object getValidatedValue() {
return validatedValue;
}

@Override
public <T> T unwrap(Class<T> type) {
throw new ValidationException("Not supported!");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.micronaut.validation.validator;

import io.micronaut.core.annotation.Introspected;
import io.micronaut.validation.Validated;
import jakarta.validation.constraints.Size;

@Validated
@Introspected
class MyBook {
@Size(max = 2, message = "Check path: {validatedPath} with value: {validatedValue}")
private String title;

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,15 @@ class ValidatorSpec extends Specification {
Exception e = thrown()
e.message.contains('''myMethod2.bean.number: must be less than or equal to 20''')
}
void "test message interpolator context attributes"() {
when:
def service = applicationContext.getBean(MyBookService)
def book = service.saveBook(new MyBook(title: "too long name"))
then:
Exception e = thrown()
e.message.contains('''saveBook.book.title: Check path: saveBook.book.title with value: too long name''')
}
}
class Bean extends AbstractMap<String, Integer> {
Expand Down Expand Up @@ -1115,3 +1124,11 @@ class BookService {
}
}
@Validated
@Singleton
class MyBookService {
MyBook saveBook(@Valid MyBook book) {
book
}
}

0 comments on commit abafc40

Please sign in to comment.