yavi
yavi copied to clipboard
Dynamic error messages
Please add support for custom dynamic error messages, for example:
In my validator I call The API that returns a list of supported values and I want to include that list in the error message:
var validator = ValidatorBuilder.<MyObject>of()
.constraint(MyObject::type, "type", x -> x.notBlank().predicate(
type -> myApi.getTypes().contains(type),
ViolationMessage.of(<How do I include the list of supported types from myApi.getTypes() here?>)))
.build();
Alternatively, I tried to implement CustomConstraint
as described in https://yavi.ik.am/#creating-a-custom-constraint, but could not make it return dynamic value from arguments()
:
@Override
public Object[] arguments() {
return new Object[] { <How do I return a result of the call myApi.getTypes() here> };
}
@Override
public String defaultMessageFormat() {
return "Type value \"{0}\" must be one of: \"{1}\".";
}
@Override
public String messageKey() {
return "type";
}
@Override
public boolean test(String type) {
return myApi.getTypes().contains(type);
}
I think it is related to https://github.com/making/yavi/issues/165
Can you try 0.9.0-SNAPSHOT? It's available in the following repository
<repository>
<id>sonatype-snapshots</id>
<name>Sonatype Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
@making I could not find in 0.9.0 how to create dynamic messages, can you point me to an example please?
Object[] arguments()
allows only defining arguments at validator "build time" - when validator is created but not when validate
is called. So I can't make the message contain dynamic values - API call results (at the time of validation) or values from the object being validated.
For example, I have a collection of elements and I want to check they are all unique and if found 2 equivalent ones, I want to add them to the violation message. How can I achieve that?
@sergtitov I also need this functionality in our project and I created a similar CustomConstraint implementation. This works in our case. Please beware that there is a small bug #173 which will be fixed in the next release.
@making Maybe this can be a candidate as a built-in validation?
import java.util.Collection;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import am.ik.yavi.core.CustomConstraint;
public final class EnumeratedConstraint<T> implements CustomConstraint<String> {
private final Set<String> values;
public static <E extends Enum<E>> EnumeratedConstraint<E> enumValues(Class<E> type) {
return new EnumeratedConstraint<>(EnumSet.allOf(type), Enum::name);
}
public static EnumeratedConstraint<String> codes(Collection<String> codes) {
return new EnumeratedConstraint<>(codes, Function.identity());
}
public EnumeratedConstraint(Collection<T> values, Function<T, String> codeMapper) {
this.values = Objects.requireNonNull(values).stream().map(codeMapper).collect(Collectors.toSet());
}
@Override
public String defaultMessageFormat() {
return "\"{0}\" value must be one of: \"{1}\".";
}
@Override
public String messageKey() {
return "string.enumerated";
}
@Override
public boolean test(String s) {
return values.contains(s);
}
@Override
public Object[] arguments() {
return new Object[] { values };
}
}
@duponter thanks for sharing your code! In my case it is more complicated since the list of allowed values is determined at runtime (via API call or some other way).
@making I see you added "enhancement" label. Does this mean custom/dynamic error messages are not supported now but will be in a future version?
I'm looking for a way to provide error messages dynamically but have little time to focus on this at this moment.
@sergtitov Can you provide a complete and minimal working example?
Where does myApi
come from?
Isn't it enough to pass myApi
in the constructor of the CustomConstraint
implementation class?
It is possible to add a breaking change that passes the target object to the arguments of arguments
method. But not sure this is what you want.
@sergtitov Here is the enhancement I can think of. https://github.com/making/yavi/pull/178 Do you think this will work for you as well?