forked from hibernate/hibernate-validator
-
Notifications
You must be signed in to change notification settings - Fork 1
/
ISBNValidator.java
89 lines (75 loc) · 2.54 KB
/
ISBNValidator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
* 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;
import java.util.function.Function;
import java.util.regex.Pattern;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.hibernate.validator.constraints.ISBN;
/**
* Checks that a given character sequence (e.g. string) is a valid ISBN.
*
* @author Marko Bekhta
*/
public class ISBNValidator implements ConstraintValidator<ISBN, CharSequence> {
/**
* Pattern to replace all non ISBN characters. ISBN can have digits or 'X'.
*/
private static Pattern NOT_DIGITS_OR_NOT_X = Pattern.compile( "[^\\dX]" );
private int length;
private Function<String, Boolean> checkChecksumFunction;
@Override
public void initialize(ISBN constraintAnnotation) {
switch ( constraintAnnotation.type() ) {
case ISBN10:
length = 10;
checkChecksumFunction = this::checkChecksumISBN10;
break;
case ISBN13:
length = 13;
checkChecksumFunction = this::checkChecksumISBN13;
break;
}
}
@Override
public boolean isValid(CharSequence isbn, ConstraintValidatorContext context) {
if ( isbn == null ) {
return true;
}
// Replace all non-digit (or !=X) chars
String digits = NOT_DIGITS_OR_NOT_X.matcher( isbn ).replaceAll( "" );
// Check if the length of resulting string matches the expecting one
if ( digits.length() != length ) {
return false;
}
return checkChecksumFunction.apply( digits );
}
/**
* Check the digits for ISBN 10 using algorithm from
* <a href="https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digits">Wikipedia</a>.
*/
private boolean checkChecksumISBN10(String isbn) {
int sum = 0;
for ( int i = 0; i < isbn.length() - 1; i++ ) {
sum += ( isbn.charAt( i ) - '0' ) * ( i + 1 );
}
char checkSum = isbn.charAt( 9 );
return sum % 11 == ( checkSum == 'X' ? 10 : checkSum - '0' );
}
/**
* Check the digits for ISBN 13 using algorithm from
* <a href="https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-13_check_digit_calculation">Wikipedia</a>.
*/
private boolean checkChecksumISBN13(String isbn) {
int sum = 0;
for ( int i = 0; i < isbn.length() - 1; i++ ) {
sum += ( isbn.charAt( i ) - '0' ) * ( i % 2 == 0 ? 1 : 3 );
}
char checkSum = isbn.charAt( 12 );
return 10 - sum % 10 == ( checkSum - '0' );
}
}