Merge branch 'eugenp:master' into master

This commit is contained in:
cesarevalenti90 2023-01-31 23:03:17 +01:00 committed by GitHub
commit 20915e1718
139 changed files with 3827 additions and 363 deletions

View File

@ -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)

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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>

View File

@ -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 + '}';
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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) {
}
}

View File

@ -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);
}
}
}

View File

@ -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));
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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>

View File

@ -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);
}
}

View File

@ -0,0 +1,12 @@
package com.baeldung.callbackfunctions;
public interface EventListener {
String onTrigger();
void respondToTrigger();
}

View File

@ -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();
}
}

View File

@ -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.");
}
}

View File

@ -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();
}
}

View File

@ -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");
}
}

View File

@ -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();
}
}

View File

@ -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);
});
});
}
}

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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>

View File

@ -0,0 +1,5 @@
package com.baeldung.checkinterface;
public class ChildClass1 implements ChildInterface1 {
}

View File

@ -0,0 +1,5 @@
package com.baeldung.checkinterface;
public class ChildClass2 implements ChildInterface2 {
}

View File

@ -0,0 +1,5 @@
package com.baeldung.checkinterface;
public interface ChildInterface1 extends MasterInterface {
}

View File

@ -0,0 +1,5 @@
package com.baeldung.checkinterface;
public interface ChildInterface2 extends MasterInterface {
}

View File

@ -0,0 +1,5 @@
package com.baeldung.checkinterface;
public class MasterClass implements MasterInterface {
}

View File

@ -0,0 +1,5 @@
package com.baeldung.checkinterface;
public interface MasterInterface {
}

View File

@ -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.");
}
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.commandline;
public class CommandLineWithoutErrorHandling {
public static void main(String[] args) {
System.out.println(args[0]);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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>

View File

@ -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;

View File

@ -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);
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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));
}
}

View File

@ -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>

View File

@ -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");

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1 @@
## Relevant Articles:

View File

@ -0,0 +1,3 @@
FROM alpine:latest
MAINTAINER baeldung.com
RUN apk update && apk add iputils && apk add bash && apk add curl

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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!')
})

View File

@ -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"
}
}

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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>

View File

@ -0,0 +1,2 @@
## Relevant Articles
- [Introduction to ScyllaDB with Java](https://www.baeldung.com/java-scylladb)

View File

@ -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>

View File

@ -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>

View File

@ -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();

View File

@ -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>

View File

@ -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");
}
}

View File

@ -0,0 +1,2 @@
logging.config=classpath:log4j2-spring.xml
spring.application.name=log4j2-extension

View File

@ -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>

View File

@ -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

View File

@ -0,0 +1,6 @@
## Spring Boot Logging with Logback
This module contains articles about logging in Spring Boot projects with Logback.
### Relevant Articles:

View File

@ -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>

View File

@ -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");
}
}

View File

@ -0,0 +1 @@
spring.application.name=logback-extension

View File

@ -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>

View File

@ -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)

View File

@ -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) {

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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");
}
}

View File

@ -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);
}
}

View File

@ -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/*/");
}
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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>

View File

@ -0,0 +1,3 @@
package com.baeldung.httpinterface;
public record Book(long id, String title, String author, int year) {}

View File

@ -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;
}
}

View File

@ -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