Skip to content

Commit

Permalink
HV-591 Treating local and domain part separately
Browse files Browse the repository at this point in the history
  • Loading branch information
hferentschik authored and gunnarmorling committed May 22, 2012
1 parent 461d681 commit 6e0a599
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 11 deletions.
Expand Up @@ -2,11 +2,14 @@

import java.net.IDN;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.hibernate.validator.constraints.Email;

import static java.util.regex.Pattern.CASE_INSENSITIVE;

/**
* Checks that a given character sequence (e.g. string) is a well-formed email address.
* <p>
Expand All @@ -23,16 +26,21 @@
*/
public class EmailValidator implements ConstraintValidator<Email, CharSequence> {
private static String ATOM = "[a-z0-9!#$%&'*+/=?^_`{|}~-]";
private static String DOMAIN = "(" + ATOM + "+(\\." + ATOM + "+)*";
private static String DOMAIN = ATOM + "+(\\." + ATOM + "+)*";
private static String IP_DOMAIN = "\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\]";

private java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(
"^" + ATOM + "+(\\." + ATOM + "+)*@"
+ DOMAIN
+ "|"
+ IP_DOMAIN
+ ")$",
java.util.regex.Pattern.CASE_INSENSITIVE
/**
* Regular expression for the local part of an email address (everything before '@')
*/
private Pattern localPattern = java.util.regex.Pattern.compile(
ATOM + "+(\\." + ATOM + "+)*", CASE_INSENSITIVE
);

/**
* Regular expression for the domain part of an email address (everything after '@')
*/
private Pattern domainPattern = java.util.regex.Pattern.compile(
DOMAIN + "|" + IP_DOMAIN, CASE_INSENSITIVE
);

public void initialize(Email annotation) {
Expand All @@ -42,8 +50,37 @@ public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
if ( value == null || value.length() == 0 ) {
return true;
}
String asciiString = IDN.toASCII( value.toString() );
Matcher m = pattern.matcher( asciiString );
return m.matches();

// split email at '@' and consider local and domain part separately
String[] emailParts = value.toString().split( "@" );
if ( emailParts.length != 2 ) {
return false;
}

// if we have a trailing dot in local or domain part we have an invalid email address.
// the regular expression match would take care of this, but IDN.toASCII drops trailing the trailing '.'
// (imo a bug in the implementation)
if ( emailParts[0].endsWith( "." ) || emailParts[1].endsWith( "." ) ) {
return false;
}

if ( !matchPart( emailParts[0], localPattern ) ) {
return false;
}

return matchPart( emailParts[1], domainPattern );
}

private boolean matchPart(String part, Pattern pattern) {
try {
part = IDN.toASCII( part );
}
catch ( IllegalArgumentException e ) {
// occurs when the label is too long (>63, even though it should probably be 64 - see http://www.rfc-editor.org/errata_search.php?rfc=3696,
// practically that should not be a problem)
return false;
}
Matcher matcher = pattern.matcher( part );
return matcher.matches();
}
}
Expand Up @@ -147,6 +147,12 @@ public void testEmailRegExp() {
assertOrgAddressesAreNotValid( violations );
}

@Test
@TestForIssue(jiraKey = "HV-591")
public void testEmailAddressLength() {
isValidEmail( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@hibernate.org" );
}

private void assertOrgAddressesAreNotValid(Set<ConstraintViolation<EmailContainer>> violations) {
assertNumberOfViolations( violations, 1 );
assertCorrectConstraintViolationMessages( violations, "ORG addresses are not valid" );
Expand All @@ -168,6 +174,7 @@ private void isInvalidEmail(CharSequence email) {
isInvalidEmail( email, "Expected a invalid email." );
}

@SuppressWarnings("unused")
private static abstract class EmailContainer {
public String email;

Expand Down

0 comments on commit 6e0a599

Please sign in to comment.