Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,49 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<groupId>it.aboutbits</groupId>
<artifactId>spring-boot-toolbox</artifactId>
<version>BUILD-SNAPSHOT</version>
<description>Utility library for Spring Boot projects.</description>
<packaging>jar</packaging>

<properties>
<java.version>21</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<!-- Utilities -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<!-- Validation -->
<!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.9.0</version>
</dependency>

<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package it.aboutbits.springboot.toolbox.type;

import it.aboutbits.springboot.toolbox.validation.util.EmailAddressValidator;
import lombok.NonNull;

/**
* A record representing an email address, validated and stored in lowercase.
* <p>
* The EmailAddress record ensures that the provided email address string
* is in a valid format and automatically converts it to lowercase for
* consistent internal representation. It implements the Comparable
* interface to allow comparison between different email addresses.
* </p>
*
* @param value the email address string
* @throws IllegalArgumentException if the provided email address is not in a valid format
*/
public record EmailAddress(String value) implements Comparable<EmailAddress> {
public EmailAddress(String value) {
if (value == null || EmailAddressValidator.isNotValid(value)) {
throw new IllegalArgumentException("Value is not a valid email address: " + value);
}

this.value = value.toLowerCase();
}

@NonNull
@Override
public String toString() {
return value;
}

@Override
public int compareTo(@NonNull EmailAddress o) {
return value().compareTo(o.value());
}
}
48 changes: 48 additions & 0 deletions src/main/java/it/aboutbits/springboot/toolbox/type/Iban.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package it.aboutbits.springboot.toolbox.type;

import it.aboutbits.springboot.toolbox.validation.util.IbanValidator;
import lombok.NonNull;

import java.util.Optional;

