Skip to content

Commit

Permalink
adding option to define a regular expression to match on @Validate
Browse files Browse the repository at this point in the history
  • Loading branch information
jbax committed Aug 2, 2018
1 parent 6746adc commit ae3bc18
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 13 deletions.
6 changes: 6 additions & 0 deletions src/main/java/com/univocity/parsers/annotations/Validate.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@
*/
boolean allowBlanks() default false;

/**
* Ensures that the value of this field matches a given regular expression.
* @return the regular expression that determines an expected format for the given value
*/
String matches() default "";

/**
* Ensures that the value of this field is one of a given set of alternatives
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,9 @@ private static Conversion getConversion(Class fieldType, AnnotatedElement target
boolean allowBlanks = AnnotationRegistry.getValue(target, validate, "allowBlanks", validate.allowBlanks());
String[] oneOf = AnnotationRegistry.getValue(target, validate, "oneOf", validate.oneOf());
String[] noneOf = AnnotationRegistry.getValue(target, validate, "noneOf", validate.noneOf());
String matches = AnnotationRegistry.getValue(target, validate, "matches", validate.matches());

return Conversions.validate(nullable, allowBlanks, oneOf, noneOf);
return Conversions.validate(nullable, allowBlanks, oneOf, noneOf, matches);
} else if (annType == EnumOptions.class) {
if (!fieldType.isEnum()) {
if (target == null) {
Expand Down
48 changes: 44 additions & 4 deletions src/main/java/com/univocity/parsers/conversions/Conversions.java
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,18 @@ public static ValidatedConversion notBlank() {
return validate(false, false, null, null);
}

/**
* Returns a {@link ValidatedConversion} that verifies the format of a given value
*
* @param regexToMatch regular expression to match and ensure the value has a given format
*
* @return a value format validator
*/
public static ValidatedConversion notBlank(String regexToMatch) {
return validate(false, false, null, null, regexToMatch);
}


/**
* Returns a {@link ValidatedConversion} that checks for nulls or blank values.
*
Expand All @@ -616,7 +628,7 @@ public static ValidatedConversion notBlank() {
* @return new instance of {@link ValidatedConversion} configured with the given parameters
*/
public static ValidatedConversion validate(boolean nullable, boolean allowBlanks) {
return new ValidatedConversion(nullable, allowBlanks, null, null);
return new ValidatedConversion(nullable, allowBlanks, null, null, null);
}

/**
Expand All @@ -630,7 +642,35 @@ public static ValidatedConversion validate(boolean nullable, boolean allowBlanks
* @return new instance of {@link ValidatedConversion} configured with the given parameters
*/
public static ValidatedConversion validate(boolean nullable, boolean allowBlanks, String[] oneOf, String[] noneOf) {
return new ValidatedConversion(nullable, allowBlanks, oneOf, noneOf);
return new ValidatedConversion(nullable, allowBlanks, oneOf, noneOf, null);
}

/**
* Returns a {@link ValidatedConversion} that checks for nulls or blank values.
*
* @param nullable flag to indicate whether values can be null
* @param allowBlanks flag to indicate whether values can be blank
* @param regexToMatch regular expression to match and ensure the value has a given format
*
* @return new instance of {@link ValidatedConversion} configured with the given parameters
*/
public static ValidatedConversion validate(boolean nullable, boolean allowBlanks, String regexToMatch) {
return new ValidatedConversion(nullable, allowBlanks, null, null, regexToMatch);
}

/**
* Returns a new instance of {@link ValidatedConversion} to validate values of a record
*
* @param nullable flag to indicate whether values can be null
* @param allowBlanks flag to indicate whether values can be blank
* @param oneOf list of accepted values.
* @param noneOf list of unacceptable values
* @param regexToMatch regular expression to match and ensure the value has a given format
*
* @return new instance of {@link ValidatedConversion} configured with the given parameters
*/
public static ValidatedConversion validate(boolean nullable, boolean allowBlanks, String[] oneOf, String[] noneOf, String regexToMatch) {
return new ValidatedConversion(nullable, allowBlanks, oneOf, noneOf, regexToMatch);
}

