Merge branch 'eugenp:master' into master
This commit is contained in:
commit
2242df334f
|
@ -84,38 +84,6 @@
|
|||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.bazaarvoice.maven.plugins</groupId>
|
||||
<artifactId>process-exec-maven-plugin</artifactId>
|
||||
<version>${process-exec-maven-plugin.version}</version>
|
||||
<executions>
|
||||
<!--Start Blade -->
|
||||
<execution>
|
||||
<id>blade-process</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>start</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<name>Blade</name>
|
||||
<waitForInterrupt>false</waitForInterrupt>
|
||||
<arguments>
|
||||
<argument>java</argument>
|
||||
<argument>-jar</argument>
|
||||
<argument>blade.jar</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<!--Stop all processes in reverse order -->
|
||||
<execution>
|
||||
<id>stop-all</id>
|
||||
<phase>post-integration-test</phase>
|
||||
<goals>
|
||||
<goal>stop-all</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>${assembly.plugin.version}</version>
|
||||
|
|
|
@ -17,8 +17,8 @@ import java.nio.file.Paths;
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
|
||||
public class HttpRequestUnitTest {
|
||||
|
||||
|
@ -51,10 +51,10 @@ public class HttpRequestUnitTest {
|
|||
|
||||
/*
|
||||
* This test will fail as soon as the given URL returns a HTTP 2 response.
|
||||
* Therefore, let's leave it commented out.
|
||||
* Therefore, let's leave it ignored.
|
||||
* */
|
||||
@Test
|
||||
@Disabled
|
||||
@Test
|
||||
@Ignore
|
||||
public void shouldFallbackToHttp1_1WhenWebsiteDoesNotUseHttp2() throws IOException, InterruptedException, URISyntaxException, NoSuchAlgorithmException {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(new URI("https://postman-echo.com/get"))
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant articles:
|
||||
|
||||
- [Collect a Java Stream to an Immutable Collection](https://www.baeldung.com/java-stream-immutable-collection)
|
|
@ -0,0 +1,48 @@
|
|||
<?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-16</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>core-java-16</name>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source.version}</source>
|
||||
<target>${maven.compiler.target.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source.version>16</maven.compiler.source.version>
|
||||
<maven.compiler.target.version>16</maven.compiler.target.version>
|
||||
<assertj.version>3.6.1</assertj.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.streams;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class StreamToImmutableUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenUsingStreamToList_thenReturnImmutableList() {
|
||||
|
||||
List<String> immutableList = Stream.of("a", "b", "c", "d")
|
||||
.toList();
|
||||
|
||||
Assertions.assertThrows(UnsupportedOperationException.class, () -> {
|
||||
immutableList.add("e");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -10,3 +10,5 @@
|
|||
- [Overview of Java Built-in Annotations](https://www.baeldung.com/java-default-annotations)
|
||||
- [Creating a Custom Annotation in Java](https://www.baeldung.com/java-custom-annotation)
|
||||
- [Efficient Word Frequency Calculator in Java](https://www.baeldung.com/java-word-frequency)
|
||||
- [Why Missing Annotations Don’t Cause ClassNotFoundException](https://www.baeldung.com/classnotfoundexception-missing-annotation)
|
||||
- [Valid @SuppressWarnings Warning Names](https://www.baeldung.com/java-suppresswarnings-valid-names)
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package com.baeldung.annotations;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings({"serial", "unchecked"})
|
||||
public class ClassWithSuppressWarningsNames implements Serializable {
|
||||
|
||||
// private static final long serialVersionUID = -1166032307853492833L;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void suppressBoxingWarning() {
|
||||
int value = 5;
|
||||
int unusedVar = 10; // no warning here
|
||||
List<Integer> list = new ArrayList<>();
|
||||
list.add(Integer.valueOf(value));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecated")
|
||||
void suppressDeprecatedWarning() {
|
||||
ClassWithSuppressWarningsNames cls = new ClassWithSuppressWarningsNames();
|
||||
cls.deprecatedMethod(); // no warning here
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
String suppressFallthroughWarning() {
|
||||
int day = 5;
|
||||
switch (day) {
|
||||
case 5:
|
||||
return "This is day 5";
|
||||
// break; // no warning here
|
||||
case 10:
|
||||
return "This is day 10";
|
||||
// break;
|
||||
default:
|
||||
return "This default day";
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
String deprecatedMethod() {
|
||||
return "deprecated method";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.missingannotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface A {
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.baeldung.missingannotation;
|
||||
|
||||
@A
|
||||
@C(D.class)
|
||||
public class B {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("It worked");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.missingannotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface C {
|
||||
Class<?> value();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package com.baeldung.missingannotation;
|
||||
|
||||
public class D {
|
||||
}
|
|
@ -6,3 +6,4 @@
|
|||
|
||||
- [ArrayList vs. LinkedList vs. HashMap in Java](https://www.baeldung.com/java-arraylist-vs-linkedlist-vs-hashmap)
|
||||
- [Java Deque vs. Stack](https://www.baeldung.com/java-deque-vs-stack)
|
||||
- [Collection.toArray(new T[0]) or .toArray(new T[size])](https://www.baeldung.com/java-collection-toarray-methods)
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
|
||||
- [Binary Semaphore vs Reentrant Lock](https://www.baeldung.com/java-binary-semaphore-vs-reentrant-lock)
|
||||
- [Bad Practices With Synchronization](https://www.baeldung.com/java-synchronization-bad-practices)
|
||||
- [Start Two Threads at the Exact Same Time in Java](https://www.baeldung.com/java-start-two-threads-at-same-time)
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package com.baeldung.threadsstartatsametime;
|
||||
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.Phaser;
|
||||
|
||||
public class ThreadsStartAtSameTime {
|
||||
|
||||
public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
|
||||
usingCountDownLatch();
|
||||
|
||||
Thread.sleep(30);
|
||||
|
||||
usingCyclicBarrier();
|
||||
|
||||
Thread.sleep(30);
|
||||
|
||||
usingPhaser();
|
||||
|
||||
}
|
||||
|
||||
private static void usingCountDownLatch() throws InterruptedException {
|
||||
System.out.println("===============================================");
|
||||
System.out.println(" >>> Using CountDownLatch <<<<");
|
||||
System.out.println("===============================================");
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
WorkerWithCountDownLatch worker1 = new WorkerWithCountDownLatch("Worker with latch 1", latch);
|
||||
WorkerWithCountDownLatch worker2 = new WorkerWithCountDownLatch("Worker with latch 2", latch);
|
||||
|
||||
worker1.start();
|
||||
worker2.start();
|
||||
|
||||
Thread.sleep(10);//simulation of some actual work
|
||||
|
||||
System.out.println("-----------------------------------------------");
|
||||
System.out.println(" Now release the latch:");
|
||||
System.out.println("-----------------------------------------------");
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
private static void usingCyclicBarrier() throws BrokenBarrierException, InterruptedException {
|
||||
System.out.println("\n===============================================");
|
||||
System.out.println(" >>> Using CyclicBarrier <<<<");
|
||||
System.out.println("===============================================");
|
||||
|
||||
CyclicBarrier barrier = new CyclicBarrier(3);
|
||||
|
||||
WorkerWithCyclicBarrier worker1 = new WorkerWithCyclicBarrier("Worker with barrier 1", barrier);
|
||||
WorkerWithCyclicBarrier worker2 = new WorkerWithCyclicBarrier("Worker with barrier 2", barrier);
|
||||
|
||||
worker1.start();
|
||||
worker2.start();
|
||||
|
||||
Thread.sleep(10);//simulation of some actual work
|
||||
|
||||
System.out.println("-----------------------------------------------");
|
||||
System.out.println(" Now open the barrier:");
|
||||
System.out.println("-----------------------------------------------");
|
||||
barrier.await();
|
||||
}
|
||||
|
||||
private static void usingPhaser() throws InterruptedException {
|
||||
System.out.println("\n===============================================");
|
||||
System.out.println(" >>> Using Phaser <<<");
|
||||
System.out.println("===============================================");
|
||||
|
||||
Phaser phaser = new Phaser();
|
||||
phaser.register();
|
||||
|
||||
WorkerWithPhaser worker1 = new WorkerWithPhaser("Worker with phaser 1", phaser);
|
||||
WorkerWithPhaser worker2 = new WorkerWithPhaser("Worker with phaser 2", phaser);
|
||||
|
||||
worker1.start();
|
||||
worker2.start();
|
||||
|
||||
Thread.sleep(10);//simulation of some actual work
|
||||
|
||||
System.out.println("-----------------------------------------------");
|
||||
System.out.println(" Now open the phaser barrier:");
|
||||
System.out.println("-----------------------------------------------");
|
||||
phaser.arriveAndAwaitAdvance();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.threadsstartatsametime;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class WorkerWithCountDownLatch extends Thread {
|
||||
private CountDownLatch latch;
|
||||
|
||||
public WorkerWithCountDownLatch(String name, CountDownLatch latch) {
|
||||
this.latch = latch;
|
||||
setName(name);
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
try {
|
||||
System.out.printf("[ %s ] created, blocked by the latch\n", getName());
|
||||
latch.await();
|
||||
System.out.printf("[ %s ] starts at: %s\n", getName(), Instant.now());
|
||||
// do actual work here...
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.threadsstartatsametime;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
|
||||
public class WorkerWithCyclicBarrier extends Thread {
|
||||
private CyclicBarrier barrier;
|
||||
|
||||
public WorkerWithCyclicBarrier(String name, CyclicBarrier barrier) {
|
||||
this.barrier = barrier;
|
||||
this.setName(name);
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
try {
|
||||
System.out.printf("[ %s ] created, blocked by the barrier\n", getName());
|
||||
barrier.await();
|
||||
System.out.printf("[ %s ] starts at: %s\n", getName(), Instant.now());
|
||||
// do actual work here...
|
||||
} catch (InterruptedException | BrokenBarrierException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.threadsstartatsametime;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Phaser;
|
||||
|
||||
public class WorkerWithPhaser extends Thread {
|
||||
private Phaser phaser;
|
||||
|
||||
public WorkerWithPhaser(String name, Phaser phaser) {
|
||||
this.phaser = phaser;
|
||||
phaser.register();
|
||||
setName(name);
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
try {
|
||||
System.out.printf("[ %s ] created, blocked by the phaser\n", getName());
|
||||
phaser.arriveAndAwaitAdvance();
|
||||
System.out.printf("[ %s ] starts at: %s\n", getName(), Instant.now());
|
||||
// do actual work here...
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,4 +13,5 @@ This module contains articles about basic Java concurrency
|
|||
- [Why are Local Variables Thread-Safe in Java](https://www.baeldung.com/java-local-variables-thread-safe)
|
||||
- [How to Stop Execution After a Certain Time in Java](https://www.baeldung.com/java-stop-execution-after-certain-time)
|
||||
- [How to Handle InterruptedException in Java](https://www.baeldung.com/java-interrupted-exception)
|
||||
- [How to Get the Number of Threads in a Java Process](https://www.baeldung.com/java-get-number-of-threads)
|
||||
- [[<-- Prev]](/core-java-modules/core-java-concurrency-basic)
|
||||
|
|
|
@ -36,6 +36,16 @@
|
|||
|
||||
<build>
|
||||
<finalName>core-java-io-conversions-2</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${source.version}</source>
|
||||
<target>${target.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
|
@ -45,6 +55,8 @@
|
|||
</build>
|
||||
|
||||
<properties>
|
||||
<source.version>11</source.version>
|
||||
<target.version>11</target.version>
|
||||
<json.version>20200518</json.version>
|
||||
<opencsv.version>4.1</opencsv.version>
|
||||
</properties>
|
||||
|
|
|
@ -21,11 +21,11 @@ import java.io.InputStream;
|
|||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Scanner;
|
||||
import java.util.UUID;
|
||||
|
@ -70,6 +70,16 @@ public class JavaInputStreamToXUnitTest {
|
|||
assertThat(text, equalTo(originalString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUsingJava9_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException {
|
||||
final String originalString = randomAlphabetic(DEFAULT_SIZE);
|
||||
final InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());
|
||||
|
||||
final String text = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
|
||||
assertThat(text, equalTo(originalString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void givenUsingJava7_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException {
|
||||
final String originalString = randomAlphabetic(DEFAULT_SIZE);
|
||||
|
@ -155,15 +165,13 @@ public class JavaInputStreamToXUnitTest {
|
|||
|
||||
@Test
|
||||
public final void whenConvertingToFile_thenCorrect() throws IOException {
|
||||
final InputStream initialStream = new FileInputStream(new File("src/test/resources/sample.txt"));
|
||||
final byte[] buffer = new byte[initialStream.available()];
|
||||
initialStream.read(buffer);
|
||||
final Path path = Paths.get("src/test/resources/sample.txt");
|
||||
final byte[] buffer = java.nio.file.Files.readAllBytes(path);
|
||||
|
||||
final File targetFile = new File("src/test/resources/targetFile.tmp");
|
||||
final OutputStream outStream = new FileOutputStream(targetFile);
|
||||
outStream.write(buffer);
|
||||
|
||||
IOUtils.closeQuietly(initialStream);
|
||||
IOUtils.closeQuietly(outStream);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,3 +7,4 @@ This module contains articles about core features in the Java language
|
|||
- [What are Compile-time Constants in Java?](https://www.baeldung.com/java-compile-time-constants)
|
||||
- [Java Objects.hash() vs Objects.hashCode()](https://www.baeldung.com/java-objects-hash-vs-objects-hashcode)
|
||||
- [Referencing a Method in Javadoc Comments](https://www.baeldung.com/java-method-in-javadoc)
|
||||
- [Tiered Compilation in JVM](https://www.baeldung.com/jvm-tiered-compilation)
|
||||
|
|
|
@ -21,6 +21,16 @@
|
|||
<artifactId>jmh-core</artifactId>
|
||||
<version>${jmh-core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung.tieredcompilation;
|
||||
|
||||
public class Article {
|
||||
|
||||
private String name;
|
||||
private String author;
|
||||
|
||||
public Article(String name, String author) {
|
||||
this.name = name;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.tieredcompilation;
|
||||
|
||||
public interface Formatter {
|
||||
|
||||
<T> String format(T object) throws Exception;
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.tieredcompilation;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
|
||||
public class JsonFormatter implements Formatter {
|
||||
|
||||
private static final JsonMapper mapper = new JsonMapper();
|
||||
|
||||
@Override
|
||||
public <T> String format(T object) throws JsonProcessingException {
|
||||
return mapper.writeValueAsString(object);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.baeldung.tieredcompilation;
|
||||
|
||||
public class TieredCompilation {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
for (int i = 0; i < 1_000_000; i++) {
|
||||
Formatter formatter;
|
||||
if (i < 500_000) {
|
||||
formatter = new JsonFormatter();
|
||||
} else {
|
||||
formatter = new XmlFormatter();
|
||||
}
|
||||
formatter.format(new Article("Tiered Compilation in JVM", "Baeldung"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.tieredcompilation;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
|
||||
public class XmlFormatter implements Formatter {
|
||||
|
||||
private static final XmlMapper mapper = new XmlMapper();
|
||||
|
||||
@Override
|
||||
public <T> String format(T object) throws JsonProcessingException {
|
||||
return mapper.writeValueAsString(object);
|
||||
}
|
||||
|
||||
}
|
|
@ -5,4 +5,5 @@ This module contains article about constructors in Java
|
|||
### Relevant Articles:
|
||||
- [A Guide to Constructors in Java](https://www.baeldung.com/java-constructors)
|
||||
- [Java Copy Constructor](https://www.baeldung.com/java-copy-constructor)
|
||||
- [Cannot Reference “X” Before Supertype Constructor Has Been Called](https://www.baeldung.com/java-cannot-reference-x-before-supertype-constructor-error)
|
||||
- [Cannot Reference “X” Before Supertype Constructor Has Been Called](https://www.baeldung.com/java-cannot-reference-x-before-supertype-constructor-error)
|
||||
- [Private Constructors in Java](https://www.baeldung.com/java-private-constructors)
|
||||
|
|
|
@ -9,4 +9,5 @@ This module contains articles about modifiers in Java
|
|||
- [The “final” Keyword in Java](https://www.baeldung.com/java-final)
|
||||
- [A Guide to the Static Keyword in Java](https://www.baeldung.com/java-static)
|
||||
- [Static and Default Methods in Interfaces in Java](https://www.baeldung.com/java-static-default-methods)
|
||||
- [The strictfp Keyword in Java](https://www.baeldung.com/java-strictfp)
|
||||
- [The strictfp Keyword in Java](https://www.baeldung.com/java-strictfp)
|
||||
- [Static Classes Versus the Singleton Pattern in Java](https://www.baeldung.com/java-static-class-vs-singleton)
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.staticsingletondifference;
|
||||
|
||||
public class CachingSingleton implements SingletonInterface {
|
||||
|
||||
private CachingSingleton() {
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
public static final CachingSingleton instance = new CachingSingleton();
|
||||
}
|
||||
|
||||
public static CachingSingleton getInstance() {
|
||||
return SingletonHolder.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describeMe() {
|
||||
return "Caching Responsibilities";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String passOnLocks(MyLock lock) {
|
||||
return lock.takeLock(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increment() {
|
||||
throw new UnsupportedOperationException("Not Supported Here");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.baeldung.staticsingletondifference;
|
||||
|
||||
public class FileSystemSingleton implements SingletonInterface{
|
||||
|
||||
private int filesWritten;
|
||||
|
||||
private FileSystemSingleton() {
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
public static final FileSystemSingleton instance = new FileSystemSingleton();
|
||||
}
|
||||
|
||||
public static FileSystemSingleton getInstance() {
|
||||
return SingletonHolder.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describeMe() {
|
||||
return "File System Responsibilities";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String passOnLocks(MyLock lock) {
|
||||
return lock.takeLock(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increment() {
|
||||
this.filesWritten++;
|
||||
}
|
||||
|
||||
public int getFilesWritten() {
|
||||
return filesWritten;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.staticsingletondifference;
|
||||
|
||||
public class MyLock {
|
||||
|
||||
protected String takeLock(int locks) {
|
||||
return "Taken Specific Lock";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.baeldung.staticsingletondifference;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class SerializableCloneableSingleton implements SingletonInterface, Serializable, Cloneable {
|
||||
|
||||
private static final long serialVersionUID = -1917003064592196223L;
|
||||
|
||||
private int state;
|
||||
|
||||
private SerializableCloneableSingleton() {
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
public static final SerializableCloneableSingleton instance = new SerializableCloneableSingleton();
|
||||
}
|
||||
|
||||
public static SerializableCloneableSingleton getInstance() {
|
||||
return SingletonHolder.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describeMe() {
|
||||
throw new UnsupportedOperationException("Not Supported Here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String passOnLocks(MyLock lock) {
|
||||
throw new UnsupportedOperationException("Not Supported Here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increment() {
|
||||
this.state++;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
return SingletonHolder.instance;
|
||||
}
|
||||
|
||||
public Object cloneObject() throws CloneNotSupportedException {
|
||||
return this.clone();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.baeldung.staticsingletondifference;
|
||||
|
||||
public interface SingletonInterface {
|
||||
|
||||
public String describeMe();
|
||||
|
||||
public String passOnLocks(MyLock lock);
|
||||
|
||||
public void increment();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.staticsingletondifference;
|
||||
|
||||
public class SingletonLock extends MyLock {
|
||||
|
||||
private SingletonLock() {
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
public static final SingletonLock instance = new SingletonLock();
|
||||
}
|
||||
|
||||
public static SingletonLock getInstance() {
|
||||
return SingletonHolder.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String takeLock(int locks) {
|
||||
return "Taken Singleton Lock";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.staticsingletondifference;
|
||||
|
||||
public class SubUtility extends SuperUtility {
|
||||
|
||||
public static String echoIt(String data) {
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.staticsingletondifference;
|
||||
|
||||
public class SuperUtility {
|
||||
|
||||
public static String echoIt(String data) {
|
||||
return "SUPER";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.baeldung.staticsingletondifference;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ForSingletonsUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenStaticUtilClassInheritance_thenOverridingFails() {
|
||||
SuperUtility superUtility = new SubUtility();
|
||||
Assert.assertNotEquals("ECHO", superUtility.echoIt("ECHO"));
|
||||
Assert.assertEquals("SUPER", superUtility.echoIt("ECHO"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSingletonDerivesBaseClass_thenRuntimePolymorphism() {
|
||||
MyLock myLock = new MyLock();
|
||||
Assert.assertEquals("Taken Specific Lock", myLock.takeLock(10));
|
||||
myLock = SingletonLock.getInstance();
|
||||
Assert.assertEquals("Taken Singleton Lock", myLock.takeLock(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSingletonImplementsInterface_thenRuntimePolymorphism() {
|
||||
SingletonInterface singleton = FileSystemSingleton.getInstance();
|
||||
Assert.assertEquals("File System Responsibilities", singleton.describeMe());
|
||||
singleton = CachingSingleton.getInstance();
|
||||
Assert.assertEquals("Caching Responsibilities", singleton.describeMe());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSingleton_thenPassAsArguments() {
|
||||
SingletonInterface singleton = FileSystemSingleton.getInstance();
|
||||
Assert.assertEquals("Taken Singleton Lock", singleton.passOnLocks(SingletonLock.getInstance()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSingleton_thenAllowState() {
|
||||
SingletonInterface singleton = FileSystemSingleton.getInstance();
|
||||
IntStream.range(0, 5)
|
||||
.forEach(i -> singleton.increment());
|
||||
Assert.assertEquals(5, ((FileSystemSingleton) singleton).getFilesWritten());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSingleton_thenAllowSerializationDeserialization() {
|
||||
SingletonInterface singleton = SerializableCloneableSingleton.getInstance();
|
||||
singleton.increment();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
new ObjectOutputStream(baos).writeObject(singleton);
|
||||
SerializableCloneableSingleton singletonNew = (SerializableCloneableSingleton) new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject();
|
||||
Assert.assertEquals(1, singletonNew.getState());
|
||||
Assert.assertEquals(singleton.hashCode(), singletonNew.hashCode());
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSingleton_thenAllowCloneable() {
|
||||
SerializableCloneableSingleton singleton = SerializableCloneableSingleton.getInstance();
|
||||
singleton.increment();
|
||||
try {
|
||||
Assert.assertEquals(2, ((SerializableCloneableSingleton) singleton.cloneObject()).getState());
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,3 +3,5 @@
|
|||
This module contains articles about Java operators
|
||||
|
||||
## Relevant Articles:
|
||||
|
||||
- [Logical vs Bitwise OR Operator](https://www.baeldung.com/java-logical-vs-bitwise-or-operator)
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package com.baeldung.oroperators;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class BitmaskingUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenIntegerShouldPrintBinaryRepresentation() {
|
||||
// given
|
||||
int intRepresentation = 1094795523;
|
||||
|
||||
// expected
|
||||
String stringRepresentation = getStringRepresentation(intRepresentation);
|
||||
assertEquals(stringRepresentation, "01000001010000010100000100000011");
|
||||
}
|
||||
|
||||
private String getStringRepresentation(int intRepresentation) {
|
||||
String binaryString = Integer.toBinaryString(intRepresentation);
|
||||
return padWithZeros(binaryString);
|
||||
}
|
||||
|
||||
private String padWithZeros(String binaryString) {
|
||||
return String.format("%" + 32 + "s", binaryString).replace(' ', '0');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenBinaryRepresentationShouldReturnNumber() {
|
||||
// given
|
||||
String stringRepresentation = "01000001010000010100000100000011";
|
||||
|
||||
// expected
|
||||
int intRepresentation = Integer.parseUnsignedInt(stringRepresentation, 2);
|
||||
assertEquals(intRepresentation, 1094795523);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenBinaryRepresentationShouldReturnCharacter() {
|
||||
// given
|
||||
String stringRepresentation = "010000010100000101000001";
|
||||
|
||||
// expected
|
||||
assertEquals(binaryToText(stringRepresentation), "AAA");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIntAndPositionNumberShouldReturnBitValue() {
|
||||
// given
|
||||
String stringRepresentation = "010000010100000101000001000000011";
|
||||
int intRepresentation = Integer.parseUnsignedInt(stringRepresentation, 2);
|
||||
|
||||
// when
|
||||
boolean value1 = extractValueAtPosition(intRepresentation, 1);
|
||||
boolean value2 = extractValueAtPosition(intRepresentation, 2);
|
||||
boolean value3 = extractValueAtPosition(intRepresentation, 3);
|
||||
|
||||
// then
|
||||
assertTrue(value1);
|
||||
assertTrue(value2);
|
||||
assertFalse(value3);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIntegerShouldExtractLastThreeBytes() {
|
||||
// given
|
||||
int intRepresentation = 1094795523;
|
||||
|
||||
// when
|
||||
int lastThreeBites = intRepresentation >> 8;
|
||||
|
||||
// expected
|
||||
String stringRepresentation = getStringRepresentation(lastThreeBites);
|
||||
assertEquals(stringRepresentation, "00000000010000010100000101000001");
|
||||
assertEquals(binaryToText(stringRepresentation), "AAA");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIntegerShouldApplyMask() {
|
||||
// given
|
||||
int intRepresentation = Integer.parseUnsignedInt("00000000010000010100000101000001", 2);
|
||||
int mask = Integer.parseUnsignedInt("00000000000000000000000000000011", 2);
|
||||
int mask2 = Integer.parseUnsignedInt("00000000000000000000000000000001", 2);
|
||||
|
||||
// when
|
||||
int masked = intRepresentation & mask;
|
||||
int masked2 = intRepresentation & mask2;
|
||||
|
||||
// expected
|
||||
assertEquals(getStringRepresentation(masked), "00000000000000000000000000000001");
|
||||
assertEquals(getStringRepresentation(masked2), "00000000000000000000000000000001");
|
||||
assertNotEquals(masked, mask);
|
||||
assertEquals(masked2, mask2);
|
||||
assertFalse((intRepresentation & mask) == mask);
|
||||
}
|
||||
|
||||
private boolean extractValueAtPosition(int intRepresentation, int position) {
|
||||
String mask = getStringRepresentation(1 << (position - 1));
|
||||
System.out.println(getStringRepresentation(intRepresentation));
|
||||
System.out.println(mask);
|
||||
System.out.println("-------------------------------- &");
|
||||
System.out.println(getStringRepresentation((intRepresentation) & (1 << (position - 1))));
|
||||
System.out.println();
|
||||
return ((intRepresentation) & (1 << (position - 1))) != 0;
|
||||
}
|
||||
|
||||
private static String binaryToText(String stringRepresentation) {
|
||||
return Arrays.stream(stringRepresentation.split("(?<=\\G.{8})"))
|
||||
.filter(eightBits -> !eightBits.equals("00000000"))
|
||||
.map(eightBits -> (char)Integer.parseInt(eightBits, 2))
|
||||
.collect(
|
||||
StringBuilder::new,
|
||||
StringBuilder::append,
|
||||
StringBuilder::append
|
||||
).toString();
|
||||
}
|
||||
}
|
|
@ -47,6 +47,24 @@
|
|||
<artifactId>javax.mail</artifactId>
|
||||
<version>1.6.2</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.github.seancfoley/ipaddress -->
|
||||
<dependency>
|
||||
<groupId>com.github.seancfoley</groupId>
|
||||
<artifactId>ipaddress</artifactId>
|
||||
<version>${seancfoley.ipaddress.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.github.jgonian/commons-ip-math -->
|
||||
<dependency>
|
||||
<groupId>com.github.jgonian</groupId>
|
||||
<artifactId>commons-ip-math</artifactId>
|
||||
<version>${jgonian.commons-ip-math.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.googlecode.java-ipv6/java-ipv6 -->
|
||||
<dependency>
|
||||
<groupId>com.googlecode.java-ipv6</groupId>
|
||||
<artifactId>java-ipv6</artifactId>
|
||||
<version>${googlecode.ipv6.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -66,6 +84,9 @@
|
|||
<jetty.embeded.version>9.4.31.v20200723</jetty.embeded.version>
|
||||
<tomcat.embeded.version>10.0.0-M7</tomcat.embeded.version>
|
||||
<assertj.version>3.11.1</assertj.version>
|
||||
<seancfoley.ipaddress.version>5.3.3</seancfoley.ipaddress.version>
|
||||
<jgonian.commons-ip-math.version>1.32</jgonian.commons-ip-math.version>
|
||||
<googlecode.ipv6.version>0.17</googlecode.ipv6.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,81 @@
|
|||
package com.baeldung.ipingivenrange;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import inet.ipaddr.IPAddress;
|
||||
import inet.ipaddr.IPAddressSeqRange;
|
||||
import inet.ipaddr.IPAddressString;
|
||||
import inet.ipaddr.AddressStringException;
|
||||
|
||||
import com.github.jgonian.ipmath.Ipv4;
|
||||
import com.github.jgonian.ipmath.Ipv4Range;
|
||||
import com.github.jgonian.ipmath.Ipv6;
|
||||
import com.github.jgonian.ipmath.Ipv6Range;
|
||||
import com.googlecode.ipv6.IPv6Address;
|
||||
import com.googlecode.ipv6.IPv6AddressRange;
|
||||
|
||||
public class IPWithGivenRangeCheck {
|
||||
|
||||
// using IPAddress library
|
||||
public static boolean checkIPIsInGivenRange(String inputIP, String rangeStartIP, String rangeEndIP) throws AddressStringException {
|
||||
IPAddress startIPAddress = new IPAddressString(rangeStartIP).getAddress();
|
||||
IPAddress endIPAddress = new IPAddressString(rangeEndIP).getAddress();
|
||||
IPAddressSeqRange ipRange = startIPAddress.toSequentialRange(endIPAddress);
|
||||
IPAddress inputIPAddress = new IPAddressString(inputIP).toAddress();
|
||||
|
||||
return ipRange.contains(inputIPAddress);
|
||||
}
|
||||
|
||||
// using Commons IP Math library for IPv4
|
||||
public static boolean checkIPv4IsInRange(String inputIP, String rangeStartIP, String rangeEndIP) {
|
||||
Ipv4 startIPAddress = Ipv4.of(rangeStartIP);
|
||||
Ipv4 endIPAddress = Ipv4.of(rangeEndIP);
|
||||
Ipv4Range ipRange = Ipv4Range.from(startIPAddress)
|
||||
.to(endIPAddress);
|
||||
Ipv4 inputIPAddress = Ipv4.of(inputIP);
|
||||
|
||||
return ipRange.contains(inputIPAddress);
|
||||
}
|
||||
|
||||
// using Commons IP Math library for IPv6
|
||||
public static boolean checkIPv6IsInRange(String inputIP, String rangeStartIP, String rangeEndIP) {
|
||||
Ipv6 startIPAddress = Ipv6.of(rangeStartIP);
|
||||
Ipv6 endIPAddress = Ipv6.of(rangeEndIP);
|
||||
Ipv6Range ipRange = Ipv6Range.from(startIPAddress)
|
||||
.to(endIPAddress);
|
||||
Ipv6 inputIPAddress = Ipv6.of(inputIP);
|
||||
|
||||
return ipRange.contains(inputIPAddress);
|
||||
}
|
||||
|
||||
// checking IP is in range by converting it to an integer
|
||||
public static boolean checkIPv4IsInRangeByConvertingToInt(String inputIP, String rangeStartIP, String rangeEndIP) throws UnknownHostException {
|
||||
long startIPAddress = ipToLongInt(InetAddress.getByName(rangeStartIP));
|
||||
long endIPAddress = ipToLongInt(InetAddress.getByName(rangeEndIP));
|
||||
long inputIPAddress = ipToLongInt(InetAddress.getByName(inputIP));
|
||||
|
||||
return (inputIPAddress >= startIPAddress && inputIPAddress <= endIPAddress);
|
||||
}
|
||||
|
||||
private static long ipToLongInt(InetAddress ipAddress) {
|
||||
long resultIP = 0;
|
||||
byte[] ipAddressOctets = ipAddress.getAddress();
|
||||
|
||||
for (byte octet : ipAddressOctets) {
|
||||
resultIP <<= 8;
|
||||
resultIP |= octet & 0xFF;
|
||||
}
|
||||
return resultIP;
|
||||
}
|
||||
|
||||
// using Java IPv6 library (which internally uses two long integers to store ip address)
|
||||
public static boolean checkIPv6IsInRangeByIPv6library(String inputIP, String rangeStartIP, String rangeEndIP) {
|
||||
IPv6Address startIPAddress = IPv6Address.fromString(rangeStartIP);
|
||||
IPv6Address endIPAddress = IPv6Address.fromString(rangeEndIP);
|
||||
IPv6AddressRange ipRange = IPv6AddressRange.fromFirstAndLast(startIPAddress, endIPAddress);
|
||||
IPv6Address inputIPAddress = IPv6Address.fromString(inputIP);
|
||||
|
||||
return ipRange.contains(inputIPAddress);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.baeldung.ipingivenrange;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.ipingivenrange.IPWithGivenRangeCheck;
|
||||
|
||||
class IPWithGivenRangeCheckUnitTest {
|
||||
|
||||
@Test
|
||||
void givenIPv4Addresses_whenIsInRange_thenReturnsTrue() throws Exception {
|
||||
// test for IPAddress library
|
||||
assertTrue(IPWithGivenRangeCheck.checkIPIsInGivenRange("192.220.3.0", "192.210.0.0", "192.255.0.0"));
|
||||
|
||||
// test for Common IP Math library
|
||||
assertTrue(IPWithGivenRangeCheck.checkIPv4IsInRange("192.220.3.0", "192.210.0.0", "192.255.0.0"));
|
||||
|
||||
// test for IPv4 by converting it to an integer and checking if it falls under the specified range.
|
||||
assertTrue(IPWithGivenRangeCheck.checkIPv4IsInRangeByConvertingToInt("192.220.3.0", "192.210.0.0", "192.255.0.0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIPv4Addresses_whenIsNotInRange_thenReturnsFalse() throws Exception {
|
||||
// test for IPAddress library
|
||||
assertFalse(IPWithGivenRangeCheck.checkIPIsInGivenRange("192.200.0.0", "192.210.0.0", "192.255.0.0"));
|
||||
|
||||
// test for Common IP Math library
|
||||
assertFalse(IPWithGivenRangeCheck.checkIPv4IsInRange("192.200.0.0", "192.210.0.0", "192.255.0.0"));
|
||||
|
||||
// test for IPv4 by converting it to an integer and checking if it falls under the specified range.
|
||||
assertFalse(IPWithGivenRangeCheck.checkIPv4IsInRangeByConvertingToInt("192.200.0.0", "192.210.0.0", "192.255.0.0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIPv6Addresses_whenIsInRange_thenReturnsTrue() throws Exception {
|
||||
// test for IPAddress library
|
||||
assertTrue(IPWithGivenRangeCheck.checkIPIsInGivenRange("2001:db8:85a3::8a03:a:b", "2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a2e:370:7334"));
|
||||
|
||||
// test for Common IP Math library
|
||||
assertTrue(IPWithGivenRangeCheck.checkIPv6IsInRange("2001:db8:85a3::8a03:a:b", "2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a2e:370:7334"));
|
||||
|
||||
// test for Java IPv6 library
|
||||
assertTrue(IPWithGivenRangeCheck.checkIPv6IsInRangeByIPv6library("fe80::226:2dff:fefa:dcba", "fe80::226:2dff:fefa:cd1f", "fe80::226:2dff:fefa:ffff"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIPv6Addresses_whenIsNotInRange_thenReturnsFalse() throws Exception {
|
||||
// test for IPAddress library
|
||||
assertFalse(IPWithGivenRangeCheck.checkIPIsInGivenRange("2002:db8:85a3::8a03:a:b", "2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a2e:370:7334"));
|
||||
|
||||
// test for Common IP Math library
|
||||
assertFalse(IPWithGivenRangeCheck.checkIPv6IsInRange("2002:db8:85a3::8a03:a:b", "2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a2e:370:7334"));
|
||||
|
||||
// test for Java IPv6 library
|
||||
assertFalse(IPWithGivenRangeCheck.checkIPv6IsInRangeByIPv6library("2002:db8:85a3::8a03:a:b", "2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a2e:370:7334"));
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Non-Capturing Regex Groups in Java](https://www.baeldung.com/java-regex-non-capturing-groups)
|
||||
- [Lookahead and Lookbehind in Java Regex](https://www.baeldung.com/java-regex-lookahead-lookbehind)
|
||||
- [Converting Camel Case and Title Case to Words in Java](https://www.baeldung.com/java-camel-case-title-case-to-words)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.regex.camelcasetowords;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Convert a string in camelCase or TitleCase into a list of words
|
||||
*/
|
||||
public class CamelCaseToWords {
|
||||
private static final Pattern WORD_FINDER = Pattern.compile("(([A-Z]?[a-z]+)|([A-Z]))");
|
||||
|
||||
/**
|
||||
* Find the words in mixed case string like ThisIsText or HereIsSomeText
|
||||
* @param text the text to parse
|
||||
* @return the list of words to process
|
||||
*/
|
||||
public static List<String> findWordsInMixedCase(String text) {
|
||||
Matcher matcher = WORD_FINDER.matcher(text);
|
||||
List<String> words = new ArrayList<>();
|
||||
while (matcher.find()) {
|
||||
words.add(matcher.group(0));
|
||||
}
|
||||
return words;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.baeldung.regex.camelcasetowords;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Recapitalize {
|
||||
private static final Set<String> STOP_WORDS = Stream.of("a", "an", "the", "and",
|
||||
"but", "for", "at", "by", "to", "or")
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
public static String sentenceCase(List<String> words) {
|
||||
List<String> capitalized = new ArrayList<>();
|
||||
for (int i = 0; i < words.size(); i++) {
|
||||
String currentWord = words.get(i);
|
||||
if (i == 0) {
|
||||
capitalized.add(capitalizeFirst(currentWord));
|
||||
} else {
|
||||
capitalized.add(currentWord.toLowerCase());
|
||||
}
|
||||
}
|
||||
return String.join(" ", capitalized) + ".";
|
||||
}
|
||||
|
||||
public static String capitalizeMyTitle(List<String> words) {
|
||||
List<String> capitalized = new ArrayList<>();
|
||||
for (int i = 0; i < words.size(); i++) {
|
||||
String currentWord = words.get(i);
|
||||
if (i == 0 || !STOP_WORDS.contains(currentWord.toLowerCase())) {
|
||||
capitalized.add(capitalizeFirst(currentWord));
|
||||
} else {
|
||||
capitalized.add(currentWord.toLowerCase());
|
||||
}
|
||||
}
|
||||
return String.join(" ", capitalized);
|
||||
}
|
||||
|
||||
private static String capitalizeFirst(String word) {
|
||||
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.baeldung.regex.camelcasetowords;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.baeldung.regex.camelcasetowords.CamelCaseToWords.findWordsInMixedCase;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class CamelCaseToWordsUnitTest {
|
||||
|
||||
@Test
|
||||
void givenPlainStringWithNonLetters_thenFindsWords() {
|
||||
assertThat(findWordsInMixedCase("some words"))
|
||||
.containsExactly("some", "words");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenWordsInCamelCase_thenFindsWords() {
|
||||
assertThat(findWordsInMixedCase("thisIsCamelCaseText"))
|
||||
.containsExactly("this", "Is", "Camel", "Case", "Text");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenWordsInTitleCase_thenFindsWords() {
|
||||
assertThat(findWordsInMixedCase("ThisIsTitleCaseText"))
|
||||
.containsExactly("This", "Is", "Title", "Case", "Text");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenWordsAcrossMultipleTexts_thenFindsWords() {
|
||||
assertThat(findWordsInMixedCase("ThisIsTitleCaseText --- andSoIsThis"))
|
||||
.containsExactly("This", "Is", "Title", "Case", "Text", "and", "So", "Is", "This");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenCamelCaseHasASingleLetterWord_thenItCanBeSplit() {
|
||||
assertThat(findWordsInMixedCase("thisHasASingleLetterWord"))
|
||||
.containsExactly("this", "Has", "A", "Single", "Letter", "Word");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.regex.camelcasetowords;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.baeldung.regex.camelcasetowords.Recapitalize.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class RecapitalizeUnitTest {
|
||||
|
||||
@Test
|
||||
void givenWords_thenCanComposeSentence() {
|
||||
assertThat(sentenceCase(Arrays.asList("these", "Words", "Form", "A", "Sentence")))
|
||||
.isEqualTo("These words form a sentence.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNonStopWords_thenTitleIsComposed() {
|
||||
assertThat(capitalizeMyTitle(Arrays.asList("title", "words", "capitalize")))
|
||||
.isEqualTo("Title Words Capitalize");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenStopWords_thenTitleHasThemInLowerCase() {
|
||||
assertThat(capitalizeMyTitle(Arrays.asList("this", "is", "A", "title", "with", "a", "stop", "word", "or", "two")))
|
||||
.isEqualTo("This Is a Title With a Stop Word or Two");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenStopWordIsFirstWord_thenTitleHasItCapitalized() {
|
||||
assertThat(capitalizeMyTitle(Arrays.asList("a", "stop", "word", "first")))
|
||||
.isEqualTo("A Stop Word First");
|
||||
}
|
||||
}
|
|
@ -17,4 +17,5 @@ This module contains articles about core Java Security
|
|||
- [InvalidAlgorithmParameterException: Wrong IV Length](https://www.baeldung.com/java-invalidalgorithmparameter-exception)
|
||||
- [The java.security.egd JVM Option](https://www.baeldung.com/java-security-egd)
|
||||
- [RSA in Java](https://www.baeldung.com/java-rsa)
|
||||
- [3DES in Java](https://www.baeldung.com/java-3des)
|
||||
- More articles: [[<-- prev]](/core-java-modules/core-java-security)
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package com.baeldung.des;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class TripleDESUnitTest {
|
||||
|
||||
@Test
|
||||
public void given3DesKey_whenEncryptAndDecryptString_thenCompareResults() throws Exception {
|
||||
byte[] secretKey = "9mng65v8jf4lxn93nabf981m".getBytes();
|
||||
byte[] iv = "a76nb5h9".getBytes();
|
||||
|
||||
String secretMessage = "Baeldung secret message";
|
||||
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, "DESede");
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
Cipher encryptCipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
|
||||
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
|
||||
byte[] secretMessagesBytes = secretMessage.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessagesBytes);
|
||||
|
||||
Cipher decryptCipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
|
||||
decryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
|
||||
byte[] decryptedMessageBytes = decryptCipher.doFinal(encryptedMessageBytes);
|
||||
String decryptedMessage = new String(decryptedMessageBytes, StandardCharsets.UTF_8);
|
||||
|
||||
Assertions.assertEquals(secretMessage, decryptedMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void given3DesKey_whenEncryptAndDecryptFile_thenCompareResults() throws Exception {
|
||||
byte[] secretKey = "9mng65v8jf4lxn93nabf981m".getBytes();
|
||||
byte[] iv = "a76nb5h9".getBytes();
|
||||
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, "DESede");
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
|
||||
String originalContent = "some secret message";
|
||||
Path tempFile = Files.createTempFile("temp", "txt");
|
||||
writeString(tempFile, originalContent);
|
||||
|
||||
byte[] fileBytes = Files.readAllBytes(tempFile);
|
||||
Cipher encryptCipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
|
||||
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
|
||||
byte[] encryptedFileBytes = encryptCipher.doFinal(fileBytes);
|
||||
try (FileOutputStream stream = new FileOutputStream(tempFile.toFile())) {
|
||||
stream.write(encryptedFileBytes);
|
||||
}
|
||||
|
||||
encryptedFileBytes = Files.readAllBytes(tempFile);
|
||||
Cipher decryptCipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
|
||||
decryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
|
||||
byte[] decryptedFileBytes = decryptCipher.doFinal(encryptedFileBytes);
|
||||
try (FileOutputStream stream = new FileOutputStream(tempFile.toFile())) {
|
||||
stream.write(decryptedFileBytes);
|
||||
}
|
||||
|
||||
String fileContent = readString(tempFile);
|
||||
|
||||
Assertions.assertEquals(originalContent, fileContent);
|
||||
}
|
||||
|
||||
private void writeString(Path path, String content) throws Exception {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
|
||||
writer.write(content);
|
||||
}
|
||||
}
|
||||
|
||||
private String readString(Path path) throws Exception {
|
||||
StringBuilder resultStringBuilder = new StringBuilder();
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(path.toFile()))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
resultStringBuilder.append(line);
|
||||
}
|
||||
}
|
||||
return resultStringBuilder.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
*.class
|
||||
|
||||
0.*
|
||||
|
||||
#folders#
|
||||
/target
|
||||
/neoDb*
|
||||
/data
|
||||
/src/main/webapp/WEB-INF/classes
|
||||
*/META-INF/*
|
||||
.resourceCache
|
||||
|
||||
# Packaged files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# Files generated by integration tests
|
||||
*.txt
|
||||
backup-pom.xml
|
||||
/bin/
|
||||
/temp
|
||||
|
||||
#IntelliJ specific
|
||||
.idea/
|
||||
*.iml
|
|
@ -0,0 +1,3 @@
|
|||
## Relevant Articles:
|
||||
|
||||
- [Count Occurrences Using Java groupingBy Collector](https://www.baeldung.com/java-groupingby-count)
|
|
@ -0,0 +1,63 @@
|
|||
<?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-streams-4</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>core-java-streams</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit</groupId>
|
||||
<artifactId>junit-bom</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>core-java-streams-4</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<compilerArgument>-parameters</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<!-- testing -->
|
||||
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,84 @@
|
|||
package com.baeldung.streamcollectors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class StreamGroupingByCollectorUnitTest {
|
||||
@Test
|
||||
public void givenListOfStrings_whenGroupingEqualStrings_thenUseCollectorsGroupingByToGroupEqualStringsAndCountOfOccurrences() {
|
||||
|
||||
List<String> list = new ArrayList<>(Arrays.asList("Foo", "Bar", "Bar", "Foo", "Bar"));
|
||||
|
||||
Map<String, Long> result = list.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
|
||||
Assert.assertEquals(new Long(2), result.get("Foo"));
|
||||
Assert.assertEquals(new Long(3), result.get("Bar"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenListOfStrings_whenGroupingEqualLengthStrings_thenUseCollectorsGroupingByConcurrentToGroupEqualLengthStringsAndCountOfOccurrences() {
|
||||
|
||||
List<String> list = new ArrayList<>(Arrays.asList("Adam", "Bill", "Jack", "Joe", "Ian"));
|
||||
|
||||
Map<Integer, Long> result = list.stream().collect(Collectors.groupingByConcurrent(String::length, Collectors.counting()));
|
||||
Assert.assertEquals(new Long(2), result.get(3));
|
||||
Assert.assertEquals(new Long(3), result.get(4));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenListOfEmployees_whenGroupingDepartmentId_thenUseCollectorsGroupingByDepartmentIdAndCountNumberOfEmployeesWithinEveryDepartment() {
|
||||
|
||||
List<Employee> list = new ArrayList<>(Arrays.asList(new Employee(1, "Joe", 1), new Employee(2, "Josh", 1), new Employee(3, "Jamie", 2), new Employee(4, "Jim", 2), new Employee(5, "Jack", 2)));
|
||||
|
||||
Map<Integer, Long> result = list.stream().collect(Collectors.groupingBy(Employee::getDepartmentId, Collectors.counting()));
|
||||
Assert.assertEquals(new Long(2), result.get(1));
|
||||
Assert.assertEquals(new Long(3), result.get(2));
|
||||
|
||||
}
|
||||
|
||||
static class Employee {
|
||||
|
||||
Integer employeeId;
|
||||
String employeeName;
|
||||
Integer departmentId;
|
||||
|
||||
Employee(Integer employeeId, String employeeName, Integer departmentId) {
|
||||
this.employeeId = employeeId;
|
||||
this.employeeName = employeeName;
|
||||
this.departmentId = departmentId;
|
||||
}
|
||||
|
||||
public Integer getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public void setEmployeeId(Integer employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
public String getEmployeeName() {
|
||||
return employeeName;
|
||||
}
|
||||
|
||||
public void setEmployeeName(String employeeName) {
|
||||
this.employeeName = employeeName;
|
||||
}
|
||||
|
||||
public Integer getDepartmentId() {
|
||||
return departmentId;
|
||||
}
|
||||
|
||||
public void setDepartmentId(Integer departmentId) {
|
||||
this.departmentId = departmentId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -7,4 +7,6 @@ This module contains articles about string conversions from/to another type.
|
|||
- [Convert String to Byte Array and Reverse in Java](https://www.baeldung.com/java-string-to-byte-array)
|
||||
- [Convert Character Array to String in Java](https://www.baeldung.com/java-char-array-to-string)
|
||||
- [Converting String to BigDecimal in Java](https://www.baeldung.com/java-string-to-bigdecimal)
|
||||
- [Converting String to BigInteger in Java](https://www.baeldung.com/java-string-to-biginteger)
|
||||
- [Convert a String to Camel Case](https://www.baeldung.com/java-string-to-camel-case)
|
||||
- More articles: [[<-- prev]](/core-java-string-conversions)
|
||||
|
|
|
@ -33,7 +33,39 @@
|
|||
<version>${hamcrest.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ibm.icu</groupId>
|
||||
<artifactId>icu4j</artifactId>
|
||||
<version>${icu.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
<version>${commons-text.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<properties>
|
||||
<icu.version>64.2</icu.version>
|
||||
<assertj.version>3.12.2</assertj.version>
|
||||
<commons-text.version>1.9</commons-text.version>
|
||||
<guava.version>30.1.1-jre</guava.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<finalName>core-java-string-conversions-2</finalName>
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
package com.baeldung.stringtocamelcase;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.ibm.icu.lang.UCharacter;
|
||||
import com.ibm.icu.text.BreakIterator;
|
||||
import org.apache.commons.text.CaseUtils;
|
||||
import org.apache.commons.text.WordUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StringToCamelCase {
|
||||
|
||||
public static String toCamelCaseByIteration(String text, char delimiter) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return text;
|
||||
}
|
||||
boolean shouldConvertNextCharToLower = true;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char currentChar = text.charAt(i);
|
||||
if (currentChar == delimiter) {
|
||||
shouldConvertNextCharToLower = false;
|
||||
} else if (shouldConvertNextCharToLower) {
|
||||
builder.append(Character.toLowerCase(currentChar));
|
||||
} else {
|
||||
builder.append(Character.toUpperCase(currentChar));
|
||||
shouldConvertNextCharToLower = true;
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String toCamelCaseBySplitting(String text, String delimiter) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return text;
|
||||
}
|
||||
String[] words = text.split(delimiter);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0, wordsLength = words.length; i < wordsLength; i++) {
|
||||
String word = words[i];
|
||||
if (i == 0) {
|
||||
//Make the first word all lowercase
|
||||
word = word.isEmpty() ? word : word.toLowerCase();
|
||||
} else {
|
||||
//Convert the first character to Uppercase and others to lowercase
|
||||
// e.g sTRING =====> String
|
||||
word = word.isEmpty() ? word : Character.toUpperCase(word.charAt(0)) + word.substring(1).toLowerCase();
|
||||
}
|
||||
builder.append(word);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String toCamelCaseBySplittingUsingStreams(String text, String delimiter) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return text;
|
||||
}
|
||||
String[] words = text.split(delimiter);
|
||||
//Convert the first word to lowercase and then every
|
||||
//other word to Title Case.
|
||||
String firstWord = words[0].toLowerCase();
|
||||
String otherWords = Arrays.stream(words, 1, words.length)
|
||||
.filter(word -> !word.isEmpty())
|
||||
.map(word -> Character.toUpperCase(word.charAt(0)) + word.substring(1).toLowerCase())
|
||||
.collect(Collectors.joining(""));
|
||||
|
||||
return firstWord + otherWords;
|
||||
}
|
||||
|
||||
public static String toCamelCaseByRegex(String text) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String[] words = text.split("[\\W_]+");
|
||||
for (int i = 0; i < words.length; i++) {
|
||||
String word = words[i];
|
||||
if (i == 0) {
|
||||
word = word.isEmpty() ? word : word.toLowerCase();
|
||||
} else {
|
||||
word = word.isEmpty() ? word : Character.toUpperCase(word.charAt(0)) + word.substring(1).toLowerCase();
|
||||
}
|
||||
builder.append(word);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
//Third-Party Libraries
|
||||
public static String toCamelCaseUsingICU4J(String text, String delimiter) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return text;
|
||||
}
|
||||
text = UCharacter.toTitleCase(text, BreakIterator.getTitleInstance()).replaceAll(delimiter, "");
|
||||
StringBuilder builder = new StringBuilder(text);
|
||||
builder.setCharAt(0, Character.toLowerCase(text.charAt(0)));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String toCamelCaseUsingGuava(String text, String delimiter) {
|
||||
String toUpperUnderscore = text.toUpperCase().replaceAll(delimiter, "_");
|
||||
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, toUpperUnderscore);
|
||||
}
|
||||
|
||||
public static String toCamelCaseUsingApacheCommons(String text, char delimiter) {
|
||||
text = WordUtils.capitalizeFully(text, delimiter).replaceAll(String.valueOf(delimiter), "");
|
||||
StringBuilder builder = new StringBuilder(text);
|
||||
builder.setCharAt(0, Character.toLowerCase(text.charAt(0)));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.baeldung.stringtobybiginteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class StringToBigIntegerUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenGetStringWithOutRadix_thenOK() {
|
||||
String inputString = "878";
|
||||
BigInteger result = new BigInteger(inputString);
|
||||
assertEquals("878", result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetStringWithRadix_thenOK() {
|
||||
String inputString = "290f98";
|
||||
BigInteger result = new BigInteger(inputString, 16);
|
||||
assertEquals("2690968", result.toString());
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void whenGetStringWithOutRadix_thenThrowError() {
|
||||
String inputString = "290f98";
|
||||
new BigInteger(inputString);
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void whenGetStringWithRadix_thenThrowError() {
|
||||
String inputString = "290f98";
|
||||
new BigInteger(inputString, 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetStringUsingByte_thenOk() {
|
||||
String inputString = "290f98";
|
||||
byte[] inputStringBytes = inputString.getBytes();
|
||||
BigInteger result = new BigInteger(inputStringBytes);
|
||||
assertEquals("290f98", new String(result.toByteArray()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package com.baeldung.stringtocamelcase;
|
||||
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import org.apache.commons.text.CaseUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.baeldung.stringtocamelcase.StringToCamelCase.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
|
||||
public class StringToCamelCaseUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenStringWithWhiteSpaces_WhenToCamelCaseByIteration_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseByIteration("THIS STRING SHOULD BE IN CAMEL CASE", ' ')).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithUnderscores_WhenToCamelCaseByIteration_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseByIteration("THIS_STRING_SHOULD_BE_IN_CAMEL_CASE", '_')).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithWhiteSpaces_WhenToCamelCaseBySplitting_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseBySplitting("THIS STRING SHOULD BE IN CAMEL CASE", " ")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithUnderscores_WhenToCamelCaseBySplitting_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseBySplitting("THIS_STRING_SHOULD_BE_IN_CAMEL_CASE", "_")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithWhiteSpaces_WhenToCamelCaseBySplittingUsingStreams_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseBySplittingUsingStreams("THIS STRING SHOULD BE IN CAMEL CASE", " ")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithUnderscores_WhenToCamelCaseBySplittingUsingStreams_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseBySplittingUsingStreams("THIS_STRING_SHOULD_BE_IN_CAMEL_CASE", "_")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithWhiteSpaces_WhenToCamelCaseUsingApacheCommonsText_ThenReturnCamelCase() {
|
||||
assertThat(CaseUtils.toCamelCase("THIS STRING SHOULD BE IN CAMEL CASE", false, ' '))
|
||||
.isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithUnderscores_WhenToCamelCaseUsingApacheCommonsText_ThenReturnCamelCase() {
|
||||
assertThat(CaseUtils.toCamelCase("THIS_STRING_SHOULD_BE_IN_CAMEL_CASE", false, '_'))
|
||||
.isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithWhiteSpaces_WhenToCamelCaseUsingICU4J_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseUsingICU4J("THIS STRING SHOULD BE IN CAMEL CASE", " ")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithUnderscores_WhenToCamelCaseUsingICU4J_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseUsingICU4J("THIS_STRING_SHOULD_BE_IN_CAMEL_CASE", "_")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithWhiteSpaces_WhenToCamelCaseUsingGuava_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseUsingGuava("THIS STRING SHOULD BE IN CAMEL CASE", " ")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithUnderscores_WhenToCamelCaseUsingGuava_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseUsingGuava("THIS_STRING_SHOULD_BE_IN_CAMEL_CASE", "_")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithWhiteSpaces_WhenToCamelCaseUsingApacheCommons_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseUsingApacheCommons("THIS STRING SHOULD BE IN CAMEL CASE", ' ')).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithUnderscores_WhenToCamelCaseUsingApacheCommons_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseUsingApacheCommons("THIS_STRING_SHOULD_BE_IN_CAMEL_CASE", '_')).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithWhiteSpaces_WhenToCamelCaseByRegex_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseByRegex("THIS STRING SHOULD BE IN CAMEL CASE")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringWithWhiteUnderscores_WhenToCamelCaseByRegex_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseByRegex("THIS_STRING_SHOULD_BE_IN_CAMEL_CASE")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRandomString_WhenToCamelCaseByRegex_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseByRegex("Please Turn this56738 to camel Case")).isEqualTo("pleaseTurnThis56738ToCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRandomStringWithDifferentDelimiters_WhenToCamelCaseByRegex_ThenReturnCamelCase() {
|
||||
assertThat(toCamelCaseByRegex("Please Turn this56738 to camel Case This should-be_in;camel-case")).isEqualTo("pleaseTurnThis56738ToCamelCaseThisShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUppercaseWordWithUnderscores_WhenCaseFormatToLowerCamel_ThenReturnCamelCase() {
|
||||
assertThat(CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "THIS_STRING_SHOULD_BE_IN_CAMEL_CASE")).isEqualTo("thisStringShouldBeInCamelCase");
|
||||
}
|
||||
|
||||
}
|
|
@ -12,3 +12,4 @@
|
|||
- [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle)
|
||||
- [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties)
|
||||
- [Deserialization Vulnerabilities in Java](https://www.baeldung.com/java-deserialization-vulnerabilities)
|
||||
- [Generating Alphanumeric UUID String in Java](https://www.baeldung.com/java-generate-alphanumeric-uuid)
|
||||
|
|
|
@ -176,8 +176,8 @@ public class UUIDGenerator {
|
|||
|
||||
byte[] hash = md.digest(bytes);
|
||||
|
||||
long msb = peekLong(hash, 0, ByteOrder.BIG_ENDIAN);
|
||||
long lsb = peekLong(hash, 8, ByteOrder.BIG_ENDIAN);
|
||||
long msb = getLeastAndMostSignificantBitsVersion5(hash, 0);
|
||||
long lsb = getLeastAndMostSignificantBitsVersion5(hash, 8);
|
||||
// Set the version field
|
||||
msb &= ~(0xfL << 12);
|
||||
msb |= ((long) 5) << 12;
|
||||
|
@ -191,18 +191,11 @@ public class UUIDGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
private static long peekLong(final byte[] src, final int offset, final ByteOrder order) {
|
||||
private static long getLeastAndMostSignificantBitsVersion5(final byte[] src, final int offset) {
|
||||
long ans = 0;
|
||||
if (order == ByteOrder.BIG_ENDIAN) {
|
||||
for (int i = offset; i < offset + 8; i += 1) {
|
||||
ans <<= 8;
|
||||
ans |= src[i] & 0xffL;
|
||||
}
|
||||
} else {
|
||||
for (int i = offset + 7; i >= offset; i -= 1) {
|
||||
ans <<= 8;
|
||||
ans |= src[i] & 0xffL;
|
||||
}
|
||||
for (int i = offset + 7; i >= offset; i -= 1) {
|
||||
ans <<= 8;
|
||||
ans |= src[i] & 0xffL;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
|
|
@ -63,11 +63,11 @@ class UUIDGeneratorUnitTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void version_5_UUID_is_correctly_generated_for_domain_baeldung_com_without_namespace() throws UnsupportedEncodingException {
|
||||
public void version_5_UUID_is_correctly_generated_for_domain_baeldung_name() {
|
||||
|
||||
UUID uuid = UUIDGenerator.generateType5UUID("baeldung.com");
|
||||
|
||||
assertEquals("a3c27ab0-2b46-55ef-b50e-0e5c57bfea94", uuid.toString());
|
||||
assertEquals("efd5462b-b07a-52a3-94ea-bf575c0e0e75", uuid.toString());
|
||||
assertEquals(5, uuid.version());
|
||||
assertEquals(2, uuid.variant());
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
<module>core-java-concurrency-collections</module>
|
||||
<module>core-java-concurrency-collections-2</module>
|
||||
<module>core-java-console</module>
|
||||
<!--<module>core-java-8-datetime</module> --> <!-- unit test case failure -->
|
||||
<module>core-java-8-datetime-2</module>
|
||||
<module>core-java-date-operations-2</module>
|
||||
<module>core-java-8-datetime</module>
|
||||
|
@ -63,7 +62,6 @@
|
|||
<module>core-java-io-4</module>
|
||||
<module>core-java-io-apis</module>
|
||||
<module>core-java-io-conversions</module>
|
||||
<module>core-java-io-conversions-2</module>
|
||||
<module>core-java-jar</module>
|
||||
<module>core-java-jndi</module>
|
||||
<module>core-java-jvm</module>
|
||||
|
@ -103,6 +101,7 @@
|
|||
<module>core-java-streams</module>
|
||||
<module>core-java-streams-2</module>
|
||||
<module>core-java-streams-3</module>
|
||||
<module>core-java-streams-4</module>
|
||||
<module>core-java-string-algorithms</module>
|
||||
<module>core-java-string-algorithms-2</module>
|
||||
<module>core-java-string-algorithms-3</module>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.lrucache;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface Cache<K, V> {
|
||||
boolean put(K key, V value);
|
||||
|
||||
Optional<V> get(K key);
|
||||
|
||||
int size();
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
void clear();
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.baeldung.lrucache;
|
||||
|
||||
/**
|
||||
* Created by arash on 09.07.21.
|
||||
*/
|
||||
|
||||
public class CacheElement<K,V> {
|
||||
private K key;
|
||||
private V value;
|
||||
|
||||
public CacheElement(K key, V value) {
|
||||
this.value = value;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(K key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(V value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package com.baeldung.lrucache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class DoublyLinkedList<T> {
|
||||
|
||||
private DummyNode<T> dummyNode;
|
||||
private LinkedListNode<T> head;
|
||||
private LinkedListNode<T> tail;
|
||||
private AtomicInteger size;
|
||||
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
public DoublyLinkedList() {
|
||||
this.dummyNode = new DummyNode<T>(this);
|
||||
clear();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
head = dummyNode;
|
||||
tail = dummyNode;
|
||||
size = new AtomicInteger(0);
|
||||
} finally {
|
||||
this.lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
this.lock.readLock().lock();
|
||||
try {
|
||||
return size.get();
|
||||
} finally {
|
||||
this.lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
this.lock.readLock().lock();
|
||||
try {
|
||||
return head.isEmpty();
|
||||
} finally {
|
||||
this.lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(T value) {
|
||||
this.lock.readLock().lock();
|
||||
try {
|
||||
return search(value).hasElement();
|
||||
} finally {
|
||||
this.lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedListNode<T> search(T value) {
|
||||
this.lock.readLock().lock();
|
||||
try {
|
||||
return head.search(value);
|
||||
} finally {
|
||||
this.lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedListNode<T> add(T value) {
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
head = new Node<T>(value, head, this);
|
||||
if (tail.isEmpty()) {
|
||||
tail = head;
|
||||
}
|
||||
size.incrementAndGet();
|
||||
return head;
|
||||
} finally {
|
||||
this.lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addAll(Collection<T> values) {
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
for (T value : values) {
|
||||
if (add(value).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
this.lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedListNode<T> remove(T value) {
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
LinkedListNode<T> linkedListNode = head.search(value);
|
||||
if (!linkedListNode.isEmpty()) {
|
||||
if (linkedListNode == tail) {
|
||||
tail = tail.getPrev();
|
||||
}
|
||||
if (linkedListNode == head) {
|
||||
head = head.getNext();
|
||||
}
|
||||
linkedListNode.detach();
|
||||
size.decrementAndGet();
|
||||
}
|
||||
return linkedListNode;
|
||||
} finally {
|
||||
this.lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedListNode<T> removeTail() {
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
LinkedListNode<T> oldTail = tail;
|
||||
if (oldTail == head) {
|
||||
tail = head = dummyNode;
|
||||
} else {
|
||||
tail = tail.getPrev();
|
||||
oldTail.detach();
|
||||
}
|
||||
if (!oldTail.isEmpty()) {
|
||||
size.decrementAndGet();
|
||||
}
|
||||
return oldTail;
|
||||
} finally {
|
||||
this.lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedListNode<T> moveToFront(LinkedListNode<T> node) {
|
||||
return node.isEmpty() ? dummyNode : updateAndMoveToFront(node, node.getElement());
|
||||
}
|
||||
|
||||
public LinkedListNode<T> updateAndMoveToFront(LinkedListNode<T> node, T newValue) {
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
if (node.isEmpty() || (this != (node.getListReference()))) {
|
||||
return dummyNode;
|
||||
}
|
||||
detach(node);
|
||||
add(newValue);
|
||||
return head;
|
||||
} finally {
|
||||
this.lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void detach(LinkedListNode<T> node) {
|
||||
if (node != tail) {
|
||||
node.detach();
|
||||
if (node == head) {
|
||||
head = head.getNext();
|
||||
}
|
||||
size.decrementAndGet();
|
||||
} else {
|
||||
removeTail();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.baeldung.lrucache;
|
||||
|
||||
/**
|
||||
* Created by arash on 09.07.21.
|
||||
*/
|
||||
public class DummyNode<T> implements LinkedListNode<T> {
|
||||
private DoublyLinkedList<T> list;
|
||||
|
||||
public DummyNode(DoublyLinkedList<T> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasElement() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getElement() throws NullPointerException {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoublyLinkedList<T> getListReference() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> setPrev(LinkedListNode<T> next) {
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> setNext(LinkedListNode<T> prev) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> getPrev() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> getNext() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> search(T value) {
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package com.baeldung.lrucache;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class LRUCache<K, V> implements Cache<K, V> {
|
||||
private int size;
|
||||
private Map<K, LinkedListNode<CacheElement<K, V>>> linkedListNodeMap;
|
||||
private DoublyLinkedList<CacheElement<K, V>> doublyLinkedList;
|
||||
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
public LRUCache(int size) {
|
||||
this.size = size;
|
||||
this.linkedListNodeMap = new ConcurrentHashMap<>(size);
|
||||
this.doublyLinkedList = new DoublyLinkedList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean put(K key, V value) {
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
CacheElement<K, V> item = new CacheElement<K, V>(key, value);
|
||||
LinkedListNode<CacheElement<K, V>> newNode;
|
||||
if (this.linkedListNodeMap.containsKey(key)) {
|
||||
LinkedListNode<CacheElement<K, V>> node = this.linkedListNodeMap.get(key);
|
||||
newNode = doublyLinkedList.updateAndMoveToFront(node, item);
|
||||
} else {
|
||||
if (this.size() >= this.size) {
|
||||
this.evictElement();
|
||||
}
|
||||
newNode = this.doublyLinkedList.add(item);
|
||||
}
|
||||
if (newNode.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
this.linkedListNodeMap.put(key, newNode);
|
||||
return true;
|
||||
} finally {
|
||||
this.lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<V> get(K key) {
|
||||
this.lock.readLock().lock();
|
||||
try {
|
||||
LinkedListNode<CacheElement<K, V>> linkedListNode = this.linkedListNodeMap.get(key);
|
||||
if (linkedListNode != null && !linkedListNode.isEmpty()) {
|
||||
linkedListNodeMap.put(key, this.doublyLinkedList.moveToFront(linkedListNode));
|
||||
return Optional.of(linkedListNode.getElement().getValue());
|
||||
}
|
||||
return Optional.empty();
|
||||
} finally {
|
||||
this.lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
this.lock.readLock().lock();
|
||||
try {
|
||||
return doublyLinkedList.size();
|
||||
} finally {
|
||||
this.lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
linkedListNodeMap.clear();
|
||||
doublyLinkedList.clear();
|
||||
} finally {
|
||||
this.lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean evictElement() {
|
||||
this.lock.writeLock().lock();
|
||||
try {
|
||||
LinkedListNode<CacheElement<K, V>> linkedListNode = doublyLinkedList.removeTail();
|
||||
if (linkedListNode.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
linkedListNodeMap.remove(linkedListNode.getElement().getKey());
|
||||
return true;
|
||||
} finally {
|
||||
this.lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.lrucache;
|
||||
|
||||
public interface LinkedListNode<V> {
|
||||
boolean hasElement();
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
V getElement() throws NullPointerException;
|
||||
|
||||
void detach();
|
||||
|
||||
DoublyLinkedList<V> getListReference();
|
||||
|
||||
LinkedListNode<V> setPrev(LinkedListNode<V> prev);
|
||||
|
||||
LinkedListNode<V> setNext(LinkedListNode<V> next);
|
||||
|
||||
LinkedListNode<V> getPrev();
|
||||
|
||||
LinkedListNode<V> getNext();
|
||||
|
||||
LinkedListNode<V> search(V value);
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.baeldung.lrucache;
|
||||
|
||||
/**
|
||||
* Created by arash on 09.07.21.
|
||||
*/
|
||||
public class Node<T> implements LinkedListNode<T> {
|
||||
private T value;
|
||||
private DoublyLinkedList<T> list;
|
||||
private LinkedListNode next;
|
||||
private LinkedListNode prev;
|
||||
|
||||
public Node(T value, LinkedListNode<T> next, DoublyLinkedList<T> list) {
|
||||
this.value = value;
|
||||
this.next = next;
|
||||
this.setPrev(next.getPrev());
|
||||
this.prev.setNext(this);
|
||||
this.next.setPrev(this);
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasElement() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public T getElement() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void detach() {
|
||||
this.prev.setNext(this.getNext());
|
||||
this.next.setPrev(this.getPrev());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoublyLinkedList<T> getListReference() {
|
||||
return this.list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> setPrev(LinkedListNode<T> prev) {
|
||||
this.prev = prev;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> setNext(LinkedListNode<T> next) {
|
||||
this.next = next;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> getPrev() {
|
||||
return this.prev;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> getNext() {
|
||||
return this.next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedListNode<T> search(T value) {
|
||||
return this.getElement() == value ? this : this.getNext().search(value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.baeldung.lrucache;
|
||||
|
||||
import org.junit.Test;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.IntStream;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class LRUCacheUnitTest {
|
||||
|
||||
@Test
|
||||
public void addSomeDataToCache_WhenGetData_ThenIsEqualWithCacheElement() {
|
||||
LRUCache<String, String> lruCache = new LRUCache<>(3);
|
||||
lruCache.put("1", "test1");
|
||||
lruCache.put("2", "test2");
|
||||
lruCache.put("3", "test3");
|
||||
assertEquals("test1", lruCache.get("1").get());
|
||||
assertEquals("test2", lruCache.get("2").get());
|
||||
assertEquals("test3", lruCache.get("3").get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addDataToCacheToTheNumberOfSize_WhenAddOneMoreData_ThenLeastRecentlyDataWillEvict() {
|
||||
LRUCache<String, String> lruCache = new LRUCache<>(3);
|
||||
lruCache.put("1", "test1");
|
||||
lruCache.put("2", "test2");
|
||||
lruCache.put("3", "test3");
|
||||
lruCache.put("4", "test4");
|
||||
assertFalse(lruCache.get("1").isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runMultiThreadTask_WhenPutDataInConcurrentToCache_ThenNoDataLost() throws Exception {
|
||||
final int size = 50;
|
||||
final ExecutorService executorService = Executors.newFixedThreadPool(5);
|
||||
Cache<Integer, String> cache = new LRUCache<>(size);
|
||||
CountDownLatch countDownLatch = new CountDownLatch(size);
|
||||
try {
|
||||
IntStream.range(0, size).<Runnable>mapToObj(key -> () -> {
|
||||
cache.put(key, "value" + key);
|
||||
countDownLatch.countDown();
|
||||
}).forEach(executorService::submit);
|
||||
countDownLatch.await();
|
||||
} finally {
|
||||
executorService.shutdown();
|
||||
}
|
||||
assertEquals(cache.size(), size);
|
||||
IntStream.range(0, size).forEach(i -> assertEquals("value" + i, cache.get(i).get()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
## Relevant Articles:
|
||||
|
||||
- [Guava’s Futures and ListenableFuture](https://www.baeldung.com/guava-futures-listenablefuture)
|
|
@ -0,0 +1,14 @@
|
|||
<?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">
|
||||
<parent>
|
||||
<artifactId>guava-modules</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>guava-concurrency</artifactId>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,105 @@
|
|||
package com.baeldung.guava.future;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.baeldung.guava.future.exception.ListenableFutureException;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListenableFutureTask;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
public class ListenableFutureService {
|
||||
|
||||
private final ListeningExecutorService lExecService;
|
||||
|
||||
public ListenableFutureService() {
|
||||
this.lExecService = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
|
||||
}
|
||||
|
||||
public ListenableFutureService(ListeningExecutorService lExecService) {
|
||||
this.lExecService = lExecService;
|
||||
}
|
||||
|
||||
public ListenableFuture<String> fetchConfig(String configKey) {
|
||||
return lExecService.submit(() -> {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
return String.format("%s.%d", configKey, new Random().nextInt(Integer.MAX_VALUE));
|
||||
});
|
||||
}
|
||||
|
||||
public FutureTask<String> fetchConfigTask(String configKey) {
|
||||
return new FutureTask<>(() -> {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
return String.format("%s.%d", configKey, new Random().nextInt(Integer.MAX_VALUE));
|
||||
});
|
||||
}
|
||||
|
||||
public ListenableFutureTask<String> fetchConfigListenableTask(String configKey) {
|
||||
return ListenableFutureTask.create(() -> {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
return String.format("%s.%d", configKey, new Random().nextInt(Integer.MAX_VALUE));
|
||||
});
|
||||
}
|
||||
|
||||
public ListenableFuture<Integer> succeedingTask() {
|
||||
return Futures.immediateFuture(new Random().nextInt(Integer.MAX_VALUE));
|
||||
}
|
||||
|
||||
public <T> ListenableFuture<T> failingTask() {
|
||||
return Futures.immediateFailedFuture(new ListenableFutureException());
|
||||
}
|
||||
|
||||
public ListenableFuture<Integer> getCartId() {
|
||||
return lExecService.submit(() -> {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
return new Random().nextInt(Integer.MAX_VALUE);
|
||||
});
|
||||
}
|
||||
|
||||
public ListenableFuture<String> getCustomerName() {
|
||||
String[] names = new String[] { "Mark", "Jane", "June" };
|
||||
return lExecService.submit(() -> {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
return names[new Random().nextInt(names.length)];
|
||||
});
|
||||
}
|
||||
|
||||
public ListenableFuture<List<String>> getCartItems() {
|
||||
String[] items = new String[] { "Apple", "Orange", "Mango", "Pineapple" };
|
||||
return lExecService.submit(() -> {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
|
||||
int noOfItems = new Random().nextInt(items.length);
|
||||
if (noOfItems == 0) ++noOfItems;
|
||||
|
||||
return Arrays.stream(items, 0, noOfItems).collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
public ListenableFuture<String> generateUsername(String firstName) {
|
||||
return lExecService.submit(() -> {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
return firstName.replaceAll("[^a-zA-Z]+","")
|
||||
.concat("@service.com");
|
||||
});
|
||||
}
|
||||
|
||||
public ListenableFuture<String> generatePassword(String username) {
|
||||
return lExecService.submit(() -> {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
if (username.contains("@")) {
|
||||
String[] parts = username.split("@");
|
||||
return parts[0] + "123@" + parts[1];
|
||||
} else {
|
||||
return username + "123";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package com.baeldung.guava.future.exception;
|
||||
|
||||
public class ListenableFutureException extends Exception {
|
||||
}
|
|
@ -0,0 +1,277 @@
|
|||
package com.baeldung.guava.future;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.guava.future.exception.ListenableFutureException;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.util.concurrent.AsyncCallable;
|
||||
import com.google.common.util.concurrent.AsyncFunction;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
public class ListenableFutureComplexUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenAllSucceedingTasks_whenAllAsList_thenAllSuccess() {
|
||||
final ListeningExecutorService listeningExecService = MoreExecutors.newDirectExecutorService();
|
||||
final ListenableFutureService service = new ListenableFutureService(listeningExecService);
|
||||
|
||||
ListenableFuture<String> task1 = service.fetchConfig("config.0");
|
||||
ListenableFuture<String> task2 = service.fetchConfig("config.1");
|
||||
ListenableFuture<String> task3 = service.fetchConfig("config.2");
|
||||
|
||||
ListenableFuture<List<String>> configsTask = Futures.allAsList(task1, task2, task3);
|
||||
Futures.addCallback(configsTask, new FutureCallback<List<String>>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable List<String> configResults) {
|
||||
assertNotNull(configResults);
|
||||
assertEquals(3, configResults.size());
|
||||
for (int i = 0; i < 3; i++) {
|
||||
assertTrue(configResults.get(i)
|
||||
.contains("config." + i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
fail("Unexpected failure detected", t);
|
||||
}
|
||||
}, listeningExecService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOneFailingTask_whenAllAsList_thenFailure() {
|
||||
final ListeningExecutorService listeningExecService = MoreExecutors.newDirectExecutorService();
|
||||
final ListenableFutureService service = new ListenableFutureService(listeningExecService);
|
||||
|
||||
ListenableFuture<String> task1 = service.fetchConfig("config.0");
|
||||
ListenableFuture<String> task2 = service.failingTask();
|
||||
ListenableFuture<String> task3 = service.fetchConfig("config.2");
|
||||
|
||||
ListenableFuture<List<String>> configsTask = Futures.allAsList(task1, task2, task3);
|
||||
Futures.addCallback(configsTask, new FutureCallback<List<String>>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable List<String> configResults) {
|
||||
fail("Expected a failed future");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
assertTrue(t instanceof ListenableFutureException);
|
||||
}
|
||||
}, listeningExecService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOneFailingTask_whenSuccessfulAsList_thenSomeSuccess() {
|
||||
final ListeningExecutorService listeningExecService = MoreExecutors.newDirectExecutorService();
|
||||
final ListenableFutureService service = new ListenableFutureService(listeningExecService);
|
||||
|
||||
ListenableFuture<String> task1 = service.fetchConfig("config.0");
|
||||
ListenableFuture<String> task2 = service.failingTask();
|
||||
ListenableFuture<String> task3 = service.fetchConfig("config.2");
|
||||
|
||||
ListenableFuture<List<String>> configsTask = Futures.successfulAsList(task1, task2, task3);
|
||||
|
||||
Futures.addCallback(configsTask, new FutureCallback<List<String>>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable List<String> configResults) {
|
||||
assertNotNull(configResults);
|
||||
assertTrue(configResults.get(0).contains("config.0"));
|
||||
assertNull(configResults.get(1));
|
||||
assertTrue(configResults.get(2).contains("config.2"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
fail("Unexpected failure detected", t);
|
||||
}
|
||||
}, listeningExecService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAllSucceedingTasks_whenAllSucceed_thenSuccess() {
|
||||
ListeningExecutorService listeningExecService = MoreExecutors.newDirectExecutorService();
|
||||
ListenableFutureService service = new ListenableFutureService(listeningExecService);
|
||||
|
||||
ListenableFuture<Integer> cartIdTask = service.getCartId();
|
||||
ListenableFuture<String> customerNameTask = service.getCustomerName();
|
||||
ListenableFuture<List<String>> cartItemsTask = service.getCartItems();
|
||||
|
||||
ListenableFuture<CartInfo> cartInfoTask = Futures.whenAllSucceed(cartIdTask, customerNameTask, cartItemsTask)
|
||||
.call(() -> {
|
||||
int cartId = Futures.getDone(cartIdTask);
|
||||
String customerName = Futures.getDone(customerNameTask);
|
||||
List<String> cartItems = Futures.getDone(cartItemsTask);
|
||||
return new CartInfo(cartId, customerName, cartItems);
|
||||
}, listeningExecService);
|
||||
|
||||
Futures.addCallback(cartInfoTask, new FutureCallback<CartInfo>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable CartInfo result) {
|
||||
assertNotNull(result);
|
||||
assertTrue(result.cartId >= 0);
|
||||
assertFalse(result.customerName.isEmpty());
|
||||
assertFalse(result.cartItems.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
fail("Unexpected failure detected", t);
|
||||
}
|
||||
}, listeningExecService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAllSucceedingTasks_whenAllComplete_thenSomeSuccess() {
|
||||
ListeningExecutorService listeningExecService = MoreExecutors.newDirectExecutorService();
|
||||
ListenableFutureService service = new ListenableFutureService(listeningExecService);
|
||||
|
||||
ListenableFuture<Integer> cartIdTask = service.getCartId();
|
||||
ListenableFuture<String> customerNameTask = service.failingTask();
|
||||
ListenableFuture<List<String>> cartItemsTask = service.getCartItems();
|
||||
|
||||
ListenableFuture<CartInfo> cartInfoTask = Futures.whenAllComplete(cartIdTask, customerNameTask, cartItemsTask)
|
||||
.call(() -> {
|
||||
Integer cartId = getOrNull(cartIdTask);
|
||||
String customerName = getOrNull(customerNameTask);
|
||||
List<String> cartItems = getOrNull(cartItemsTask);
|
||||
return new CartInfo(cartId, customerName, cartItems);
|
||||
}, listeningExecService);
|
||||
|
||||
Futures.addCallback(cartInfoTask, new FutureCallback<CartInfo>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable CartInfo result) {
|
||||
assertNotNull(result);
|
||||
assertTrue(result.cartId >= 0);
|
||||
assertNull(result.customerName);
|
||||
assertFalse(result.cartItems.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
fail("Unexpected failure detected", t);
|
||||
}
|
||||
}, listeningExecService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTransform_thenTransformSuccess() {
|
||||
ListeningExecutorService listenExecService = MoreExecutors.newDirectExecutorService();
|
||||
ListenableFutureService service = new ListenableFutureService(listenExecService);
|
||||
|
||||
ListenableFuture<List<String>> cartItemsTask = service.getCartItems();
|
||||
|
||||
Function<List<String>, Integer> itemCountFunc = cartItems -> {
|
||||
assertNotNull(cartItems);
|
||||
return cartItems.size();
|
||||
};
|
||||
|
||||
ListenableFuture<Integer> itemCountTask = Futures.transform(cartItemsTask, itemCountFunc, listenExecService);
|
||||
|
||||
Futures.addCallback(itemCountTask, new FutureCallback<Integer>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Integer cartItemCount) {
|
||||
assertNotNull(cartItemCount);
|
||||
assertTrue(cartItemCount > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
fail("Unexpected failure detected", t);
|
||||
}
|
||||
}, listenExecService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSubmitAsync_thenSuccess() {
|
||||
ListeningExecutorService executor = MoreExecutors.newDirectExecutorService();
|
||||
ListenableFutureService service = new ListenableFutureService(executor);
|
||||
|
||||
AsyncCallable<String> asyncConfigTask = () -> {
|
||||
ListenableFuture<String> configTask = service.fetchConfig("config.a");
|
||||
TimeUnit.MILLISECONDS.sleep(500); //some long running task
|
||||
return configTask;
|
||||
};
|
||||
|
||||
ListenableFuture<String> configTask = Futures.submitAsync(asyncConfigTask, executor);
|
||||
|
||||
Futures.addCallback(configTask, new FutureCallback<String>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable String result) {
|
||||
assertNotNull(result);
|
||||
assertTrue(result.contains("config.a"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
fail("Unexpected failure detected", t);
|
||||
}
|
||||
}, executor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAsyncTransform_thenSuccess() {
|
||||
ListeningExecutorService executor = MoreExecutors.newDirectExecutorService();
|
||||
ListenableFutureService service = new ListenableFutureService(executor);
|
||||
|
||||
ListenableFuture<String> usernameTask = service.generateUsername("john");
|
||||
AsyncFunction<String, String> passwordFunc = username -> {
|
||||
ListenableFuture<String> generatePasswordTask = service.generatePassword(username);
|
||||
TimeUnit.MILLISECONDS.sleep(500); // some long running task
|
||||
return generatePasswordTask;
|
||||
};
|
||||
|
||||
ListenableFuture<String> passwordTask = Futures.transformAsync(usernameTask, passwordFunc, executor);
|
||||
|
||||
Futures.addCallback(passwordTask, new FutureCallback<String>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable String password) {
|
||||
assertNotNull(password);
|
||||
assertTrue(password.contains("john"));
|
||||
assertTrue(password.contains("@"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
fail("Unexpected failure detected", t);
|
||||
}
|
||||
}, executor);
|
||||
}
|
||||
|
||||
private static <T> T getOrNull(ListenableFuture<T> future) {
|
||||
try {
|
||||
return Futures.getDone(future);
|
||||
} catch (ExecutionException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class CartInfo {
|
||||
Integer cartId;
|
||||
String customerName;
|
||||
List<String> cartItems;
|
||||
|
||||
public CartInfo(Integer cartId, String customerName, List<String> cartItems) {
|
||||
this.cartId = cartId;
|
||||
this.customerName = customerName;
|
||||
this.cartItems = cartItems;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package com.baeldung.guava.future;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.guava.future.exception.ListenableFutureException;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListenableFutureTask;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
public class ListenableFutureSimpleUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenSubmitToListeningExecutor_thenSuccess() throws ExecutionException, InterruptedException {
|
||||
ExecutorService execService = Executors.newSingleThreadExecutor();
|
||||
ListeningExecutorService listeningExecService = MoreExecutors.listeningDecorator(execService);
|
||||
|
||||
ListenableFuture<Integer> asyncTask = listeningExecService.submit(() -> {
|
||||
TimeUnit.MILLISECONDS.sleep(500); // long running task
|
||||
return 5;
|
||||
});
|
||||
|
||||
assertEquals(5, asyncTask.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
givenJavaExecutor_whenSubmitListeningTask_thenSuccess() throws ExecutionException, InterruptedException {
|
||||
Executor executor = Executors.newSingleThreadExecutor();
|
||||
ListenableFutureService service = new ListenableFutureService();
|
||||
|
||||
FutureTask<String> configFuture = service.fetchConfigTask("future.value");
|
||||
executor.execute(configFuture);
|
||||
assertTrue(configFuture.get().contains("future.value"));
|
||||
|
||||
ListenableFutureTask<String> configListenableFuture =
|
||||
service.fetchConfigListenableTask("listenable.value");
|
||||
executor.execute(configListenableFuture);
|
||||
assertTrue(configListenableFuture.get().contains("listenable.value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNonFailingTask_whenCallbackListen_thenSuccess() {
|
||||
Executor listeningExecutor = MoreExecutors.directExecutor();
|
||||
|
||||
ListenableFuture<Integer> succeedingTask = new ListenableFutureService().succeedingTask();
|
||||
Futures.addCallback(succeedingTask, new FutureCallback<Integer>() {
|
||||
@Override
|
||||
public void onSuccess(Integer result) {
|
||||
assertNotNull(result);
|
||||
assertTrue(result >= 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
fail("Succeeding task cannot failed", t);
|
||||
}
|
||||
}, listeningExecutor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenFailingTask_whenCallbackListen_thenThrows() {
|
||||
Executor listeningExecutor = MoreExecutors.directExecutor();
|
||||
|
||||
ListenableFuture<Integer> failingTask = new ListenableFutureService().failingTask();
|
||||
Futures.addCallback(failingTask, new FutureCallback<Integer>() {
|
||||
@Override
|
||||
public void onSuccess(Integer result) {
|
||||
fail("Failing task cannot succeed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
assertTrue(t instanceof ListenableFutureException);
|
||||
}
|
||||
}, listeningExecutor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNonFailingTask_whenDirectListen_thenListenerExecutes() {
|
||||
Executor listeningExecutor = MoreExecutors.directExecutor();
|
||||
|
||||
int nextTask = 1;
|
||||
Set<Integer> runningTasks = ConcurrentHashMap.newKeySet();
|
||||
runningTasks.add(nextTask);
|
||||
|
||||
ListenableFuture<Integer> nonFailingTask = new ListenableFutureService().succeedingTask();
|
||||
nonFailingTask.addListener(() -> runningTasks.remove(nextTask), listeningExecutor);
|
||||
|
||||
assertTrue(runningTasks.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenFailingTask_whenDirectListen_thenListenerExecutes() {
|
||||
final Executor listeningExecutor = MoreExecutors.directExecutor();
|
||||
|
||||
int nextTask = 1;
|
||||
Set<Integer> runningTasks = ConcurrentHashMap.newKeySet();
|
||||
runningTasks.add(nextTask);
|
||||
|
||||
final ListenableFuture<Integer> failingTask = new ListenableFutureService().failingTask();
|
||||
failingTask.addListener(() -> runningTasks.remove(nextTask),listeningExecutor);
|
||||
|
||||
assertTrue(runningTasks.isEmpty());
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
<module>guava-collections-list</module>
|
||||
<module>guava-collections-map</module>
|
||||
<module>guava-collections-set</module>
|
||||
<module>guava-concurrency</module>
|
||||
<module>guava-io</module>
|
||||
</modules>
|
||||
|
||||
|
|
|
@ -11,4 +11,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
|
|||
- [How to Set TLS Version in Apache HttpClient](https://www.baeldung.com/apache-httpclient-tls)
|
||||
- [Reading an HTTP Response Body as a String in Java](https://www.baeldung.com/java-http-response-body-as-string)
|
||||
- [How To Get Cookies From the Apache HttpClient Response](https://www.baeldung.com/java-apache-httpclient-cookies)
|
||||
- [Enabling Logging for Apache HttpClient](https://www.baeldung.com/java-httpclient-enable-logging)
|
||||
- More articles: [[<-- prev]](../httpclient)
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||
<artifactId>httpclient5</artifactId>
|
||||
<version>${httpclient5.version}</version>
|
||||
</dependency>
|
||||
<!-- rest template -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
@ -63,6 +68,7 @@
|
|||
|
||||
<properties>
|
||||
<httpclient.version>4.5.8</httpclient.version>
|
||||
<httpclient5.version>5.1</httpclient5.version>
|
||||
<maven.compiler.source.version>11</maven.compiler.source.version>
|
||||
<maven.compiler.target.version>11</maven.compiler.target.version>
|
||||
<spring-boot.version>2.1.7.RELEASE</spring-boot.version>
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package com.baeldung.httpclient.readresponsebodystring;
|
||||
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.ParseException;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ApacheHttpClient5UnitTest {
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
public static final String DUMMY_URL = "https://postman-echo.com/get";
|
||||
|
||||
@Test
|
||||
public void whenUseApacheHttpClient_thenCorrect() throws IOException, ParseException {
|
||||
HttpGet request = new HttpGet(DUMMY_URL);
|
||||
|
||||
try (CloseableHttpClient client = HttpClients.createDefault(); CloseableHttpResponse response = client.execute(request)) {
|
||||
HttpEntity entity = response.getEntity();
|
||||
logger.debug("Response -> {}", EntityUtils.toString(entity));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,10 +7,13 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
|||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ApacheHttpClientUnitTest {
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
public static final String DUMMY_URL = "https://postman-echo.com/get";
|
||||
|
||||
@Test
|
||||
|
@ -19,8 +22,7 @@ public class ApacheHttpClientUnitTest {
|
|||
|
||||
try (CloseableHttpClient client = HttpClients.createDefault(); CloseableHttpResponse response = client.execute(request)) {
|
||||
HttpEntity entity = response.getEntity();
|
||||
String result = EntityUtils.toString(entity);
|
||||
System.out.println("Response -> " + result);
|
||||
logger.debug("Response -> {}", EntityUtils.toString(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<configuration debug="false">
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%date [%level] %logger - %msg %n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.baeldung.httpclient.readresponsebodystring" level="debug"/>
|
||||
<logger name="org.apache.http" level="debug"/>
|
||||
<logger name="org.apache.hc.client5.http" level="debug"/>
|
||||
|
||||
<root level="WARN">
|
||||
<appender-ref ref="stdout"/>
|
||||
</root>
|
||||
</configuration>
|
|
@ -3,3 +3,4 @@
|
|||
- [Probability in Java](https://www.baeldung.com/java-probability)
|
||||
- [Understanding the & 0xff Value in Java](https://www.baeldung.com/java-and-0xff)
|
||||
- [Determine if an Integer’s Square Root Is an Integer in Java](https://www.baeldung.com/java-find-if-square-root-is-integer)
|
||||
- [Guide to Java BigInteger](https://www.baeldung.com/java-biginteger)
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package com.baeldung.biginteger;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class BigIntegerUnitTest {
|
||||
|
||||
@Test
|
||||
void givenPositiveAndNegativeAndZeroBigInteger_whenGetSigNumValue_shouldReturnOneAndMinusOneAndZero() {
|
||||
assertEquals(1, BigInteger.TEN.signum());
|
||||
assertEquals(-1, BigInteger.TEN.negate().signum());
|
||||
assertEquals(0, BigInteger.ZERO.signum());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenByteArrays_whenCreateBigInteger_shouldTranslateToTwosComplementBinary() {
|
||||
assertEquals(new BigInteger("1"), new BigInteger(new byte[]{0b1}));
|
||||
assertEquals(new BigInteger("2"), new BigInteger(new byte[]{0b10}));
|
||||
assertEquals(new BigInteger("4"), new BigInteger(new byte[]{0b100}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenSingleByte_whenCreateBigIntegerAndDifferentSigNum_thenOppositeValues() {
|
||||
byte[] bytes = { (byte) -128 }; // 0b1000_0000
|
||||
|
||||
BigInteger positive = new BigInteger(1, bytes);
|
||||
BigInteger negative = new BigInteger(-1, bytes);
|
||||
|
||||
assertEquals(new BigInteger("128"), positive);
|
||||
assertEquals("10000000", positive.toString(2));
|
||||
|
||||
assertEquals(new BigInteger("-128"), negative);
|
||||
assertEquals("-10000000", negative.toString(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenZeroBigInteger_whenCheckMagnitude_thenIsEmpty() {
|
||||
assertEquals(0, BigInteger.ZERO.bitCount());
|
||||
assertEquals(BigInteger.ZERO, new BigInteger(0, new byte[]{}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void given63rdBitSet_whenCreateBigInteger_thenIsLargerThanLongByOne() {
|
||||
// first
|
||||
BigInteger bi1 = BigInteger.ZERO.setBit(63);
|
||||
String str1 = bi1.toString(2);
|
||||
|
||||
// second
|
||||
byte[] bytes = ByteBuffer.allocate(Long.BYTES).putLong(Long.MIN_VALUE).array();
|
||||
BigInteger bi2 = new BigInteger(1, bytes);
|
||||
String str2 = bi2.toString(2);
|
||||
|
||||
largerThanLongAssertionSet(bi1, str1);
|
||||
|
||||
assertEquals(bi1, bi2);
|
||||
|
||||
largerThanLongAssertionSet(bi2, str2);
|
||||
|
||||
}
|
||||
|
||||
private static void largerThanLongAssertionSet(BigInteger bi, String str)
|
||||
{
|
||||
assertEquals(64, bi.bitLength());
|
||||
assertEquals(1, bi.signum());
|
||||
assertEquals("9223372036854775808", bi.toString());
|
||||
assertEquals(BigInteger.ONE, bi.subtract(BigInteger.valueOf(Long.MAX_VALUE)));
|
||||
|
||||
assertEquals(64, str.length());
|
||||
assertTrue(str.matches("^10{63}$")); // 1000 0000
|
||||
}
|
||||
}
|
|
@ -487,7 +487,7 @@
|
|||
|
||||
<properties>
|
||||
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
|
||||
<mvc.api.version>1.0.0</mvc.api.version>
|
||||
<mvc.api.version>1.0-edr2</mvc.api.version>
|
||||
<java.min.version>1.8</java.min.version>
|
||||
<maven.min.version>3.0.0</maven.min.version>
|
||||
<javaee_api.version>7.0</javaee_api.version>
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: web-app-deployment
|
||||
spec:
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 2
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: web-app
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: web-app
|
||||
spec:
|
||||
containers:
|
||||
- name: web-app
|
||||
image: hello-world:nanoserver-1809
|
||||
volumeMounts:
|
||||
- name: counter
|
||||
mountPath: /app/
|
||||
volumes:
|
||||
- name: counter
|
||||
persistentVolumeClaim:
|
||||
claimName: counter
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: counter
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 50Mi
|
||||
storageClassName: default
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: web-app-service
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
nodePort: 30080
|
||||
selector:
|
||||
name: web-app
|
||||
type: NodePort
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: counter
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 50Mi
|
||||
storageClassName: default
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: web-app-service
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
nodePort: 30080
|
||||
selector:
|
||||
name: web-app
|
||||
type: NodePort
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: myclaim
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
name: web
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: nginx
|
|
@ -0,0 +1,28 @@
|
|||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: web
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
serviceName: "nginx"
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
name: web
|
||||
volumeMounts:
|
||||
- name: www
|
||||
mountPath: /usr/share/nginx/html
|
||||
volumes:
|
||||
- name: www
|
||||
persistentVolumeClaim:
|
||||
claimName: myclaim
|
|
@ -0,0 +1,11 @@
|
|||
FROM adoptopenjdk:11-jre-hotspot as builder
|
||||
ARG JAR_FILE=target/*.jar
|
||||
COPY ${JAR_FILE} application.jar
|
||||
RUN java -Djarmode=layertools -jar application.jar extract
|
||||
|
||||
FROM adoptopenjdk:11-jre-hotspot
|
||||
COPY --from=builder dependencies/ ./
|
||||
COPY --from=builder snapshot-dependencies/ ./
|
||||
COPY --from=builder spring-boot-loader/ ./
|
||||
COPY --from=builder application/ ./
|
||||
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
|
|
@ -0,0 +1,86 @@
|
|||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>./../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>k8s-admission-controller</artifactId>
|
||||
<name>k8s-admission-controller</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
<mainClass>com.baeldung.kubernetes.admission.Application</mainClass>
|
||||
<layers>
|
||||
<enabled>true</enabled>
|
||||
</layers>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,17 @@
|
|||
package com.baeldung.kubernetes.admission;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
|
||||
import com.baeldung.kubernetes.admission.config.AdmissionControllerProperties;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties(AdmissionControllerProperties.class)
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package com.baeldung.kubernetes.admission.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@ConfigurationProperties(prefix = "admission-controller")
|
||||
@Data
|
||||
public class AdmissionControllerProperties {
|
||||
|
||||
private boolean disabled;
|
||||
private String annotation = "com.baeldung/wait-for-it";
|
||||
private String waitForItImage = "willwill/wait-for-it";
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package com.baeldung.kubernetes.admission.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.baeldung.kubernetes.admission.dto.AdmissionReviewResponse;
|
||||
import com.baeldung.kubernetes.admission.service.AdmissionService;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class AdmissionReviewController {
|
||||
|
||||
private final AdmissionService admissionService;
|
||||
|
||||
@PostMapping(path = "/mutate")
|
||||
public Mono<AdmissionReviewResponse> processAdmissionReviewRequest(@RequestBody Mono<ObjectNode> request) {
|
||||
return request.map((body) -> admissionService.processAdmission(body));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package com.baeldung.kubernetes.admission.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Result sent to the API server after reviewing and, possibly
|
||||
* modifying the incoming request
|
||||
*/
|
||||
@Builder
|
||||
@Data
|
||||
public class AdmissionReviewData {
|
||||
|
||||
final String uid;
|
||||
final boolean allowed;
|
||||
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
final String patchType;
|
||||
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
final String patch;
|
||||
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
final AdmissionStatus status;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.kubernetes.admission.dto;
|
||||
|
||||
public class AdmissionReviewException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final int code;
|
||||
|
||||
public AdmissionReviewException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public AdmissionReviewException(String message) {
|
||||
super(message);
|
||||
this.code = 400;
|
||||
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package com.baeldung.kubernetes.admission.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Builder.Default;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Response "envelope" sent back to the API Server
|
||||
*/
|
||||
@Builder
|
||||
@Data
|
||||
public class AdmissionReviewResponse {
|
||||
|
||||
@Default
|
||||
final String apiVersion = "admission.k8s.io/v1";
|
||||
|
||||
@Default
|
||||
final String kind = "AdmissionReview";
|
||||
|
||||
final AdmissionReviewData response;
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue