Skip to content

Commit 3b9bc51

Browse files
authored
Merge pull request #3 from aboutbits/ab-238-be-extract-value-objects-to-aboutbits-java-toolbox
add custom types
2 parents 4df098f + 20d1dfe commit 3b9bc51

11 files changed

Lines changed: 696 additions & 0 deletions

File tree

.idea/encodings.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pom.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,49 @@
33
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
44
<modelVersion>4.0.0</modelVersion>
55

6+
<parent>
7+
<groupId>org.springframework.boot</groupId>
8+
<artifactId>spring-boot-starter-parent</artifactId>
9+
<version>3.3.2</version>
10+
<relativePath/> <!-- lookup parent from repository -->
11+
</parent>
12+
613
<groupId>it.aboutbits</groupId>
714
<artifactId>spring-boot-toolbox</artifactId>
815
<version>BUILD-SNAPSHOT</version>
916
<description>Utility library for Spring Boot projects.</description>
17+
<packaging>jar</packaging>
1018

1119
<properties>
1220
<java.version>21</java.version>
1321
</properties>
1422

1523
<dependencies>
24+
<dependency>
25+
<groupId>org.springframework.boot</groupId>
26+
<artifactId>spring-boot-starter-validation</artifactId>
27+
</dependency>
28+
29+
<!-- Utilities -->
30+
<dependency>
31+
<groupId>org.projectlombok</groupId>
32+
<artifactId>lombok</artifactId>
33+
<optional>true</optional>
34+
</dependency>
35+
36+
<!-- Validation -->
37+
<!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
38+
<dependency>
39+
<groupId>commons-validator</groupId>
40+
<artifactId>commons-validator</artifactId>
41+
<version>1.9.0</version>
42+
</dependency>
1643

44+
<!-- Testing -->
45+
<dependency>
46+
<groupId>org.springframework.boot</groupId>
47+
<artifactId>spring-boot-starter-test</artifactId>
48+
</dependency>
1749
</dependencies>
1850

