Skip to content

Instantly share code, notes, and snippets.

@dami-i
Last active June 16, 2024 20:28
Show Gist options
  • Save dami-i/08b25f6990672f4eb22d505e99444424 to your computer and use it in GitHub Desktop.
Save dami-i/08b25f6990672f4eb22d505e99444424 to your computer and use it in GitHub Desktop.
CPF Value Object
import java.util.stream.IntStream;
public class CPF {
private final String root;
private final String checksum;
private final int regionCode;
private final Region region;
public CPF(String baseValue) {
String numericCharacters = stripNonNumericCharacters(baseValue);
validateInput(numericCharacters);
String rootCandidate = numericCharacters.substring(0, 9);
String checksumCandidate = numericCharacters.substring(9);
validateChecksum(rootCandidate, checksumCandidate);
root = rootCandidate;
checksum = checksumCandidate;
regionCode = Integer.parseUnsignedInt(String.valueOf(numericCharacters.charAt(8)));
region = Region.fromCode(regionCode);
}
private String stripNonNumericCharacters(String value) {
return value.trim().replaceAll("\\D", "");
}
private void validateInput(String value) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException("CPF deve ser informado");
}
if (!value.matches("\\d{11}")) {
throw new IllegalArgumentException("CPF deve conter 11 dígitos numéricos");
}
// Se o CPF informado for uma repetição de um mesmo algarismo (ex.: "11111111111"), será considerado inválido
if (value.equals(String.valueOf(value.charAt(0)).repeat(11))) {
throw new IllegalArgumentException("CPF inválido");
}
}
private void validateChecksum(String root, String checksum) {
if (!checksum.equals(getChecksumFor(root))) {
throw new IllegalArgumentException("CPF inválido");
}
}
private String getChecksumFor(String root) {
StringBuilder resultChecksum = new StringBuilder();
StringBuilder tempRoot = new StringBuilder(root);
int firstSum = IntStream.range(0, 9)
.map(i -> Character.getNumericValue(tempRoot.toString().charAt(i)) * (i + 1))
.sum();
int firstDigit = (firstSum % 11) % 10;
resultChecksum.append(firstDigit);
tempRoot.append(firstDigit);
int secondSum = IntStream.range(0, 10)
.map(i -> Character.getNumericValue(tempRoot.toString().charAt(i)) * i)
.sum();
int secondDigit = (secondSum % 11) % 10;
resultChecksum.append(secondDigit);
return resultChecksum.toString();
}
@Override
public String toString() {
return root.substring(0, 3) + '.'
+ root.substring(3, 6) + '.'
+ root.substring(6, 9)
+ '-' + checksum.substring(0, 2);
}
}
public enum Region {
RS(0),
DF_GO_MS_MT_TO(1),
AC_AM_AP_PA_RO_RR(2),
CE_MA_PI(3),
AL_PB_PE_RN(4),
BA_SE(5),
MG(6),
ES_RJ(7),
SP(8),
PR_SC(9);
private final int code;
Region(int code) {
this.code = code;
}
public static Region fromCode(int code) {
for (Region region : values()) {
if (region.code == code) {
return region;
}
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment