Merge branch 'eugenp:master' into master
This commit is contained in:
commit
20915e1718
|
@ -20,4 +20,5 @@ Two scripts are included to easily start middleware using Docker matching the pr
|
||||||
- [Multi-Entity Aggregates in Axon](https://www.baeldung.com/java-axon-multi-entity-aggregates)
|
- [Multi-Entity Aggregates in Axon](https://www.baeldung.com/java-axon-multi-entity-aggregates)
|
||||||
- [Snapshotting Aggregates in Axon](https://www.baeldung.com/axon-snapshotting-aggregates)
|
- [Snapshotting Aggregates in Axon](https://www.baeldung.com/axon-snapshotting-aggregates)
|
||||||
- [Dispatching Queries in Axon Framework](https://www.baeldung.com/axon-query-dispatching)
|
- [Dispatching Queries in Axon Framework](https://www.baeldung.com/axon-query-dispatching)
|
||||||
- [Persisting the Query Model](https://www.baeldung.com/axon-persisting-query-model)
|
- [Persisting the Query Model](https://www.baeldung.com/persisting-the-query-model)
|
||||||
|
- [Using and testing Axon applications via REST](https://www.baeldung.com/using-and-testing-axon-applications-via-rest)
|
||||||
|
|
13
axon/pom.xml
13
axon/pom.xml
|
@ -81,13 +81,22 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.awaitility</groupId>
|
<groupId>org.awaitility</groupId>
|
||||||
<artifactId>awaitility</artifactId>
|
<artifactId>awaitility</artifactId>
|
||||||
<version>4.2.0</version>
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webflux</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.projectreactor.netty</groupId>
|
||||||
|
<artifactId>reactor-netty-http</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<axon-bom.version>4.6.2</axon-bom.version>
|
<axon-bom.version>4.6.3</axon-bom.version>
|
||||||
<de.flapdoodle.embed.mongo.version>3.4.8</de.flapdoodle.embed.mongo.version>
|
<de.flapdoodle.embed.mongo.version>3.4.8</de.flapdoodle.embed.mongo.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
package com.baeldung.axon.gui;
|
||||||
|
|
||||||
|
import com.baeldung.axon.OrderApplication;
|
||||||
|
import com.baeldung.axon.querymodel.OrderResponse;
|
||||||
|
import com.baeldung.axon.querymodel.OrderStatusResponse;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.*;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClientResponseException;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.netty.http.client.HttpClient;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = OrderApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
|
class OrderRestEndpointIntegrationTest {
|
||||||
|
|
||||||
|
@LocalServerPort
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DirtiesContext
|
||||||
|
void givenCreateOrderCalled_whenCallingAllOrders_thenOneCreatedOrderIsReturned() {
|
||||||
|
WebClient client = WebClient.builder()
|
||||||
|
.clientConnector(httpConnector())
|
||||||
|
.build();
|
||||||
|
createRandomNewOrder(client);
|
||||||
|
StepVerifier.create(retrieveListResponse(client.get()
|
||||||
|
.uri("http://localhost:" + port + "/all-orders")))
|
||||||
|
.expectNextMatches(list -> 1 == list.size() && list.get(0)
|
||||||
|
.getOrderStatus() == OrderStatusResponse.CREATED)
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DirtiesContext
|
||||||
|
void givenCreateOrderCalledThreeTimesAnd_whenCallingAllOrdersStreaming_thenTwoCreatedOrdersAreReturned() {
|
||||||
|
WebClient client = WebClient.builder()
|
||||||
|
.clientConnector(httpConnector())
|
||||||
|
.build();
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
createRandomNewOrder(client);
|
||||||
|
}
|
||||||
|
StepVerifier.create(retrieveStreamingResponse(client.get()
|
||||||
|
.uri("http://localhost:" + port + "/all-orders-streaming")))
|
||||||
|
.expectNextMatches(o -> o.getOrderStatus() == OrderStatusResponse.CREATED)
|
||||||
|
.expectNextMatches(o -> o.getOrderStatus() == OrderStatusResponse.CREATED)
|
||||||
|
.expectNextMatches(o -> o.getOrderStatus() == OrderStatusResponse.CREATED)
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DirtiesContext
|
||||||
|
void givenRuleExistThatNeedConfirmationBeforeShipping_whenCallingShipUnconfirmed_thenErrorReturned() {
|
||||||
|
WebClient client = WebClient.builder()
|
||||||
|
.clientConnector(httpConnector())
|
||||||
|
.build();
|
||||||
|
StepVerifier.create(retrieveResponse(client.post()
|
||||||
|
.uri("http://localhost:" + port + "/ship-unconfirmed-order")))
|
||||||
|
.verifyError(WebClientResponseException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DirtiesContext
|
||||||
|
void givenShipOrderCalled_whenCallingAllShippedChairs_then234PlusOneIsReturned() {
|
||||||
|
WebClient client = WebClient.builder()
|
||||||
|
.clientConnector(httpConnector())
|
||||||
|
.build();
|
||||||
|
verifyVoidPost(client, "http://localhost:" + port + "/ship-order");
|
||||||
|
StepVerifier.create(retrieveIntegerResponse(client.get()
|
||||||
|
.uri("http://localhost:" + port + "/total-shipped/Deluxe Chair")))
|
||||||
|
.assertNext(r -> assertEquals(235, r))
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DirtiesContext
|
||||||
|
void givenOrdersAreUpdated_whenCallingOrderUpdates_thenUpdatesReturned() {
|
||||||
|
WebClient updaterClient = WebClient.builder()
|
||||||
|
.clientConnector(httpConnector())
|
||||||
|
.build();
|
||||||
|
WebClient receiverClient = WebClient.builder()
|
||||||
|
.clientConnector(httpConnector())
|
||||||
|
.build();
|
||||||
|
String orderId = UUID.randomUUID()
|
||||||
|
.toString();
|
||||||
|
String productId = UUID.randomUUID()
|
||||||
|
.toString();
|
||||||
|
StepVerifier.create(retrieveResponse(updaterClient.post()
|
||||||
|
.uri("http://localhost:" + port + "/order/" + orderId)))
|
||||||
|
.assertNext(Assertions::assertNotNull)
|
||||||
|
.verifyComplete();
|
||||||
|
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
executor.schedule(() -> addIncrementDecrementConfirmAndShipProduct(orderId, productId), 1L, TimeUnit.SECONDS);
|
||||||
|
try {
|
||||||
|
StepVerifier.create(retrieveStreamingResponse(receiverClient.get()
|
||||||
|
.uri("http://localhost:" + port + "/order-updates/" + orderId)))
|
||||||
|
.assertNext(p -> assertTrue(p.getProducts()
|
||||||
|
.isEmpty()))
|
||||||
|
.assertNext(p -> assertEquals(1, p.getProducts()
|
||||||
|
.get(productId)))
|
||||||
|
.assertNext(p -> assertEquals(2, p.getProducts()
|
||||||
|
.get(productId)))
|
||||||
|
.assertNext(p -> assertEquals(1, p.getProducts()
|
||||||
|
.get(productId)))
|
||||||
|
.assertNext(p -> assertEquals(OrderStatusResponse.CONFIRMED, p.getOrderStatus()))
|
||||||
|
.assertNext(p -> assertEquals(OrderStatusResponse.SHIPPED, p.getOrderStatus()))
|
||||||
|
.thenCancel()
|
||||||
|
.verify();
|
||||||
|
} finally {
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addIncrementDecrementConfirmAndShipProduct(String orderId, String productId) {
|
||||||
|
WebClient client = WebClient.builder()
|
||||||
|
.clientConnector(httpConnector())
|
||||||
|
.build();
|
||||||
|
String base = "http://localhost:" + port + "/order/" + orderId;
|
||||||
|
verifyVoidPost(client, base + "/product/" + productId);
|
||||||
|
verifyVoidPost(client, base + "/product/" + productId + "/increment");
|
||||||
|
verifyVoidPost(client, base + "/product/" + productId + "/decrement");
|
||||||
|
verifyVoidPost(client, base + "/confirm");
|
||||||
|
verifyVoidPost(client, base + "/ship");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createRandomNewOrder(WebClient client){
|
||||||
|
StepVerifier.create(retrieveResponse(client.post()
|
||||||
|
.uri("http://localhost:" + port + "/order")))
|
||||||
|
.assertNext(Assertions::assertNotNull)
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyVoidPost(WebClient client, String uri) {
|
||||||
|
StepVerifier.create(retrieveResponse(client.post()
|
||||||
|
.uri(uri)))
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReactorClientHttpConnector httpConnector() {
|
||||||
|
HttpClient httpClient = HttpClient.create()
|
||||||
|
.wiretap(true);
|
||||||
|
return new ReactorClientHttpConnector(httpClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<String> retrieveResponse(WebClient.RequestBodySpec spec) {
|
||||||
|
return spec.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<ResponseList> retrieveListResponse(WebClient.RequestHeadersSpec<?> spec) {
|
||||||
|
return spec.accept(MediaType.APPLICATION_JSON)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(ResponseList.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<Integer> retrieveIntegerResponse(WebClient.RequestHeadersSpec<?> spec) {
|
||||||
|
return spec.retrieve()
|
||||||
|
.bodyToMono(Integer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Flux<OrderResponse> retrieveStreamingResponse(WebClient.RequestHeadersSpec<?> spec) {
|
||||||
|
return spec.retrieve()
|
||||||
|
.bodyToFlux(OrderResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ResponseList extends ArrayList<OrderResponse> {
|
||||||
|
|
||||||
|
private ResponseList() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,20 @@
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>${gson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -32,6 +46,8 @@
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source.version>11</maven.compiler.source.version>
|
<maven.compiler.source.version>11</maven.compiler.source.version>
|
||||||
<maven.compiler.target.version>11</maven.compiler.target.version>
|
<maven.compiler.target.version>11</maven.compiler.target.version>
|
||||||
|
<jackson.version>2.14.1</jackson.version>
|
||||||
|
<gson.version>2.10</gson.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.baeldung.httppojo;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Todo {
|
||||||
|
|
||||||
|
int userId;
|
||||||
|
int id;
|
||||||
|
String title;
|
||||||
|
boolean completed;
|
||||||
|
|
||||||
|
public Todo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Todo(int userId, int id, String title, boolean completed) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.id = id;
|
||||||
|
this.title = title;
|
||||||
|
this.completed = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(int userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCompleted() {
|
||||||
|
return completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompleted(boolean completed) {
|
||||||
|
this.completed = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o)
|
||||||
|
return true;
|
||||||
|
if (o == null || getClass() != o.getClass())
|
||||||
|
return false;
|
||||||
|
Todo todo = (Todo) o;
|
||||||
|
return userId == todo.userId && id == todo.id && completed == todo.completed && Objects.equals(title, todo.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(userId, id, title, completed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{" + "userId=" + userId + ", id=" + id + ", title='" + title + '\'' + ", completed=" + completed + '}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
package com.baeldung.httppojo;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.net.http.HttpResponse.BodyHandlers;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
public class TodoAppClient {
|
||||||
|
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
|
public String sampleApiRequest() throws Exception {
|
||||||
|
HttpClient client = HttpClient.newHttpClient();
|
||||||
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create("https://jsonplaceholder.typicode.com/todos"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
|
||||||
|
|
||||||
|
return response.body();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Todo syncGson() throws Exception {
|
||||||
|
String response = sampleApiRequest();
|
||||||
|
|
||||||
|
List<Todo> todo = gson.fromJson(response, new TypeToken<List<Todo>>() {
|
||||||
|
}.getType());
|
||||||
|
|
||||||
|
return todo.get(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Todo syncJackson() throws Exception {
|
||||||
|
String response = sampleApiRequest();
|
||||||
|
|
||||||
|
Todo[] todo = objectMapper.readValue(response, Todo[].class);
|
||||||
|
|
||||||
|
return todo[1];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Todo asyncJackson() throws Exception {
|
||||||
|
|
||||||
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create("https://jsonplaceholder.typicode.com/todos"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
TodoAppClient todoAppClient = new TodoAppClient();
|
||||||
|
|
||||||
|
List<Todo> todo = HttpClient.newHttpClient()
|
||||||
|
.sendAsync(request, BodyHandlers.ofString())
|
||||||
|
.thenApply(HttpResponse::body)
|
||||||
|
.thenApply(todoAppClient::readValueJackson)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return todo.get(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Todo asyncGson() throws Exception {
|
||||||
|
|
||||||
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create("https://jsonplaceholder.typicode.com/todos"))
|
||||||
|
.build();
|
||||||
|
TodoAppClient todoAppClient = new TodoAppClient();
|
||||||
|
|
||||||
|
List<Todo> todo = HttpClient.newHttpClient()
|
||||||
|
.sendAsync(request, BodyHandlers.ofString())
|
||||||
|
.thenApply(HttpResponse::body)
|
||||||
|
.thenApply(todoAppClient::readValueGson)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return todo.get(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Todo> readValueJackson(String content) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(content, new TypeReference<List<Todo>>() {
|
||||||
|
});
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new CompletionException(ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Todo> readValueGson(String content) {
|
||||||
|
|
||||||
|
return gson.fromJson(content, new TypeToken<List<Todo>>() {
|
||||||
|
}.getType());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.baeldung.httppojo;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class HttpClientPojoClassUnitTest {
|
||||||
|
|
||||||
|
Todo expectedTodo = new Todo(1, 2, "quis ut nam facilis et officia qui", false);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenSampleApiCall_whenResponseIsMappedByGson_thenCompareResponseMappedByGson() throws Exception {
|
||||||
|
TodoAppClient sampleGson = new TodoAppClient();
|
||||||
|
|
||||||
|
assertEquals(expectedTodo, sampleGson.syncGson());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenSampleApiCall_whenResponseIsMappedByJackson_thenCompareResponseMappedByJackson() throws Exception {
|
||||||
|
TodoAppClient sampleJackson = new TodoAppClient();
|
||||||
|
|
||||||
|
assertEquals(expectedTodo, sampleJackson.syncJackson());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenSampleRestApi_whenApiIsConsumedByHttpClient_thenCompareJsonString() throws Exception {
|
||||||
|
TodoAppClient sampleTest = new TodoAppClient();
|
||||||
|
assertNotNull(sampleTest.sampleApiRequest());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenSampleApiAsyncCall_whenResponseIsMappedByJackson_thenCompareResponseMappedByJackson() throws Exception {
|
||||||
|
TodoAppClient sampleAsynJackson = new TodoAppClient();
|
||||||
|
assertEquals(expectedTodo, sampleAsynJackson.asyncJackson());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenSampleApiAsyncCall_whenResponseIsMappedByGson_thenCompareResponseMappedByGson() throws Exception {
|
||||||
|
TodoAppClient sampleAsynGson = new TodoAppClient();
|
||||||
|
assertEquals(expectedTodo, sampleAsynGson.asyncGson());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package com.baeldung.features;
|
||||||
|
|
||||||
|
import jdk.incubator.concurrent.StructuredTaskScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||||
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||||
|
|
||||||
|
public class JEP428StructuredConcurrencyUnitTest {
|
||||||
|
|
||||||
|
private static final String ERROR_MESSAGE = "Failed to get the result";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenStructuredConcurrency_whenThrowingException_thenCorrect() {
|
||||||
|
assertThatThrownBy(() -> {
|
||||||
|
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
|
||||||
|
Future<Shelter> shelter = scope.fork(this::getShelter);
|
||||||
|
Future<List<Dog>> dogs = scope.fork(this::getDogsWithException);
|
||||||
|
scope.throwIfFailed(e -> new RuntimeException(ERROR_MESSAGE));
|
||||||
|
scope.join();
|
||||||
|
Response response = new Response(shelter.resultNow(), dogs.resultNow());
|
||||||
|
|
||||||
|
assertThat(response).isNotNull();
|
||||||
|
assertThat(response.shelter()).isNotNull();
|
||||||
|
assertThat(response.dogs()).isNotNull();
|
||||||
|
assertThat(response.dogs().size()).isEqualTo(2);
|
||||||
|
}
|
||||||
|
}).isInstanceOf(RuntimeException.class)
|
||||||
|
.hasMessage(ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenStructuredConcurrency_whenSlowTasksReachesDeadline_thenCorrect() {
|
||||||
|
assertThatThrownBy(() -> {
|
||||||
|
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
|
||||||
|
Future<Shelter> shelter = scope.fork(this::getShelter);
|
||||||
|
Future<List<Dog>> dogs = scope.fork(this::getDogsSlowly);
|
||||||
|
scope.throwIfFailed(e -> new RuntimeException(ERROR_MESSAGE));
|
||||||
|
scope.join();
|
||||||
|
scope.joinUntil(Instant.now().plusMillis(50));
|
||||||
|
Response response = new Response(shelter.resultNow(), dogs.resultNow());
|
||||||
|
|
||||||
|
assertThat(response).isNotNull();
|
||||||
|
assertThat(response.shelter()).isNotNull();
|
||||||
|
assertThat(response.dogs()).isNotNull();
|
||||||
|
assertThat(response.dogs().size()).isEqualTo(2);
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}).isInstanceOf(IllegalStateException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenStructuredConcurrency_whenResultNow_thenCorrect() {
|
||||||
|
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
|
||||||
|
Future<Shelter> shelter = scope.fork(this::getShelter);
|
||||||
|
Future<List<Dog>> dogs = scope.fork(this::getDogs);
|
||||||
|
scope.join();
|
||||||
|
|
||||||
|
Response response = new Response(shelter.resultNow(), dogs.resultNow());
|
||||||
|
|
||||||
|
assertThat(response).isNotNull();
|
||||||
|
assertThat(response.shelter()).isNotNull();
|
||||||
|
assertThat(response.dogs()).isNotNull();
|
||||||
|
assertThat(response.dogs().size()).isEqualTo(2);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenUnstructuredConcurrency_whenGet_thenCorrect() {
|
||||||
|
Future<Shelter> shelter;
|
||||||
|
Future<List<Dog>> dogs;
|
||||||
|
try (ExecutorService executorService = Executors.newFixedThreadPool(3)) {
|
||||||
|
shelter = executorService.submit(this::getShelter);
|
||||||
|
dogs = executorService.submit(this::getDogs);
|
||||||
|
Shelter theShelter = shelter.get(); // Join the shelter
|
||||||
|
List<Dog> theDogs = dogs.get(); // Join the dogs
|
||||||
|
Response response = new Response(theShelter, theDogs);
|
||||||
|
|
||||||
|
assertThat(response).isNotNull();
|
||||||
|
assertThat(response.shelter()).isNotNull();
|
||||||
|
assertThat(response.dogs()).isNotNull();
|
||||||
|
assertThat(response.dogs().size()).isEqualTo(2);
|
||||||
|
|
||||||
|
} catch (ExecutionException | InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Shelter getShelter() {
|
||||||
|
return new Shelter("Shelter");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Dog> getDogs() {
|
||||||
|
return List.of(new Dog("Buddy"), new Dog("Simba"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Dog> getDogsWithException() {
|
||||||
|
throw new RuntimeException(ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Dog> getDogsSlowly() throws InterruptedException {
|
||||||
|
Thread.sleep(1500);
|
||||||
|
throw new RuntimeException(ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
record Shelter(String name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record Dog(String name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record Response(Shelter shelter, List<Dog> dogs) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.baeldung.initializearraylistwithnullorzeros;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class InitializeArrayListWithNullOrZeros {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
ArrayList<Integer> arrayList = new ArrayList<>();
|
||||||
|
for (int i = 0; i< 10; i++) {
|
||||||
|
arrayList.add(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
package com.baeldung.initializearraylistwithnullorzeros;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class InitializeArrayListWithNullOrZerosUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInitializingListWithNCopies_thenListIsCorrectlyPopulated() {
|
||||||
|
// when
|
||||||
|
ArrayList<Integer> list = IntStream.of(new int[10])
|
||||||
|
.boxed()
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
|
||||||
|
// then
|
||||||
|
Assertions.assertEquals(10, list.size());
|
||||||
|
Assertions.assertTrue(list.stream().allMatch(elem -> elem == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInitializingListWithStream_thenListIsCorrectlyPopulated() {
|
||||||
|
|
||||||
|
// when
|
||||||
|
ArrayList<Integer> listWithZeros = Stream.generate(() -> 0)
|
||||||
|
.limit(10).collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
|
||||||
|
ArrayList<Object> listWithNulls = Stream.generate(() -> null)
|
||||||
|
.limit(10).collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
|
||||||
|
// then
|
||||||
|
Assertions.assertEquals(10, listWithZeros.size());
|
||||||
|
Assertions.assertTrue(listWithZeros.stream().allMatch(elem -> elem == 0));
|
||||||
|
|
||||||
|
Assertions.assertEquals(10, listWithNulls.size());
|
||||||
|
Assertions.assertTrue(listWithNulls.stream().allMatch(Objects::isNull));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void whenInitializingListWithIntStream_thenListIsCorrectlyPopulated() {
|
||||||
|
// when
|
||||||
|
ArrayList<Integer> list = IntStream.of(new int[10])
|
||||||
|
.boxed()
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
|
||||||
|
// then
|
||||||
|
Assertions.assertEquals(10, list.size());
|
||||||
|
Assertions.assertTrue(list.stream().allMatch(elem -> elem == 0)); }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInitializingListWithAsList_thenListIsCorrectlyPopulated() {
|
||||||
|
// when
|
||||||
|
Integer[] integers = new Integer[10];
|
||||||
|
Arrays.fill(integers, 0);
|
||||||
|
List<Integer> integerList = new ArrayList<>(Arrays.asList(integers));
|
||||||
|
|
||||||
|
// then
|
||||||
|
Assertions.assertEquals(10, integerList.size());
|
||||||
|
Assertions.assertTrue(integerList.stream().allMatch(elem -> elem == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInitializingListWithVector_thenListIsCorrectlyPopulated() {
|
||||||
|
// when
|
||||||
|
List<Integer> integerList = new Vector<>() {{setSize(10);}};
|
||||||
|
|
||||||
|
// then
|
||||||
|
Assertions.assertEquals(10, integerList.size());
|
||||||
|
Assertions.assertTrue(integerList.stream().allMatch(Objects::isNull));
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,3 +3,4 @@
|
||||||
This module contains articles about the Java List collection
|
This module contains articles about the Java List collection
|
||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
- [Java List Interface](https://www.baeldung.com/java-list-interface)
|
||||||
|
|
|
@ -9,4 +9,5 @@ This module contains articles about core java exceptions
|
||||||
- [“Sneaky Throws” in Java](https://www.baeldung.com/java-sneaky-throws)
|
- [“Sneaky Throws” in Java](https://www.baeldung.com/java-sneaky-throws)
|
||||||
- [Get the Current Stack Trace in Java](https://www.baeldung.com/java-get-current-stack-trace)
|
- [Get the Current Stack Trace in Java](https://www.baeldung.com/java-get-current-stack-trace)
|
||||||
- [Errors and Exceptions in Java](https://www.baeldung.com/java-errors-vs-exceptions)
|
- [Errors and Exceptions in Java](https://www.baeldung.com/java-errors-vs-exceptions)
|
||||||
|
- [Fix the IllegalArgumentException: No enum const class](https://www.baeldung.com/java-fix-no-enum-const-class)
|
||||||
- [[<-- Prev]](../core-java-exceptions-3)
|
- [[<-- Prev]](../core-java-exceptions-3)
|
||||||
|
|
|
@ -14,4 +14,30 @@
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-inline</artifactId>
|
||||||
|
<version>${mockito-inline.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>core-java-functional</finalName>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<mockito-inline.version>3.8.0</mockito-inline.version>
|
||||||
|
<assertj.version>3.22.0</assertj.version>
|
||||||
|
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||||
|
<vavr.version>0.10.4</vavr.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.baeldung.callbackfunctions;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class ConsumerCallback {
|
||||||
|
public void getAge(int initialAge, Consumer<Integer> callback) {
|
||||||
|
callback.accept(initialAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void increaseAge(int initialAge, int ageDifference, Consumer<Integer> callback) {
|
||||||
|
System.out.println("===== Increase age ====");
|
||||||
|
|
||||||
|
int newAge = initialAge + ageDifference;
|
||||||
|
callback.accept(newAge);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.baeldung.callbackfunctions;
|
||||||
|
|
||||||
|
public interface EventListener {
|
||||||
|
|
||||||
|
String onTrigger();
|
||||||
|
|
||||||
|
void respondToTrigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.baeldung.callbackfunctions.asynchronous;
|
||||||
|
|
||||||
|
import com.baeldung.callbackfunctions.EventListener;
|
||||||
|
|
||||||
|
public class AsynchronousEventConsumer{
|
||||||
|
|
||||||
|
private EventListener listener;
|
||||||
|
|
||||||
|
public AsynchronousEventConsumer(EventListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doAsynchronousOperation()
|
||||||
|
{
|
||||||
|
System.out.println("Performing operation in Asynchronous Task");
|
||||||
|
|
||||||
|
new Thread(() -> listener.onTrigger()).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.baeldung.callbackfunctions.asynchronous;
|
||||||
|
|
||||||
|
import com.baeldung.callbackfunctions.EventListener;
|
||||||
|
|
||||||
|
public class AsynchronousEventListenerImpl implements EventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String onTrigger()
|
||||||
|
{
|
||||||
|
respondToTrigger();
|
||||||
|
return "Asynchronously running callback function";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void respondToTrigger(){
|
||||||
|
System.out.println("This is a side effect of the asynchronous trigger.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.callbackfunctions.synchronous;
|
||||||
|
|
||||||
|
import com.baeldung.callbackfunctions.EventListener;
|
||||||
|
|
||||||
|
public class SynchronousEventConsumer {
|
||||||
|
|
||||||
|
private final EventListener eventListener;
|
||||||
|
|
||||||
|
public SynchronousEventConsumer(EventListener listener)
|
||||||
|
{
|
||||||
|
this.eventListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String doSynchronousOperation()
|
||||||
|
{
|
||||||
|
System.out.println("Performing callback before synchronous Task");
|
||||||
|
|
||||||
|
return eventListener.onTrigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.baeldung.callbackfunctions.synchronous;
|
||||||
|
|
||||||
|
import com.baeldung.callbackfunctions.EventListener;
|
||||||
|
|
||||||
|
public class SynchronousEventListenerImpl implements EventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String onTrigger()
|
||||||
|
{
|
||||||
|
return "Synchronously running callback function";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void respondToTrigger(){
|
||||||
|
System.out.println("Response to trigger");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.callbackfunctions;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import com.baeldung.callbackfunctions.EventListener;
|
||||||
|
import com.baeldung.callbackfunctions.asynchronous.AsynchronousEventConsumer;
|
||||||
|
import com.baeldung.callbackfunctions.asynchronous.AsynchronousEventListenerImpl;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
public class AsynchronousCallbackUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCallbackIsInvokedAsynchronously_shouldRunAsynchronousOperation(){
|
||||||
|
EventListener listener = Mockito.mock(AsynchronousEventListenerImpl.class);
|
||||||
|
AsynchronousEventConsumer asynchronousEventListenerConsumer = new AsynchronousEventConsumer(listener);
|
||||||
|
asynchronousEventListenerConsumer.doAsynchronousOperation();
|
||||||
|
|
||||||
|
verify(listener, times(1)).onTrigger();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.baeldung.callbackfunctions;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import com.baeldung.callbackfunctions.ConsumerCallback;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class ConsumerCallbackUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenIncreasingInitialAgeByGivenValueThroughCallback_shouldIncreaseAge(){
|
||||||
|
ConsumerCallback consumerCallback = new ConsumerCallback();
|
||||||
|
consumerCallback.getAge(20, (initialAge) -> {
|
||||||
|
int ageDifference = 10;
|
||||||
|
consumerCallback.increaseAge(initialAge, ageDifference, (newAge) -> {
|
||||||
|
assertEquals(initialAge + ageDifference, newAge);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package callbackFunctions;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import com.baeldung.callbackfunctions.EventListener;
|
||||||
|
import com.baeldung.callbackfunctions.synchronous.SynchronousEventConsumer;
|
||||||
|
import com.baeldung.callbackfunctions.synchronous.SynchronousEventListenerImpl;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
public class SynchronousCallbackUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCallbackIsInvokedSynchronously_shouldRunSynchronousOperation(){
|
||||||
|
EventListener listener = new SynchronousEventListenerImpl();
|
||||||
|
SynchronousEventConsumer synchronousEventConsumer = new SynchronousEventConsumer(listener);
|
||||||
|
String result = synchronousEventConsumer.doSynchronousOperation();
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals("Synchronously running callback function", result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ public class InMemoryCompilationUnitTest {
|
||||||
|
|
||||||
boolean result = task.call();
|
boolean result = task.call();
|
||||||
|
|
||||||
if (result) {
|
if (!result) {
|
||||||
diagnostics.getDiagnostics()
|
diagnostics.getDiagnostics()
|
||||||
.forEach(d -> LOGGER.error(String.valueOf(d)));
|
.forEach(d -> LOGGER.error(String.valueOf(d)));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,6 +11,8 @@ public class Book implements Serializable {
|
||||||
private transient int copies;
|
private transient int copies;
|
||||||
private final transient String bookCategory = "Fiction";
|
private final transient String bookCategory = "Fiction";
|
||||||
|
|
||||||
|
private final transient String bookCategoryNewOperator = new String("Fiction with new Operator");
|
||||||
|
|
||||||
public String getBookName() {
|
public String getBookName() {
|
||||||
return bookName;
|
return bookName;
|
||||||
}
|
}
|
||||||
|
@ -39,4 +41,7 @@ public class Book implements Serializable {
|
||||||
return bookCategory;
|
return bookCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getBookCategoryNewOperator() {
|
||||||
|
return bookCategoryNewOperator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,16 @@ class TransientUnitTest {
|
||||||
assertEquals("Fiction", book2.getBookCategory());
|
assertEquals("Fiction", book2.getBookCategory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenFinalTransientWithNewOperator_whenSerDe_thenValuePersisted() throws Exception {
|
||||||
|
Book book = new Book();
|
||||||
|
|
||||||
|
BookSerDe.serialize(book);
|
||||||
|
Book book2 = BookSerDe.deserialize();
|
||||||
|
|
||||||
|
assertNull(book2.getBookCategoryNewOperator());
|
||||||
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
public static void cleanup() {
|
public static void cleanup() {
|
||||||
File file = new File(BookSerDe.fileName);
|
File file = new File(BookSerDe.fileName);
|
||||||
|
|
|
@ -12,4 +12,5 @@ This module contains articles about core features in the Java language
|
||||||
- [Infinity in Java](https://www.baeldung.com/java-infinity)
|
- [Infinity in Java](https://www.baeldung.com/java-infinity)
|
||||||
- [Type Parameter vs Wildcard in Java Generics](https://www.baeldung.com/java-generics-type-parameter-vs-wildcard)
|
- [Type Parameter vs Wildcard in Java Generics](https://www.baeldung.com/java-generics-type-parameter-vs-wildcard)
|
||||||
- [Convert Between int and char in Java](https://www.baeldung.com/java-convert-int-char)
|
- [Convert Between int and char in Java](https://www.baeldung.com/java-convert-int-char)
|
||||||
-
|
- [Converting a Number from One Base to Another in Java](https://www.baeldung.com/java-converting-a-number-from-one-base-to-another)
|
||||||
|
- [Check if Command-Line Arguments Are Null in Java](https://www.baeldung.com/java-check-command-line-args)
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||||
|
<reflections.version>0.10.2</reflections.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<finalName>core-java-lang-5</finalName>
|
<finalName>core-java-lang-5</finalName>
|
||||||
<resources>
|
<resources>
|
||||||
|
@ -24,4 +30,18 @@
|
||||||
</resources>
|
</resources>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${commons-lang3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.reflections</groupId>
|
||||||
|
<artifactId>reflections</artifactId>
|
||||||
|
<version>${reflections.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.baeldung.checkinterface;
|
||||||
|
|
||||||
|
public class ChildClass1 implements ChildInterface1 {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.baeldung.checkinterface;
|
||||||
|
|
||||||
|
public class ChildClass2 implements ChildInterface2 {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.baeldung.checkinterface;
|
||||||
|
|
||||||
|
public interface ChildInterface1 extends MasterInterface {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.baeldung.checkinterface;
|
||||||
|
|
||||||
|
public interface ChildInterface2 extends MasterInterface {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.baeldung.checkinterface;
|
||||||
|
|
||||||
|
public class MasterClass implements MasterInterface {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.baeldung.checkinterface;
|
||||||
|
|
||||||
|
public interface MasterInterface {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.baeldung.commandline;
|
||||||
|
|
||||||
|
public class CommandLineWithErrorHandling {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
if (args.length > 0) {
|
||||||
|
System.out.println(args[0]);
|
||||||
|
} else {
|
||||||
|
System.out.println("No command line arguments were provided.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.baeldung.commandline;
|
||||||
|
|
||||||
|
public class CommandLineWithoutErrorHandling {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
System.out.println(args[0]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
package com.baeldung.checkinterface;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ClassUtils;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.reflections.ReflectionUtils;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
|
public class CheckInterfaceUnitTest {
|
||||||
|
|
||||||
|
protected static Reflections reflections;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void initializeReflectionsLibrary() {
|
||||||
|
|
||||||
|
reflections = new Reflections("com.baeldung.checkinterface");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflectionGetInterfaces_thenDirectlyImplementedInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
List<Class<?>> interfaces = Arrays.asList(childClass2.getClass().getInterfaces());
|
||||||
|
|
||||||
|
assertEquals(1, interfaces.size());
|
||||||
|
assertTrue(interfaces.contains(ChildInterface2.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflectionGetInterfaces_thenParentInterfaceIsNotFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
List<Class<?>> interfaces = Arrays.asList(childClass2.getClass().getInterfaces());
|
||||||
|
|
||||||
|
assertFalse(interfaces.contains(MasterInterface.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflectionGetInterfacesRecursively_thenParentInterfaceIsFound() {
|
||||||
|
|
||||||
|
Set<Class<?>> interfaces = getAllExtendedOrImplementedInterfacesRecursively(ChildClass2.class);
|
||||||
|
|
||||||
|
assertTrue(interfaces.contains(ChildInterface2.class));
|
||||||
|
assertTrue(interfaces.contains(MasterInterface.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflectionIsAssignableFrom_thenDirectlyImplementedInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
|
||||||
|
assertTrue(ChildInterface2.class.isAssignableFrom(childClass2.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflectionIsAssignableFrom_thenParentInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
|
||||||
|
assertTrue(MasterInterface.class.isAssignableFrom(childClass2.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflectionIsInstance_thenDirectlyImplementedInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
|
||||||
|
assertTrue(ChildInterface2.class.isInstance(childClass2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflectionIsInstance_thenParentInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
|
||||||
|
assertTrue(MasterInterface.class.isInstance(childClass2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflectionInstanceOf_thenDirectlyImplementedInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
|
||||||
|
assertTrue(childClass2 instanceof ChildInterface2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflectionInstanceOf_thenParentInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
|
||||||
|
assertTrue(childClass2 instanceof MasterInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingCommons_thenDirectlyImplementedInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
List<Class<?>> interfaces = ClassUtils.getAllInterfaces(childClass2.getClass());
|
||||||
|
|
||||||
|
assertTrue(interfaces.contains(ChildInterface2.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingCommons_thenParentInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
List<Class<?>> interfaces = ClassUtils.getAllInterfaces(childClass2.getClass());
|
||||||
|
|
||||||
|
assertTrue(interfaces.contains(MasterInterface.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflections_thenDirectlyImplementedInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
Set<Class<?>> interfaces = reflections.get(ReflectionUtils.Interfaces.of(childClass2.getClass()));
|
||||||
|
|
||||||
|
assertTrue(interfaces.contains(ChildInterface2.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUsingReflections_thenParentInterfaceIsFound() {
|
||||||
|
|
||||||
|
ChildClass2 childClass2 = new ChildClass2();
|
||||||
|
Set<Class<?>> interfaces = reflections.get(ReflectionUtils.Interfaces.of(childClass2.getClass()));
|
||||||
|
|
||||||
|
assertTrue(interfaces.contains(MasterInterface.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Set<Class<?>> getAllExtendedOrImplementedInterfacesRecursively(Class<?> clazz) {
|
||||||
|
|
||||||
|
Set<Class<?>> res = new HashSet<Class<?>>();
|
||||||
|
Class<?>[] interfaces = clazz.getInterfaces();
|
||||||
|
|
||||||
|
if (interfaces.length > 0) {
|
||||||
|
res.addAll(Arrays.asList(interfaces));
|
||||||
|
for (Class<?> interfaze : interfaces) {
|
||||||
|
res.addAll(getAllExtendedOrImplementedInterfacesRecursively(interfaze));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.baeldung.commandline;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class CommandLineWithoutErrorHandlingUnitTest {
|
||||||
|
|
||||||
|
@Test(expected = NullPointerException.class)
|
||||||
|
public void givenNullCommandLineArgument_whenPassedToMainFunction_thenExpectNullPointerException() {
|
||||||
|
CommandLineWithoutErrorHandling.main(null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package com.baeldung.enums.comparestrenum;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static com.baeldung.enums.comparestrenum.Weekday.Fri;
|
||||||
|
import static com.baeldung.enums.comparestrenum.Weekday.Sat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
enum Weekday {
|
||||||
|
Mon("Monday"),
|
||||||
|
Tue("Tuesday"),
|
||||||
|
Wed("Wednesday"),
|
||||||
|
Thu("Thursday"),
|
||||||
|
Fri("Friday"),
|
||||||
|
Sat("Saturday");
|
||||||
|
|
||||||
|
private String fullName;
|
||||||
|
|
||||||
|
Weekday(String fullName) {
|
||||||
|
this.fullName = fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullName() {
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Optional<Weekday> byFullNameIgnoreCase(String givenFullName) {
|
||||||
|
return Arrays.stream(values()).filter(it -> it.fullName.equalsIgnoreCase(givenFullName)).findAny();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Optional<Weekday> byNameIgnoreCase(String givenName) {
|
||||||
|
return Arrays.stream(values()).filter(it -> it.name().equalsIgnoreCase(givenName)).findAny();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CompareStringAndEnumUnitTest {
|
||||||
|
private static final String SAT = "sAt";
|
||||||
|
private static final String SATURDAY = "sAtuRdAy";
|
||||||
|
private static final String TYPO_FRI = "ffri";
|
||||||
|
private static final String TYPO_FRIDAY = "ffriday";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenAString_whenCompareEnumWithName_thenGetExpectedResult() {
|
||||||
|
assertTrue(SAT.equalsIgnoreCase(Sat.name()));
|
||||||
|
assertFalse(TYPO_FRI.equalsIgnoreCase(Fri.name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenAString_whenCompareEnumWithProperty_thenGetExpectedResult() {
|
||||||
|
assertTrue(SATURDAY.equalsIgnoreCase(Sat.getFullName()));
|
||||||
|
assertFalse(TYPO_FRI.equalsIgnoreCase(Fri.getFullName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenAString_whenFindEnumByName_thenGetExpectedResult() {
|
||||||
|
Optional<Weekday> optResult = Weekday.byNameIgnoreCase(SAT);
|
||||||
|
assertTrue(optResult.isPresent());
|
||||||
|
assertEquals(Sat, optResult.get());
|
||||||
|
|
||||||
|
Optional<Weekday> optResult2 = Weekday.byNameIgnoreCase(TYPO_FRI);
|
||||||
|
assertFalse(optResult2.isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenAString_whenFindEnumByProperty_thenGetExpectedResult() {
|
||||||
|
Optional<Weekday> optResult = Weekday.byFullNameIgnoreCase(SATURDAY);
|
||||||
|
assertTrue(optResult.isPresent());
|
||||||
|
assertEquals(Sat, optResult.get());
|
||||||
|
|
||||||
|
Optional<Weekday> optResult2 = Weekday.byFullNameIgnoreCase(TYPO_FRIDAY);
|
||||||
|
assertFalse(optResult2.isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -25,15 +25,20 @@
|
||||||
<version>${commons-lang3.version}</version>
|
<version>${commons-lang3.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.mail</groupId>
|
<groupId>org.eclipse.angus</groupId>
|
||||||
<artifactId>mail</artifactId>
|
<artifactId>angus-mail</artifactId>
|
||||||
<version>${javax.mail.version}</version>
|
<version>${angus.mail.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.asynchttpclient</groupId>
|
<groupId>org.asynchttpclient</groupId>
|
||||||
<artifactId>async-http-client</artifactId>
|
<artifactId>async-http-client</artifactId>
|
||||||
<version>${async-http-client.version}</version>
|
<version>${async-http-client.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.xml.bind</groupId>
|
||||||
|
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||||
|
<version>${jakarta.bind.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.icegreen</groupId>
|
<groupId>com.icegreen</groupId>
|
||||||
<artifactId>greenmail</artifactId>
|
<artifactId>greenmail</artifactId>
|
||||||
|
@ -48,9 +53,10 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<httpclient.version>4.5.9</httpclient.version>
|
<httpclient.version>4.5.9</httpclient.version>
|
||||||
<javax.mail.version>1.5.0-b01</javax.mail.version>
|
<angus.mail.version>2.0.1</angus.mail.version>
|
||||||
<async-http-client.version>2.4.5</async-http-client.version>
|
<async-http-client.version>2.4.5</async-http-client.version>
|
||||||
<greenmail.version>1.5.8</greenmail.version>
|
<jakarta.bind.version>2.3.3</jakarta.bind.version>
|
||||||
|
<greenmail.version>2.0.0-alpha-3</greenmail.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -1,19 +1,20 @@
|
||||||
package com.baeldung.mail;
|
package com.baeldung.mail;
|
||||||
|
|
||||||
import javax.mail.Authenticator;
|
|
||||||
import javax.mail.Message;
|
|
||||||
import javax.mail.Multipart;
|
|
||||||
import javax.mail.PasswordAuthentication;
|
|
||||||
import javax.mail.Session;
|
|
||||||
import javax.mail.Transport;
|
|
||||||
import javax.mail.internet.InternetAddress;
|
|
||||||
import javax.mail.internet.MimeBodyPart;
|
|
||||||
import javax.mail.internet.MimeMessage;
|
|
||||||
import javax.mail.internet.MimeMultipart;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import jakarta.mail.Authenticator;
|
||||||
|
import jakarta.mail.Message;
|
||||||
|
import jakarta.mail.Multipart;
|
||||||
|
import jakarta.mail.PasswordAuthentication;
|
||||||
|
import jakarta.mail.Session;
|
||||||
|
import jakarta.mail.Transport;
|
||||||
|
import jakarta.mail.internet.InternetAddress;
|
||||||
|
import jakarta.mail.internet.MimeBodyPart;
|
||||||
|
import jakarta.mail.internet.MimeMessage;
|
||||||
|
import jakarta.mail.internet.MimeMultipart;
|
||||||
|
|
||||||
public class EmailService {
|
public class EmailService {
|
||||||
|
|
||||||
private String username;
|
private String username;
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
package com.baeldung.mail.mailwithattachment;
|
package com.baeldung.mail.mailwithattachment;
|
||||||
|
|
||||||
import javax.mail.BodyPart;
|
|
||||||
import javax.mail.Message;
|
|
||||||
import javax.mail.MessagingException;
|
|
||||||
import javax.mail.Multipart;
|
|
||||||
import javax.mail.PasswordAuthentication;
|
|
||||||
import javax.mail.Session;
|
|
||||||
import javax.mail.Transport;
|
|
||||||
import javax.mail.internet.InternetAddress;
|
|
||||||
import javax.mail.internet.MimeBodyPart;
|
|
||||||
import javax.mail.internet.MimeMessage;
|
|
||||||
import javax.mail.internet.MimeMultipart;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import jakarta.mail.Authenticator;
|
||||||
|
import jakarta.mail.BodyPart;
|
||||||
|
import jakarta.mail.Message;
|
||||||
|
import jakarta.mail.MessagingException;
|
||||||
|
import jakarta.mail.Multipart;
|
||||||
|
import jakarta.mail.PasswordAuthentication;
|
||||||
|
import jakarta.mail.Session;
|
||||||
|
import jakarta.mail.Transport;
|
||||||
|
import jakarta.mail.internet.InternetAddress;
|
||||||
|
import jakarta.mail.internet.MimeBodyPart;
|
||||||
|
import jakarta.mail.internet.MimeMessage;
|
||||||
|
import jakarta.mail.internet.MimeMultipart;
|
||||||
|
|
||||||
public class MailWithAttachmentService {
|
public class MailWithAttachmentService {
|
||||||
|
|
||||||
private final String username;
|
private final String username;
|
||||||
|
@ -37,7 +39,7 @@ public class MailWithAttachmentService {
|
||||||
props.put("mail.smtp.host", this.host);
|
props.put("mail.smtp.host", this.host);
|
||||||
props.put("mail.smtp.port", this.port);
|
props.put("mail.smtp.port", this.port);
|
||||||
|
|
||||||
return Session.getInstance(props, new javax.mail.Authenticator() {
|
return Session.getInstance(props, new Authenticator() {
|
||||||
protected PasswordAuthentication getPasswordAuthentication() {
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
return new PasswordAuthentication(username, password);
|
return new PasswordAuthentication(username, password);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package com.baeldung.download;
|
package com.baeldung.download;
|
||||||
|
|
||||||
import org.junit.After;
|
import static org.junit.Assert.assertTrue;
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -13,7 +10,11 @@ import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import javax.xml.bind.DatatypeConverter;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
public class FileDownloadIntegrationTest {
|
public class FileDownloadIntegrationTest {
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
package com.baeldung.mail;
|
package com.baeldung.mail;
|
||||||
|
|
||||||
import com.icegreen.greenmail.junit.GreenMailRule;
|
import static org.junit.Assert.assertEquals;
|
||||||
import com.icegreen.greenmail.util.ServerSetupTest;
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.mail.MessagingException;
|
import com.icegreen.greenmail.junit.GreenMailRule;
|
||||||
import javax.mail.internet.MimeMessage;
|
import com.icegreen.greenmail.util.ServerSetupTest;
|
||||||
import javax.mail.internet.MimeMultipart;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import jakarta.mail.MessagingException;
|
||||||
|
import jakarta.mail.internet.MimeMessage;
|
||||||
|
import jakarta.mail.internet.MimeMultipart;
|
||||||
|
|
||||||
public class EmailServiceLiveTest {
|
public class EmailServiceLiveTest {
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
package com.baeldung.mail.mailwithattachment;
|
package com.baeldung.mail.mailwithattachment;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import com.icegreen.greenmail.configuration.GreenMailConfiguration;
|
import com.icegreen.greenmail.configuration.GreenMailConfiguration;
|
||||||
import com.icegreen.greenmail.junit.GreenMailRule;
|
import com.icegreen.greenmail.junit.GreenMailRule;
|
||||||
import com.icegreen.greenmail.util.GreenMailUtil;
|
import com.icegreen.greenmail.util.GreenMailUtil;
|
||||||
import com.icegreen.greenmail.util.ServerSetupTest;
|
import com.icegreen.greenmail.util.ServerSetupTest;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import jakarta.mail.MessagingException;
|
||||||
import javax.mail.MessagingException;
|
import jakarta.mail.Session;
|
||||||
import javax.mail.Session;
|
import jakarta.mail.internet.MimeMessage;
|
||||||
import javax.mail.internet.MimeMessage;
|
import jakarta.mail.internet.MimeMultipart;
|
||||||
import javax.mail.internet.MimeMultipart;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
public class MailWithAttachmentServiceLiveTest {
|
public class MailWithAttachmentServiceLiveTest {
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ public class MailWithAttachmentServiceLiveTest {
|
||||||
.withUser(USERNAME, PASSWORD)
|
.withUser(USERNAME, PASSWORD)
|
||||||
);
|
);
|
||||||
|
|
||||||
@Resource
|
|
||||||
private MailWithAttachmentService emailService;
|
private MailWithAttachmentService emailService;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -73,5 +72,4 @@ public class MailWithAttachmentServiceLiveTest {
|
||||||
return GreenMailUtil.getBody(((MimeMultipart) receivedMessage.getContent())
|
return GreenMailUtil.getBody(((MimeMultipart) receivedMessage.getContent())
|
||||||
.getBodyPart(2));
|
.getBodyPart(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,9 @@
|
||||||
<version>${tomcat.embeded.version}</version>
|
<version>${tomcat.embeded.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sun.mail</groupId>
|
<groupId>org.eclipse.angus</groupId>
|
||||||
<artifactId>javax.mail</artifactId>
|
<artifactId>angus-mail</artifactId>
|
||||||
<version>${javax.mail.version}</version>
|
<version>${angus.mail.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/com.github.seancfoley/ipaddress -->
|
<!-- https://mvnrepository.com/artifact/com.github.seancfoley/ipaddress -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
<seancfoley.ipaddress.version>5.3.3</seancfoley.ipaddress.version>
|
<seancfoley.ipaddress.version>5.3.3</seancfoley.ipaddress.version>
|
||||||
<jgonian.commons-ip-math.version>1.32</jgonian.commons-ip-math.version>
|
<jgonian.commons-ip-math.version>1.32</jgonian.commons-ip-math.version>
|
||||||
<googlecode.ipv6.version>0.17</googlecode.ipv6.version>
|
<googlecode.ipv6.version>0.17</googlecode.ipv6.version>
|
||||||
<javax.mail.version>1.6.2</javax.mail.version>
|
<angus.mail.version>2.0.1</angus.mail.version>
|
||||||
<apache.commons-validator.version>1.7</apache.commons-validator.version>
|
<apache.commons-validator.version>1.7</apache.commons-validator.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
@ -6,16 +6,16 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.mail.Address;
|
import jakarta.mail.Address;
|
||||||
import javax.mail.Folder;
|
import jakarta.mail.Folder;
|
||||||
import javax.mail.Message;
|
import jakarta.mail.Message;
|
||||||
import javax.mail.MessagingException;
|
import jakarta.mail.MessagingException;
|
||||||
import javax.mail.Multipart;
|
import jakarta.mail.Multipart;
|
||||||
import javax.mail.NoSuchProviderException;
|
import jakarta.mail.NoSuchProviderException;
|
||||||
import javax.mail.Part;
|
import jakarta.mail.Part;
|
||||||
import javax.mail.Session;
|
import jakarta.mail.Session;
|
||||||
import javax.mail.Store;
|
import jakarta.mail.Store;
|
||||||
import javax.mail.internet.MimeBodyPart;
|
import jakarta.mail.internet.MimeBodyPart;
|
||||||
|
|
||||||
public class DownloadEmailAttachments {
|
public class DownloadEmailAttachments {
|
||||||
private String downloadDirectory;
|
private String downloadDirectory;
|
||||||
|
@ -24,7 +24,7 @@ public class DownloadEmailAttachments {
|
||||||
this.downloadDirectory = dir;
|
this.downloadDirectory = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void downloadEmailAttachments(String host, String port, String userName, String password) throws NoSuchProviderException, MessagingException, IOException {
|
public void downloadEmailAttachments(String host, String port, String userName, String password) throws MessagingException, IOException {
|
||||||
Properties properties = setMailServerProperties(host, port);
|
Properties properties = setMailServerProperties(host, port);
|
||||||
Store store = setSessionStoreProperties(userName, password, properties);
|
Store store = setSessionStoreProperties(userName, password, properties);
|
||||||
Folder inbox = store.getFolder("INBOX");
|
Folder inbox = store.getFolder("INBOX");
|
||||||
|
@ -67,7 +67,7 @@ public class DownloadEmailAttachments {
|
||||||
return downloadedAttachments;
|
return downloadedAttachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Store setSessionStoreProperties(String userName, String password, Properties properties) throws NoSuchProviderException, MessagingException {
|
public Store setSessionStoreProperties(String userName, String password, Properties properties) throws MessagingException {
|
||||||
Session session = Session.getDefaultInstance(properties);
|
Session session = Session.getDefaultInstance(properties);
|
||||||
|
|
||||||
Store store = session.getStore("pop3");
|
Store store = session.getStore("pop3");
|
||||||
|
|
|
@ -6,3 +6,4 @@
|
||||||
- [List All Factors of a Number in Java](https://www.baeldung.com/java-list-factors-integer)
|
- [List All Factors of a Number in Java](https://www.baeldung.com/java-list-factors-integer)
|
||||||
- [Make Division of Two Integers Result in a Float](https://www.baeldung.com/java-integer-division-float-result)
|
- [Make Division of Two Integers Result in a Float](https://www.baeldung.com/java-integer-division-float-result)
|
||||||
- [Creating Random Numbers With No Duplicates in Java](https://www.baeldung.com/java-unique-random-numbers)
|
- [Creating Random Numbers With No Duplicates in Java](https://www.baeldung.com/java-unique-random-numbers)
|
||||||
|
- [Multiply a BigDecimal by an Integer in Java](https://www.baeldung.com/java-bigdecimal-multiply-integer)
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.baeldung;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
|
||||||
|
public class IntegerNullOrZero {
|
||||||
|
private IntegerNullOrZero() {
|
||||||
|
throw new RuntimeException("This class cannot be instantiated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean usingStandardWay(Integer num) {
|
||||||
|
return num == null || num == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean usingTernaryOperator(Integer num) {
|
||||||
|
return 0 == (num == null ? 0 : num);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean usingOptional(Integer num) {
|
||||||
|
return Optional.ofNullable(num).orElse(0) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean usingObjectUtils(Integer num) {
|
||||||
|
return ObjectUtils.defaultIfNull(num, 0) == 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.bigdecimaltimesint;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class BigDecimalxIntegerUnitTest {
|
||||||
|
private static final BigDecimal BIG = new BigDecimal("42.42");
|
||||||
|
private static final int INT = 10;
|
||||||
|
private static final BigDecimal EXPECTED = new BigDecimal("424.2");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenBigDecimalAndInt_whenTimes_thenGetExpectedResult() {
|
||||||
|
BigDecimal result = BIG.multiply(BigDecimal.valueOf(INT));
|
||||||
|
|
||||||
|
assertEquals(0, EXPECTED.compareTo(result));
|
||||||
|
assertThat(result).isEqualByComparingTo(EXPECTED);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.baeldung.intnullorzero;
|
||||||
|
|
||||||
|
import static com.baeldung.IntegerNullOrZero.usingObjectUtils;
|
||||||
|
import static com.baeldung.IntegerNullOrZero.usingOptional;
|
||||||
|
import static com.baeldung.IntegerNullOrZero.usingStandardWay;
|
||||||
|
import static com.baeldung.IntegerNullOrZero.usingTernaryOperator;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class IntegerNullOrZeroUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenInts_whenUsingStandardWay_thenGetExpectedResult() {
|
||||||
|
int n0 = 0;
|
||||||
|
boolean result0 = usingStandardWay(n0);
|
||||||
|
assertTrue(result0);
|
||||||
|
|
||||||
|
boolean resultNull = usingStandardWay(null);
|
||||||
|
assertTrue(resultNull);
|
||||||
|
|
||||||
|
int n42 = 42;
|
||||||
|
boolean result42 = usingStandardWay(n42);
|
||||||
|
assertFalse(result42);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenInts_whenUsingTernaryOperator_thenGetExpectedResult() {
|
||||||
|
int n0 = 0;
|
||||||
|
boolean result0 = usingTernaryOperator(n0);
|
||||||
|
assertTrue(result0);
|
||||||
|
|
||||||
|
boolean resultNull = usingTernaryOperator(null);
|
||||||
|
assertTrue(resultNull);
|
||||||
|
|
||||||
|
int n42 = 42;
|
||||||
|
boolean result42 = usingTernaryOperator(n42);
|
||||||
|
assertFalse(result42);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenInts_whenUsingOptional_thenGetExpectedResult() {
|
||||||
|
int n0 = 0;
|
||||||
|
boolean result0 = usingOptional(n0);
|
||||||
|
assertTrue(result0);
|
||||||
|
|
||||||
|
boolean resultNull = usingOptional(null);
|
||||||
|
assertTrue(resultNull);
|
||||||
|
|
||||||
|
int n42 = 42;
|
||||||
|
boolean result42 = usingOptional(n42);
|
||||||
|
assertFalse(result42);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenInts_whenUsingObjectUtils_thenGetExpectedResult() {
|
||||||
|
int n0 = 0;
|
||||||
|
boolean result0 = usingObjectUtils(n0);
|
||||||
|
assertTrue(result0);
|
||||||
|
|
||||||
|
boolean resultNull = usingObjectUtils(null);
|
||||||
|
assertTrue(resultNull);
|
||||||
|
|
||||||
|
int n42 = 42;
|
||||||
|
boolean result42 = usingObjectUtils(n42);
|
||||||
|
assertFalse(result42);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,20 +14,20 @@ public class CustomBatchIterator<T> implements Iterator<List<T>> {
|
||||||
private List<T> currentBatch;
|
private List<T> currentBatch;
|
||||||
private final Iterator<T> iterator;
|
private final Iterator<T> iterator;
|
||||||
|
|
||||||
public CustomBatchIterator(Iterator<T> sourceIterator, int batchSize) {
|
private CustomBatchIterator(Iterator<T> sourceIterator, int batchSize) {
|
||||||
this.batchSize = batchSize;
|
this.batchSize = batchSize;
|
||||||
this.iterator = sourceIterator;
|
this.iterator = sourceIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<T> next() {
|
public List<T> next() {
|
||||||
|
prepareNextBatch();
|
||||||
return currentBatch;
|
return currentBatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
prepareNextBatch();
|
return iterator.hasNext();
|
||||||
return currentBatch != null && !currentBatch.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Stream<List<T>> batchStreamOf(Stream<T> stream, int batchSize) {
|
public static <T> Stream<List<T>> batchStreamOf(Stream<T> stream, int batchSize) {
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.baeldung.streams.streamtoiterable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import joptsimple.internal.Strings;
|
||||||
|
|
||||||
|
public class StreamToIterable {
|
||||||
|
public String streamToIterableLambda(List<String> listOfStrings) {
|
||||||
|
Stream<String> stringStream = listOfStrings.stream();
|
||||||
|
StringBuilder sentence = new StringBuilder();
|
||||||
|
for (String eachString : (Iterable<String>) () -> stringStream.iterator()) {
|
||||||
|
doSomethingOnString(eachString, sentence);
|
||||||
|
}
|
||||||
|
return sentence.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String streamToIterableMethodReference(List<String> listOfStrings) {
|
||||||
|
Stream<String> stringStream = listOfStrings.stream();
|
||||||
|
StringBuilder sentence = new StringBuilder();
|
||||||
|
for (String eachString : (Iterable<String>) stringStream::iterator) {
|
||||||
|
doSomethingOnString(eachString, sentence);
|
||||||
|
}
|
||||||
|
return sentence.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String streamToList(List<String> listOfStrings) {
|
||||||
|
Stream<String> stringStream = listOfStrings.stream();
|
||||||
|
StringBuilder sentence = new StringBuilder();
|
||||||
|
for (String eachString : stringStream.collect(Collectors.toList())) {
|
||||||
|
doSomethingOnString(eachString, sentence);
|
||||||
|
}
|
||||||
|
return sentence.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSomethingOnString(String s, StringBuilder sentence) {
|
||||||
|
if (!Strings.isNullOrEmpty(s)) {
|
||||||
|
sentence.append(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.baeldung.streams.streamtoiterable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class StreamToIterableUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenList_whenLambdaIsUsed_ThenStreamAsIterable(){
|
||||||
|
StreamToIterable streamToIterable = new StreamToIterable();
|
||||||
|
String actualString = streamToIterable.streamToIterableLambda(getListOfStrings());
|
||||||
|
String expectedString = "Thisisasentencewithnospaces";
|
||||||
|
Assert.assertEquals(expectedString, actualString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenList_whenMethodReferenceIsUsed_ThenStreamAsIterable(){
|
||||||
|
StreamToIterable streamToIterable = new StreamToIterable();
|
||||||
|
String actualString = streamToIterable.streamToIterableMethodReference(getListOfStrings());
|
||||||
|
String expectedString = "Thisisasentencewithnospaces";
|
||||||
|
Assert.assertEquals(expectedString, actualString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenList_whenCollectedToList_ThenStreamAsIterable(){
|
||||||
|
StreamToIterable streamToIterable = new StreamToIterable();
|
||||||
|
String actualString = streamToIterable.streamToList(getListOfStrings());
|
||||||
|
String expectedString = "Thisisasentencewithnospaces";
|
||||||
|
Assert.assertEquals(expectedString, actualString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getListOfStrings(){
|
||||||
|
List<String> listOfStrings = new ArrayList<>();
|
||||||
|
listOfStrings.add("This");
|
||||||
|
listOfStrings.add("is");
|
||||||
|
listOfStrings.add("a");
|
||||||
|
listOfStrings.add(null);
|
||||||
|
listOfStrings.add("sentence");
|
||||||
|
listOfStrings.add("with");
|
||||||
|
listOfStrings.add("no");
|
||||||
|
listOfStrings.add(null);
|
||||||
|
listOfStrings.add("spaces");
|
||||||
|
return listOfStrings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<guava.version>31.1-jre</guava.version>
|
<guava.version>31.1-jre</guava.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<guava.version>31.1-jre</guava.version>
|
<guava.version>31.1-jre</guava.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
## Relevant Articles:
|
|
@ -0,0 +1,3 @@
|
||||||
|
FROM alpine:latest
|
||||||
|
MAINTAINER baeldung.com
|
||||||
|
RUN apk update && apk add iputils && apk add bash && apk add curl
|
|
@ -0,0 +1,7 @@
|
||||||
|
FROM node:8.16.1-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY host_docker_internal/package.json /app
|
||||||
|
COPY host_docker_internal/index.js /app
|
||||||
|
RUN npm install
|
||||||
|
CMD node index.js
|
||||||
|
EXPOSE 8080
|
|
@ -0,0 +1,20 @@
|
||||||
|
services:
|
||||||
|
alpine-app-1:
|
||||||
|
container_name: alpine-app-1
|
||||||
|
image: alpine-app-1
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
tty: true
|
||||||
|
ports:
|
||||||
|
- 8081:8081
|
||||||
|
|
||||||
|
alpine-app-2:
|
||||||
|
container_name: alpine-app-2
|
||||||
|
image: alpine-app-2
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
tty: true
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
|
@ -0,0 +1,29 @@
|
||||||
|
services:
|
||||||
|
alpine-app-1:
|
||||||
|
container_name: alpine-app-1
|
||||||
|
extra_hosts: # for linux hosts since version 20.10
|
||||||
|
- host.docker.internal:host-gateway
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: alpine-app-1
|
||||||
|
tty: true
|
||||||
|
networks:
|
||||||
|
- first-network
|
||||||
|
|
||||||
|
node-app:
|
||||||
|
container_name: node-app
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile.node
|
||||||
|
image: node-app
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
networks:
|
||||||
|
- second-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
first-network:
|
||||||
|
driver: bridge
|
||||||
|
second-network:
|
||||||
|
driver: bridge
|
|
@ -0,0 +1,10 @@
|
||||||
|
var express = require('express')
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
app.get('/', function (req, res) {
|
||||||
|
res.send('Hello World!')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(8080, function () {
|
||||||
|
console.log('app listening on port 8080!')
|
||||||
|
})
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "host_docker_internal",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "node js app",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "Baeldung",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.18.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
services:
|
||||||
|
alpine-app-1:
|
||||||
|
container_name: alpine-app-1
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: alpine-app-1
|
||||||
|
tty: true
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
networks:
|
||||||
|
network-example:
|
||||||
|
ipv4_address: 10.5.0.2
|
||||||
|
|
||||||
|
alpine-app-2:
|
||||||
|
container_name: alpine-app-2
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: alpine-app-2
|
||||||
|
tty: true
|
||||||
|
ports:
|
||||||
|
- 8081:8081
|
||||||
|
networks:
|
||||||
|
network-example:
|
||||||
|
ipv4_address: 10.5.0.3
|
||||||
|
|
||||||
|
networks:
|
||||||
|
network-example:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: 10.5.0.0/16
|
||||||
|
gateway: 10.5.0.1
|
|
@ -0,0 +1,36 @@
|
||||||
|
services:
|
||||||
|
alpine-app-1:
|
||||||
|
container_name: alpine-app-1
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: alpine-app-1
|
||||||
|
tty: true
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
networks:
|
||||||
|
network-example:
|
||||||
|
ipv4_address: 192.168.2.2
|
||||||
|
|
||||||
|
alpine-app-2:
|
||||||
|
container_name: alpine-app-2
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: alpine-app-2
|
||||||
|
tty: true
|
||||||
|
ports:
|
||||||
|
- 8081:8081
|
||||||
|
networks:
|
||||||
|
network-example:
|
||||||
|
ipv4_address: 192.168.2.3
|
||||||
|
|
||||||
|
networks:
|
||||||
|
network-example:
|
||||||
|
driver: macvlan
|
||||||
|
driver_opts:
|
||||||
|
parent: enp0s3
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: 192.168.2.0/24
|
||||||
|
gateway: 192.168.2.1
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?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>
|
||||||
|
<artifactId>docker-compose-2</artifactId>
|
||||||
|
<description>Demo project for Spring Boot and Docker - Module docker-compose-2</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-boot-2</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-2</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
</project>
|
|
@ -18,6 +18,7 @@
|
||||||
<modules>
|
<modules>
|
||||||
<module>docker-caching</module>
|
<module>docker-caching</module>
|
||||||
<module>docker-compose</module>
|
<module>docker-compose</module>
|
||||||
|
<module>docker-compose-2</module>
|
||||||
<module>docker-containers</module>
|
<module>docker-containers</module>
|
||||||
<module>docker-images</module>
|
<module>docker-images</module>
|
||||||
<module>docker-spring-boot</module>
|
<module>docker-spring-boot</module>
|
||||||
|
|
|
@ -1,129 +1,171 @@
|
||||||
package com.baeldung.httpclient;
|
package com.baeldung.httpclient;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.hc.client5.http.ConnectTimeoutException;
|
||||||
import org.apache.http.client.config.RequestConfig;
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.http.client.params.ClientPNames;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.http.config.SocketConfig;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
|
||||||
import org.apache.http.conn.ConnectTimeoutException;
|
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
|
||||||
import org.apache.http.params.CoreConnectionPNames;
|
|
||||||
import org.apache.http.params.HttpParams;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class HttpClientTimeoutLiveTest {
|
import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager;
|
||||||
|
|
||||||
private CloseableHttpResponse response;
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
|
import org.apache.hc.core5.http.io.SocketConfig;
|
||||||
|
import org.apache.hc.core5.util.Timeout;
|
||||||
|
|
||||||
@After
|
|
||||||
public final void after() throws IllegalStateException, IOException {
|
|
||||||
ResponseUtil.closeResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tests
|
import com.baeldung.handler.CustomHttpClientResponseHandler;
|
||||||
@Test
|
|
||||||
public final void givenUsingOldApi_whenSettingTimeoutViaParameter_thenCorrect() throws IOException {
|
|
||||||
|
|
||||||
DefaultHttpClient httpClient = new DefaultHttpClient();
|
class HttpClientTimeoutLiveTest {
|
||||||
int timeout = 5; // seconds
|
|
||||||
HttpParams httpParams = httpClient.getParams();
|
|
||||||
httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000);
|
|
||||||
httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, timeout * 1000);
|
|
||||||
httpParams.setParameter(ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000));
|
|
||||||
|
|
||||||
final HttpGet request = new HttpGet("http://www.github.com");
|
|
||||||
HttpResponse execute = httpClient.execute(request);
|
|
||||||
assertThat(execute.getStatusLine().getStatusCode(), equalTo(200));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public final void givenUsingNewApi_whenSettingTimeoutViaRequestConfig_thenCorrect() throws IOException {
|
void givenUsingNewApi_whenSettingTimeoutViaHighLevelApi_thenCorrect() throws IOException {
|
||||||
final int timeout = 2;
|
|
||||||
final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build();
|
|
||||||
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
|
|
||||||
final HttpGet request = new HttpGet("http://www.github.com");
|
|
||||||
|
|
||||||
response = client.execute(request);
|
|
||||||
|
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public final void givenUsingNewApi_whenSettingTimeoutViaSocketConfig_thenCorrect() throws IOException {
|
|
||||||
final int timeout = 2;
|
final int timeout = 2;
|
||||||
|
|
||||||
final SocketConfig config = SocketConfig.custom().setSoTimeout(timeout * 1000).build();
|
ConnectionConfig connConfig = ConnectionConfig.custom()
|
||||||
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultSocketConfig(config).build();
|
.setConnectTimeout(timeout, TimeUnit.MILLISECONDS)
|
||||||
|
.setSocketTimeout(timeout, TimeUnit.MILLISECONDS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectionRequestTimeout(Timeout.ofMilliseconds(2000L))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager();
|
||||||
|
cm.setConnectionConfig(connConfig);
|
||||||
|
|
||||||
|
|
||||||
final HttpGet request = new HttpGet("http://www.github.com");
|
final HttpGet request = new HttpGet("http://www.github.com");
|
||||||
|
|
||||||
response = client.execute(request);
|
try (CloseableHttpClient client = HttpClientBuilder.create()
|
||||||
|
.setDefaultRequestConfig(requestConfig)
|
||||||
|
.setConnectionManager(cm)
|
||||||
|
.build();
|
||||||
|
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(request, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public final void givenUsingNewApi_whenSettingTimeoutViaHighLevelApi_thenCorrect() throws IOException {
|
void givenUsingNewApi_whenSettingTimeoutViaSocketConfig_thenCorrect() throws IOException {
|
||||||
final int timeout = 5;
|
final int timeout = 2000;
|
||||||
|
final SocketConfig config = SocketConfig.custom().setSoTimeout(timeout, TimeUnit.MILLISECONDS).build();
|
||||||
|
|
||||||
final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build();
|
BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager();
|
||||||
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
|
cm.setSocketConfig(config);
|
||||||
|
|
||||||
final HttpGet request = new HttpGet("http://www.github.com");
|
final HttpGet request = new HttpGet("http://www.github.com");
|
||||||
|
|
||||||
response = client.execute(request);
|
try (CloseableHttpClient client = HttpClientBuilder.create()
|
||||||
|
.setConnectionManager(cm)
|
||||||
|
.build();
|
||||||
|
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(request, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This simulates a timeout against a domain with multiple routes/IPs to it (not a single raw IP)
|
* This simulates a timeout against a domain with multiple routes/IPs to it (not a single raw IP)
|
||||||
*/
|
*/
|
||||||
@Test(expected = ConnectTimeoutException.class)
|
@Disabled
|
||||||
@Ignore
|
void givenTimeoutIsConfigured_whenTimingOut_thenTimeoutException() throws IOException {
|
||||||
public final void givenTimeoutIsConfigured_whenTimingOut_thenTimeoutException() throws IOException {
|
|
||||||
final int timeout = 3;
|
final int timeout = 3;
|
||||||
|
|
||||||
final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build();
|
ConnectionConfig connConfig = ConnectionConfig.custom()
|
||||||
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
|
.setConnectTimeout(timeout, TimeUnit.MILLISECONDS)
|
||||||
|
.setSocketTimeout(timeout, TimeUnit.MILLISECONDS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectionRequestTimeout(Timeout.ofMilliseconds(3000L))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager();
|
||||||
|
cm.setConnectionConfig(connConfig);
|
||||||
|
|
||||||
final HttpGet request = new HttpGet("http://www.google.com:81");
|
final HttpGet request = new HttpGet("http://www.google.com:81");
|
||||||
client.execute(request);
|
|
||||||
|
assertThrows(ConnectTimeoutException.class, () -> {
|
||||||
|
try (CloseableHttpClient client = HttpClientBuilder.create()
|
||||||
|
.setDefaultRequestConfig(requestConfig)
|
||||||
|
.setConnectionManager(cm)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(request, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenSecuredRestApiIsConsumed_then200OK() throws IOException {
|
void whenSecuredRestApiIsConsumed_then200OK() throws IOException {
|
||||||
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
int timeout = 20000; // milliseconds
|
||||||
|
|
||||||
|
ConnectionConfig connConfig = ConnectionConfig.custom()
|
||||||
|
.setConnectTimeout(timeout, TimeUnit.MILLISECONDS)
|
||||||
|
.setSocketTimeout(timeout, TimeUnit.MILLISECONDS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectionRequestTimeout(Timeout.ofMilliseconds(20000L))
|
||||||
|
.build();
|
||||||
|
|
||||||
int timeout = 20; // seconds
|
|
||||||
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout * 1000)
|
|
||||||
.setConnectTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build();
|
|
||||||
HttpGet getMethod = new HttpGet("http://localhost:8082/httpclient-simple/api/bars/1");
|
HttpGet getMethod = new HttpGet("http://localhost:8082/httpclient-simple/api/bars/1");
|
||||||
getMethod.setConfig(requestConfig);
|
getMethod.setConfig(requestConfig);
|
||||||
|
|
||||||
int hardTimeout = 5; // seconds
|
|
||||||
|
BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager();
|
||||||
|
cm.setConnectionConfig(connConfig);
|
||||||
|
|
||||||
|
int hardTimeout = 5000; // milliseconds
|
||||||
TimerTask task = new TimerTask() {
|
TimerTask task = new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
getMethod.abort();
|
getMethod.abort();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
new Timer(true).schedule(task, hardTimeout * 1000);
|
new Timer(true).schedule(task, hardTimeout);
|
||||||
|
|
||||||
|
try (CloseableHttpClient client = HttpClientBuilder.create()
|
||||||
|
.setDefaultRequestConfig(requestConfig)
|
||||||
|
.setConnectionManager(cm)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(getMethod, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
System.out.println("HTTP Status of response: " + statusCode);
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
|
}
|
||||||
|
|
||||||
HttpResponse response = httpClient.execute(getMethod);
|
|
||||||
System.out.println("HTTP Status of response: " + response.getStatusLine().getStatusCode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
package com.baeldung.httpclient;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.config.SocketConfig;
|
||||||
|
import org.apache.http.conn.ConnectTimeoutException;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class HttpClientTimeoutV4LiveTest {
|
||||||
|
|
||||||
|
private CloseableHttpResponse response;
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public final void after() throws IllegalStateException, IOException {
|
||||||
|
ResponseUtil.closeResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenUsingNewApi_whenSettingTimeoutViaRequestConfig_thenCorrect() throws IOException {
|
||||||
|
final int timeout = 2;
|
||||||
|
final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build();
|
||||||
|
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
|
||||||
|
final HttpGet request = new HttpGet("http://www.github.com");
|
||||||
|
|
||||||
|
response = client.execute(request);
|
||||||
|
|
||||||
|
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenUsingNewApi_whenSettingTimeoutViaSocketConfig_thenCorrect() throws IOException {
|
||||||
|
final int timeout = 2;
|
||||||
|
|
||||||
|
final SocketConfig config = SocketConfig.custom().setSoTimeout(timeout * 1000).build();
|
||||||
|
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultSocketConfig(config).build();
|
||||||
|
|
||||||
|
final HttpGet request = new HttpGet("http://www.github.com");
|
||||||
|
|
||||||
|
response = client.execute(request);
|
||||||
|
|
||||||
|
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenUsingNewApi_whenSettingTimeoutViaHighLevelApi_thenCorrect() throws IOException {
|
||||||
|
final int timeout = 5;
|
||||||
|
|
||||||
|
final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build();
|
||||||
|
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
|
||||||
|
|
||||||
|
final HttpGet request = new HttpGet("http://www.github.com");
|
||||||
|
|
||||||
|
response = client.execute(request);
|
||||||
|
|
||||||
|
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This simulates a timeout against a domain with multiple routes/IPs to it (not a single raw IP)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
public final void givenTimeoutIsConfigured_whenTimingOut_thenTimeoutException() throws IOException {
|
||||||
|
final int timeout = 3;
|
||||||
|
|
||||||
|
final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build();
|
||||||
|
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
|
||||||
|
|
||||||
|
final HttpGet request = new HttpGet("http://www.google.com:81");
|
||||||
|
|
||||||
|
assertThrows(ConnectTimeoutException.class, () -> {
|
||||||
|
client.execute(request);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenSecuredRestApiIsConsumed_then200OK() throws IOException {
|
||||||
|
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
||||||
|
|
||||||
|
int timeout = 20; // seconds
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout * 1000)
|
||||||
|
.setConnectTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build();
|
||||||
|
HttpGet getMethod = new HttpGet("http://localhost:8082/httpclient-simple/api/bars/1");
|
||||||
|
getMethod.setConfig(requestConfig);
|
||||||
|
|
||||||
|
int hardTimeout = 5; // seconds
|
||||||
|
TimerTask task = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
getMethod.abort();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new Timer(true).schedule(task, hardTimeout * 1000);
|
||||||
|
|
||||||
|
HttpResponse response = httpClient.execute(getMethod);
|
||||||
|
System.out.println("HTTP Status of response: " + response.getStatusLine().getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -65,14 +65,14 @@
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sun.mail</groupId>
|
<groupId>org.eclipse.angus</groupId>
|
||||||
<artifactId>javax.mail</artifactId>
|
<artifactId>angus-mail</artifactId>
|
||||||
<version>${javax.mail.version}</version>
|
<version>${angus.mail.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.activation</groupId>
|
<groupId>org.eclipse.angus</groupId>
|
||||||
<artifactId>javax.activation-api</artifactId>
|
<artifactId>angus-activation</artifactId>
|
||||||
<version>${javax.activation.version}</version>
|
<version>${angus.activation.version}</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -116,8 +116,8 @@
|
||||||
<json.version>20180130</json.version>
|
<json.version>20180130</json.version>
|
||||||
<logback.contrib.version>0.1.5</logback.contrib.version>
|
<logback.contrib.version>0.1.5</logback.contrib.version>
|
||||||
<docx4j.version>3.3.5</docx4j.version>
|
<docx4j.version>3.3.5</docx4j.version>
|
||||||
<javax.mail.version>1.6.2</javax.mail.version>
|
<angus.mail.version>2.0.1</angus.mail.version>
|
||||||
<javax.activation.version>1.2.0</javax.activation.version>
|
<angus.activation.version>2.0.0</angus.activation.version>
|
||||||
<logback.version>1.3.5</logback.version>
|
<logback.version>1.3.5</logback.version>
|
||||||
<slf4j.version>2.0.4</slf4j.version>
|
<slf4j.version>2.0.4</slf4j.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
## Relevant Articles
|
||||||
|
- [Introduction to ScyllaDB with Java](https://www.baeldung.com/java-scylladb)
|
|
@ -51,6 +51,7 @@
|
||||||
<module>spring-boot-libraries</module>
|
<module>spring-boot-libraries</module>
|
||||||
<module>spring-boot-libraries-2</module>
|
<module>spring-boot-libraries-2</module>
|
||||||
<module>spring-boot-process-automation</module>
|
<module>spring-boot-process-automation</module>
|
||||||
|
<module>spring-boot-logging-logback</module>
|
||||||
<module>spring-boot-logging-log4j2</module>
|
<module>spring-boot-logging-log4j2</module>
|
||||||
<module>spring-boot-mvc</module>
|
<module>spring-boot-mvc</module>
|
||||||
<module>spring-boot-mvc-2</module>
|
<module>spring-boot-mvc-2</module>
|
||||||
|
|
|
@ -18,10 +18,6 @@
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
||||||
|
@ -81,7 +77,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||||
<version>2.3.1</version>
|
<version>2.5.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>xjc</id>
|
<id>xjc</id>
|
||||||
|
@ -101,4 +97,8 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<start-class>com.baeldung.keycloak.SpringBoot</start-class>
|
||||||
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -30,7 +30,7 @@ class SecurityConfig {
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http.authorizeRequests()
|
http.authorizeRequests()
|
||||||
.antMatchers("/customers*", "/users*")
|
.antMatchers("/customers*")
|
||||||
.hasRole("USER")
|
.hasRole("USER")
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.permitAll();
|
.permitAll();
|
||||||
|
|
|
@ -55,6 +55,10 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-log4j2</artifactId>
|
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-spring-boot</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.baeldung.extensions;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@PropertySource("classpath:application-log4j2-extensions.properties")
|
||||||
|
public class SpringBootLog4j2ExtensionsApplication {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger(SpringBootLog4j2ExtensionsApplication.class);
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpringBootLog4j2ExtensionsApplication.class, args);
|
||||||
|
|
||||||
|
logger.trace("Trace log message");
|
||||||
|
logger.debug("Debug log message");
|
||||||
|
logger.info("Info log message");
|
||||||
|
logger.error("Error log message");
|
||||||
|
logger.warn("Warn log message");
|
||||||
|
logger.fatal("Fatal log message");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
logging.config=classpath:log4j2-spring.xml
|
||||||
|
spring.application.name=log4j2-extension
|
|
@ -7,6 +7,11 @@
|
||||||
pattern="%style{%d{ISO8601}}{black} %highlight{%-5level }[%style{%t}{bright,blue}] %style{%C{1.}}{bright,yellow}: %msg%n%throwable" />
|
pattern="%style{%d{ISO8601}}{black} %highlight{%-5level }[%style{%t}{bright,blue}] %style{%C{1.}}{bright,yellow}: %msg%n%throwable" />
|
||||||
</Console>
|
</Console>
|
||||||
|
|
||||||
|
<Console name="Console-Extensions" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout
|
||||||
|
pattern="%d %p %c{1.} [%t] ${spring:spring.application.name} %m%n" />
|
||||||
|
</Console>
|
||||||
|
|
||||||
<RollingFile name="RollingFile"
|
<RollingFile name="RollingFile"
|
||||||
fileName="./logs/spring-boot-logger-log4j2.log"
|
fileName="./logs/spring-boot-logger-log4j2.log"
|
||||||
filePattern="./logs/$${date:yyyy-MM}/spring-boot-logger-log4j2-%d{-dd-MMMM-yyyy}-%i.log.gz">
|
filePattern="./logs/$${date:yyyy-MM}/spring-boot-logger-log4j2-%d{-dd-MMMM-yyyy}-%i.log.gz">
|
||||||
|
@ -37,7 +42,20 @@
|
||||||
</Root>
|
</Root>
|
||||||
|
|
||||||
<!-- LOG "com.baeldung*" at TRACE level -->
|
<!-- LOG "com.baeldung*" at TRACE level -->
|
||||||
|
<SpringProfile name="!development, !production">
|
||||||
<Logger name="com.baeldung" level="trace"></Logger>
|
<Logger name="com.baeldung" level="trace"></Logger>
|
||||||
|
</SpringProfile>
|
||||||
|
|
||||||
|
<SpringProfile name="development">
|
||||||
|
<Logger name="com.baeldung.extensions" level="debug"></Logger>
|
||||||
|
</SpringProfile>
|
||||||
|
|
||||||
|
<SpringProfile name="production">
|
||||||
|
<Logger name="com.baeldung.extensions" level="error">
|
||||||
|
<AppenderRef ref="Console-Extensions" />
|
||||||
|
</Logger>
|
||||||
|
</SpringProfile>
|
||||||
|
|
||||||
</Loggers>
|
</Loggers>
|
||||||
|
|
||||||
</Configuration>
|
</Configuration>
|
|
@ -0,0 +1 @@
|
||||||
|
log4j2.debug=true
|
|
@ -0,0 +1,29 @@
|
||||||
|
/target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/build/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
/logs/
|
||||||
|
/bin/
|
||||||
|
/mvnw
|
||||||
|
/mvnw.cmd
|
|
@ -0,0 +1,6 @@
|
||||||
|
## Spring Boot Logging with Logback
|
||||||
|
|
||||||
|
This module contains articles about logging in Spring Boot projects with Logback.
|
||||||
|
|
||||||
|
### Relevant Articles:
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?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>spring-boot-logging-logback</artifactId>
|
||||||
|
<name>spring-boot-logging-logback</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<description>Demo project for Spring Boot Logging with Logback</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung.spring-boot-modules</groupId>
|
||||||
|
<artifactId>spring-boot-modules</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.extensions;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SpringBootLogbackExtensionsApplication {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(SpringBootLogbackExtensionsApplication.class);
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpringBootLogbackExtensionsApplication.class, args);
|
||||||
|
|
||||||
|
logger.debug("Debug log message");
|
||||||
|
logger.info("Info log message");
|
||||||
|
logger.error("Error log message");
|
||||||
|
logger.warn("Warn log message");
|
||||||
|
logger.trace("Trace log message");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
spring.application.name=logback-extension
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<property name="LOGS" value="./logs" />
|
||||||
|
<springProperty scope="context" name="application.name" source="spring.application.name" />
|
||||||
|
|
||||||
|
<springProfile name="development">
|
||||||
|
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||||
|
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="Console" />
|
||||||
|
</root>
|
||||||
|
</springProfile>
|
||||||
|
|
||||||
|
<springProfile name="production">
|
||||||
|
<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOGS}/${application.name}.log</file>
|
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||||
|
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOGS}/archived/${application.name}-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="RollingFile" />
|
||||||
|
</root>
|
||||||
|
</springProfile>
|
||||||
|
|
||||||
|
</configuration>
|
|
@ -4,3 +4,4 @@ This module contains articles about Spring Web MVC in Spring Boot projects.
|
||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
- [Enable and Disable Endpoints at Runtime With Spring Boot](https://www.baeldung.com/spring-boot-enable-disable-endpoints-at-runtime)
|
- [Enable and Disable Endpoints at Runtime With Spring Boot](https://www.baeldung.com/spring-boot-enable-disable-endpoints-at-runtime)
|
||||||
|
- [Extracting a Custom Header From the Request](https://www.baeldung.com/spring-extract-custom-header-request)
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
package com.baeldung.web.log.app;
|
package com.baeldung.web.log.app;
|
||||||
|
|
||||||
import javax.servlet.ServletRegistration;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
import com.baeldung.web.log.config.CustomeRequestLoggingFilter;
|
|
||||||
|
|
||||||
@EnableAutoConfiguration
|
|
||||||
@ComponentScan("com.baeldung.web.log")
|
@ComponentScan("com.baeldung.web.log")
|
||||||
@PropertySource("application-log.properties")
|
@PropertySource("application-log.properties")
|
||||||
@SpringBootApplication
|
@SpringBootApplication(exclude = {
|
||||||
|
SecurityAutoConfiguration.class,
|
||||||
|
ManagementWebSecurityAutoConfiguration.class
|
||||||
|
})
|
||||||
public class Application {
|
public class Application {
|
||||||
|
|
||||||
public static void main(final String[] args) {
|
public static void main(final String[] args) {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.baeldung.web.log.app;
|
||||||
|
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
|
import javax.servlet.ServletInputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class CachedHttpServletRequest extends HttpServletRequestWrapper {
|
||||||
|
|
||||||
|
private byte[] cachedPayload;
|
||||||
|
|
||||||
|
public CachedHttpServletRequest(HttpServletRequest request) throws IOException {
|
||||||
|
super(request);
|
||||||
|
InputStream requestInputStream = request.getInputStream();
|
||||||
|
this.cachedPayload = StreamUtils.copyToByteArray(requestInputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServletInputStream getInputStream() {
|
||||||
|
return new CachedServletInputStream(this.cachedPayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BufferedReader getReader() {
|
||||||
|
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedPayload);
|
||||||
|
return new BufferedReader(new InputStreamReader(byteArrayInputStream));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.baeldung.web.log.app;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.servlet.ReadListener;
|
||||||
|
import javax.servlet.ServletInputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class CachedServletInputStream extends ServletInputStream {
|
||||||
|
|
||||||
|
private final static Logger LOGGER = LoggerFactory.getLogger(CachedServletInputStream.class);
|
||||||
|
private InputStream cachedInputStream;
|
||||||
|
|
||||||
|
public CachedServletInputStream(byte[] cachedBody) {
|
||||||
|
this.cachedInputStream = new ByteArrayInputStream(cachedBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFinished() {
|
||||||
|
try {
|
||||||
|
return cachedInputStream.available() == 0;
|
||||||
|
} catch (IOException exp) {
|
||||||
|
LOGGER.error(exp.getMessage());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadListener(ReadListener readListener) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
return cachedInputStream.read();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.baeldung.web.log.app;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.annotation.WebFilter;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
@Order(value = Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
@Component
|
||||||
|
@WebFilter(filterName = "RequestCachingFilter", urlPatterns = "/*")
|
||||||
|
public class RequestCachingFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private final static Logger LOGGER = LoggerFactory.getLogger(RequestCachingFilter.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
CachedHttpServletRequest cachedHttpServletRequest = new CachedHttpServletRequest(request);
|
||||||
|
LOGGER.info("REQUEST DATA: " + IOUtils.toString(cachedHttpServletRequest.getInputStream(), StandardCharsets.UTF_8));
|
||||||
|
filterChain.doFilter(cachedHttpServletRequest, response);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,44 +0,0 @@
|
||||||
package com.baeldung.web.log.app;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
|
||||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
|
||||||
|
|
||||||
import com.baeldung.web.log.util.RequestLoggingUtil;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class TaxiFareRequestInterceptor extends HandlerInterceptorAdapter {
|
|
||||||
|
|
||||||
private final static Logger LOGGER = LoggerFactory.getLogger(TaxiFareRequestInterceptor.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
|
||||||
String postData;
|
|
||||||
HttpServletRequest requestCacheWrapperObject = null;
|
|
||||||
try {
|
|
||||||
// Uncomment to produce the stream closed issue
|
|
||||||
// postData = RequestLoggingUtil.getStringFromInputStream(request.getInputStream());
|
|
||||||
|
|
||||||
// To overcome request stream closed issue
|
|
||||||
requestCacheWrapperObject = new ContentCachingRequestWrapper(request);
|
|
||||||
requestCacheWrapperObject.getParameterMap();
|
|
||||||
} catch (Exception exception) {
|
|
||||||
exception.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
postData = RequestLoggingUtil.readPayload(requestCacheWrapperObject);
|
|
||||||
LOGGER.info("REQUEST DATA: " + postData);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
|
||||||
LOGGER.info("RESPONSE: " + response.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package com.baeldung.web.log.config;
|
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.ServletRegistration;
|
|
||||||
|
|
||||||
import org.springframework.web.context.ContextLoaderListener;
|
|
||||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
|
||||||
import org.springframework.web.servlet.DispatcherServlet;
|
|
||||||
import org.springframework.web.WebApplicationInitializer;
|
|
||||||
|
|
||||||
public class CustomWebAppInitializer implements WebApplicationInitializer {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStartup(ServletContext container) throws ServletException {
|
|
||||||
|
|
||||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
|
||||||
context.setConfigLocation("com.baeldung.web.log");
|
|
||||||
container.addListener(new ContextLoaderListener(context));
|
|
||||||
|
|
||||||
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(context));
|
|
||||||
dispatcher.setLoadOnStartup(1);
|
|
||||||
dispatcher.addMapping("/");
|
|
||||||
|
|
||||||
container.addFilter("customRequestLoggingFilter", CustomeRequestLoggingFilter.class).addMappingForServletNames(null, false, "dispatcher");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package com.baeldung.web.log.config;
|
|
||||||
|
|
||||||
import org.springframework.web.filter.CommonsRequestLoggingFilter;
|
|
||||||
|
|
||||||
public class CustomeRequestLoggingFilter extends CommonsRequestLoggingFilter {
|
|
||||||
|
|
||||||
public CustomeRequestLoggingFilter() {
|
|
||||||
super.setIncludeQueryString(true);
|
|
||||||
super.setIncludePayload(true);
|
|
||||||
super.setMaxPayloadLength(10000);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package com.baeldung.web.log.config;
|
|
||||||
|
|
||||||
import com.baeldung.web.log.app.TaxiFareRequestInterceptor;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class TaxiFareMVCConfig implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TaxiFareRequestInterceptor taxiFareRequestInterceptor;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
registry.addInterceptor(taxiFareRequestInterceptor).addPathPatterns("/taxifare/*/");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package com.baeldung.web.log.util;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
|
||||||
import org.springframework.web.util.WebUtils;
|
|
||||||
|
|
||||||
public class RequestLoggingUtil {
|
|
||||||
|
|
||||||
public static String getStringFromInputStream(InputStream is) {
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
String encoding = "UTF-8";
|
|
||||||
try {
|
|
||||||
IOUtils.copy(is, writer, encoding);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return writer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String readPayload(final HttpServletRequest request) throws IOException {
|
|
||||||
String payloadData = null;
|
|
||||||
ContentCachingRequestWrapper contentCachingRequestWrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
|
|
||||||
if (null != contentCachingRequestWrapper) {
|
|
||||||
byte[] buf = contentCachingRequestWrapper.getContentAsByteArray();
|
|
||||||
if (buf.length > 0) {
|
|
||||||
payloadData = new String(buf, 0, buf.length, contentCachingRequestWrapper.getCharacterEncoding());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return payloadData;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -7,6 +7,10 @@
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter">
|
||||||
|
<level value="DEBUG" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
</root>
|
</root>
|
||||||
|
|
|
@ -1,23 +1,19 @@
|
||||||
package com.baeldung.web.controller;
|
package com.baeldung.web.controller;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import com.baeldung.web.log.app.Application;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import com.baeldung.web.log.data.TaxiRide;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||||
import org.springframework.boot.web.server.LocalServerPort;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
||||||
|
|
||||||
import com.baeldung.web.log.app.Application;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import com.baeldung.web.log.data.TaxiRide;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@SpringBootTest(classes = { Application.class, TaxiFareControllerIntegrationTest.SecurityConfig.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
@SpringBootTest(classes = { Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
public class TaxiFareControllerIntegrationTest {
|
public class TaxiFareControllerIntegrationTest {
|
||||||
|
|
||||||
@LocalServerPort
|
@LocalServerPort
|
||||||
|
@ -25,8 +21,6 @@ public class TaxiFareControllerIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenRequest_whenFetchTaxiFareRateCard_thanOK() {
|
public void givenRequest_whenFetchTaxiFareRateCard_thanOK() {
|
||||||
|
|
||||||
System.out.println(port);
|
|
||||||
String URL = "http://localhost:" + port + "/spring-rest";
|
String URL = "http://localhost:" + port + "/spring-rest";
|
||||||
TestRestTemplate testRestTemplate = new TestRestTemplate();
|
TestRestTemplate testRestTemplate = new TestRestTemplate();
|
||||||
TaxiRide taxiRide = new TaxiRide(true, 10l);
|
TaxiRide taxiRide = new TaxiRide(true, 10l);
|
||||||
|
@ -37,16 +31,4 @@ public class TaxiFareControllerIntegrationTest {
|
||||||
assertThat(fare, equalTo("200"));
|
assertThat(fare, equalTo("200"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
|
||||||
static class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|
||||||
@Override
|
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
|
||||||
System.out.println("security being set");
|
|
||||||
http
|
|
||||||
.authorizeRequests()
|
|
||||||
.anyRequest().permitAll()
|
|
||||||
.and()
|
|
||||||
.csrf().disable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -10,27 +10,39 @@
|
||||||
<url>http://www.baeldung.com</url>
|
<url>http://www.baeldung.com</url>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>parent-modules</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>3.0.1</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
<version>${spring.boot.version}</version>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mock-server</groupId>
|
||||||
|
<artifactId>mockserver-netty</artifactId>
|
||||||
|
<version>${mockserver.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mock-server</groupId>
|
||||||
|
<artifactId>mockserver-client-java</artifactId>
|
||||||
|
<version>${mockserver.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<version>${spring.boot.version}</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>io.projectreactor</groupId>
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
<artifactId>reactor-test</artifactId>
|
||||||
<version>${junit-jupiter.version}</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -76,13 +88,23 @@
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<spring.boot.version>2.7.5</spring.boot.version>
|
<mockserver.version>5.14.0</mockserver.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,3 @@
|
||||||
|
package com.baeldung.httpinterface;
|
||||||
|
|
||||||
|
public record Book(long id, String title, String author, int year) {}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.baeldung.httpinterface;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
import org.springframework.web.reactive.function.client.support.WebClientAdapter;
|
||||||
|
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class BooksClient {
|
||||||
|
|
||||||
|
private final BooksService booksService;
|
||||||
|
|
||||||
|
public BooksClient(WebClient webClient) {
|
||||||
|
HttpServiceProxyFactory httpServiceProxyFactory =
|
||||||
|
HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient))
|
||||||
|
.build();
|
||||||
|
booksService = httpServiceProxyFactory.createClient(BooksService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooksService getBooksService() {
|
||||||
|
return booksService;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.baeldung.httpinterface;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.service.annotation.DeleteExchange;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
interface BooksService {
|
||||||
|
|
||||||
|
@GetExchange("/books")
|
||||||
|
List<Book> getBooks();
|
||||||
|
|
||||||
|
@GetExchange("/books/{id}")
|
||||||
|
Book getBook(@PathVariable long id);
|
||||||
|
|
||||||
|
@PostExchange("/books")
|
||||||
|
Book saveBook(@RequestBody Book book);
|
||||||
|
|
||||||
|
@DeleteExchange("/books/{id}")
|
||||||
|
ResponseEntity<Void> deleteBook(@PathVariable long id);
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue