Last active
June 16, 2024 20:28
-
-
Save dami-i/08b25f6990672f4eb22d505e99444424 to your computer and use it in GitHub Desktop.
CPF Value Object
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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