Skip to content

Commit

Permalink
HV-1822 add russian specific INN annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
Boiarshinov authored and gsmet committed Dec 23, 2020
1 parent 3304647 commit d8c8faa
Show file tree
Hide file tree
Showing 28 changed files with 525 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ public ConstraintHelper(Types typeUtils, AnnotationApiHelper annotationApiHelper
registerAllowedTypesForBuiltInConstraint( HibernateValidatorTypes.REGON_CHECK, CharSequence.class );
registerAllowedTypesForBuiltInConstraint( HibernateValidatorTypes.NIP_CHECK, CharSequence.class );
registerAllowedTypesForBuiltInConstraint( HibernateValidatorTypes.PESEL_CHECK, CharSequence.class );
registerAllowedTypesForBuiltInConstraint( HibernateValidatorTypes.INN_CHECK, CharSequence.class );
registerAllowedTypesForBuiltInConstraint( HibernateValidatorTypes.NOT_BLANK, CharSequence.class );
registerAllowedTypesForBuiltInConstraint( HibernateValidatorTypes.NOT_EMPTY, TYPES_SUPPORTED_BY_SIZE_AND_NOT_EMPTY_ANNOTATIONS );
registerAllowedTypesForBuiltInConstraint( HibernateValidatorTypes.NORMALIZED, CharSequence.class );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public static class HibernateValidatorTypes {
public static final String REGON_CHECK = ORG_HIBERNATE_VALIDATOR_CONSTRAINTS + ".pl.REGON";
public static final String NIP_CHECK = ORG_HIBERNATE_VALIDATOR_CONSTRAINTS + ".pl.NIP";
public static final String PESEL_CHECK = ORG_HIBERNATE_VALIDATOR_CONSTRAINTS + ".pl.PESEL";
public static final String INN_CHECK = ORG_HIBERNATE_VALIDATOR_CONSTRAINTS + ".ru.INN";
public static final String NORMALIZED = ORG_HIBERNATE_VALIDATOR_CONSTRAINTS + ".Normalized";
public static final String NOT_BLANK = ORG_HIBERNATE_VALIDATOR_CONSTRAINTS + ".NotBlank";
public static final String NOT_EMPTY = ORG_HIBERNATE_VALIDATOR_CONSTRAINTS + ".NotEmpty";
Expand Down
5 changes: 5 additions & 0 deletions documentation/src/main/asciidoc/ch02.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,11 @@ Hibernate Validator!
Hibernate metadata impact::: None
Country::: Poland

`@INN`:: Checks that the annotated character sequence represents a Russian taxpayer identification number (https://ru.wikipedia.org/wiki/%D0%98%D0%B4%D0%B5%D0%BD%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%BE%D0%BF%D0%BB%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%89%D0%B8%D0%BA%D0%B0[INN]). Can be applied to both individual and juridical versions of INN
Supported data types::: `CharSequence`
Hibernate metadata impact::: None
Country::: Russia

[TIP]
====
In some cases neither the Jakarta Bean Validation constraints nor the custom constraints provided by
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.cfg.defs.ru;

import org.hibernate.validator.cfg.ConstraintDef;
import org.hibernate.validator.constraints.ru.INN;

/**
* @author Artem Boiarshinov
*/
public class INNDef extends ConstraintDef<INNDef, INN> {

public INNDef() {
super( INN.class );
}

public INNDef type(INN.Type type) {
addParameter( "type", type );
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/

/**
* <p>Russian specific constraint definition classes for programmatic constraint definition API.</p>
* <p>This package is part of the public Hibernate Validator API.</p>
*/

package org.hibernate.validator.cfg.defs.ru;
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.constraints.ru;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;

import org.hibernate.validator.constraints.ru.INN.List;

/**
* Checks that the annotated character sequence is a valid russian taxpayer
* identification number (INN in russian transliteration).
*
* @author Artem Boiarshinov
* @see <a href="https://www.nalog.ru/rn77/fl/interest/inn/">russian taxpayer identification number</a>
*/
@Documented
@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@ReportAsSingleViolation
public @interface INN {

String message() default "{org.hibernate.validator.constraints.ru.INN.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

Type type() default Type.ANY;

/**
* Defines several {@code @INN} annotations on the same element.
*/
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
public @interface List {

INN[] value();
}

/**
* Defines the INN length. Valid lengths of INN are {@code 12} for individual usage
* and {@code 10} for juridical which are represented as {@link INN.Type#INDIVIDUAL}
* and {@link INN.Type#JURIDICAL} respectively.
* <p>
* Using {@link INN.Type#ANY} allows to validate values that could either be personal
* or juridical.
* In such case, INN type would be determined by the length of the corresponding value.
*/
enum Type {
INDIVIDUAL,
JURIDICAL,
ANY
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/

/**
* <p>Hibernate Validator Russian constraints.</p>
* <p>This package is part of the public Hibernate Validator API.</p>
*/
package org.hibernate.validator.constraints.ru;
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.internal.constraintvalidators.hv.ru;

import java.util.regex.Pattern;

import org.hibernate.validator.constraints.ru.INN;
import org.hibernate.validator.internal.util.Contracts;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
* Checks that a given character sequence (e.g. string) is a valid INN.
*
* @author Artem Boiarshinov
*/
public class INNValidator implements ConstraintValidator<INN, CharSequence> {

private static final Pattern NUMBERS_ONLY_PATTERN = Pattern.compile( "[0-9]+" );
private static final int RADIX = 10;

private INNValidationAlgorithm innValidationAlgorithm;

@Override
public void initialize(INN constraintAnnotation) {
this.innValidationAlgorithm = INNValidationAlgorithm.from( constraintAnnotation.type() );
}

@Override
public boolean isValid(CharSequence innCharSeq, ConstraintValidatorContext context) {
if ( innCharSeq == null ) {
return true;
}

final String inn = innCharSeq.toString();

final boolean hasOnlyNumbers = NUMBERS_ONLY_PATTERN.matcher( inn ).matches();
if ( !hasOnlyNumbers ) {
return false;
}

if ( !innValidationAlgorithm.isValidLength( inn.length() ) ) {
return false;
}

final int[] digits = inn.codePoints().map( symbol -> Character.digit( symbol, RADIX ) ).toArray();

return innValidationAlgorithm.isValidChecksum( digits );

}

private interface INNValidationAlgorithm {
boolean isValidLength(int length);

boolean isValidChecksum(int[] digits);

static INNValidationAlgorithm from(org.hibernate.validator.constraints.ru.INN.Type type) {
Contracts.assertNotNull( type );
switch ( type ) {
case JURIDICAL:
return INNValidationAlgorithmImpl.JURIDICAL;
case INDIVIDUAL:
return INNValidationAlgorithmImpl.INDIVIDUAL;
case ANY:
default:
return INNValidationAlgorithmImpl.ANY;
}
}
}

private enum INNValidationAlgorithmImpl implements INNValidationAlgorithm {

INDIVIDUAL {
@Override
public boolean isValidLength(int length) {
return 12 == length;
}

@Override
public boolean isValidChecksum(int[] digits) {
return checkChecksumPersonalINN( digits );
}
},
JURIDICAL {
@Override
public boolean isValidLength(int length) {
return 10 == length;
}

@Override
public boolean isValidChecksum(int[] digits) {
return checkChecksumJuridicalINN( digits );
}
},
ANY {
@Override
public boolean isValidLength(int length) {
return 10 == length || 12 == length;
}

@Override
public boolean isValidChecksum(int[] digits) {
final int length = digits.length;
if ( length == 12 ) {
return checkChecksumPersonalINN( digits );
}
else if ( length == 10 ) {
return checkChecksumJuridicalINN( digits );
}
throw new IllegalStateException( "Invalid/unsupported inn value length" );
}
};

private static final int[] INDIVIDUAL_WEIGHTS_11 = { 7, 2, 4, 10, 3, 5, 9, 4, 6, 8 };
private static final int[] INDIVIDUAL_WEIGHTS_12 = { 3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8 };
private static final int[] JURIDICAL_WEIGHTS = { 2, 4, 10, 3, 5, 9, 4, 6, 8 };

private static final int MOD_11 = 11;
private static final int MOD_10 = 10;

/**
* Check the digits for personal INN using algorithm from
* <a href="https://ru.wikipedia.org/wiki/%D0%98%D0%B4%D0%B5%D0%BD%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%BE%D0%BF%D0%BB%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%89%D0%B8%D0%BA%D0%B0#%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D1%8C%D0%BD%D1%8B%D1%85_%D1%86%D0%B8%D1%84%D1%80">Wikipedia</a>.
*/
private static boolean checkChecksumPersonalINN(int[] digits) {
final int checkSum11 = getCheckSum( digits, INDIVIDUAL_WEIGHTS_11 );
final int checkSum12 = getCheckSum( digits, INDIVIDUAL_WEIGHTS_12 );

final boolean isCheckSum11Correct = checkSum11 == digits[digits.length - 2];
final boolean isCheckSum12Correct = checkSum12 == digits[digits.length - 1];

return isCheckSum11Correct && isCheckSum12Correct;
}

/**
* Check the digits for juridical INN using algorithm from
* <a href="https://ru.wikipedia.org/wiki/%D0%98%D0%B4%D0%B5%D0%BD%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%BE%D0%BF%D0%BB%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%89%D0%B8%D0%BA%D0%B0#%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D1%8C%D0%BD%D1%8B%D1%85_%D1%86%D0%B8%D1%84%D1%80">Wikipedia</a>.
*/
private static boolean checkChecksumJuridicalINN(int[] digits) {
final int checkSum = getCheckSum( digits, JURIDICAL_WEIGHTS );
return digits[digits.length - 1] == checkSum;
}

private static int getCheckSum(int[] digits, int[] weights) {
int sum = 0;
for ( int i = 0; i < weights.length; i++ ) {
sum += digits[i] * weights[i];
}
return ( sum % MOD_11 ) % MOD_10;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ enum BuiltinConstraint {
ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_PL_NIP("org.hibernate.validator.constraints.pl.NIP"),
ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_PL_PESEL("org.hibernate.validator.constraints.pl.PESEL"),
ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_PL_REGON("org.hibernate.validator.constraints.pl.REGON"),
ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_RU_INN("org.hibernate.validator.constraints.ru.INN"),
ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_TIME_DURATION_MAX("org.hibernate.validator.constraints.time.DurationMax"),
ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_TIME_DURATION_MIN("org.hibernate.validator.constraints.time.DurationMin");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import static org.hibernate.validator.internal.metadata.core.BuiltinConstraint.ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_PL_PESEL;
import static org.hibernate.validator.internal.metadata.core.BuiltinConstraint.ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_PL_REGON;
import static org.hibernate.validator.internal.metadata.core.BuiltinConstraint.ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_RANGE;
import static org.hibernate.validator.internal.metadata.core.BuiltinConstraint.ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_RU_INN;
import static org.hibernate.validator.internal.metadata.core.BuiltinConstraint.ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_SCRIPT_ASSERT;
import static org.hibernate.validator.internal.metadata.core.BuiltinConstraint.ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_TIME_DURATION_MAX;
import static org.hibernate.validator.internal.metadata.core.BuiltinConstraint.ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_TIME_DURATION_MIN;
Expand Down Expand Up @@ -126,6 +127,7 @@
import org.hibernate.validator.constraints.pl.NIP;
import org.hibernate.validator.constraints.pl.PESEL;
import org.hibernate.validator.constraints.pl.REGON;
import org.hibernate.validator.constraints.ru.INN;
import org.hibernate.validator.constraints.time.DurationMax;
import org.hibernate.validator.constraints.time.DurationMin;
import org.hibernate.validator.internal.constraintvalidators.bv.AssertFalseValidator;
Expand Down Expand Up @@ -341,6 +343,7 @@
import org.hibernate.validator.internal.constraintvalidators.hv.pl.NIPValidator;
import org.hibernate.validator.internal.constraintvalidators.hv.pl.PESELValidator;
import org.hibernate.validator.internal.constraintvalidators.hv.pl.REGONValidator;
import org.hibernate.validator.internal.constraintvalidators.hv.ru.INNValidator;
import org.hibernate.validator.internal.constraintvalidators.hv.time.DurationMaxValidator;
import org.hibernate.validator.internal.constraintvalidators.hv.time.DurationMinValidator;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorDescriptor;
Expand Down Expand Up @@ -797,6 +800,9 @@ private ConstraintHelper(Set<BuiltinConstraint> enabledBuiltinConstraints) {
if ( enabledBuiltinConstraints.contains( ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_PL_REGON ) ) {
putBuiltinConstraint( tmpConstraints, REGON.class, REGONValidator.class );
}
if ( enabledBuiltinConstraints.contains( ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_RU_INN ) ) {
putBuiltinConstraint( tmpConstraints, INN.class, INNValidator.class );
}
if ( enabledBuiltinConstraints.contains( ORG_HIBERNATE_VALIDATOR_CONSTRAINTS_SCRIPT_ASSERT ) ) {
putBuiltinConstraint( tmpConstraints, ScriptAssert.class, ScriptAssertValidator.class );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,7 @@ org.hibernate.validator.constraints.pl.REGON.message = invalid Po
org.hibernate.validator.constraints.pl.NIP.message = invalid VAT Identification Number (NIP)
org.hibernate.validator.constraints.pl.PESEL.message = invalid Polish National Identification Number (PESEL)

org.hibernate.validator.constraints.ru.INN.message = invalid Russian taxpayer identification number (INN)

org.hibernate.validator.constraints.time.DurationMax.message = must be shorter than${inclusive == true ? ' or equal to' : ''}${days == 0 ? '' : days == 1 ? ' 1 day' : ' ' += days += ' days'}${hours == 0 ? '' : hours == 1 ? ' 1 hour' : ' ' += hours += ' hours'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minute' : ' ' += minutes += ' minutes'}${seconds == 0 ? '' : seconds == 1 ? ' 1 second' : ' ' += seconds += ' seconds'}${millis == 0 ? '' : millis == 1 ? ' 1 milli' : ' ' += millis += ' millis'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nano' : ' ' += nanos += ' nanos'}
org.hibernate.validator.constraints.time.DurationMin.message = must be longer than${inclusive == true ? ' or equal to' : ''}${days == 0 ? '' : days == 1 ? ' 1 day' : ' ' += days += ' days'}${hours == 0 ? '' : hours == 1 ? ' 1 hour' : ' ' += hours += ' hours'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minute' : ' ' += minutes += ' minutes'}${seconds == 0 ? '' : seconds == 1 ? ' 1 second' : ' ' += seconds += ' seconds'}${millis == 0 ? '' : millis == 1 ? ' 1 milli' : ' ' += millis += ' millis'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nano' : ' ' += nanos += ' nanos'}
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@ org.hibernate.validator.constraints.pl.REGON.message = neplatn\u0
org.hibernate.validator.constraints.pl.NIP.message = neplatn\u00e9 da\u0148ov\u00e9 identifika\u010dn\u00ed \u010d\u00edslo (NIP)
org.hibernate.validator.constraints.pl.PESEL.message = neplatn\u00e9 Polsk\u00e9 n\u00e1rodn\u00ed Identifika\u010dn\u00ed \u010d\u00edslo (PESEL)

org.hibernate.validator.constraints.ru.INN.message = neplatn\u00e9 ru\u0161tina Identifika\u010dn\u00ed \u010d\u00edslo pl\u00e1tn\u011b dan\u011b (INN)

org.hibernate.validator.constraints.time.DurationMax.message = mus\u00ed b\u00fdt krat\u0161\u00ed ne\u017e${inclusive == true ? ' nebo rovno hodnot\u011b' : ''}${days == 0 ? '' : days == 1 ? ' 1 den' : ' ' += days += ' dny/\u016f'}${hours == 0 ? '' : hours == 1 ? ' 1 hod' : ' ' += hours += ' hod'}${minutes == 0 ? '' : minutes == 1 ? ' 1 min' : ' ' += minutes += ' min'}${seconds == 0 ? '' : seconds == 1 ? ' 1 s' : ' ' += seconds += ' s'}${millis == 0 ? '' : millis == 1 ? ' 1 ms' : ' ' += millis += ' ms'}${nanos == 0 ? '' : nanos == 1 ? ' 1 ns' : ' ' += nanos += ' ns'}
org.hibernate.validator.constraints.time.DurationMin.message = mus\u00ed b\u00fdt del\u0161\u00ed ne\u017e${inclusive == true ? ' nebo rovno hodnot\u011b' : ''}${days == 0 ? '' : days == 1 ? ' 1 den' : ' ' += days += ' dny/\u016f'}${hours == 0 ? '' : hours == 1 ? ' 1 hod' : ' ' += hours += ' hod'}${minutes == 0 ? '' : minutes == 1 ? ' 1 min' : ' ' += minutes += ' min'}${seconds == 0 ? '' : seconds == 1 ? ' 1 s' : ' ' += seconds += ' s'}${millis == 0 ? '' : millis == 1 ? ' 1 ms' : ' ' += millis += ' ms'}${nanos == 0 ? '' : nanos == 1 ? ' 1 ns' : ' ' += nanos += ' ns'}
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@ org.hibernate.validator.constraints.pl.REGON.message = ugyldigt po
org.hibernate.validator.constraints.pl.NIP.message = ugyldigt momsidentifikationsnummer (NIP)
org.hibernate.validator.constraints.pl.PESEL.message = ugyldigt polsk nationalt identifikationsnummer (PESEL)

org.hibernate.validator.constraints.ru.INN.message = ugyldigt russisk skattebetalers identifikationsnummer (INN)

org.hibernate.validator.constraints.time.DurationMax.message = skal v\u00e6re kortere end${inclusive == true ? ' eller lig med' : ''}${days == 0 ? '' : days == 1 ? ' 1 dag' : ' ' += days += ' dage'}${hours == 0 ? '' : hours == 1 ? ' 1 time' : ' ' += hours += ' timer'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minut' : ' ' += minutes += ' minutter'}${seconds == 0 ? '' : seconds == 1 ? ' 1 sekund' : ' ' += seconds += ' sekunder'}${millis == 0 ? '' : millis == 1 ? ' 1 millisekund' : ' ' += millis += ' millisekunder'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nanosekund' : ' ' += nanos += ' nanosekunder'}
org.hibernate.validator.constraints.time.DurationMin.message = skal v\u00e6re l\u00e6ngere end${inclusive == true ? ' eller lig med' : ''}${days == 0 ? '' : days == 1 ? ' 1 dag' : ' ' += days += ' dage'}${hours == 0 ? '' : hours == 1 ? ' 1 time' : ' ' += hours += ' timer'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minut' : ' ' += minutes += ' minutter'}${seconds == 0 ? '' : seconds == 1 ? ' 1 sekund' : ' ' += seconds += ' sekunder'}${millis == 0 ? '' : millis == 1 ? ' 1 millisekund' : ' ' += millis += ' millisekunder'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nanosekund' : ' ' += nanos += ' nanosekunder'}
Loading

0 comments on commit d8c8faa

Please sign in to comment.