/**
* The {@code Iban} class represents an International Bank Account Number (IBAN) and provides functionality for validation
* and comparison of IBANs. It ensures the valid format of the IBAN according to predefined rules.
*
* @param value the IBAN value, which must be a valid and non-null string
*/
public record Iban(String value) implements Comparable<Iban> {
public Iban(String value) {
if (value == null || IbanValidator.isNotValid(value.toUpperCase())) {
throw new IllegalArgumentException("Value is not a valid IBAN: " + value);
}

this.value = value.toUpperCase();
}

@NonNull
@Override
public String toString() {
return value;
}

/**
* Retrieves the ABI (Bank Branch Code) if the IBAN belongs to an Italian bank.
*
* @return An {@code Optional} containing the ABI value if the IBAN is Italian, or an empty {@code Optional} otherwise.
*/
@NonNull
public Optional<String> getAbiIfItalian() {
var iban = value();

if (!iban.startsWith("IT")) {
return Optional.empty();
}
return Optional.of(iban.substring(5, 10));
}

@Override
public int compareTo(@NonNull Iban o) {
return value().compareTo(o.value());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
package it.aboutbits.springboot.toolbox.type;

import lombok.NonNull;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;

/**
* A record that represents a scaled BigDecimal with a fixed MathContext.
* This class provides various constructors for creating instances with different numerical types.
* It also provides a set of arithmetic operations that return new instances with the appropriate scale and rounding.
*/
public record ScaledBigDecimal(
@NonNull BigDecimal value
) implements Comparable<ScaledBigDecimal> {
private static final MathContext MATH_CONTEXT = new MathContext(15, RoundingMode.HALF_UP);

public static final ScaledBigDecimal ZERO = new ScaledBigDecimal(0);
public static final ScaledBigDecimal ONE = new ScaledBigDecimal(1);
public static final ScaledBigDecimal TWO = new ScaledBigDecimal(2);
public static final ScaledBigDecimal TEN = new ScaledBigDecimal(10);

public ScaledBigDecimal(@NonNull BigDecimal value) {
this.value = value.setScale(MATH_CONTEXT.getPrecision(), MATH_CONTEXT.getRoundingMode());
}

public ScaledBigDecimal(int value) {
this(new BigDecimal(value, MATH_CONTEXT));
}

public ScaledBigDecimal(@NonNull Integer value) {
this(new BigDecimal(value, MATH_CONTEXT));
}

public ScaledBigDecimal(@NonNull BigInteger value) {
this(new BigDecimal(value, MATH_CONTEXT));
}

public ScaledBigDecimal(long value) {
this(new BigDecimal(value, MATH_CONTEXT));
}

public ScaledBigDecimal(@NonNull Long value) {
this(new BigDecimal(value, MATH_CONTEXT));
}

public ScaledBigDecimal(float value) {
this(new BigDecimal(String.valueOf(value), MATH_CONTEXT));
}

public ScaledBigDecimal(@NonNull Float value) {
this(new BigDecimal(String.valueOf(value), MATH_CONTEXT));
}

public ScaledBigDecimal(double value) {
this(new BigDecimal(String.valueOf(value), MATH_CONTEXT));
}

public ScaledBigDecimal(@NonNull Double value) {
this(new BigDecimal(String.valueOf(value), MATH_CONTEXT));
}

public ScaledBigDecimal(@NonNull String value) {
this(new BigDecimal(value, MATH_CONTEXT));
}

public static ScaledBigDecimal valueOf(int value) {
return new ScaledBigDecimal(value);
}

public static ScaledBigDecimal valueOf(@NonNull Integer value) {
return new ScaledBigDecimal(value);
}

public static ScaledBigDecimal valueOf(@NonNull BigInteger value) {
return new ScaledBigDecimal(value);
}

public static ScaledBigDecimal valueOf(long value) {
return new ScaledBigDecimal(value);
}

public static ScaledBigDecimal valueOf(@NonNull Long value) {
return new ScaledBigDecimal(value);
}

public static ScaledBigDecimal valueOf(float value) {
return new ScaledBigDecimal(value);
}

public static ScaledBigDecimal valueOf(@NonNull Float value) {
return new ScaledBigDecimal(value);
}

public static ScaledBigDecimal valueOf(double value) {
return new ScaledBigDecimal(value);
}

public static ScaledBigDecimal valueOf(@NonNull Double value) {
return new ScaledBigDecimal(value);
}

public static ScaledBigDecimal valueOf(@NonNull String value) {
return new ScaledBigDecimal(value);
}

@NonNull
public ScaledBigDecimal add(@NonNull ScaledBigDecimal other) {
return new ScaledBigDecimal(this.value().add(other.value()));
}

@NonNull
public ScaledBigDecimal subtract(@NonNull ScaledBigDecimal other) {
return new ScaledBigDecimal(this.value().subtract(other.value()));
}

@NonNull
public ScaledBigDecimal multiply(@NonNull ScaledBigDecimal other) {
return new ScaledBigDecimal(this.value().multiply(other.value()));
}

@NonNull
public ScaledBigDecimal divide(@NonNull ScaledBigDecimal other) {
return new ScaledBigDecimal(this.value().divide(other.value(), MATH_CONTEXT));
}

@NonNull
public ScaledBigDecimal add(@NonNull BigDecimal other) {
return new ScaledBigDecimal(this.value().add(other));
}

@NonNull
public ScaledBigDecimal subtract(@NonNull BigDecimal other) {
return new ScaledBigDecimal(this.value().subtract(other));
}

@NonNull
public ScaledBigDecimal multiply(@NonNull BigDecimal other) {
return new ScaledBigDecimal(this.value().multiply(other));
}

@NonNull
public ScaledBigDecimal divide(@NonNull BigDecimal other) {
return new ScaledBigDecimal(this.value().divide(other, MATH_CONTEXT));
}

@NonNull
public ScaledBigDecimal remainder(@NonNull ScaledBigDecimal divisor) {
return new ScaledBigDecimal(this.value().remainder(divisor.value(), MATH_CONTEXT));
}

@NonNull
public ScaledBigDecimal remainder(@NonNull BigDecimal divisor) {
return new ScaledBigDecimal(this.value().remainder(divisor, MATH_CONTEXT));
}

@NonNull
public ScaledBigDecimal sqrt() {
return new ScaledBigDecimal(this.value().sqrt(MATH_CONTEXT));
}

@NonNull
public ScaledBigDecimal pow(int n) {
return new ScaledBigDecimal(this.value().pow(n, MATH_CONTEXT));
}

@NonNull
public ScaledBigDecimal abs() {
return new ScaledBigDecimal(this.value().abs(MATH_CONTEXT));
}

@NonNull
public ScaledBigDecimal negate() {
return new ScaledBigDecimal(this.value().negate(MATH_CONTEXT));
}

@NonNull
public ScaledBigDecimal min(@NonNull ScaledBigDecimal val) {
return new ScaledBigDecimal(this.value().min(val.value()));
}

@NonNull
public ScaledBigDecimal min(@NonNull BigDecimal val) {
return new ScaledBigDecimal(this.value().min(val));
}

@NonNull
public ScaledBigDecimal max(@NonNull ScaledBigDecimal val) {
return new ScaledBigDecimal(this.value().max(val.value()));
}

@NonNull
public ScaledBigDecimal max(@NonNull BigDecimal val) {
return new ScaledBigDecimal(this.value().max(val));
}

@NonNull
public BigDecimal toBigDecimal(int scale) {
return this.value().setScale(scale, RoundingMode.HALF_UP);
}

@NonNull
public ScaledBigDecimal roundToScale(int scale) {
return new ScaledBigDecimal(this.value().setScale(scale, RoundingMode.HALF_UP));
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}

if (o instanceof ScaledBigDecimal other) {
return this.value().compareTo(other.value()) == 0;
}

return false;
}

@Override
public int hashCode() {
return value().hashCode();
}

@Override
public int compareTo(@NonNull ScaledBigDecimal o) {
return this.value().compareTo(o.value());
}
}
Loading