1951
<build>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package it.aboutbits.springboot.toolbox.type;
2+
3+
import it.aboutbits.springboot.toolbox.validation.util.EmailAddressValidator;
4+
import lombok.NonNull;
5+
6+
/**
7+
* A record representing an email address, validated and stored in lowercase.
8+
* <p>
9+
* The EmailAddress record ensures that the provided email address string
10+
* is in a valid format and automatically converts it to lowercase for
11+
* consistent internal representation. It implements the Comparable
12+
* interface to allow comparison between different email addresses.
13+
* </p>
14+
*
15+
* @param value the email address string
16+
* @throws IllegalArgumentException if the provided email address is not in a valid format
17+
*/
18+
public record EmailAddress(String value) implements Comparable<EmailAddress> {
19+
public EmailAddress(String value) {
20+
if (value == null || EmailAddressValidator.isNotValid(value)) {
21+
throw new IllegalArgumentException("Value is not a valid email address: " + value);
22+
}
23+
24+
this.value = value.toLowerCase();
25+
}
26+
27+
@NonNull
28+
@Override
29+
public String toString() {
30+
return value;
31+
}
32+
33+
@Override
34+
public int compareTo(@NonNull EmailAddress o) {
35+
return value().compareTo(o.value());
36+
}
37+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package it.aboutbits.springboot.toolbox.type;
2+
3+
import it.aboutbits.springboot.toolbox.validation.util.IbanValidator;
4+
import lombok.NonNull;
5+
6+
import java.util.Optional;
7+
8+
/**
9+
* The {@code Iban} class represents an International Bank Account Number (IBAN) and provides functionality for validation
10+
* and comparison of IBANs. It ensures the valid format of the IBAN according to predefined rules.
11+
*
12+
* @param value the IBAN value, which must be a valid and non-null string
13+
*/
14+
public record Iban(String value) implements Comparable<Iban> {
15+
public Iban(String value) {
16+
if (value == null || IbanValidator.isNotValid(value.toUpperCase())) {
17+
throw new IllegalArgumentException("Value is not a valid IBAN: " + value);
18+
}
19+
20+
this.value = value.toUpperCase();
21+
}
22+
23+
@NonNull
24+
@Override
25+
public String toString() {
26+
return value;
27+
}
28+
29+
/**
30+
* Retrieves the ABI (Bank Branch Code) if the IBAN belongs to an Italian bank.
31+
*
32+
* @return An {@code Optional} containing the ABI value if the IBAN is Italian, or an empty {@code Optional} otherwise.
33+
*/
34+
@NonNull
35+
public Optional<String> getAbiIfItalian() {
36+
var iban = value();
37+
38+
if (!iban.startsWith("IT")) {
39+
return Optional.empty();
40+
}
41+
return Optional.of(iban.substring(5, 10));
42+
}
43+
44+
@Override
45+
public int compareTo(@NonNull Iban o) {
46+
return value().compareTo(o.value());
47+
}
48+
}
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package it.aboutbits.springboot.toolbox.type;
2+
3+
import lombok.NonNull;
4+
5+
import java.math.BigDecimal;
6+
import java.math.BigInteger;
7+
import java.math.MathContext;
8+
import java.math.RoundingMode;
9+
10+
/**
11+
* A record that represents a scaled BigDecimal with a fixed MathContext.
12+
* This class provides various constructors for creating instances with different numerical types.
13+
* It also provides a set of arithmetic operations that return new instances with the appropriate scale and rounding.
14+
*/
15+
public record ScaledBigDecimal(
16+
@NonNull BigDecimal value
17+
) implements Comparable<ScaledBigDecimal> {
18+
private static final MathContext MATH_CONTEXT = new MathContext(15, RoundingMode.HALF_UP);
19+
20+
public static final ScaledBigDecimal ZERO = new ScaledBigDecimal(0);
21+
public static final ScaledBigDecimal ONE = new ScaledBigDecimal(1);
22+
public static final ScaledBigDecimal TWO = new ScaledBigDecimal(2);
23+
public static final ScaledBigDecimal TEN = new ScaledBigDecimal(10);
24+
25+
public ScaledBigDecimal(@NonNull BigDecimal value) {
26+
this.value = value.setScale(MATH_CONTEXT.getPrecision(), MATH_CONTEXT.getRoundingMode());
27+
}
28+
29+
public ScaledBigDecimal(int value) {
30+
this(new BigDecimal(value, MATH_CONTEXT));
31+
}
32+
33+
public ScaledBigDecimal(@NonNull Integer value) {
34+
this(new BigDecimal(value, MATH_CONTEXT));
35+
}
36+
37+
public ScaledBigDecimal(@NonNull BigInteger value) {
38+
this(new BigDecimal(value, MATH_CONTEXT));
39+
}
40+
41+
public ScaledBigDecimal(long value) {
42+
this(new BigDecimal(value, MATH_CONTEXT));
43+
}
44+
45+
public ScaledBigDecimal(@NonNull Long value) {
46+
this(new BigDecimal(value, MATH_CONTEXT));
47+
}
48+
49+
public ScaledBigDecimal(float value) {
50+
this(new BigDecimal(String.valueOf(value), MATH_CONTEXT));
51+
}
52+
53+
public ScaledBigDecimal(@NonNull Float value) {
54+
this(new BigDecimal(String.valueOf(value), MATH_CONTEXT));
55+
}
56+
57+
public ScaledBigDecimal(double value) {
58+
this(new BigDecimal(String.valueOf(value), MATH_CONTEXT));
59+
}
60+
61+
public ScaledBigDecimal(@NonNull Double value) {
62+
this(new BigDecimal(String.valueOf(value), MATH_CONTEXT));
63+
}
64+
65+
public ScaledBigDecimal(@NonNull String value) {
66+
this(new BigDecimal(value, MATH_CONTEXT));
67+
}
68+
69+
public static ScaledBigDecimal valueOf(int value) {
70+
return new ScaledBigDecimal(value);
71+
}
72+
73+
public static ScaledBigDecimal valueOf(@NonNull Integer value) {
74+
return new ScaledBigDecimal(value);
75+
}
76+
77+
public static ScaledBigDecimal valueOf(@NonNull BigInteger value) {
78+
return new ScaledBigDecimal(value);
79+
}
80+
81+
public static ScaledBigDecimal valueOf(long value) {
82+
return new ScaledBigDecimal(value);
83+
}
84+
85+
public static ScaledBigDecimal valueOf(@NonNull Long value) {
86+
return new ScaledBigDecimal(value);
87+
}
88+
89+
public static ScaledBigDecimal valueOf(float value) {
90+
return new ScaledBigDecimal(value);
91+
}
92+
93+
public static ScaledBigDecimal valueOf(@NonNull Float value) {
94+
return new ScaledBigDecimal(value);
95+
}
96+
97+
public static ScaledBigDecimal valueOf(double value) {
98+
return new ScaledBigDecimal(value);
99+
}
100+
101+
public static ScaledBigDecimal valueOf(@NonNull Double value) {
102+
return new ScaledBigDecimal(value);
103+
}
104+
105+
public static ScaledBigDecimal valueOf(@NonNull String value) {
106+
return new ScaledBigDecimal(value);
107+
}
108+
109+
@NonNull
110+
public ScaledBigDecimal add(@NonNull ScaledBigDecimal other) {
111+
return new ScaledBigDecimal(this.value().add(other.value()));
112+
}
113+
114+
@NonNull
115+
public ScaledBigDecimal subtract(@NonNull ScaledBigDecimal other) {
116+
return new ScaledBigDecimal(this.value().subtract(other.value()));
117+
}
118+
119+
@NonNull
120+
public ScaledBigDecimal multiply(@NonNull ScaledBigDecimal other) {
121+
return new ScaledBigDecimal(this.value().multiply(other.value()));
122+
}
123+
124+
@NonNull
125+
public ScaledBigDecimal divide(@NonNull ScaledBigDecimal other) {
126+
return new ScaledBigDecimal(this.value().divide(other.value(), MATH_CONTEXT));
127+
}
128+
129+
@NonNull
130+
public ScaledBigDecimal add(@NonNull BigDecimal other) {
131+
return new ScaledBigDecimal(this.value().add(other));
132+
}
133+
134+
@NonNull
135+
public ScaledBigDecimal subtract(@NonNull BigDecimal other) {
136+
return new ScaledBigDecimal(this.value().subtract(other));
137+
}
138+
139+
@NonNull
140+
public ScaledBigDecimal multiply(@NonNull BigDecimal other) {
141+
return new ScaledBigDecimal(this.value().multiply(other));
142+
}
143+
144+
@NonNull
145+
public ScaledBigDecimal divide(@NonNull BigDecimal other) {
146+
return new ScaledBigDecimal(this.value().divide(other, MATH_CONTEXT));
147+
}
148+
149+
@NonNull
150+
public ScaledBigDecimal remainder(@NonNull ScaledBigDecimal divisor) {
151+
return new ScaledBigDecimal(this.value().remainder(divisor.value(), MATH_CONTEXT));
152+
}
153+
154+
@NonNull
155+
public ScaledBigDecimal remainder(@NonNull BigDecimal divisor) {
156+
return new ScaledBigDecimal(this.value().remainder(divisor, MATH_CONTEXT));
157+
}
158+
159+
@NonNull
160+
public ScaledBigDecimal sqrt() {
161+
return new ScaledBigDecimal(this.value().sqrt(MATH_CONTEXT));
162+
}
163+
164+
@NonNull
165+
public ScaledBigDecimal pow(int n) {
166+
return new ScaledBigDecimal(this.value().pow(n, MATH_CONTEXT));
167+
}
168+
169+
@NonNull
170+
public ScaledBigDecimal abs() {
171+
return new ScaledBigDecimal(this.value().abs(MATH_CONTEXT));
172+
}
173+
174+
@NonNull
175+
public ScaledBigDecimal negate() {
176+
return new ScaledBigDecimal(this.value().negate(MATH_CONTEXT));
177+
}
178+
179+
@NonNull
180+
public ScaledBigDecimal min(@NonNull ScaledBigDecimal val) {
181+
return new ScaledBigDecimal(this.value().min(val.value()));
182+
}
183+
184+
@NonNull
185+
public ScaledBigDecimal min(@NonNull BigDecimal val) {
186+
return new ScaledBigDecimal(this.value().min(val));
187+
}
188+
189+
@NonNull
190+
public ScaledBigDecimal max(@NonNull ScaledBigDecimal val) {
191+
return new ScaledBigDecimal(this.value().max(val.value()));
192+
}
193+
194+
@NonNull
195+
public ScaledBigDecimal max(@NonNull BigDecimal val) {
196+
return new ScaledBigDecimal(this.value().max(val));
197+
}
198+
199+
@NonNull
200+
public BigDecimal toBigDecimal(int scale) {
201+
return this.value().setScale(scale, RoundingMode.HALF_UP);
202+
}
203+
204+
@NonNull
205+
public ScaledBigDecimal roundToScale(int scale) {
206+
return new ScaledBigDecimal(this.value().setScale(scale, RoundingMode.HALF_UP));
207+
}
208+
209+
@Override
210+
public boolean equals(Object o) {
211+
if (this == o) {
212+
return true;
213+
}
214+
215+
if (o instanceof ScaledBigDecimal other) {
216+
return this.value().compareTo(other.value()) == 0;
217+
}
218+
219+
return false;
220+
}
221+
222+
@Override
223+
public int hashCode() {
224+
return value().hashCode();
225+
}
226+
227+
@Override
228+
public int compareTo(@NonNull ScaledBigDecimal o) {
229+
return this.value().compareTo(o.value());
230+
}
231+
}

0 commit comments

Comments
 (0)