Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
a8290e27cd
@ -13,3 +13,4 @@ You can build the project from the command line using: *mvn clean install*, or i
|
|||||||
- [Read Data From the Beginning Using Kafka Consumer API](https://www.baeldung.com/java-kafka-consumer-api-read)
|
- [Read Data From the Beginning Using Kafka Consumer API](https://www.baeldung.com/java-kafka-consumer-api-read)
|
||||||
- [Get Partition Count for a Topic in Kafka](https://www.baeldung.com/java-kafka-partition-count-topic)
|
- [Get Partition Count for a Topic in Kafka](https://www.baeldung.com/java-kafka-partition-count-topic)
|
||||||
- [bootstrap-server in Kafka Configuration](https://www.baeldung.com/java-kafka-bootstrap-server)
|
- [bootstrap-server in Kafka Configuration](https://www.baeldung.com/java-kafka-bootstrap-server)
|
||||||
|
- [Introduction to Apache Kafka](https://www.baeldung.com/apache-kafka)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
## Relevant Articles
|
## Relevant Articles
|
||||||
- [Sequenced Collections in Java 21](https://www.baeldung.com/java-21-sequenced-collections)
|
- [Sequenced Collections in Java 21](https://www.baeldung.com/java-21-sequenced-collections)
|
||||||
- [String Templates in Java 21](https://www.baeldung.com/java-21-string-templates)
|
- [String Templates in Java 21](https://www.baeldung.com/java-21-string-templates)
|
||||||
|
- [Unnamed Classes and Instance Main Methods in Java 21](https://www.baeldung.com/java-21-unnamed-class-instance-main)
|
||||||
|
- [Unnamed Patterns and Variables in Java 21](https://www.baeldung.com/java-unnamed-patterns-variables)
|
||||||
|
@ -5,3 +5,4 @@ This module contains articles about Java Character Class
|
|||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
- [Character#isAlphabetic vs. Character#isLetter](https://www.baeldung.com/java-character-isletter-isalphabetic)
|
- [Character#isAlphabetic vs. Character#isLetter](https://www.baeldung.com/java-character-isletter-isalphabetic)
|
||||||
- [Difference Between Java’s “char” and “String”](https://www.baeldung.com/java-char-vs-string)
|
- [Difference Between Java’s “char” and “String”](https://www.baeldung.com/java-char-vs-string)
|
||||||
|
- [Increment Character in Java](https://www.baeldung.com/java-char-sequence)
|
||||||
|
@ -5,4 +5,6 @@
|
|||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
- [Introduction to Roaring Bitmap](https://www.baeldung.com/java-roaring-bitmap-intro)
|
- [Introduction to Roaring Bitmap](https://www.baeldung.com/java-roaring-bitmap-intro)
|
||||||
- [Creating Custom Iterator in Java](https://www.baeldung.com/java-creating-custom-iterator)
|
- [Creating Custom Iterator in Java](https://www.baeldung.com/java-creating-custom-iterator)
|
||||||
|
- [Difference Between Arrays.sort() and Collections.sort()](https://www.baeldung.com/java-arrays-collections-sort-methods)
|
||||||
|
- [Skipping the First Iteration in Java](https://www.baeldung.com/java-skip-first-iteration)
|
||||||
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-4)
|
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-4)
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
This module contains articles about the Java ArrayList collection
|
This module contains articles about the Java ArrayList collection
|
||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
- [Create an ArrayList with Multiple Object Types](https://www.baeldung.com/arraylist-with-multiple-object-types)
|
- [Create an ArrayList with Multiple Object Types](https://www.baeldung.com/java-arraylist-multiple-object-types)
|
||||||
|
@ -3,3 +3,4 @@
|
|||||||
This module contains articles about conversions among Collection types in Java.
|
This module contains articles about conversions among Collection types in Java.
|
||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
- [Converting HashMap Values to an ArrayList in Java](https://www.baeldung.com/java-hashmap-arraylist)
|
||||||
|
@ -12,10 +12,10 @@ public class EpochTimeToLocalDateTimeConverterUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testConvertEpochTimeToLocalDateTime() {
|
public void testConvertEpochTimeToLocalDateTime() {
|
||||||
long epochTimeMillis = 1624962431000L; // Example epoch time in milliseconds
|
long epochTimeMillis = 1624962431000L; // Example epoch time in milliseconds
|
||||||
LocalDateTime expectedDateTime = LocalDateTime.of(2021, 6, 29, 12, 13, 51);
|
LocalDateTime expectedDateTime = LocalDateTime.of(2021, 6, 29, 10, 27, 11);
|
||||||
|
|
||||||
Instant instant = Instant.ofEpochMilli(epochTimeMillis);
|
Instant instant = Instant.ofEpochMilli(epochTimeMillis);
|
||||||
ZoneId zoneId = ZoneId.systemDefault();
|
ZoneId zoneId = ZoneId.of("UTC");
|
||||||
LocalDateTime actualDateTime = instant.atZone(zoneId).toLocalDateTime();
|
LocalDateTime actualDateTime = instant.atZone(zoneId).toLocalDateTime();
|
||||||
|
|
||||||
assertEquals(expectedDateTime, actualDateTime);
|
assertEquals(expectedDateTime, actualDateTime);
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
This module contains articles about core Java input and output (IO)
|
This module contains articles about core Java input and output (IO)
|
||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
- [Get File Extension From MIME Type in Java](https://www.baeldung.com/java-mime-type-file-extension)
|
||||||
- [[<-- Prev]](/core-java-modules/core-java-io-4)
|
- [[<-- Prev]](/core-java-modules/core-java-io-4)
|
||||||
|
|
||||||
|
@ -25,8 +25,12 @@
|
|||||||
<version>${commons-codec}</version>
|
<version>${commons-codec}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>${guava.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<finalName>core-java-numbers-6</finalName>
|
<finalName>core-java-numbers-6</finalName>
|
||||||
<resources>
|
<resources>
|
||||||
@ -39,5 +43,6 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<commons-codec>1.15</commons-codec>
|
<commons-codec>1.15</commons-codec>
|
||||||
|
<guava.version>32.1.2-jre</guava.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.baeldung.bigintegerroot;
|
||||||
|
|
||||||
|
public class BenchmarkRunner {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
org.openjdk.jmh.Main.main(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.baeldung.bigintegerroot;
|
||||||
|
|
||||||
|
public class BigIntegerHolder {
|
||||||
|
|
||||||
|
private BigIntegerHolder() {
|
||||||
|
}
|
||||||
|
public static final String BIG_NUMBER = "179769313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
|
||||||
|
public static final String VERY_BIG_NUMBER = "32473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834";
|
||||||
|
public static final String INSANELY_BIG_NUMBER = "3247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834";
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package com.baeldung.bigintegerroot;
|
||||||
|
|
||||||
|
import static com.baeldung.bigintegerroot.BigIntegerHolder.*;
|
||||||
|
|
||||||
|
import com.baeldung.bigintegerroot.algorithms.Newton;
|
||||||
|
import com.baeldung.bigintegerroot.algorithms.NewtonPlus;
|
||||||
|
import com.google.common.math.BigIntegerMath;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Fork;
|
||||||
|
import org.openjdk.jmh.annotations.Measurement;
|
||||||
|
import org.openjdk.jmh.annotations.Mode;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
import org.openjdk.jmh.annotations.Warmup;
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
|
||||||
|
@Warmup(iterations = 1)
|
||||||
|
@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.MINUTES)
|
||||||
|
@Fork(1)
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
public class BigIntegerSquareRootBenchmark {
|
||||||
|
|
||||||
|
@Param({BIG_NUMBER, VERY_BIG_NUMBER, INSANELY_BIG_NUMBER})
|
||||||
|
public String number;
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
public void calculateRootWithJava(Blackhole blackhole) {
|
||||||
|
final BigInteger integer = new BigInteger(number);
|
||||||
|
final BigInteger root = integer.sqrt();
|
||||||
|
blackhole.consume(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
public void calculateRootWithGuava(Blackhole blackhole) {
|
||||||
|
final BigInteger integer = new BigInteger(number);
|
||||||
|
final BigInteger root = BigIntegerMath.sqrt(integer, RoundingMode.DOWN);
|
||||||
|
blackhole.consume(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
public void calculateRootWithNewtonPlus(Blackhole blackhole) {
|
||||||
|
final BigInteger integer = new BigInteger(number);
|
||||||
|
final BigInteger root = NewtonPlus.sqrt(integer);
|
||||||
|
blackhole.consume(root);
|
||||||
|
}
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
public void calculateRootWithNewton(Blackhole blackhole) {
|
||||||
|
final BigInteger integer = new BigInteger(number);
|
||||||
|
final BigInteger root = Newton.sqrt(integer);
|
||||||
|
blackhole.consume(root);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.baeldung.bigintegerroot.algorithms;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
public class Newton {
|
||||||
|
|
||||||
|
private Newton() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BigInteger sqrt(BigInteger n) {
|
||||||
|
// Initial approximation
|
||||||
|
BigInteger x = n.divide(BigInteger.TWO);
|
||||||
|
|
||||||
|
// Tolerance level (small positive integer)
|
||||||
|
BigInteger tolerance = BigInteger.ONE;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// x_new = 0.5 * (x + n / x)
|
||||||
|
BigInteger xNew = x.add(n.divide(x)).divide(BigInteger.TWO);
|
||||||
|
|
||||||
|
// Check for convergence within tolerance
|
||||||
|
if (x.subtract(xNew).abs().compareTo(tolerance) <= 0) {
|
||||||
|
return xNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = xNew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
package com.baeldung.bigintegerroot.algorithms;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
public class NewtonPlus {
|
||||||
|
|
||||||
|
private NewtonPlus() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// A fast square root by Ryan Scott White.
|
||||||
|
public static BigInteger sqrt(BigInteger x) {
|
||||||
|
if (x.compareTo(BigInteger.valueOf(144838757784765629L)) < 0) {
|
||||||
|
long xAsLong = x.longValue();
|
||||||
|
long vInt = (long)Math.sqrt(xAsLong);
|
||||||
|
if (vInt * vInt > xAsLong)
|
||||||
|
vInt--;
|
||||||
|
return BigInteger.valueOf(vInt); }
|
||||||
|
|
||||||
|
double xAsDub = x.doubleValue();
|
||||||
|
BigInteger val;
|
||||||
|
if (xAsDub < 2.1267e37) // 2.12e37 largest here
|
||||||
|
// since sqrt(long.max*long.max) > long.max
|
||||||
|
{
|
||||||
|
long vInt = (long)Math.sqrt(xAsDub);
|
||||||
|
val = BigInteger.valueOf
|
||||||
|
((vInt + x.divide(BigInteger.valueOf(vInt)).longValue()) >> 1);
|
||||||
|
}
|
||||||
|
else if (xAsDub < 4.3322e127) {
|
||||||
|
// Convert a double to a BigInteger
|
||||||
|
long bits = Double.doubleToLongBits(Math.sqrt(xAsDub));
|
||||||
|
int exp = ((int) (bits >> 52) & 0x7ff) - 1075;
|
||||||
|
val = BigInteger.valueOf((bits & ((1L << 52)) - 1) | (1L << 52)).shiftLeft(exp);
|
||||||
|
|
||||||
|
val = x.divide(val).add(val).shiftRight(1);
|
||||||
|
if (xAsDub > 2e63) {
|
||||||
|
val = x.divide(val).add(val).shiftRight(1); }
|
||||||
|
}
|
||||||
|
else // handle large numbers over 4.3322e127
|
||||||
|
{
|
||||||
|
int xLen = x.bitLength();
|
||||||
|
int wantedPrecision = ((xLen + 1) / 2);
|
||||||
|
int xLenMod = xLen + (xLen & 1) + 1;
|
||||||
|
|
||||||
|
//////// Do the first Sqrt on Hardware ////////
|
||||||
|
long tempX = x.shiftRight(xLenMod - 63).longValue();
|
||||||
|
double tempSqrt1 = Math.sqrt(tempX);
|
||||||
|
long valLong = Double.doubleToLongBits(tempSqrt1) & 0x1fffffffffffffL;
|
||||||
|
|
||||||
|
if (valLong == 0)
|
||||||
|
valLong = 1L << 53;
|
||||||
|
|
||||||
|
//////// Classic Newton Iterations ////////
|
||||||
|
val = BigInteger.valueOf(valLong).shiftLeft(53 - 1)
|
||||||
|
.add((x.shiftRight(xLenMod -
|
||||||
|
(3 * 53))).divide(BigInteger.valueOf(valLong)));
|
||||||
|
|
||||||
|
int size = 106;
|
||||||
|
for (; size < 256; size <<= 1) {
|
||||||
|
val = val.shiftLeft(size - 1).add(x.shiftRight
|
||||||
|
(xLenMod - (3*size)).divide(val));}
|
||||||
|
|
||||||
|
if (xAsDub > 4e254) { // 4e254 = 1<<845.77
|
||||||
|
int numOfNewtonSteps = 31 -
|
||||||
|
Integer.numberOfLeadingZeros(wantedPrecision / size)+1;
|
||||||
|
|
||||||
|
////// Apply Starting Size ////////
|
||||||
|
int wantedSize = (wantedPrecision >> numOfNewtonSteps) + 2;
|
||||||
|
int needToShiftBy = size - wantedSize;
|
||||||
|
val = val.shiftRight(needToShiftBy);
|
||||||
|
|
||||||
|
size = wantedSize;
|
||||||
|
do {
|
||||||
|
//////// Newton Plus Iteration ////////
|
||||||
|
int shiftX = xLenMod - (3 * size);
|
||||||
|
BigInteger valSqrd = val.multiply(val).shiftLeft(size - 1);
|
||||||
|
BigInteger valSU = x.shiftRight(shiftX).subtract(valSqrd);
|
||||||
|
val = val.shiftLeft(size).add(valSU.divide(val));
|
||||||
|
size *= 2;
|
||||||
|
} while (size < wantedPrecision);
|
||||||
|
}
|
||||||
|
val = val.shiftRight(size - wantedPrecision);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect a round ups. This function can be further optimized - see article.
|
||||||
|
// For a ~7% speed bump the following line can be removed but round-ups will occur.
|
||||||
|
if (val.multiply(val).compareTo(x) > 0)
|
||||||
|
val = val.subtract(BigInteger.ONE);
|
||||||
|
|
||||||
|
// Enabling the below will guarantee an error is stopped for larger numbers.
|
||||||
|
// Note: As of this writing, there are no known errors.
|
||||||
|
BigInteger tmp = val.multiply(val);
|
||||||
|
if (tmp.compareTo(x) > 0) {
|
||||||
|
System.out.println("val^2(" + val.multiply(val).toString()
|
||||||
|
+ ") ≥ x(" + x.toString()+")");
|
||||||
|
System.console().readLine();
|
||||||
|
//throw new Exception("Sqrt function had internal error - value too high");
|
||||||
|
}
|
||||||
|
if (tmp.add(val.shiftLeft(1)).add(BigInteger.ONE).compareTo(x) <= 0) {
|
||||||
|
System.out.println("(val+1)^2("
|
||||||
|
+ val.add(BigInteger.ONE).multiply(val.add(BigInteger.ONE)).toString()
|
||||||
|
+ ") ≥ x(" + x.toString() + ")");
|
||||||
|
System.console().readLine();
|
||||||
|
//throw new Exception("Sqrt function had internal error - value too low");
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.baeldung.bigintegerroot;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import com.baeldung.bigintegerroot.algorithms.Newton;
|
||||||
|
import com.baeldung.bigintegerroot.algorithms.NewtonPlus;
|
||||||
|
import com.google.common.math.BigIntegerMath;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.apache.commons.math3.util.Pair;
|
||||||
|
import org.junit.jupiter.api.condition.EnabledForJreRange;
|
||||||
|
import org.junit.jupiter.api.condition.JRE;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
|
class BigIntegerSquareRootUnitTest {
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {
|
||||||
|
BigIntegerHolder.BIG_NUMBER,
|
||||||
|
BigIntegerHolder.VERY_BIG_NUMBER,
|
||||||
|
BigIntegerHolder.VERY_BIG_NUMBER
|
||||||
|
})
|
||||||
|
void squareRootTest(String number) {
|
||||||
|
final BigInteger bigInteger = new BigInteger(number);
|
||||||
|
final BigInteger javaRoot = bigInteger.sqrt();
|
||||||
|
final BigInteger guavaRoot = BigIntegerMath.sqrt(bigInteger, RoundingMode.DOWN);
|
||||||
|
final BigInteger newtonRoot = Newton.sqrt(bigInteger);
|
||||||
|
final BigInteger newtonPlusRoot = NewtonPlus.sqrt(bigInteger);
|
||||||
|
|
||||||
|
assertTrue(Stream.of(
|
||||||
|
new Pair<>(javaRoot, guavaRoot),
|
||||||
|
new Pair<>(guavaRoot, newtonRoot),
|
||||||
|
new Pair<>(newtonRoot, newtonPlusRoot)
|
||||||
|
).allMatch(pair -> pair.getFirst().equals(pair.getSecond())));
|
||||||
|
}
|
||||||
|
}
|
@ -14,5 +14,6 @@ This module contains articles about working with the operating system (OS) in Ja
|
|||||||
- [How to Run a Shell Command in Java](http://www.baeldung.com/run-shell-command-in-java)
|
- [How to Run a Shell Command in Java](http://www.baeldung.com/run-shell-command-in-java)
|
||||||
- [Taking Screenshots Using Java](https://www.baeldung.com/java-taking-screenshots)
|
- [Taking Screenshots Using Java](https://www.baeldung.com/java-taking-screenshots)
|
||||||
- [Java Sound API – Capturing Microphone](https://www.baeldung.com/java-sound-api-capture-mic)
|
- [Java Sound API – Capturing Microphone](https://www.baeldung.com/java-sound-api-capture-mic)
|
||||||
|
- [How to Detect the Username Using Java](https://www.baeldung.com/java-get-username)
|
||||||
|
|
||||||
This module uses Java 9, so make sure to have the JDK 9 installed to run it.
|
This module uses Java 9, so make sure to have the JDK 9 installed to run it.
|
||||||
|
@ -9,4 +9,5 @@
|
|||||||
- [Regular Expression: \z vs \Z Anchors in Java](https://www.baeldung.com/java-regular-expression-z-vs-z-anchors)
|
- [Regular Expression: \z vs \Z Anchors in Java](https://www.baeldung.com/java-regular-expression-z-vs-z-anchors)
|
||||||
- [Extract Text Between Square Brackets](https://www.baeldung.com/java-get-content-between-square-brackets)
|
- [Extract Text Between Square Brackets](https://www.baeldung.com/java-get-content-between-square-brackets)
|
||||||
- [Get the Indexes of Regex Pattern Matches in Java](https://www.baeldung.com/java-indexes-regex-pattern-matches)
|
- [Get the Indexes of Regex Pattern Matches in Java](https://www.baeldung.com/java-indexes-regex-pattern-matches)
|
||||||
|
- [Check if a String is Strictly Alphanumeric With Java](https://www.baeldung.com/java-check-string-contains-only-letters-numbers)
|
||||||
- More articles: [[<-- prev]](/core-java-modules/core-java-regex)
|
- More articles: [[<-- prev]](/core-java-modules/core-java-regex)
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<spring.version>6.0.10</spring.version>
|
<spring.version>6.0.12</spring.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
This module contains articles about RSocket in Spring Framework 6.
|
This module contains articles about RSocket in Spring Framework 6.
|
||||||
|
|
||||||
### Relevant articles
|
### Relevant articles
|
||||||
|
- [RSocket Interface in Spring 6](https://www.baeldung.com/spring-rsocket)
|
||||||
|
|
||||||
- [Introduction to RSocket](#)
|
|
@ -9,9 +9,10 @@
|
|||||||
<description>This is simple boot application for Spring boot actuator test</description>
|
<description>This is simple boot application for Spring boot actuator test</description>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
<artifactId>spring-boot-modules</artifactId>
|
<artifactId>parent-boot-3</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-3</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -39,16 +40,6 @@
|
|||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>javax.servlet</groupId>
|
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.servlet</groupId>
|
|
||||||
<artifactId>jstl</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
@ -1,36 +1,56 @@
|
|||||||
package com.baeldung.endpoints.enabling;
|
package com.baeldung.endpoints.enabling;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
|
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.core.userdetails.User;
|
||||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||||
|
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
@Configuration
|
||||||
|
public class SecurityConfiguration {
|
||||||
|
|
||||||
@Override
|
@Bean
|
||||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
|
||||||
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
return new MvcRequestMatcher.Builder(introspector);
|
||||||
auth.inMemoryAuthentication()
|
}
|
||||||
.withUser("user")
|
|
||||||
.password(encoder.encode("password"))
|
@Bean
|
||||||
|
public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
|
||||||
|
http.httpBasic(Customizer.withDefaults());
|
||||||
|
http.securityMatcher(EndpointRequest.toAnyEndpoint());
|
||||||
|
http.authorizeHttpRequests(authz -> {
|
||||||
|
authz.requestMatchers(mvc.pattern("/actuator/**"))
|
||||||
|
.hasRole("ADMIN")
|
||||||
|
.anyRequest()
|
||||||
|
.authenticated();
|
||||||
|
});
|
||||||
|
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public InMemoryUserDetailsManager userDetailsService() {
|
||||||
|
UserDetails user = User.withDefaultPasswordEncoder()
|
||||||
|
.username("user")
|
||||||
|
.password("password")
|
||||||
.roles("USER")
|
.roles("USER")
|
||||||
.and()
|
.build();
|
||||||
.withUser("admin")
|
UserDetails admin = User.withDefaultPasswordEncoder()
|
||||||
.password(encoder.encode("admin"))
|
.username("admin")
|
||||||
.roles("USER", "ADMIN");
|
.password("password")
|
||||||
}
|
.roles("USER", "ADMIN")
|
||||||
|
.build();
|
||||||
@Override
|
return new InMemoryUserDetailsManager(user, admin);
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
|
||||||
http.requestMatcher(EndpointRequest.toAnyEndpoint())
|
|
||||||
.authorizeRequests((requests) -> requests.anyRequest()
|
|
||||||
.hasRole("ADMIN"));
|
|
||||||
http.httpBasic();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package com.baeldung.endpoints.info;
|
package com.baeldung.endpoints.info;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import javax.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import javax.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import javax.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "users")
|
@Table(name = "users")
|
||||||
|
@ -15,7 +15,7 @@ import org.springframework.context.annotation.ComponentScan;
|
|||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
import org.springframework.web.context.request.RequestContextListener;
|
import org.springframework.web.context.request.RequestContextListener;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
|
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@ComponentScan("com.baeldung.metrics")
|
@ComponentScan("com.baeldung.metrics")
|
||||||
|
@ -7,14 +7,14 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||||
|
|
||||||
import javax.servlet.Filter;
|
import jakarta.servlet.Filter;
|
||||||
import javax.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import javax.servlet.FilterConfig;
|
import jakarta.servlet.FilterConfig;
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class MetricFilter implements Filter {
|
public class MetricFilter implements Filter {
|
||||||
|
@ -13,20 +13,20 @@ import org.springframework.test.web.servlet.MockMvc;
|
|||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
@AutoConfigureMockMvc
|
@AutoConfigureMockMvc
|
||||||
public class EndpointEnablingIntegrationTest {
|
class EndpointEnablingIntegrationTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@WithMockUser(username = "user", password = "password", roles = "USER")
|
@WithMockUser(username = "user", password = "password", roles = "USER")
|
||||||
public void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception {
|
void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception {
|
||||||
mockMvc.perform(get("/actuator"))
|
mockMvc.perform(get("/actuator"))
|
||||||
.andExpect(status().isForbidden());
|
.andExpect(status().isForbidden());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@WithMockUser(username = "admin", password = "admin", roles = "ADMIN")
|
@WithMockUser(username = "admin", password = "admin", roles = "ADMIN")
|
||||||
public void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception {
|
void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception {
|
||||||
mockMvc.perform(get("/actuator"))
|
mockMvc.perform(get("/actuator"))
|
||||||
.andExpect(jsonPath("$._links").exists())
|
.andExpect(jsonPath("$._links").exists())
|
||||||
.andExpect(jsonPath("$._links.beans").exists())
|
.andExpect(jsonPath("$._links.beans").exists())
|
||||||
|
@ -93,8 +93,8 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<swagger-core-jakarta.version>2.2.11</swagger-core-jakarta.version>
|
<swagger-core-jakarta.version>2.2.11</swagger-core-jakarta.version>
|
||||||
<springwolf-kafka.version>0.12.1</springwolf-kafka.version>
|
<springwolf-kafka.version>0.14.0</springwolf-kafka.version>
|
||||||
<springwolf-ui.version>0.8.0</springwolf-ui.version>
|
<springwolf-ui.version>0.14.0</springwolf-ui.version>
|
||||||
<testcontainers-kafka.version>1.18.3</testcontainers-kafka.version>
|
<testcontainers-kafka.version>1.18.3</testcontainers-kafka.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
"operationId": "incoming-topic_publish",
|
"operationId": "incoming-topic_publish",
|
||||||
"description": "More details for the incoming topic",
|
"description": "More details for the incoming topic",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"kafka": { }
|
"kafka": {
|
||||||
|
"bindingVersion": "0.4.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
|
"schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
|
||||||
@ -32,7 +34,9 @@
|
|||||||
"$ref": "#/components/schemas/SpringKafkaDefaultHeadersIncomingPayloadDto"
|
"$ref": "#/components/schemas/SpringKafkaDefaultHeadersIncomingPayloadDto"
|
||||||
},
|
},
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"kafka": { }
|
"kafka": {
|
||||||
|
"bindingVersion": "0.4.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,7 +46,9 @@
|
|||||||
"operationId": "outgoing-topic_subscribe",
|
"operationId": "outgoing-topic_subscribe",
|
||||||
"description": "More details for the outgoing topic",
|
"description": "More details for the outgoing topic",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"kafka": { }
|
"kafka": {
|
||||||
|
"bindingVersion": "0.4.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
|
"schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
|
||||||
@ -56,7 +62,9 @@
|
|||||||
"$ref": "#/components/schemas/SpringKafkaDefaultHeadersOutgoingPayloadDto"
|
"$ref": "#/components/schemas/SpringKafkaDefaultHeadersOutgoingPayloadDto"
|
||||||
},
|
},
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"kafka": { }
|
"kafka": {
|
||||||
|
"bindingVersion": "0.4.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
spring-boot-modules/spring-boot-graalvm-docker/README.md
Normal file
2
spring-boot-modules/spring-boot-graalvm-docker/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
## Relevant Articles
|
||||||
|
- [Create a GraalVM Docker Image](https://www.baeldung.com/java-graalvm-docker-image)
|
@ -9,9 +9,10 @@
|
|||||||
<description>Module For Spring Boot MVC Web</description>
|
<description>Module For Spring Boot MVC Web</description>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
<artifactId>spring-boot-modules</artifactId>
|
<artifactId>parent-boot-3</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-3</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -4,10 +4,10 @@ import java.io.IOException;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
import jakarta.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
public class HelloWorldServlet extends HttpServlet {
|
public class HelloWorldServlet extends HttpServlet {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ -4,10 +4,10 @@ import java.io.IOException;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
import jakarta.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
public class SpringHelloWorldServlet extends HttpServlet {
|
public class SpringHelloWorldServlet extends HttpServlet {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ -2,7 +2,7 @@ package com.baeldung.common.error;
|
|||||||
|
|
||||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||||
|
|
||||||
import javax.servlet.Servlet;
|
import jakarta.servlet.Servlet;
|
||||||
|
|
||||||
public class SpringHelloServletRegistrationBean extends ServletRegistrationBean {
|
public class SpringHelloServletRegistrationBean extends ServletRegistrationBean {
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ import org.springframework.web.WebApplicationInitializer;
|
|||||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||||
import org.springframework.web.context.support.XmlWebApplicationContext;
|
import org.springframework.web.context.support.XmlWebApplicationContext;
|
||||||
import org.springframework.web.servlet.DispatcherServlet;
|
import org.springframework.web.servlet.DispatcherServlet;
|
||||||
import javax.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.ServletRegistration;
|
import jakarta.servlet.ServletRegistration;
|
||||||
|
|
||||||
public class WebAppInitializer implements WebApplicationInitializer {
|
public class WebAppInitializer implements WebApplicationInitializer {
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package com.baeldung.servlets.servlets;
|
package com.baeldung.servlets.servlets;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
import jakarta.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.baeldung.servlets.servlets.javaee;
|
package com.baeldung.servlets.servlets.javaee;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.annotation.WebServlet;
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
import javax.servlet.http.HttpServlet;
|
import jakarta.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@WebServlet(name = "AnnotationServlet", description = "Example Servlet Using Annotations", urlPatterns = { "/annotationservlet" })
|
@WebServlet(name = "AnnotationServlet", description = "Example Servlet Using Annotations", urlPatterns = { "/annotationservlet" })
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package com.baeldung.servlets.servlets.javaee;
|
package com.baeldung.servlets.servlets.javaee;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
import jakarta.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.baeldung.utils;
|
package com.baeldung.utils;
|
||||||
|
|
||||||
import javax.annotation.security.RolesAllowed;
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.baeldung.utils.controller;
|
package com.baeldung.utils.controller;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
@ -1,32 +1,34 @@
|
|||||||
package com.baeldung.utils;
|
package com.baeldung.utils;
|
||||||
|
|
||||||
import com.baeldung.utils.controller.UtilsController;
|
import com.baeldung.utils.controller.UtilsController;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
|
||||||
|
import static org.mockito.MockitoAnnotations.openMocks;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
public class UtilsControllerIntegrationTest {
|
class UtilsControllerIntegrationTest {
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private UtilsController utilsController;
|
private UtilsController utilsController;
|
||||||
|
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
openMocks(this);
|
||||||
this.mockMvc = MockMvcBuilders.standaloneSetup(utilsController).build();
|
this.mockMvc = MockMvcBuilders.standaloneSetup(utilsController).build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception {
|
void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception {
|
||||||
String param = "testparam";
|
String param = "testparam";
|
||||||
this.mockMvc.perform(post("/setParam").param("param", param).sessionAttr("parameter", param)).andExpect(status().isOk());
|
this.mockMvc.perform(post("/setParam").param("param", param).sessionAttr("parameter", param)).andExpect(status().isOk());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.baeldung.spytest;
|
||||||
|
|
||||||
|
public interface ExternalAlertService {
|
||||||
|
public boolean alert(Order order);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.baeldung.spytest;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class NotificationService {
|
||||||
|
|
||||||
|
private ExternalAlertService externalAlertService;
|
||||||
|
|
||||||
|
public void notify(Order order) {
|
||||||
|
System.out.println(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean raiseAlert(Order order) {
|
||||||
|
return externalAlertService.alert(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.baeldung.spytest;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Order {
|
||||||
|
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private OrderType orderType;
|
||||||
|
|
||||||
|
private double orderQuantity;
|
||||||
|
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
public Order(UUID id, String name, double orderQuantity, String address) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.orderQuantity = orderQuantity;
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum OrderType {
|
||||||
|
INDIVIDUAL, BULK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getOrderQuantity() {
|
||||||
|
return orderQuantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.baeldung.spytest;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class OrderRepository {
|
||||||
|
|
||||||
|
public static final HashMap<UUID, Order> orders = new HashMap<>();
|
||||||
|
|
||||||
|
public Order save(Order order) {
|
||||||
|
UUID orderId = UUID.randomUUID();
|
||||||
|
order.setId(orderId);
|
||||||
|
orders.put(UUID.randomUUID(), order);
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.baeldung.spytest;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class OrderService {
|
||||||
|
|
||||||
|
public final OrderRepository orderRepository;
|
||||||
|
|
||||||
|
public final NotificationService notificationService;
|
||||||
|
|
||||||
|
public OrderService(OrderRepository orderRepository, NotificationService notificationService) {
|
||||||
|
this.orderRepository = orderRepository;
|
||||||
|
this.notificationService = notificationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Order save(Order order) {
|
||||||
|
order = orderRepository.save(order);
|
||||||
|
notificationService.notify(order);
|
||||||
|
if (!notificationService.raiseAlert(order)) {
|
||||||
|
throw new RuntimeException("Alert not raised");
|
||||||
|
}
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.baeldung.spytest;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SpyTestApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpyTestApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.baeldung.spytest;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class OrderServiceIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
OrderRepository orderRepository;
|
||||||
|
@SpyBean
|
||||||
|
NotificationService notificationService;
|
||||||
|
@SpyBean
|
||||||
|
OrderService orderService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenNotificationServiceIsUsingSpyBean_whenOrderServiceIsCalled_thenNotificationServiceSpyBeanShouldBeInvoked() {
|
||||||
|
|
||||||
|
Order orderInput = new Order(null, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
|
||||||
|
doReturn(true).when(notificationService)
|
||||||
|
.raiseAlert(any(Order.class));
|
||||||
|
Order order = orderService.save(orderInput);
|
||||||
|
Assertions.assertNotNull(order);
|
||||||
|
Assertions.assertNotNull(order.getId());
|
||||||
|
verify(notificationService).notify(any(Order.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.baeldung.spytest;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
class OrderServiceUnitTest {
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
OrderRepository orderRepository;
|
||||||
|
@Spy
|
||||||
|
NotificationService notificationService;
|
||||||
|
@InjectMocks
|
||||||
|
OrderService orderService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenNotificationServiceIsUsingSpy_whenOrderServiceIsCalled_thenNotificationServiceSpyShouldBeInvoked() {
|
||||||
|
|
||||||
|
UUID orderId = UUID.randomUUID();
|
||||||
|
Order orderInput = new Order(orderId, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
|
||||||
|
doReturn(orderInput).when(orderRepository)
|
||||||
|
.save(any());
|
||||||
|
doReturn(true).when(notificationService)
|
||||||
|
.raiseAlert(any(Order.class));
|
||||||
|
Order order = orderService.save(orderInput);
|
||||||
|
Assertions.assertNotNull(order);
|
||||||
|
Assertions.assertEquals(orderId, order.getId());
|
||||||
|
verify(notificationService).notify(any(Order.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
## Spring Cloud Gateway
|
||||||
|
|
||||||
|
This module contains articles about Spring Cloud Gateway
|
||||||
|
|
||||||
|
### Relevant Articles:
|
||||||
|
|
||||||
|
- [Exploring the New Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway)
|
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>gateway-2</artifactId>
|
||||||
|
<name>gateway-2</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-boot-2</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../../parent-boot-2</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit</groupId>
|
||||||
|
<artifactId>junit-bom</artifactId>
|
||||||
|
<version>${junit-jupiter.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-dependencies</artifactId>
|
||||||
|
<version>${spring-cloud-dependencies.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-dependencies</artifactId>
|
||||||
|
<version>${spring-boot.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<spring-cloud-dependencies.version>2021.0.3</spring-cloud-dependencies.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.baeldung.springcloudgateway.custompredicates;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class CustomPredicatesApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new SpringApplicationBuilder(CustomPredicatesApplication.class)
|
||||||
|
.profiles("customroutes")
|
||||||
|
.run(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.baeldung.springcloudgateway.custompredicates.config;
|
||||||
|
|
||||||
|
import org.springframework.cloud.gateway.route.RouteLocator;
|
||||||
|
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import com.baeldung.springcloudgateway.custompredicates.factories.GoldenCustomerRoutePredicateFactory;
|
||||||
|
import com.baeldung.springcloudgateway.custompredicates.factories.GoldenCustomerRoutePredicateFactory.Config;
|
||||||
|
import com.baeldung.springcloudgateway.custompredicates.service.GoldenCustomerService;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class CustomPredicatesConfig {
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public GoldenCustomerRoutePredicateFactory goldenCustomer(GoldenCustomerService goldenCustomerService) {
|
||||||
|
return new GoldenCustomerRoutePredicateFactory(goldenCustomerService);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//@Bean
|
||||||
|
public RouteLocator routes(RouteLocatorBuilder builder, GoldenCustomerRoutePredicateFactory gf ) {
|
||||||
|
|
||||||
|
return builder.routes()
|
||||||
|
.route("dsl_golden_route", r ->
|
||||||
|
r.predicate(gf.apply(new Config(true, "customerId")))
|
||||||
|
.and()
|
||||||
|
.path("/dsl_api/**")
|
||||||
|
.filters(f -> f.stripPrefix(1))
|
||||||
|
.uri("https://httpbin.org")
|
||||||
|
)
|
||||||
|
.route("dsl_common_route", r ->
|
||||||
|
r.predicate(gf.apply(new Config(false, "customerId")))
|
||||||
|
.and()
|
||||||
|
.path("/dsl_api/**")
|
||||||
|
.filters(f -> f.stripPrefix(1))
|
||||||
|
.uri("https://httpbin.org")
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.baeldung.springcloudgateway.custompredicates.factories;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
|
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
|
||||||
|
import org.springframework.http.HttpCookie;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
|
import com.baeldung.springcloudgateway.custompredicates.service.GoldenCustomerService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Philippe
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class GoldenCustomerRoutePredicateFactory extends AbstractRoutePredicateFactory<GoldenCustomerRoutePredicateFactory.Config> {
|
||||||
|
|
||||||
|
private final GoldenCustomerService goldenCustomerService;
|
||||||
|
|
||||||
|
public GoldenCustomerRoutePredicateFactory(GoldenCustomerService goldenCustomerService ) {
|
||||||
|
super(Config.class);
|
||||||
|
this.goldenCustomerService = goldenCustomerService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> shortcutFieldOrder() {
|
||||||
|
return Arrays.asList("isGolden","customerIdCookie");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Predicate<ServerWebExchange> apply(Config config) {
|
||||||
|
|
||||||
|
return (ServerWebExchange t) -> {
|
||||||
|
List<HttpCookie> cookies = t.getRequest()
|
||||||
|
.getCookies()
|
||||||
|
.get(config.getCustomerIdCookie());
|
||||||
|
|
||||||
|
boolean isGolden;
|
||||||
|
if ( cookies == null || cookies.isEmpty()) {
|
||||||
|
isGolden = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String customerId = cookies.get(0).getValue();
|
||||||
|
isGolden = goldenCustomerService.isGoldenCustomer(customerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.isGolden()?isGolden:!isGolden;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Validated
|
||||||
|
public static class Config {
|
||||||
|
boolean isGolden = true;
|
||||||
|
|
||||||
|
@NotEmpty
|
||||||
|
String customerIdCookie = "customerId";
|
||||||
|
|
||||||
|
|
||||||
|
public Config() {}
|
||||||
|
|
||||||
|
public Config( boolean isGolden, String customerIdCookie) {
|
||||||
|
this.isGolden = isGolden;
|
||||||
|
this.customerIdCookie = customerIdCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGolden() {
|
||||||
|
return isGolden;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGolden(boolean value) {
|
||||||
|
this.isGolden = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the customerIdCookie
|
||||||
|
*/
|
||||||
|
public String getCustomerIdCookie() {
|
||||||
|
return customerIdCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param customerIdCookie the customerIdCookie to set
|
||||||
|
*/
|
||||||
|
public void setCustomerIdCookie(String customerIdCookie) {
|
||||||
|
this.customerIdCookie = customerIdCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.baeldung.springcloudgateway.custompredicates.service;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Philippe
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class GoldenCustomerService {
|
||||||
|
|
||||||
|
public boolean isGoldenCustomer(String customerId) {
|
||||||
|
|
||||||
|
// TODO: Add some AI logic to check is this customer deserves a "golden" status ;^)
|
||||||
|
if ( "baeldung".equalsIgnoreCase(customerId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.baeldung.springcloudgateway.introduction;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@PropertySource("classpath:introduction-application.properties")
|
||||||
|
public class IntroductionGatewayApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(IntroductionGatewayApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
spring:
|
||||||
|
cloud:
|
||||||
|
gateway:
|
||||||
|
routes:
|
||||||
|
- id: golden_route
|
||||||
|
uri: https://httpbin.org
|
||||||
|
predicates:
|
||||||
|
- Path=/api/**
|
||||||
|
- GoldenCustomer=true
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
|
- AddRequestHeader=GoldenCustomer,true
|
||||||
|
- id: common_route
|
||||||
|
uri: https://httpbin.org
|
||||||
|
predicates:
|
||||||
|
- Path=/api/**
|
||||||
|
- name: GoldenCustomer
|
||||||
|
args:
|
||||||
|
golden: false
|
||||||
|
customerIdCookie: customerId
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
|
- AddRequestHeader=GoldenCustomer,false
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
|||||||
|
logging:
|
||||||
|
level:
|
||||||
|
org.springframework.cloud.gateway: DEBUG
|
||||||
|
reactor.netty.http.client: DEBUG
|
@ -0,0 +1,7 @@
|
|||||||
|
spring.cloud.gateway.routes[0].id=baeldung_route
|
||||||
|
spring.cloud.gateway.routes[0].uri=http://www.baeldung.com
|
||||||
|
spring.cloud.gateway.routes[0].predicates[0]=Path=/baeldung
|
||||||
|
|
||||||
|
management.endpoints.web.exposure.include=*
|
||||||
|
|
||||||
|
server.port=80
|
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.baeldung.springcloudgateway.custompredicates;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.json.JSONTokener;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||||
|
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||||
|
import org.springframework.boot.web.server.LocalServerPort;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.RequestEntity;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test requires
|
||||||
|
*/
|
||||||
|
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||||
|
@ActiveProfiles("customroutes")
|
||||||
|
public class CustomPredicatesApplicationLiveTest {
|
||||||
|
|
||||||
|
@LocalServerPort
|
||||||
|
String serverPort;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TestRestTemplate restTemplate;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenNormalCustomer_whenCallHeadersApi_thenResponseForNormalCustomer() throws JSONException {
|
||||||
|
|
||||||
|
String url = "http://localhost:" + serverPort + "/api/headers";
|
||||||
|
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
|
||||||
|
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject(response.getBody());
|
||||||
|
JSONObject headers = json.getJSONObject("headers");
|
||||||
|
assertThat(headers.getString("Goldencustomer")).isEqualTo("false");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenGoldenCustomer_whenCallHeadersApi_thenResponseForGoldenCustomer() throws JSONException {
|
||||||
|
|
||||||
|
String url = "http://localhost:" + serverPort + "/api/headers";
|
||||||
|
RequestEntity<Void> request = RequestEntity
|
||||||
|
.get(URI.create(url))
|
||||||
|
.header("Cookie", "customerId=baeldung")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(request, String.class);
|
||||||
|
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject(response.getBody());
|
||||||
|
JSONObject headers = json.getJSONObject("headers");
|
||||||
|
assertThat(headers.getString("Goldencustomer")).isEqualTo("true");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.baeldung.springcloudgateway.introduction;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.AppenderBase;
|
||||||
|
|
||||||
|
public class LoggerListAppender extends AppenderBase<ILoggingEvent> {
|
||||||
|
|
||||||
|
static private List<ILoggingEvent> events = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void append(ILoggingEvent eventObject) {
|
||||||
|
events.add(eventObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ILoggingEvent> getEvents() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearEventList() {
|
||||||
|
events.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.baeldung.springcloudgateway.introduction;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import com.baeldung.springcloudgateway.introduction.IntroductionGatewayApplication;
|
||||||
|
|
||||||
|
|
||||||
|
@SpringBootTest(classes = IntroductionGatewayApplication.class)
|
||||||
|
public class SpringContextTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="LISTAPPENDER"
|
||||||
|
class="com.baeldung.springcloudgateway.introduction.LoggerListAppender">
|
||||||
|
</appender>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="LISTAPPENDER" />
|
||||||
|
</root>
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
@ -18,6 +18,7 @@
|
|||||||
<module>config</module>
|
<module>config</module>
|
||||||
<module>discovery</module>
|
<module>discovery</module>
|
||||||
<module>gateway</module>
|
<module>gateway</module>
|
||||||
|
<module>gateway-2</module>
|
||||||
<module>svc-book</module>
|
<module>svc-book</module>
|
||||||
<module>svc-rating</module>
|
<module>svc-rating</module>
|
||||||
<module>customer-service</module>
|
<module>customer-service</module>
|
||||||
|
@ -9,3 +9,4 @@
|
|||||||
- [JUnit – Testing Methods That Call System.exit()](https://www.baeldung.com/junit-system-exit)
|
- [JUnit – Testing Methods That Call System.exit()](https://www.baeldung.com/junit-system-exit)
|
||||||
- [Single Assert Call for Multiple Properties in Java Unit Testing](https://www.baeldung.com/java-testing-single-assert-multiple-properties)
|
- [Single Assert Call for Multiple Properties in Java Unit Testing](https://www.baeldung.com/java-testing-single-assert-multiple-properties)
|
||||||
- [Creating a Test Suite With JUnit](https://www.baeldung.com/java-junit-test-suite)
|
- [Creating a Test Suite With JUnit](https://www.baeldung.com/java-junit-test-suite)
|
||||||
|
- [Testing Interface Contract in Java](https://www.baeldung.com/java-junit-verify-interface-contract)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user