All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.validator.internal.constraintvalidators.hv.pl.PESELValidator Maven / Gradle / Ivy

There is a newer version: 8.0.1.Final
Show newest version
/*
 * Hibernate Validator, declare and validate application constraints
 *
 * License: Apache License, Version 2.0
 * See the license.txt file in the root directory or .
 */
package org.hibernate.validator.internal.constraintvalidators.hv.pl;

import java.time.DateTimeException;
import java.time.LocalDate;
import java.util.Collections;
import java.util.List;

import jakarta.validation.ConstraintValidator;

import org.hibernate.validator.constraints.pl.PESEL;
import org.hibernate.validator.internal.constraintvalidators.hv.ModCheckBase;
import org.hibernate.validator.internal.util.ModUtil;

/**
 * Validator for {@link PESEL}.
 *
 * @author Marko Bekhta
 */
public class PESELValidator extends ModCheckBase implements ConstraintValidator {

	private static final int[] WEIGHTS_PESEL = { 1, 3, 7, 9, 1, 3, 7, 9, 1, 3 };

	@Override
	public void initialize(PESEL constraintAnnotation) {
		super.initialize(
				0,
				Integer.MAX_VALUE,
				-1,
				false
		);
	}

	@Override
	public boolean isCheckDigitValid(List digits, char checkDigit) {
		// if the length of the number is incorrect we can return fast
		if ( digits.size() != WEIGHTS_PESEL.length ) {
			return false;
		}

		int monthCode = doubleDigitNumberFromSubList( digits, 2 );
		try {
			// PESEL format is YYMMDD*****, where MM is coded month (depending on the century
			// 0/20/40/60/80 can be added to the month value) see javadoc on `year()`.
			// Need to make sure that these first 6 digits represent a valid date
			LocalDate.of(
					year( doubleDigitNumberFromSubList( digits, 0 ), monthCode / 20 ),
					monthCode % 20,
					doubleDigitNumberFromSubList( digits, 4 )
			);
		}
		catch (DateTimeException e) {
			return false;
		}

		// now that we are done with custom logic we can proceeed with regular mod check of the checkdigit:
		Collections.reverse( digits );

		int modResult = ModUtil.calculateModXCheckWithWeights( digits, 10, Integer.MAX_VALUE, WEIGHTS_PESEL );
		switch ( modResult ) {
			case 10:
				return checkDigit == '0';
			default:
				return Character.isDigit( checkDigit ) && modResult == extractDigit( checkDigit );
		}
	}

	private int doubleDigitNumberFromSubList(List digits, int start) {
		// index access is ok here as we use ArrayLists.
		return digits.get( start ) * 10 + digits.get( start + 1 );
	}

	/**
	 * 1800–1899 - 80
	 * 1900–1999 - 00
	 * 2000–2099 - 20
	 * 2100–2199 - 40
	 * 2200–2299 - 60
	 */
	private int year(int year, int centuryCode) {
		switch ( centuryCode ) {
			case 4: return 1800 + year;
			case 0: return 1900 + year;
			case 1: return 2000 + year;
			case 2: return 2100 + year;
			case 3: return 2200 + year;
			default:
				throw new IllegalStateException( "Invalid century code." );
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy