Merge branch 'eugenp:master' into master
This commit is contained in:
commit
2d18d5a529
@ -31,15 +31,21 @@
|
|||||||
<version>${jackson-databind.version}</version>
|
<version>${jackson-databind.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate.orm</groupId>
|
||||||
<artifactId>hibernate-core</artifactId>
|
<artifactId>hibernate-core</artifactId>
|
||||||
<version>${hibernate.version}</version>
|
<version>${hibernate.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate.orm</groupId>
|
||||||
<artifactId>hibernate-hikaricp</artifactId>
|
<artifactId>hibernate-hikaricp</artifactId>
|
||||||
<version>${hibernate.version}</version>
|
<version>${hibernate.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.zaxxer</groupId>
|
||||||
|
<artifactId>HikariCP</artifactId>
|
||||||
|
<version>${hikari.cp.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.postgresql</groupId>
|
<groupId>org.postgresql</groupId>
|
||||||
<artifactId>postgresql</artifactId>
|
<artifactId>postgresql</artifactId>
|
||||||
@ -70,11 +76,12 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
<hibernate.version>5.4.21.Final</hibernate.version>
|
<hibernate.version>6.4.2.Final</hibernate.version>
|
||||||
<aws-lambda-java-core.version>1.2.0</aws-lambda-java-core.version>
|
<aws-lambda-java-core.version>1.2.0</aws-lambda-java-core.version>
|
||||||
<aws-lambda-java-events.version>3.1.0</aws-lambda-java-events.version>
|
<aws-lambda-java-events.version>3.1.0</aws-lambda-java-events.version>
|
||||||
<jackson-databind.version>2.11.2</jackson-databind.version>
|
<jackson-databind.version>2.11.2</jackson-databind.version>
|
||||||
<postgresql.version>42.2.16</postgresql.version>
|
<postgresql.version>42.2.16</postgresql.version>
|
||||||
|
<hikari.cp.version>5.1.0</hikari.cp.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -83,7 +83,7 @@ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static SessionFactory createSessionFactory() {
|
private static SessionFactory createSessionFactory() {
|
||||||
Map<String, String> settings = new HashMap<>();
|
Map<String, Object> settings = new HashMap<>();
|
||||||
settings.put(URL, System.getenv("DB_URL"));
|
settings.put(URL, System.getenv("DB_URL"));
|
||||||
settings.put(DIALECT, "org.hibernate.dialect.PostgreSQLDialect");
|
settings.put(DIALECT, "org.hibernate.dialect.PostgreSQLDialect");
|
||||||
settings.put(DEFAULT_SCHEMA, "shipping");
|
settings.put(DEFAULT_SCHEMA, "shipping");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.baeldung.lambda.shipping;
|
package com.baeldung.lambda.shipping;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import javax.persistence.Embeddable;
|
import jakarta.persistence.Embeddable;
|
||||||
|
|
||||||
@Embeddable
|
@Embeddable
|
||||||
public class Checkin {
|
public class Checkin {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.baeldung.lambda.shipping;
|
package com.baeldung.lambda.shipping;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static javax.persistence.FetchType.EAGER;
|
import static jakarta.persistence.FetchType.EAGER;
|
||||||
|
|
||||||
@Entity(name = "consignment")
|
@Entity(name = "consignment")
|
||||||
@Table(name = "consignment")
|
@Table(name = "consignment")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.baeldung.lambda.shipping;
|
package com.baeldung.lambda.shipping;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import javax.persistence.Embeddable;
|
import jakarta.persistence.Embeddable;
|
||||||
|
|
||||||
@Embeddable
|
@Embeddable
|
||||||
public class Item {
|
public class Item {
|
||||||
|
@ -63,7 +63,7 @@ public class VectorAPIExamples {
|
|||||||
public float[] scalarNormOfTwoArrays(float[] arr1, float[] arr2) {
|
public float[] scalarNormOfTwoArrays(float[] arr1, float[] arr2) {
|
||||||
float[] finalResult = new float[arr1.length];
|
float[] finalResult = new float[arr1.length];
|
||||||
for (int i = 0; i < arr1.length; i++) {
|
for (int i = 0; i < arr1.length; i++) {
|
||||||
finalResult[i] = (arr1[i] * arr1[i] + arr2[i] * arr2[i]) * -1.0f;
|
finalResult[i] = (float) Math.sqrt(arr1[i] * arr1[i] + arr2[i] * arr2[i]);
|
||||||
}
|
}
|
||||||
return finalResult;
|
return finalResult;
|
||||||
}
|
}
|
||||||
@ -77,13 +77,13 @@ public class VectorAPIExamples {
|
|||||||
var vb = FloatVector.fromArray(PREFERRED_SPECIES, arr2, i);
|
var vb = FloatVector.fromArray(PREFERRED_SPECIES, arr2, i);
|
||||||
var vc = va.mul(va)
|
var vc = va.mul(va)
|
||||||
.add(vb.mul(vb))
|
.add(vb.mul(vb))
|
||||||
.neg();
|
.sqrt();
|
||||||
vc.intoArray(finalResult, i);
|
vc.intoArray(finalResult, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// tail cleanup
|
// tail cleanup
|
||||||
for (; i < arr1.length; i++) {
|
for (; i < arr1.length; i++) {
|
||||||
finalResult[i] = (arr1[i] * arr1[i] + arr2[i] * arr2[i]) * -1.0f;
|
finalResult[i] = (float) Math.sqrt(arr1[i] * arr1[i] + arr2[i] * arr2[i]);
|
||||||
}
|
}
|
||||||
return finalResult;
|
return finalResult;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ public class VectorAPIUnitTest {
|
|||||||
public void whenTwoValuesProvided_thenComputeScalarNorm() {
|
public void whenTwoValuesProvided_thenComputeScalarNorm() {
|
||||||
float[] arr1 = { 1, 2.3f };
|
float[] arr1 = { 1, 2.3f };
|
||||||
float[] arr2 = { 1.3f, 2.0f };
|
float[] arr2 = { 1.3f, 2.0f };
|
||||||
float[] result = { -2.6899998f, -9.29f };
|
float[] result = { 1.6401219f, 3.047950f };
|
||||||
Assertions.assertArrayEquals(result, vector.scalarNormOfTwoArrays(arr1, arr2));
|
Assertions.assertArrayEquals(result, vector.scalarNormOfTwoArrays(arr1, arr2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ public class VectorAPIUnitTest {
|
|||||||
public void whenTwoValuesProvided_thenComputeVectorNorm() {
|
public void whenTwoValuesProvided_thenComputeVectorNorm() {
|
||||||
float[] arr1 = { 1, 2.3f };
|
float[] arr1 = { 1, 2.3f };
|
||||||
float[] arr2 = { 1.3f, 2.0f };
|
float[] arr2 = { 1.3f, 2.0f };
|
||||||
float[] result = { -2.6899998f, -9.29f };
|
float[] result = { 1.6401219f, 3.047950f };
|
||||||
Assertions.assertArrayEquals(result, vector.vectorNormalForm(arr1, arr2));
|
Assertions.assertArrayEquals(result, vector.vectorNormalForm(arr1, arr2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,111 @@
|
|||||||
|
package com.baeldung.map.entrysettolinkedhashmap;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class EntrySetToLinkedHashMapUnitTest {
|
||||||
|
|
||||||
|
private Map<Integer, String> map;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenMap_whenUsingCollectorsGroupingBy_thenCollectToLinkedHashMap() {
|
||||||
|
Map<String, Set<String>> countryToCities = Map.of("Paris", "France", "Nice", "France", "Madrid", "Spain")
|
||||||
|
.entrySet()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.groupingBy(Map.Entry::getValue, LinkedHashMap::new, Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));
|
||||||
|
|
||||||
|
assertThat(countryToCities).isExactlyInstanceOf(LinkedHashMap.class)
|
||||||
|
.containsOnly(entry("France", Set.of("Paris", "Nice")), entry("Spain", Set.of("Madrid")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenMap_whenUsingCollectorsToMap_thenCollectAndConvertToLinkedHashMap() {
|
||||||
|
Map<Integer, String> result = new LinkedHashMap<>(map.entrySet()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||||
|
|
||||||
|
assertThat(result).isExactlyInstanceOf(LinkedHashMap.class)
|
||||||
|
.containsOnly(entry(1, "value 1"), entry(2, "value 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenMap_whenUsingCollectorsToMap_thenCollectToLinkedHashMap() {
|
||||||
|
Map<Integer, String> result = map.entrySet()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
Map.Entry::getKey, Map.Entry::getValue,
|
||||||
|
(e1, e2) -> {
|
||||||
|
throw new RuntimeException();
|
||||||
|
},
|
||||||
|
LinkedHashMap::new));
|
||||||
|
|
||||||
|
assertThat(result).isExactlyInstanceOf(LinkedHashMap.class)
|
||||||
|
.containsOnly(entry(1, "value 1"), entry(2, "value 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenMap_whenUsingLinkedHashMapConstructor_thenObtainLinkedHashMap() {
|
||||||
|
Map<Integer, String> result = new LinkedHashMap<>(map);
|
||||||
|
|
||||||
|
assertThat(result).isExactlyInstanceOf(LinkedHashMap.class)
|
||||||
|
.containsOnly(entry(1, "value 1"), entry(2, "value 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenMap_whenUsingPutWithForLoop_thenInsertIntoLinkedHashMap() {
|
||||||
|
Map<Integer, String> result = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, String> entry : map.entrySet()) {
|
||||||
|
result.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(result).isExactlyInstanceOf(LinkedHashMap.class)
|
||||||
|
.containsOnly(entry(1, "value 1"), entry(2, "value 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenMap_whenUsingPutWithMapForEach_thenInsertIntoLinkedHashMap() {
|
||||||
|
Map<Integer, String> result = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
map.forEach((k, v) -> result.put(k, v));
|
||||||
|
|
||||||
|
assertThat(result).isExactlyInstanceOf(LinkedHashMap.class)
|
||||||
|
.containsOnly(entry(1, "value 1"), entry(2, "value 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenMap_whenUsingPutWithSetForEach_thenInsertIntoLinkedHashMap() {
|
||||||
|
Map<Integer, String> result = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
map.entrySet()
|
||||||
|
.forEach(entry -> result.put(entry.getKey(), entry.getValue()));
|
||||||
|
|
||||||
|
assertThat(result).isExactlyInstanceOf(LinkedHashMap.class)
|
||||||
|
.containsOnly(entry(1, "value 1"), entry(2, "value 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenMap_whenUsingPutWithStreamForEach_thenInsertIntoLinkedHashMapp() {
|
||||||
|
Map<Integer, String> result = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
map.entrySet()
|
||||||
|
.stream()
|
||||||
|
.forEach(entry -> result.put(entry.getKey(), entry.getValue()));
|
||||||
|
|
||||||
|
assertThat(result).isExactlyInstanceOf(LinkedHashMap.class)
|
||||||
|
.containsOnly(entry(1, "value 1"), entry(2, "value 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void init() {
|
||||||
|
map = Map.of(1, "value 1", 2, "value 2");
|
||||||
|
}
|
||||||
|
}
|
@ -9,3 +9,4 @@
|
|||||||
- [How to Log to the Console in Color](https://www.baeldung.com/java-log-console-in-color)
|
- [How to Log to the Console in Color](https://www.baeldung.com/java-log-console-in-color)
|
||||||
- [Create Table Using ASCII in a Console in Java](https://www.baeldung.com/java-console-ascii-make-table)
|
- [Create Table Using ASCII in a Console in Java](https://www.baeldung.com/java-console-ascii-make-table)
|
||||||
- [Printing Message on Console without Using main() Method in Java](https://www.baeldung.com/java-no-main-print-message-console)
|
- [Printing Message on Console without Using main() Method in Java](https://www.baeldung.com/java-no-main-print-message-console)
|
||||||
|
- [Guide to System.in.read()](https://www.baeldung.com/java-system-in-read)
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.baeldung.systemin;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
class SystemInRead {
|
||||||
|
static void readSingleCharacter() {
|
||||||
|
System.out.println("Enter a character:");
|
||||||
|
try {
|
||||||
|
int input = System.in.read();
|
||||||
|
System.out.println((char) input);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
System.err.println("Error reading input: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void readMultipleCharacters() {
|
||||||
|
System.out.println("Enter characters (Press 'Enter' to quit):");
|
||||||
|
try {
|
||||||
|
int input;
|
||||||
|
while ((input = System.in.read()) != '\n') {
|
||||||
|
System.out.print((char) input);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error reading input: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readWithParameters() {
|
||||||
|
try {
|
||||||
|
byte[] byteArray = new byte[5];
|
||||||
|
int bytesRead;
|
||||||
|
int totalBytesRead = 0;
|
||||||
|
|
||||||
|
while ((bytesRead = System.in.read(byteArray, 0, byteArray.length)) != -1) {
|
||||||
|
System.out.print("Data read: " + new String(byteArray, 0, bytesRead));
|
||||||
|
totalBytesRead += bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("\nBytes Read: " + totalBytesRead);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.baeldung.systemin;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class SystemInReadUnitTest {
|
||||||
|
@Test
|
||||||
|
void givenUserInput_whenUsingReadMultipleCharacters_thenRead() {
|
||||||
|
System.setIn(new ByteArrayInputStream("Hello\n".getBytes()));
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
System.setOut(new PrintStream(outputStream));
|
||||||
|
SystemInRead.readMultipleCharacters();
|
||||||
|
|
||||||
|
assertEquals("Enter characters (Press 'Enter' to quit):\n" + "Hello", outputStream.toString().trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenUserInput_whenUsingReadSingleCharacter_thenRead() {
|
||||||
|
System.setIn(new ByteArrayInputStream("A".getBytes()));
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
System.setOut(new PrintStream(outputStream));
|
||||||
|
SystemInRead.readSingleCharacter();
|
||||||
|
|
||||||
|
assertEquals("Enter a character:\nA", outputStream.toString().trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenUserInput_whenUsingReadWithParameters_thenRead() {
|
||||||
|
System.setIn(new ByteArrayInputStream("ABC".getBytes()));
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
System.setOut(new PrintStream(outputStream));
|
||||||
|
SystemInRead.readWithParameters();
|
||||||
|
|
||||||
|
assertEquals("Data read: ABC\n" + "Bytes Read: 3", outputStream.toString().trim());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
### Relevant Articles:
|
72
core-java-modules/core-java-string-operations-8/pom.xml
Normal file
72
core-java-modules/core-java-string-operations-8/pom.xml
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
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>
|
||||||
|
<artifactId>core-java-string-operations-8</artifactId>
|
||||||
|
<name>core-java-string-operations-8</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung.core-java-modules</groupId>
|
||||||
|
<artifactId>core-java-modules</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${apache.commons.lang3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-text</artifactId>
|
||||||
|
<version>${commons-text.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.liquibase</groupId>
|
||||||
|
<artifactId>liquibase-core</artifactId>
|
||||||
|
<version>4.9.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<version>5.8.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.liquibase</groupId>
|
||||||
|
<artifactId>liquibase-core</artifactId>
|
||||||
|
<version>4.9.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13.2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven.compiler.source}</source>
|
||||||
|
<target>${maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<apache.commons.lang3.version>3.13.0</apache.commons.lang3.version>
|
||||||
|
<commons-text.version>1.10.0</commons-text.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,53 @@
|
|||||||
|
package com.baeldung.emailandphonemasking;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class EmailAndPhoneMaskingUnitTest {
|
||||||
|
|
||||||
|
|
||||||
|
String phoneNumber = "+12344567890";
|
||||||
|
String expectedMaskedPhoneNumber = "+*******7890";
|
||||||
|
String email = "testemailaddress@example.com";
|
||||||
|
String expectedMaskedEmail = "te**************@example.com";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenEmailAddress_whenUsingStringManipulation_thenMaskEmail() {
|
||||||
|
int atIndex = email.indexOf('@');
|
||||||
|
String repeatedString = IntStream.range(0, atIndex - 2).mapToObj(i -> "*").collect(Collectors.joining());
|
||||||
|
String maskedPart = email.substring(0, atIndex - repeatedString.length()) + repeatedString;
|
||||||
|
String maskedEmail = maskedPart + email.substring(atIndex);
|
||||||
|
assertEquals(expectedMaskedEmail, maskedEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenEmailAddress_whenUsingRegex_thenMaskEmail() {
|
||||||
|
int atIndex = email.indexOf('@');
|
||||||
|
String regex = "(.{2})(.*)(@.*)";
|
||||||
|
String repeatedAsterisks = "*".repeat(atIndex - 2);
|
||||||
|
String maskedEmail = email.replaceAll(regex, "$1" + repeatedAsterisks + "$3");
|
||||||
|
assertEquals(expectedMaskedEmail, maskedEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenPhoneNumber_whenUsingStringManipulation_thenMaskPhone() {
|
||||||
|
String maskedPhoneNumber = phoneNumber.replaceAll("\\d(?=\\d{4})", "*");
|
||||||
|
assertEquals(expectedMaskedPhoneNumber, maskedPhoneNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenPhoneNumber_whenUsingRegex_thenMaskPhone() {
|
||||||
|
int lastDigitsIndex = phoneNumber.length() - 5;
|
||||||
|
String regex = "(\\+)(\\d+)(\\d{4})";
|
||||||
|
String repeatedAsterisks = "*".repeat(Math.max(0, lastDigitsIndex));
|
||||||
|
String maskedPhoneNumber = phoneNumber.replaceAll(regex, "$1" + repeatedAsterisks + "$3");
|
||||||
|
assertEquals(expectedMaskedPhoneNumber, maskedPhoneNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -33,6 +33,7 @@
|
|||||||
<!-- <module>core-java-modules/core-java-14</module> --> <!-- JAVA-26056 -->
|
<!-- <module>core-java-modules/core-java-14</module> --> <!-- JAVA-26056 -->
|
||||||
<!-- <module>core-java-modules/core-java-16</module> --> <!-- JAVA-26056 -->
|
<!-- <module>core-java-modules/core-java-16</module> --> <!-- JAVA-26056 -->
|
||||||
<!-- <module>core-java-modules/core-java-17</module> --> <!-- JAVA-26056 -->
|
<!-- <module>core-java-modules/core-java-17</module> --> <!-- JAVA-26056 -->
|
||||||
|
<!-- <module>core-java-modules/core-java-18</module> --> <!-- JAVA-26056 -->
|
||||||
<!-- <module>core-java-modules/core-java-19</module> --> <!-- JAVA-26056 -->
|
<!-- <module>core-java-modules/core-java-19</module> --> <!-- JAVA-26056 -->
|
||||||
<module>core-java-numbers-conversions</module>
|
<module>core-java-numbers-conversions</module>
|
||||||
<module>core-java-9-improvements</module>
|
<module>core-java-9-improvements</module>
|
||||||
@ -199,6 +200,7 @@
|
|||||||
<module>core-java-string-operations-2</module>
|
<module>core-java-string-operations-2</module>
|
||||||
<module>core-java-string-operations-6</module>
|
<module>core-java-string-operations-6</module>
|
||||||
<module>core-java-string-operations-7</module>
|
<module>core-java-string-operations-7</module>
|
||||||
|
<module>core-java-string-operations-8</module>
|
||||||
<module>core-java-regex</module>
|
<module>core-java-regex</module>
|
||||||
<module>core-java-regex-2</module>
|
<module>core-java-regex-2</module>
|
||||||
<module>core-java-regex-3</module>
|
<module>core-java-regex-3</module>
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.baeldung.preventexpressingintasfloat;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static String draft = "[{\"id\":4077395,\"field_id\":242566,\"body\":\"\"}, " +
|
||||||
|
"{\"id\":4077398,\"field_id\":242569,\"body\":[[273019,0],[273020,1],[273021,0]]}, " +
|
||||||
|
"{\"id\":4077399,\"field_id\":242570,\"body\":[[273022,0],[273023,1],[273024,0]]}]";
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ArrayList<Hashtable<String, Object>> responses;
|
||||||
|
Type ResponseList = new TypeToken<ArrayList<Hashtable<String, Object>>>() {
|
||||||
|
}.getType();
|
||||||
|
responses = new Gson().fromJson(draft, ResponseList);
|
||||||
|
System.out.println(responses);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.baeldung.preventexpressingintasfloat;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class PreventExpressingIntAsFloatUnitTest {
|
||||||
|
|
||||||
|
public String jsonString = "[{\"id\":4077395,\"field_id\":242566,\"body\":\"\"}, " +
|
||||||
|
"{\"id\":4077398,\"field_id\":242569,\"body\":[[273019,0],[273020,1],[273021,0]]}, " +
|
||||||
|
"{\"id\":4077399,\"field_id\":242570,\"body\":[[273022,0],[273023,1],[273024,0]]}]";
|
||||||
|
|
||||||
|
public String expectedOutput = "[{body=, field_id=242566, id=4077395}, " +
|
||||||
|
"{body=[[273019, 0], [273020, 1], [273021, 0]], field_id=242569, id=4077398}, " +
|
||||||
|
"{body=[[273022, 0], [273023, 1], [273024, 0]], field_id=242570, id=4077399}]";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenJsonString_whenUsingsetObjectToNumberStrategyMethod_thenValidateOutput() {
|
||||||
|
Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create();
|
||||||
|
ArrayList<Hashtable<String, Object>> responses = gson.fromJson(jsonString, new TypeToken<ArrayList<Hashtable<String, Object>>>() {
|
||||||
|
}.getType());
|
||||||
|
|
||||||
|
assertEquals(expectedOutput, responses.toString());
|
||||||
|
}
|
||||||
|
}
|
@ -31,7 +31,7 @@
|
|||||||
<version>${rest-assured.version}</version>
|
<version>${rest-assured.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate.orm</groupId>
|
||||||
<artifactId>hibernate-core</artifactId>
|
<artifactId>hibernate-core</artifactId>
|
||||||
<version>${hibernate-core.version}</version>
|
<version>${hibernate-core.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<hibernate-core.version>5.2.16.Final</hibernate-core.version>
|
<hibernate-core.version>6.4.2.Final</hibernate-core.version>
|
||||||
<mysql-connector.version>8.2.0</mysql-connector.version>
|
<mysql-connector.version>8.2.0</mysql-connector.version>
|
||||||
<spring-boot.version>2.7.5</spring-boot.version>
|
<spring-boot.version>2.7.5</spring-boot.version>
|
||||||
<rest-assured.version>5.3.0</rest-assured.version>
|
<rest-assured.version>5.3.0</rest-assured.version>
|
||||||
|
@ -6,8 +6,8 @@ import com.baeldung.daopattern.daos.JpaUserDao;
|
|||||||
import com.baeldung.daopattern.entities.User;
|
import com.baeldung.daopattern.entities.User;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import javax.persistence.Persistence;
|
import jakarta.persistence.Persistence;
|
||||||
|
|
||||||
public class UserApplication {
|
public class UserApplication {
|
||||||
|
|
||||||
|
@ -8,10 +8,10 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import javax.persistence.EntityManagerFactory;
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
import javax.persistence.spi.PersistenceUnitInfo;
|
import jakarta.persistence.spi.PersistenceUnitInfo;
|
||||||
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
|
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
|
||||||
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
|
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import javax.persistence.SharedCacheMode;
|
import jakarta.persistence.SharedCacheMode;
|
||||||
import javax.persistence.ValidationMode;
|
import jakarta.persistence.ValidationMode;
|
||||||
import javax.persistence.spi.ClassTransformer;
|
import jakarta.persistence.spi.ClassTransformer;
|
||||||
import javax.persistence.spi.PersistenceUnitInfo;
|
import jakarta.persistence.spi.PersistenceUnitInfo;
|
||||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
import jakarta.persistence.spi.PersistenceUnitTransactionType;
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||||
|
|
||||||
public class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
|
public class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
|
||||||
|
@ -5,9 +5,9 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import javax.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import javax.persistence.EntityTransaction;
|
import jakarta.persistence.EntityTransaction;
|
||||||
import javax.persistence.Query;
|
import jakarta.persistence.Query;
|
||||||
|
|
||||||
public class JpaUserDao implements Dao<User> {
|
public class JpaUserDao implements Dao<User> {
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.baeldung.daopattern.entities;
|
package com.baeldung.daopattern.entities;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import javax.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import javax.persistence.GenerationType;
|
import jakarta.persistence.GenerationType;
|
||||||
import javax.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import javax.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "users")
|
@Table(name = "users")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.baeldung.repositoryvsdaopattern;
|
package com.baeldung.repositoryvsdaopattern;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
|
|
||||||
public class UserDaoImpl implements UserDao {
|
public class UserDaoImpl implements UserDao {
|
||||||
|
|
||||||
|
4
pom.xml
4
pom.xml
@ -822,7 +822,7 @@
|
|||||||
<module>spring-actuator</module>
|
<module>spring-actuator</module>
|
||||||
<module>spring-ai</module>
|
<module>spring-ai</module>
|
||||||
<module>spring-aop-2</module>
|
<module>spring-aop-2</module>
|
||||||
<!--<module>spring-aop</module>--><!-- JAVA-30541 -->
|
<module>spring-aop</module>
|
||||||
<module>spring-batch-2</module>
|
<module>spring-batch-2</module>
|
||||||
<module>spring-batch</module>
|
<module>spring-batch</module>
|
||||||
<module>spring-boot-modules</module>
|
<module>spring-boot-modules</module>
|
||||||
@ -1063,7 +1063,7 @@
|
|||||||
<module>spring-actuator</module>
|
<module>spring-actuator</module>
|
||||||
<module>spring-ai</module>
|
<module>spring-ai</module>
|
||||||
<module>spring-aop-2</module>
|
<module>spring-aop-2</module>
|
||||||
<!--<module>spring-aop</module>--><!-- JAVA-30541 -->
|
<module>spring-aop</module>
|
||||||
<module>spring-batch-2</module>
|
<module>spring-batch-2</module>
|
||||||
<module>spring-batch</module>
|
<module>spring-batch</module>
|
||||||
<module>spring-boot-modules</module>
|
<module>spring-boot-modules</module>
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<aspectj-plugin.version>1.14.0</aspectj-plugin.version>
|
<aspectj-plugin.version>1.14.0</aspectj-plugin.version>
|
||||||
|
<java.version>16</java.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -1,5 +1,6 @@
|
|||||||
package com.baeldung.joinpoint;
|
package com.baeldung.joinpoint;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -21,6 +22,10 @@ public class JoinPointAroundCacheAspectIntegrationTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ArticleService articleService;
|
private ArticleService articleService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void removeCache() {
|
||||||
|
JoinPointAroundCacheAspect.CACHE.clear();
|
||||||
|
}
|
||||||
@Test
|
@Test
|
||||||
public void shouldPopulateCache() {
|
public void shouldPopulateCache() {
|
||||||
assertTrue(JoinPointAroundCacheAspect.CACHE.isEmpty());
|
assertTrue(JoinPointAroundCacheAspect.CACHE.isEmpty());
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<module>spring-security-oauth2-sso</module>
|
<module>spring-security-oauth2-sso</module>
|
||||||
<module>spring-security-oidc</module>
|
<module>spring-security-oidc</module>
|
||||||
<module>spring-security-okta</module>
|
<module>spring-security-okta</module>
|
||||||
<module>spring-security-saml</module>
|
<!-- <module>spring-security-saml</module>--> <!-- This module wasn't able to update to spring boot 3 because Jakarta clashes with javax -->
|
||||||
<module>spring-security-social-login</module> <!-- spring-social-facebook is deprecated and not supported in latest version of spring security. JAVA-29302 -->
|
<module>spring-security-social-login</module> <!-- spring-social-facebook is deprecated and not supported in latest version of spring security. JAVA-29302 -->
|
||||||
<module>spring-security-web-angular</module>
|
<module>spring-security-web-angular</module>
|
||||||
<module>spring-security-web-boot-1</module>
|
<module>spring-security-web-boot-1</module>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
Note: For integration testing get the OPA server running first. Check the official [OPA documentation](https://www.openpolicyagent.org/docs/latest/) for instructions on how to run the OPA server.
|
||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>spring-security-opa</artifactId>
|
<artifactId>spring-security-opa</artifactId>
|
||||||
<description>Spring Security with OPA authorization</description>
|
<description>Spring Security with OPA authorization</description>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
<artifactId>spring-security-modules</artifactId>
|
<artifactId>parent-boot-3</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-3</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -28,7 +29,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
<version>31.0.1-jre</version>
|
<version>${guava.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
@ -17,9 +17,8 @@ public class OpaConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
public WebClient opaWebClient(WebClient.Builder builder) {
|
public WebClient opaWebClient(WebClient.Builder builder) {
|
||||||
|
|
||||||
return builder
|
return builder.baseUrl(opaProperties.getEndpoint())
|
||||||
.baseUrl(opaProperties.getEndpoint())
|
.build();
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package com.baeldung.security.opa.config;
|
package com.baeldung.security.opa.config;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "opa")
|
@ConfigurationProperties(prefix = "opa")
|
||||||
@Data
|
@Data
|
||||||
public class OpaProperties {
|
public class OpaProperties {
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private String endpoint = "http://localhost:8181";
|
private String endpoint = "http://localhost:8181";
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package com.baeldung.security.opa.config;
|
package com.baeldung.security.opa.config;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -11,17 +9,16 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.client.reactive.ClientHttpRequest;
|
|
||||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||||
import org.springframework.security.web.server.authorization.AuthorizationContext;
|
import org.springframework.security.web.server.authorization.AuthorizationContext;
|
||||||
import org.springframework.web.reactive.function.BodyInserter;
|
|
||||||
import org.springframework.web.reactive.function.BodyInserters;
|
|
||||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
@ -33,78 +30,64 @@ import reactor.core.publisher.Mono;
|
|||||||
@Configuration
|
@Configuration
|
||||||
public class SecurityConfiguration {
|
public class SecurityConfiguration {
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityWebFilterChain accountAuthorization(ServerHttpSecurity http, @Qualifier("opaWebClient")WebClient opaWebClient) {
|
public SecurityWebFilterChain accountAuthorization(ServerHttpSecurity http, @Qualifier("opaWebClient") WebClient opaWebClient) {
|
||||||
|
return http.httpBasic(Customizer.withDefaults())
|
||||||
// @formatter:on
|
.authorizeExchange(exchanges -> exchanges.pathMatchers("/account/*")
|
||||||
return http
|
.access(opaAuthManager(opaWebClient)))
|
||||||
.httpBasic()
|
.build();
|
||||||
.and()
|
|
||||||
.authorizeExchange(exchanges -> {
|
|
||||||
exchanges
|
|
||||||
.pathMatchers("/account/*")
|
|
||||||
.access(opaAuthManager(opaWebClient));
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
// @formatter:on
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ReactiveAuthorizationManager<AuthorizationContext> opaAuthManager(WebClient opaWebClient) {
|
public ReactiveAuthorizationManager<AuthorizationContext> opaAuthManager(WebClient opaWebClient) {
|
||||||
|
return (auth, context) -> opaWebClient.post()
|
||||||
return (auth, context) -> {
|
.accept(MediaType.APPLICATION_JSON)
|
||||||
return opaWebClient.post()
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.accept(MediaType.APPLICATION_JSON)
|
.body(toAuthorizationPayload(auth, context), Map.class)
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.exchangeToMono(this::toDecision);
|
||||||
.body(toAuthorizationPayload(auth,context), Map.class)
|
|
||||||
.exchangeToMono(this::toDecision);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<AuthorizationDecision> toDecision(ClientResponse response) {
|
private Mono<AuthorizationDecision> toDecision(ClientResponse response) {
|
||||||
|
if (!response.statusCode()
|
||||||
if ( !response.statusCode().is2xxSuccessful()) {
|
.is2xxSuccessful()) {
|
||||||
return Mono.just(new AuthorizationDecision(false));
|
return Mono.just(new AuthorizationDecision(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response.bodyToMono(ObjectNode.class)
|
||||||
.bodyToMono(ObjectNode.class)
|
.map(node -> {
|
||||||
.map(node -> {
|
boolean authorized = node.path("result")
|
||||||
boolean authorized = node.path("result").path("authorized").asBoolean(false);
|
.path("authorized")
|
||||||
return new AuthorizationDecision(authorized);
|
.asBoolean(false);
|
||||||
});
|
return new AuthorizationDecision(authorized);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Publisher<Map<String,Object>> toAuthorizationPayload(Mono<Authentication> auth, AuthorizationContext context) {
|
private Publisher<Map<String, Object>> toAuthorizationPayload(Mono<Authentication> auth, AuthorizationContext context) {
|
||||||
// @formatter:off
|
return auth.defaultIfEmpty(
|
||||||
return auth
|
new AnonymousAuthenticationToken("**ANONYMOUS**", new Object(), Collections.singletonList(new SimpleGrantedAuthority("ANONYMOUS"))))
|
||||||
.defaultIfEmpty(new AnonymousAuthenticationToken("**ANONYMOUS**", new Object(), Arrays.asList(new SimpleGrantedAuthority("ANONYMOUS"))))
|
.map(a -> {
|
||||||
.map( a -> {
|
Map<String, String> headers = context.getExchange()
|
||||||
|
.getRequest()
|
||||||
|
.getHeaders()
|
||||||
|
.toSingleValueMap();
|
||||||
|
|
||||||
Map<String,String> headers = context.getExchange().getRequest()
|
Map<String, Object> attributes = ImmutableMap.<String, Object> builder()
|
||||||
.getHeaders()
|
.put("principal", a.getName())
|
||||||
.toSingleValueMap();
|
.put("authorities", a.getAuthorities()
|
||||||
|
.stream()
|
||||||
|
.map(GrantedAuthority::getAuthority)
|
||||||
|
.collect(Collectors.toList()))
|
||||||
|
.put("uri", context.getExchange()
|
||||||
|
.getRequest()
|
||||||
|
.getURI()
|
||||||
|
.getPath())
|
||||||
|
.put("headers", headers)
|
||||||
|
.build();
|
||||||
|
|
||||||
Map<String,Object> attributes = ImmutableMap.<String,Object>builder()
|
return ImmutableMap.<String, Object> builder()
|
||||||
.put("principal",a.getName())
|
.put("input", attributes)
|
||||||
.put("authorities",
|
.build();
|
||||||
a.getAuthorities()
|
});
|
||||||
.stream()
|
|
||||||
.map(g -> g.getAuthority())
|
|
||||||
.collect(Collectors.toList()))
|
|
||||||
.put("uri", context.getExchange().getRequest().getURI().getPath())
|
|
||||||
.put("headers",headers)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Map<String,Object> input = ImmutableMap.<String,Object>builder()
|
|
||||||
.put("input",attributes)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
return input;
|
|
||||||
});
|
|
||||||
// @formatter:on
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,12 @@ public class Account {
|
|||||||
private BigDecimal balance;
|
private BigDecimal balance;
|
||||||
private String currency;
|
private String currency;
|
||||||
|
|
||||||
|
|
||||||
public static Account of(String id, BigDecimal balance, String currency) {
|
public static Account of(String id, BigDecimal balance, String currency) {
|
||||||
Account acc = new Account();
|
Account account = new Account();
|
||||||
acc.setId(id);
|
account.setId(id);
|
||||||
acc.setBalance(balance);
|
account.setBalance(balance);
|
||||||
acc.setCurrency(currency);
|
account.setCurrency(currency);
|
||||||
|
return account;
|
||||||
return acc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package com.baeldung.security.opa.service;
|
package com.baeldung.security.opa.service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -13,25 +10,20 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Philippe
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Service
|
@Service
|
||||||
public class AccountService {
|
public class AccountService {
|
||||||
|
|
||||||
private Map<String, Account> accounts = ImmutableMap.<String, Account>builder()
|
private Map<String, Account> accounts = ImmutableMap.<String, Account> builder()
|
||||||
.put("0001", Account.of("0001", BigDecimal.valueOf(100.00), "USD"))
|
.put("0001", Account.of("0001", BigDecimal.valueOf(100.00), "USD"))
|
||||||
.put("0002", Account.of("0002", BigDecimal.valueOf(101.00), "EUR"))
|
.put("0002", Account.of("0002", BigDecimal.valueOf(101.00), "EUR"))
|
||||||
.put("0003", Account.of("0003", BigDecimal.valueOf(102.00), "BRL"))
|
.put("0003", Account.of("0003", BigDecimal.valueOf(102.00), "BRL"))
|
||||||
.put("0004", Account.of("0004", BigDecimal.valueOf(103.00), "AUD"))
|
.put("0004", Account.of("0004", BigDecimal.valueOf(103.00), "AUD"))
|
||||||
.put("0005", Account.of("0005", BigDecimal.valueOf(10400.00), "JPY"))
|
.put("0005", Account.of("0005", BigDecimal.valueOf(10400.00), "JPY"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
public Mono<Account> findByAccountId(String accountId) {
|
public Mono<Account> findByAccountId(String accountId) {
|
||||||
return Mono.just(accounts.get(accountId))
|
return Mono.just(accounts.get(accountId))
|
||||||
.switchIfEmpty(Mono.error(new IllegalArgumentException("invalid.account")));
|
.switchIfEmpty(Mono.error(new IllegalArgumentException("invalid.account")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import org.springframework.security.test.context.support.WithMockUser;
|
|||||||
import org.springframework.test.context.ActiveProfiles;
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
|
|
||||||
// !!! NOTICE: Start OPA server before running this test class !!!
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
@ActiveProfiles("test")
|
@ActiveProfiles("test")
|
||||||
class AccountControllerLiveTest {
|
class AccountControllerLiveTest {
|
||||||
@ -24,44 +23,42 @@ class AccountControllerLiveTest {
|
|||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.rest = WebTestClient.bindToApplicationContext(this.context)
|
this.rest = WebTestClient.bindToApplicationContext(this.context)
|
||||||
.apply(springSecurity())
|
.apply(springSecurity())
|
||||||
.configureClient()
|
.configureClient()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@WithMockUser(username = "user1", roles = { "account:read:0001"} )
|
@WithMockUser(username = "user1", roles = { "account:read:0001" })
|
||||||
void testGivenValidUser_thenSuccess() {
|
void testGivenValidUser_thenSuccess() {
|
||||||
rest.get()
|
rest.get()
|
||||||
.uri("/account/0001")
|
.uri("/account/0001")
|
||||||
.accept(MediaType.APPLICATION_JSON)
|
.accept(MediaType.APPLICATION_JSON)
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus()
|
.expectStatus()
|
||||||
.is2xxSuccessful();
|
.is2xxSuccessful();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@WithMockUser(username = "user1", roles = { "account:read:0002"} )
|
@WithMockUser(username = "user1", roles = { "account:read:0002" })
|
||||||
void testGivenValidUser_thenUnauthorized() {
|
void testGivenValidUser_thenUnauthorized() {
|
||||||
rest.get()
|
rest.get()
|
||||||
.uri("/account/0001")
|
.uri("/account/0001")
|
||||||
.accept(MediaType.APPLICATION_JSON)
|
.accept(MediaType.APPLICATION_JSON)
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus()
|
.expectStatus()
|
||||||
.isForbidden();
|
.isForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@WithMockUser(username = "user1", roles = {} )
|
@WithMockUser(username = "user1", roles = {})
|
||||||
void testGivenNoAuthorities_thenForbidden() {
|
void testGivenNoAuthorities_thenForbidden() {
|
||||||
rest.get()
|
rest.get()
|
||||||
.uri("/account/0001")
|
.uri("/account/0001")
|
||||||
.accept(MediaType.APPLICATION_JSON)
|
.accept(MediaType.APPLICATION_JSON)
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus()
|
.expectStatus()
|
||||||
.isForbidden();
|
.isForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package com.baeldung.saml;
|
|||||||
|
|
||||||
import static org.springframework.security.config.Customizer.withDefaults;
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
@ -13,26 +12,30 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP
|
|||||||
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
|
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
|
||||||
import org.springframework.security.saml2.provider.service.web.Saml2MetadataFilter;
|
import org.springframework.security.saml2.provider.service.web.Saml2MetadataFilter;
|
||||||
import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;
|
import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;
|
||||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
|
|
||||||
@Autowired
|
private final RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
|
||||||
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
DefaultRelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository);
|
DefaultRelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(
|
||||||
|
this.relyingPartyRegistrationRepository);
|
||||||
Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());
|
Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());
|
||||||
|
|
||||||
http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
|
http.csrf(AbstractHttpConfigurer::disable)
|
||||||
.saml2Login(withDefaults())
|
.authorizeHttpRequests(authorize -> authorize.anyRequest()
|
||||||
.saml2Logout(withDefaults())
|
.authenticated())
|
||||||
.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
|
.saml2Login(withDefaults())
|
||||||
DefaultSecurityFilterChain chain = http.build();
|
.saml2Logout(withDefaults())
|
||||||
return chain;
|
.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityConfig(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
|
||||||
|
this.relyingPartyRegistrationRepository = relyingPartyRegistrationRepository;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
<artifactId>parent-boot-2</artifactId>
|
<artifactId>parent-boot-3</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<relativePath>../../parent-boot-2</relativePath>
|
<relativePath>../../parent-boot-3</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -54,11 +54,30 @@
|
|||||||
<artifactId>json-patch</artifactId>
|
<artifactId>json-patch</artifactId>
|
||||||
<version>${jsonpatch.version}</version>
|
<version>${jsonpatch.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||||
|
<artifactId>httpclient5</artifactId>
|
||||||
|
<version>${httpclient5.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<xstream.version>1.4.9</xstream.version>
|
<xstream.version>1.4.9</xstream.version>
|
||||||
<jsonpatch.version>1.12</jsonpatch.version>
|
<jsonpatch.version>1.12</jsonpatch.version>
|
||||||
|
<httpclient5.version>5.2.1</httpclient5.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -1,22 +1,22 @@
|
|||||||
package com.baeldung.responseheaders.controllers;
|
package com.baeldung.responseheaders.controllers;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/filter-response-header")
|
@RequestMapping("/filter-response-header")
|
||||||
public class FilterResponseHeaderController {
|
public class FilterResponseHeaderController {
|
||||||
|
|
||||||
@GetMapping("/no-extra-header")
|
@GetMapping("/no-extra-header")
|
||||||
public String FilterHeaderResponseWithNoExtraHeader() {
|
public String filterHeaderResponseWithNoExtraHeader() {
|
||||||
return "Response body with Filter header and no extra header";
|
return "Response body with Filter header and no extra header";
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/extra-header")
|
@GetMapping("/extra-header")
|
||||||
public String FilterHeaderResponseWithExtraHeader(HttpServletResponse response) {
|
public String filterHeaderResponseWithExtraHeader(HttpServletResponse response) {
|
||||||
response.addHeader("Baeldung-Example-Header", "Value-ExtraHeader");
|
response.addHeader("Baeldung-Example-Header", "Value-ExtraHeader");
|
||||||
return "Response body with Filter header and one extra header";
|
return "Response body with Filter header and one extra header";
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
@ -2,18 +2,18 @@ package com.baeldung.responseheaders.filter;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.Filter;
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.FilterConfig;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import javax.servlet.annotation.WebFilter;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import jakarta.servlet.Filter;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.FilterConfig;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.ServletRequest;
|
||||||
|
import jakarta.servlet.ServletResponse;
|
||||||
|
import jakarta.servlet.annotation.WebFilter;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
@WebFilter("/filter-response-header/*")
|
@WebFilter("/filter-response-header/*")
|
||||||
public class AddResponseHeaderFilter implements Filter {
|
public class AddResponseHeaderFilter implements Filter {
|
||||||
|
|
||||||
|
@ -23,8 +23,6 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
|||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(value = "/customers")
|
@RequestMapping(value = "/customers")
|
||||||
public class CustomerRestController {
|
public class CustomerRestController {
|
||||||
@ -40,25 +38,28 @@ public class CustomerRestController {
|
|||||||
public ResponseEntity<Customer> createCustomer(@RequestBody Customer customer) {
|
public ResponseEntity<Customer> createCustomer(@RequestBody Customer customer) {
|
||||||
Customer customerCreated = customerService.createCustomer(customer);
|
Customer customerCreated = customerService.createCustomer(customer);
|
||||||
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
|
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
|
||||||
.path("/{id}")
|
.path("/{id}")
|
||||||
.buildAndExpand(customerCreated.getId())
|
.buildAndExpand(customerCreated.getId())
|
||||||
.toUri();
|
.toUri();
|
||||||
return ResponseEntity.created(location).build();
|
return ResponseEntity.created(location)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PatchMapping(path = "/{id}", consumes = "application/json-patch+json")
|
@PatchMapping(path = "/{id}", consumes = "application/json-patch+json")
|
||||||
public ResponseEntity<Customer> updateCustomer(@PathVariable String id,
|
public ResponseEntity<Customer> updateCustomer(@PathVariable String id, @RequestBody JsonPatch patch) {
|
||||||
@RequestBody JsonPatch patch) {
|
|
||||||
try {
|
try {
|
||||||
Customer customer = customerService.findCustomer(id).orElseThrow(CustomerNotFoundException::new);
|
Customer customer = customerService.findCustomer(id)
|
||||||
|
.orElseThrow(CustomerNotFoundException::new);
|
||||||
Customer customerPatched = applyPatchToCustomer(patch, customer);
|
Customer customerPatched = applyPatchToCustomer(patch, customer);
|
||||||
customerService.updateCustomer(customerPatched);
|
customerService.updateCustomer(customerPatched);
|
||||||
|
|
||||||
return ResponseEntity.ok(customerPatched);
|
return ResponseEntity.ok(customerPatched);
|
||||||
} catch (CustomerNotFoundException e) {
|
} catch (CustomerNotFoundException e) {
|
||||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
|
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||||
|
.build();
|
||||||
} catch (JsonPatchException | JsonProcessingException e) {
|
} catch (JsonPatchException | JsonProcessingException e) {
|
||||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user