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)
|
||||
- [Snapshotting Aggregates in Axon](https://www.baeldung.com/axon-snapshotting-aggregates)
|
||||
- [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>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<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>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
@ -32,6 +46,8 @@
|
|||
<properties>
|
||||
<maven.compiler.source.version>11</maven.compiler.source.version>
|
||||
<maven.compiler.target.version>11</maven.compiler.target.version>
|
||||
<jackson.version>2.14.1</jackson.version>
|
||||
<gson.version>2.10</gson.version>
|
||||
</properties>
|
||||
|
||||
</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
|
||||
|
||||
### 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)
|
||||
- [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)
|
||||
- [Fix the IllegalArgumentException: No enum const class](https://www.baeldung.com/java-fix-no-enum-const-class)
|
||||
- [[<-- Prev]](../core-java-exceptions-3)
|
||||
|
|
|
@ -14,4 +14,30 @@
|
|||
<version>0.0.1-SNAPSHOT</version>
|
||||
</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>
|
|
@ -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();
|
||||
|
||||
if (result) {
|
||||
if (!result) {
|
||||
diagnostics.getDiagnostics()
|
||||
.forEach(d -> LOGGER.error(String.valueOf(d)));
|
||||
} else {
|
||||
|
|
|
@ -11,6 +11,8 @@ public class Book implements Serializable {
|
|||
private transient int copies;
|
||||
private final transient String bookCategory = "Fiction";
|
||||
|
||||
private final transient String bookCategoryNewOperator = new String("Fiction with new Operator");
|
||||
|
||||
public String getBookName() {
|
||||
return bookName;
|
||||
}
|
||||
|
@ -39,4 +41,7 @@ public class Book implements Serializable {
|
|||
return bookCategory;
|
||||
}
|
||||
|
||||
public String getBookCategoryNewOperator() {
|
||||
return bookCategoryNewOperator;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,16 @@ class TransientUnitTest {
|
|||
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
|
||||
public static void cleanup() {
|
||||
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)
|
||||
- [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)
|
||||
-
|
||||
- [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>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<reflections.version>0.10.2</reflections.version>
|
||||
</properties>
|
||||
|
||||
|
||||
<build>
|
||||
<finalName>core-java-lang-5</finalName>
|
||||
<resources>
|
||||
|
@ -24,4 +30,18 @@
|
|||
</resources>
|
||||
</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>
|
|
@ -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>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
<version>${javax.mail.version}</version>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>angus-mail</artifactId>
|
||||
<version>${angus.mail.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.asynchttpclient</groupId>
|
||||
<artifactId>async-http-client</artifactId>
|
||||
<version>${async-http-client.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<version>${jakarta.bind.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.icegreen</groupId>
|
||||
<artifactId>greenmail</artifactId>
|
||||
|
@ -48,9 +53,10 @@
|
|||
|
||||
<properties>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
</project>
|
|
@ -1,19 +1,20 @@
|
|||
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.net.URI;
|
||||
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 {
|
||||
|
||||
private String username;
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
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.IOException;
|
||||
import java.net.URI;
|
||||
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 {
|
||||
|
||||
private final String username;
|
||||
|
@ -37,7 +39,7 @@ public class MailWithAttachmentService {
|
|||
props.put("mail.smtp.host", this.host);
|
||||
props.put("mail.smtp.port", this.port);
|
||||
|
||||
return Session.getInstance(props, new javax.mail.Authenticator() {
|
||||
return Session.getInstance(props, new Authenticator() {
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package com.baeldung.download;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
|
@ -13,7 +10,11 @@ import java.security.MessageDigest;
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
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 {
|
||||
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
package com.baeldung.mail;
|
||||
|
||||
import com.icegreen.greenmail.junit.GreenMailRule;
|
||||
import com.icegreen.greenmail.util.ServerSetupTest;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import java.io.IOException;
|
||||
import com.icegreen.greenmail.junit.GreenMailRule;
|
||||
import com.icegreen.greenmail.util.ServerSetupTest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.mail.internet.MimeMultipart;
|
||||
|
||||
public class EmailServiceLiveTest {
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
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.junit.GreenMailRule;
|
||||
import com.icegreen.greenmail.util.GreenMailUtil;
|
||||
import com.icegreen.greenmail.util.ServerSetupTest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.mail.internet.MimeMultipart;
|
||||
|
||||
public class MailWithAttachmentServiceLiveTest {
|
||||
|
||||
|
@ -29,7 +29,6 @@ public class MailWithAttachmentServiceLiveTest {
|
|||
.withUser(USERNAME, PASSWORD)
|
||||
);
|
||||
|
||||
@Resource
|
||||
private MailWithAttachmentService emailService;
|
||||
|
||||
@Before
|
||||
|
@ -73,5 +72,4 @@ public class MailWithAttachmentServiceLiveTest {
|
|||
return GreenMailUtil.getBody(((MimeMultipart) receivedMessage.getContent())
|
||||
.getBodyPart(2));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
<version>${tomcat.embeded.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>${javax.mail.version}</version>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>angus-mail</artifactId>
|
||||
<version>${angus.mail.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.github.seancfoley/ipaddress -->
|
||||
<dependency>
|
||||
|
@ -95,7 +95,7 @@
|
|||
<seancfoley.ipaddress.version>5.3.3</seancfoley.ipaddress.version>
|
||||
<jgonian.commons-ip-math.version>1.32</jgonian.commons-ip-math.version>
|
||||
<googlecode.ipv6.version>0.17</googlecode.ipv6.version>
|
||||
<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>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -6,16 +6,16 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.NoSuchProviderException;
|
||||
import javax.mail.Part;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Store;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import jakarta.mail.Address;
|
||||
import jakarta.mail.Folder;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.Multipart;
|
||||
import jakarta.mail.NoSuchProviderException;
|
||||
import jakarta.mail.Part;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Store;
|
||||
import jakarta.mail.internet.MimeBodyPart;
|
||||
|
||||
public class DownloadEmailAttachments {
|
||||
private String downloadDirectory;
|
||||
|
@ -24,7 +24,7 @@ public class DownloadEmailAttachments {
|
|||
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);
|
||||
Store store = setSessionStoreProperties(userName, password, properties);
|
||||
Folder inbox = store.getFolder("INBOX");
|
||||
|
@ -67,7 +67,7 @@ public class DownloadEmailAttachments {
|
|||
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);
|
||||
|
||||
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)
|
||||
- [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)
|
||||
- [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 final Iterator<T> iterator;
|
||||
|
||||
public CustomBatchIterator(Iterator<T> sourceIterator, int batchSize) {
|
||||
private CustomBatchIterator(Iterator<T> sourceIterator, int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
this.iterator = sourceIterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> next() {
|
||||
prepareNextBatch();
|
||||
return currentBatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
prepareNextBatch();
|
||||
return currentBatch != null && !currentBatch.isEmpty();
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<guava.version>31.1-jre</guava.version>
|
||||
</properties>
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<guava.version>31.1-jre</guava.version>
|
||||
</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>
|
||||
<module>docker-caching</module>
|
||||
<module>docker-compose</module>
|
||||
<module>docker-compose-2</module>
|
||||
<module>docker-containers</module>
|
||||
<module>docker-images</module>
|
||||
<module>docker-spring-boot</module>
|
||||
|
|
|
@ -1,129 +1,171 @@
|
|||
package com.baeldung.httpclient;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
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.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.client.params.ClientPNames;
|
||||
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.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;
|
||||
import org.apache.hc.client5.http.ConnectTimeoutException;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||
|
||||
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
|
||||
@Test
|
||||
public final void givenUsingOldApi_whenSettingTimeoutViaParameter_thenCorrect() throws IOException {
|
||||
import com.baeldung.handler.CustomHttpClientResponseHandler;
|
||||
|
||||
DefaultHttpClient httpClient = new DefaultHttpClient();
|
||||
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));
|
||||
}
|
||||
class HttpClientTimeoutLiveTest {
|
||||
|
||||
@Test
|
||||
public final 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
|
||||
public final void givenUsingNewApi_whenSettingTimeoutViaSocketConfig_thenCorrect() throws IOException {
|
||||
void givenUsingNewApi_whenSettingTimeoutViaHighLevelApi_thenCorrect() throws IOException {
|
||||
final int timeout = 2;
|
||||
|
||||
final SocketConfig config = SocketConfig.custom().setSoTimeout(timeout * 1000).build();
|
||||
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultSocketConfig(config).build();
|
||||
ConnectionConfig connConfig = ConnectionConfig.custom()
|
||||
.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");
|
||||
|
||||
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
|
||||
public final void givenUsingNewApi_whenSettingTimeoutViaHighLevelApi_thenCorrect() throws IOException {
|
||||
final int timeout = 5;
|
||||
void givenUsingNewApi_whenSettingTimeoutViaSocketConfig_thenCorrect() throws IOException {
|
||||
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();
|
||||
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
|
||||
BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager();
|
||||
cm.setSocketConfig(config);
|
||||
|
||||
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)
|
||||
*/
|
||||
@Test(expected = ConnectTimeoutException.class)
|
||||
@Ignore
|
||||
public final void givenTimeoutIsConfigured_whenTimingOut_thenTimeoutException() throws IOException {
|
||||
@Disabled
|
||||
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();
|
||||
ConnectionConfig connConfig = ConnectionConfig.custom()
|
||||
.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");
|
||||
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
|
||||
public void whenSecuredRestApiIsConsumed_then200OK() throws IOException {
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
||||
void whenSecuredRestApiIsConsumed_then200OK() throws IOException {
|
||||
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");
|
||||
getMethod.setConfig(requestConfig);
|
||||
|
||||
int hardTimeout = 5; // seconds
|
||||
|
||||
BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager();
|
||||
cm.setConnectionConfig(connConfig);
|
||||
|
||||
int hardTimeout = 5000; // milliseconds
|
||||
TimerTask task = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
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>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>${javax.mail.version}</version>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>angus-mail</artifactId>
|
||||
<version>${angus.mail.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>javax.activation-api</artifactId>
|
||||
<version>${javax.activation.version}</version>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>angus-activation</artifactId>
|
||||
<version>${angus.activation.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -116,8 +116,8 @@
|
|||
<json.version>20180130</json.version>
|
||||
<logback.contrib.version>0.1.5</logback.contrib.version>
|
||||
<docx4j.version>3.3.5</docx4j.version>
|
||||
<javax.mail.version>1.6.2</javax.mail.version>
|
||||
<javax.activation.version>1.2.0</javax.activation.version>
|
||||
<angus.mail.version>2.0.1</angus.mail.version>
|
||||
<angus.activation.version>2.0.0</angus.activation.version>
|
||||
<logback.version>1.3.5</logback.version>
|
||||
<slf4j.version>2.0.4</slf4j.version>
|
||||
</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-2</module>
|
||||
<module>spring-boot-process-automation</module>
|
||||
<module>spring-boot-logging-logback</module>
|
||||
<module>spring-boot-logging-log4j2</module>
|
||||
<module>spring-boot-mvc</module>
|
||||
<module>spring-boot-mvc-2</module>
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
||||
|
@ -81,7 +77,7 @@
|
|||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<version>2.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>xjc</id>
|
||||
|
@ -101,4 +97,8 @@
|
|||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<start-class>com.baeldung.keycloak.SpringBoot</start-class>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -30,7 +30,7 @@ class SecurityConfig {
|
|||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
.antMatchers("/customers*", "/users*")
|
||||
.antMatchers("/customers*")
|
||||
.hasRole("USER")
|
||||
.anyRequest()
|
||||
.permitAll();
|
||||
|
|
|
@ -55,6 +55,10 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-spring-boot</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<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" />
|
||||
</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"
|
||||
fileName="./logs/spring-boot-logger-log4j2.log"
|
||||
filePattern="./logs/$${date:yyyy-MM}/spring-boot-logger-log4j2-%d{-dd-MMMM-yyyy}-%i.log.gz">
|
||||
|
@ -37,7 +42,20 @@
|
|||
</Root>
|
||||
|
||||
<!-- LOG "com.baeldung*" at TRACE level -->
|
||||
<SpringProfile name="!development, !production">
|
||||
<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>
|
||||
|
||||
</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:
|
||||
- [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;
|
||||
|
||||
import javax.servlet.ServletRegistration;
|
||||
|
||||
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.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
import com.baeldung.web.log.config.CustomeRequestLoggingFilter;
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan("com.baeldung.web.log")
|
||||
@PropertySource("application-log.properties")
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(exclude = {
|
||||
SecurityAutoConfiguration.class,
|
||||
ManagementWebSecurityAutoConfiguration.class
|
||||
})
|
||||
public class Application {
|
||||
|
||||
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>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter">
|
||||
<level value="DEBUG" />
|
||||
</logger>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
package com.baeldung.web.controller;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
import com.baeldung.web.log.app.Application;
|
||||
import com.baeldung.web.log.data.TaxiRide;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
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 com.baeldung.web.log.data.TaxiRide;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
@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 {
|
||||
|
||||
@LocalServerPort
|
||||
|
@ -25,8 +21,6 @@ public class TaxiFareControllerIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void givenRequest_whenFetchTaxiFareRateCard_thanOK() {
|
||||
|
||||
System.out.println(port);
|
||||
String URL = "http://localhost:" + port + "/spring-rest";
|
||||
TestRestTemplate testRestTemplate = new TestRestTemplate();
|
||||
TaxiRide taxiRide = new TaxiRide(true, 10l);
|
||||
|
@ -37,16 +31,4 @@ public class TaxiFareControllerIntegrationTest {
|
|||
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>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<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>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -76,13 +88,23 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</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>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<spring.boot.version>2.7.5</spring.boot.version>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<mockserver.version>5.14.0</mockserver.version>
|
||||
</properties>
|
||||
|
||||
</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