/**
Expand All @@ -643,7 +683,7 @@ public static ValidatedConversion validate(boolean nullable, boolean allowBlanks
* @return new instance of {@link ValidatedConversion} configured with the given parameters
*/
public static ValidatedConversion oneOf(String... oneOf) {
return new ValidatedConversion(false, false, oneOf, null);
return new ValidatedConversion(false, false, oneOf, null, null);
}


Expand All @@ -657,6 +697,6 @@ public static ValidatedConversion oneOf(String... oneOf) {
* @return new instance of {@link ValidatedConversion} configured with the given parameters
*/
public static ValidatedConversion noneOf(String... noneOf) {
return new ValidatedConversion(false, false, null, noneOf);
return new ValidatedConversion(false, false, null, noneOf, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,32 @@
import com.univocity.parsers.common.*;

import java.util.*;
import java.util.regex.*;

/**
* Performs one or more validations against the values of a given record.
*/
public class ValidatedConversion implements Conversion<Object, Object> {

private final String regexToMatch;
private final boolean nullable;
private final boolean allowBlanks;
private final Set<String> oneOf;
private final Set<String> noneOf;
private final Matcher matcher;

public ValidatedConversion(String regexToMatch) {
this(false, false, null, null, regexToMatch);
}

public ValidatedConversion(boolean nullable, boolean allowBlanks) {
this(nullable, allowBlanks, null, null);
this(nullable, allowBlanks, null, null, null);
}


public ValidatedConversion(boolean nullable, boolean allowBlanks, String[] oneOf, String[] noneOf) {
public ValidatedConversion(boolean nullable, boolean allowBlanks, String[] oneOf, String[] noneOf, String regexToMatch) {
this.regexToMatch = regexToMatch;
this.matcher = regexToMatch == null || regexToMatch.isEmpty() ? null : Pattern.compile(regexToMatch).matcher("");
this.nullable = nullable;
this.allowBlanks = allowBlanks;
this.oneOf = oneOf == null || oneOf.length == 0 ? null : new HashSet<String>(Arrays.asList(oneOf));
Expand Down Expand Up @@ -88,6 +97,16 @@ private void validate(Object value) {
}
}
}

if (matcher != null && e == null) {
boolean match;
synchronized (matcher) {
match = matcher.reset(str).matches();
}
if (!match) {
e = new DataValidationException("Value '{value}' does not match expected pattern: '" + regexToMatch + "'");
}
}
}

if (oneOf != null && !oneOf.contains(str)) {
Expand Down
18 changes: 12 additions & 6 deletions src/test/java/com/univocity/parsers/issues/github/Github_251.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public static class A {
@Parsed(index = 3)
@Validate(nullable = true, oneOf = {"a", "b"})
public String aOrBOrNull;

@Parsed(index = 4)
@Validate(allowBlanks = true, matches = "^[^\\d\\s]+$") //yet regex disallows whitespace
public String noDigits;
}

@Test
Expand All @@ -73,14 +77,16 @@ public void handleError(DataProcessingException error, Object[] inputRow, Parsin
CsvParser p = new CsvParser(s);

p.parse(new StringReader("" +
",a,a,\" \",\n" +
"\" \",c,b,"));
",a,a,\" \",3z\n" +
"\" \",c,b,,a b"));

assertEquals(errorDetails.size(), 4);
assertEquals(errorDetails.size(), 6);
assertEquals(errorDetails.get(0), new Object[]{1L, 3, " "});
assertEquals(errorDetails.get(1), new Object[]{2L, 0, " "});
assertEquals(errorDetails.get(2), new Object[]{2L, 1, "c"});
assertEquals(errorDetails.get(3), new Object[]{2L, 2, "b"});
assertEquals(errorDetails.get(1), new Object[]{1L, 4, "3z"});
assertEquals(errorDetails.get(2), new Object[]{2L, 0, " "});
assertEquals(errorDetails.get(3), new Object[]{2L, 1, "c"});
assertEquals(errorDetails.get(4), new Object[]{2L, 2, "b"});
assertEquals(errorDetails.get(5), new Object[]{2L, 4, "a b"});

List<A> beans = processor.getBeans();
assertEquals(beans.size(), 2);
Expand Down

0 comments on commit ae3bc18

Please sign in to comment.