Merge branch 'master' into BAEL-7278

This commit is contained in:
Wynn Teo 2023-12-12 09:48:29 +08:00 committed by GitHub
commit c314363bcf
2238 changed files with 30412 additions and 6881 deletions

View File

@ -4,4 +4,5 @@
- [Find the N Most Frequent Elements in a Java Array](https://www.baeldung.com/java-n-most-frequent-elements-array)
- [Getting Pixel Array From Image in Java](https://www.baeldung.com/java-getting-pixel-array-from-image)
- [Calculate Distance Between Two Coordinates in Java](https://www.baeldung.com/java-find-distance-between-points)
- [Rotate Arrays in Java](https://www.baeldung.com/java-rotate-arrays)
- More articles: [[<-- prev]](/algorithms-miscellaneous-6)

View File

@ -0,0 +1,102 @@
package com.baeldung.algorithms.rotatearray;
/**
* To speed up the rotation, we narrow k rotations to the remainder of k divided by the array length, or k module the array length.
* Therefore, a large rotation number will be translated into the relative smallest rotation.
* All solutions replace the original array, although they might use an extra array to compute the rotation.
*/
public class RotateArray {
private RotateArray() {
throw new IllegalStateException("Rotate array algorithm utility methods class");
}
/**
*
* @param arr array to apply rotation to
* @param k number of rotations
*/
public static void bruteForce(int[] arr, int k) {
checkInvalidInput(arr, k);
k %= arr.length;
int temp;
int previous;
for (int i = 0; i < k; i++) {
previous = arr[arr.length - 1];
for (int j = 0; j < arr.length; j++) {
temp = arr[j];
arr[j] = previous;
previous = temp;
}
}
}
/**
*
* @param arr array to apply rotation to
* @param k number of rotations
*/
public static void withExtraArray(int[] arr, int k) {
checkInvalidInput(arr, k);
int[] extraArray = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
extraArray[(i + k) % arr.length] = arr[i];
}
System.arraycopy(extraArray, 0, arr, 0, arr.length);
}
/**
*
* @param arr array to apply rotation to
* @param k number of rotations
*/
public static void cyclicReplacement(int[] arr, int k) {
checkInvalidInput(arr, k);
k = k % arr.length;
int count = 0;
for (int start = 0; count < arr.length; start++) {
int current = start;
int prev = arr[start];
do {
int next = (current + k) % arr.length;
int temp = arr[next];
arr[next] = prev;
prev = temp;
current = next;
count++;
} while (start != current);
}
}
/**
*
* @param arr array to apply rotation to
* @param k number of rotations
*/
public static void reverse(int[] arr, int k) {
checkInvalidInput(arr, k);
k %= arr.length;
reverse(arr, 0, arr.length - 1);
reverse(arr, 0, k - 1);
reverse(arr, k, arr.length - 1);
}
private static void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
private static void checkInvalidInput(int[] arr, int rotation) {
if (rotation < 1 || arr == null)
throw new IllegalArgumentException("Rotation must be greater than zero or array must be not null");
}
}

View File

@ -0,0 +1,129 @@
package com.baeldung.algorithms.connect4;
import java.util.ArrayList;
import java.util.List;
public class GameBoard {
private final List<List<Piece>> columns;
private final int rows;
public GameBoard(int columns, int rows) {
this.rows = rows;
this.columns = new ArrayList<>();
for (int i = 0; i < columns; ++i) {
this.columns.add(new ArrayList<>());
}
}
public int getRows() {
return rows;
}
public int getColumns() {
return columns.size();
}
public Piece getCell(int x, int y) {
assert(x >= 0 && x < getColumns());
assert(y >= 0 && y < getRows());
List<Piece> column = columns.get(x);
if (column.size() > y) {
return column.get(y);
} else {
return null;
}
}
public boolean move(int x, Piece player) {
assert(x >= 0 && x < getColumns());
List<Piece> column = columns.get(x);
if (column.size() >= this.rows) {
throw new IllegalArgumentException("That column is full");
}
column.add(player);
return checkWin(x, column.size() - 1, player);
}
private boolean checkWin(int x, int y, Piece player) {
// Vertical line
if (checkLine(x, y, 0, -1, player)) {
return true;
}
for (int offset = 0; offset < 4; ++offset) {
// Horizontal line
if (checkLine(x - 3 + offset, y, 1, 0, player)) {
return true;
}
// Leading diagonal
if (checkLine(x - 3 + offset, y + 3 - offset, 1, -1, player)) {
return true;
}
// Trailing diagonal
if (checkLine(x - 3 + offset, y - 3 + offset, 1, 1, player)) {
return true;
}
}
return false;
}
private boolean checkLine(int x1, int y1, int xDiff, int yDiff, Piece player) {
for (int i = 0; i < 4; ++i) {
int x = x1 + (xDiff * i);
int y = y1 + (yDiff * i);
if (x < 0 || x > columns.size() - 1) {
return false;
}
if (y < 0 || y > rows - 1) {
return false;
}
if (player != getCell(x, y)) {
return false;
}
}
return true;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (int y = getRows() - 1; y >= 0; --y) {
for (int x = 0; x < getColumns(); ++x) {
Piece piece = getCell(x, y);
result.append("|");
if (piece == null) {
result.append(" ");
} else if (piece == Piece.PLAYER_1) {
result.append("X");
} else if (piece == Piece.PLAYER_2) {
result.append("O");
}
}
result.append("|\n");
for (int i = 0; i < getColumns(); ++i) {
result.append("+-");
}
result.append("+\n");
}
return result.toString();
}
}

View File

@ -0,0 +1,40 @@
package com.baeldung.algorithms.connect4;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class GameUnitTest {
@Test
public void blankGame() {
GameBoard gameBoard = new GameBoard(8, 6);
System.out.println(gameBoard);
}
@Test
public void playedGame() {
GameBoard gameBoard = new GameBoard(8, 6);
assertFalse(gameBoard.move(3, Piece.PLAYER_1));
assertFalse(gameBoard.move(2, Piece.PLAYER_2));
assertFalse(gameBoard.move(4, Piece.PLAYER_1));
assertFalse(gameBoard.move(3, Piece.PLAYER_2));
assertFalse(gameBoard.move(5, Piece.PLAYER_1));
assertFalse(gameBoard.move(6, Piece.PLAYER_2));
assertFalse(gameBoard.move(5, Piece.PLAYER_1));
assertFalse(gameBoard.move(4, Piece.PLAYER_2));
assertFalse(gameBoard.move(5, Piece.PLAYER_1));
assertFalse(gameBoard.move(5, Piece.PLAYER_2));
assertFalse(gameBoard.move(6, Piece.PLAYER_1));
assertTrue(gameBoard.move(4, Piece.PLAYER_2));
System.out.println(gameBoard);
}
}

View File

@ -0,0 +1,6 @@
package com.baeldung.algorithms.connect4;
public enum Piece {
PLAYER_1,
PLAYER_2
}

View File

@ -0,0 +1,2 @@
## Relevant Articles
- [Implement Connect 4 Game with Java](https://www.baeldung.com/java-connect-4-game)

View File

@ -0,0 +1,124 @@
package com.baeldung.algorithms.rotatearray;
import static com.baeldung.algorithms.rotatearray.RotateArray.bruteForce;
import static com.baeldung.algorithms.rotatearray.RotateArray.cyclicReplacement;
import static com.baeldung.algorithms.rotatearray.RotateArray.reverse;
import static com.baeldung.algorithms.rotatearray.RotateArray.withExtraArray;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
class RotateArrayUnitTest {
private final int[] arr = { 1, 2, 3, 4, 5, 6 };
private final int rotationLtArrayLength = 1;
private final int rotationGtArrayLength = arr.length + 2;
private final int[] ltArrayLengthRotation = { 6, 1, 2, 3, 4, 5 };
private final int[] gtArrayLengthRotation = { 5, 6, 1, 2, 3, 4 };
@Test
void givenInputArray_whenNoRotationOrEmptyArray_thenThrowIllegalArgumentException() {
final int noRotation = 0;
final int someRotation = arr.length - 1;
assertThrows(IllegalArgumentException.class, () -> bruteForce(arr, noRotation));
assertThrows(IllegalArgumentException.class, () -> withExtraArray(arr, noRotation));
assertThrows(IllegalArgumentException.class, () -> cyclicReplacement(arr, noRotation));
assertThrows(IllegalArgumentException.class, () -> reverse(arr, noRotation));
assertThrows(IllegalArgumentException.class, () -> bruteForce(null, someRotation));
assertThrows(IllegalArgumentException.class, () -> withExtraArray(null, someRotation));
assertThrows(IllegalArgumentException.class, () -> cyclicReplacement(null, someRotation));
assertThrows(IllegalArgumentException.class, () -> reverse(null, someRotation));
}
@Test
void givenInputArray_whenUseBruteForceRotationLtArrayLength_thenRotateArrayOk() {
bruteForce(arr, rotationLtArrayLength);
assertArrayEquals(ltArrayLengthRotation, arr);
}
@Test
void givenInputArray_whenUseBruteForceRotationGtArrayLength_thenRotateArrayOk() {
bruteForce(arr, rotationGtArrayLength);
assertArrayEquals(gtArrayLengthRotation, arr);
}
@Test
void givenInputArray_whenUseBruteForceRotationEqArrayLength_thenDoNothing() {
int[] expected = arr.clone();
bruteForce(arr, arr.length);
assertArrayEquals(expected, arr);
}
@Test
void givenInputArray_whenUseExtraArrayRotationLtArrayLength_thenRotateArrayOk() {
withExtraArray(arr, rotationLtArrayLength);
assertArrayEquals(ltArrayLengthRotation, arr);
}
@Test
void givenInputArray_whenUseExtraArrayRotationGtArrayLength_thenRotateArrayOk() {
withExtraArray(arr, rotationGtArrayLength);
assertArrayEquals(gtArrayLengthRotation, arr);
}
@Test
void givenInputArray_whenUseExtraArrayWithRotationEqArrayLength_thenDoNothing() {
int[] clone = arr.clone();
withExtraArray(arr, arr.length);
assertArrayEquals(clone, arr);
}
@Test
void givenInputArray_whenUseCyclicReplacementRotationLtArrayLength_thenRotateArrayOk() {
cyclicReplacement(arr, rotationLtArrayLength);
assertArrayEquals(ltArrayLengthRotation, arr);
}
@Test
void givenInputArray_whenUseCyclicReplacementRotationGtArrayLength_thenRotateArrayOk() {
cyclicReplacement(arr, rotationGtArrayLength);
assertArrayEquals(gtArrayLengthRotation, arr);
}
@Test
void givenInputArray_whenUseCyclicReplacementRotationEqArrayLength_thenDoNothing() {
int[] clone = arr.clone();
cyclicReplacement(arr, arr.length);
assertArrayEquals(clone, arr);
}
@Test
void givenInputArray_whenUseReverseRotationLtArrayLength_thenRotateArrayOk() {
reverse(arr, rotationLtArrayLength);
assertArrayEquals(ltArrayLengthRotation, arr);
}
@Test
void givenInputArray_whenUseReverseRotationGtArrayLength_thenRotateArrayOk() {
reverse(arr, rotationGtArrayLength);
assertArrayEquals(gtArrayLengthRotation, arr);
}
@Test
void givenInputArray_whenUseReverseRotationEqArrayLength_thenDoNothing() {
int[] clone = arr.clone();
reverse(arr, arr.length);
assertArrayEquals(clone, arr);
}
}

View File

@ -28,7 +28,7 @@
</modules>
<properties>
<commons-codec.version>1.11</commons-codec.version>
<commons-codec.version>1.16.0</commons-codec.version>
<commons-math3.version>3.6.1</commons-math3.version>
<cobertura.plugin.version>2.7</cobertura.plugin.version>
<tradukisto.version>1.0.1</tradukisto.version>

View File

@ -58,7 +58,7 @@
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>${wiremock.version}</version>
<scope>test</scope>
@ -77,11 +77,11 @@
<properties>
<mockserver.version>5.6.1</mockserver.version>
<wiremock.version>2.5.1</wiremock.version>
<wiremock.version>3.3.1</wiremock.version>
<!-- http client & core 5 -->
<httpcore5.version>5.2</httpcore5.version>
<httpclient5.version>5.2</httpclient5.version>
<httpclient5-fluent.version>5.2</httpclient5-fluent.version>
<httpcore5.version>5.2.2</httpcore5.version>
<httpclient5.version>5.2.2</httpclient5.version>
<httpclient5-fluent.version>5.2.2</httpclient5-fluent.version>
</properties>
</project>

View File

@ -8,7 +8,7 @@ import static org.mockserver.model.HttpResponse.response;
import java.io.IOException;
import java.net.ServerSocket;
import org.apache.http.HttpStatus;
import org.apache.hc.core5.http.HttpStatus;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.mockserver.client.MockServerClient;

View File

@ -25,6 +25,7 @@ import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBu
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
@ -33,13 +34,10 @@ import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.reactor.IOReactorConfig;
import org.apache.hc.core5.ssl.SSLContexts;
import org.apache.hc.core5.ssl.TrustStrategy;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.junit.jupiter.api.Test;
class HttpAsyncClientLiveTest extends GetRequestMockServer {
private static final String HOST = "http://www.google.com";
private static final String HOST_WITH_SSL = "https://mms.nw.ru/";
private static final String HOST_WITH_PROXY = "http://httpbin.org/";
private static final String URL_SECURED_BY_BASIC_AUTHENTICATION = "http://browserspy.dk/password-ok.php";// "http://localhost:8080/spring-security-rest-basic-auth/api/foos/1";
@ -122,7 +120,7 @@ class HttpAsyncClientLiveTest extends GetRequestMockServer {
.build();
final TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
.setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
.setHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setSslContext(sslContext)
.build();
@ -201,7 +199,7 @@ class HttpAsyncClientLiveTest extends GetRequestMockServer {
@Override
public void run() {
try {
final Future<SimpleHttpResponse> future = client.execute(SimpleHttpRequest.copy(request), context, null);
final Future<SimpleHttpResponse> future = client.execute(SimpleRequestBuilder.copy(request).build(), context, null);
final HttpResponse response = future.get();
assertThat(response.getCode(), equalTo(200));
} catch (final Exception ex) {

View File

@ -1,10 +1,10 @@
package com.baeldung.httpclient;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import java.io.IOException;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.core5.http.HttpEntity;
public final class ResponseUtil {
private ResponseUtil() {
}

View File

@ -103,7 +103,7 @@ class HttpClientAdvancedConfigurationIntegrationTest {
void givenServerThatIsBehindProxy_whenClientIsConfiguredToSendRequestViaProxy_shouldReturn200() throws IOException {
//given
proxyMock.stubFor(get(urlMatching(".*"))
.willReturn(aResponse().proxiedFrom("http://localhost:8089/")));
.willReturn(aResponse().proxiedFrom("http://localhost:8089")));
serviceMock.stubFor(get(urlEqualTo("/private"))
.willReturn(aResponse().withStatus(200)));
@ -129,7 +129,7 @@ class HttpClientAdvancedConfigurationIntegrationTest {
public void givenServerThatIsBehindAuthorizationProxy_whenClientSendRequest_shouldAuthorizeProperly() throws IOException {
//given
proxyMock.stubFor(get(urlMatching("/private"))
.willReturn(aResponse().proxiedFrom("http://localhost:8089/")));
.willReturn(aResponse().proxiedFrom("http://localhost:8089")));
serviceMock.stubFor(get(urlEqualTo("/private"))
.willReturn(aResponse().withStatus(200)));

View File

@ -158,7 +158,7 @@
<version>${mockserver.version}</version>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>${wiremock.version}</version>
<scope>test</scope>
@ -234,10 +234,10 @@
<properties>
<!-- util -->
<commons-codec.version>1.10</commons-codec.version>
<commons-codec.version>1.16.0</commons-codec.version>
<httpasyncclient.version>4.1.5</httpasyncclient.version>
<!-- testing -->
<wiremock.version>2.5.1</wiremock.version>
<wiremock.version>3.3.1</wiremock.version>
<httpcore.version>4.4.16</httpcore.version>
<httpclient.version>4.5.14</httpclient.version>
<mockserver.version>5.11.2</mockserver.version>

View File

@ -7,14 +7,14 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
public class CustomWebSecurityConfigurerAdapter {
@Autowired private RestAuthenticationEntryPoint authenticationEntryPoint;
@ -27,8 +27,8 @@ public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAda
.authorities("ROLE_USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/securityNone")
@ -40,6 +40,8 @@ public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAda
.authenticationEntryPoint(authenticationEntryPoint);
http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class);
return http.build();
}
@Bean

View File

@ -102,7 +102,7 @@ class HttpClientAdvancedConfigurationIntegrationTest {
void givenServerThatIsBehindProxy_whenClientIsConfiguredToSendRequestViaProxy_shouldReturn200() throws IOException {
//given
proxyMock.stubFor(get(urlMatching(".*"))
.willReturn(aResponse().proxiedFrom("http://localhost:8089/")));
.willReturn(aResponse().proxiedFrom("http://localhost:8089")));
serviceMock.stubFor(get(urlEqualTo("/private"))
.willReturn(aResponse().withStatus(200)));
@ -128,7 +128,7 @@ class HttpClientAdvancedConfigurationIntegrationTest {
void givenServerThatIsBehindAuthorizationProxy_whenClientSendRequest_shouldAuthorizeProperly() throws IOException {
//given
proxyMock.stubFor(get(urlMatching("/private"))
.willReturn(aResponse().proxiedFrom("http://localhost:8089/")));
.willReturn(aResponse().proxiedFrom("http://localhost:8089")));
serviceMock.stubFor(get(urlEqualTo("/private"))
.willReturn(aResponse().withStatus(200)));

View File

@ -13,3 +13,5 @@ You can build the project from the command line using: *mvn clean install*, or i
- [Read Data From the Beginning Using Kafka Consumer API](https://www.baeldung.com/java-kafka-consumer-api-read)
- [Get Partition Count for a Topic in Kafka](https://www.baeldung.com/java-kafka-partition-count-topic)
- [bootstrap-server in Kafka Configuration](https://www.baeldung.com/java-kafka-bootstrap-server)
- [Introduction to Apache Kafka](https://www.baeldung.com/apache-kafka)
- [Ensuring Message Ordering in Kafka: Strategies and Configurations](https://www.baeldung.com/kafka-message-ordering)

View File

@ -1 +0,0 @@
log4j.rootLogger=INFO, stdout

View File

@ -23,11 +23,6 @@
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
@ -57,13 +52,19 @@
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.databind.version}</version>
</dependency>
</dependencies>
<properties>
<jna.version>5.7.0</jna.version>
<kafka.version>2.8.0</kafka.version>
<testcontainers-kafka.version>1.15.3</testcontainers-kafka.version>
<testcontainers-kafka.version>1.19.3</testcontainers-kafka.version>
<testcontainers-jupiter.version>1.15.3</testcontainers-jupiter.version>
<jackson.databind.version>2.15.2</jackson.databind.version>
</properties>
</project>

View File

@ -0,0 +1,11 @@
package com.baeldung.kafka.message.ordering;
public class Config {
public static final String CONSUMER_VALUE_DESERIALIZER_SERIALIZED_CLASS = "value.deserializer.serializedClass";
public static final String MULTI_PARTITION_TOPIC = "multi_partition_topic";
public static final String SINGLE_PARTITION_TOPIC = "single_partition_topic";
public static final int MULTIPLE_PARTITIONS = 5;
public static final int SINGLE_PARTITION = 1;
public static final short REPLICATION_FACTOR = 1;
}

View File

@ -0,0 +1,61 @@
package com.baeldung.kafka.message.ordering.payload;
import java.util.Objects;
public class UserEvent implements Comparable<UserEvent> {
private String userEventId;
private long eventNanoTime;
private long globalSequenceNumber;
@SuppressWarnings("unused")
public UserEvent() {
// Required for Jackson Serialization and Deserialization
}
public UserEvent(String userEventId) {
this.userEventId = userEventId;
}
public String getUserEventId() {
return userEventId;
}
public long getEventNanoTime() {
return eventNanoTime;
}
public void setEventNanoTime(long eventNanoTime) {
this.eventNanoTime = eventNanoTime;
}
public long getGlobalSequenceNumber() {
return globalSequenceNumber;
}
public void setGlobalSequenceNumber(long globalSequenceNumber) {
this.globalSequenceNumber = globalSequenceNumber;
}
@Override
public int compareTo(UserEvent other) {
return Long.compare(this.globalSequenceNumber, other.globalSequenceNumber);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof UserEvent)) {
return false;
}
UserEvent userEvent = (UserEvent) obj;
return this.globalSequenceNumber == userEvent.globalSequenceNumber;
}
@Override
public int hashCode() {
return Objects.hash(globalSequenceNumber);
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.kafka.message.ordering.serialization;
import com.baeldung.kafka.message.ordering.Config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.kafka.common.serialization.Deserializer;
import java.util.Map;
/**
* Configured via {@link org.apache.kafka.clients.consumer.ConsumerConfig#VALUE_DESERIALIZER_CLASS_CONFIG}
*/
public class JacksonDeserializer<T> implements Deserializer<T> {
private final ObjectMapper objectMapper = new ObjectMapper();
private Class<T> type;
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
this.type = (Class<T>) configs.get(Config.CONSUMER_VALUE_DESERIALIZER_SERIALIZED_CLASS);
}
@Override
public T deserialize(String topic, byte[] bytes) {
if (bytes == null) {
return null;
}
try {
return objectMapper.readValue(bytes, type);
} catch (Exception e) {
throw new RuntimeException("Error deserializing value", e);
}
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.kafka.message.ordering.serialization;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.kafka.common.serialization.Serializer;
/**
* Configured via {@link org.apache.kafka.clients.producer.ProducerConfig#VALUE_SERIALIZER_CLASS_CONFIG}
*/
public class JacksonSerializer<T> implements Serializer<T> {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public byte[] serialize(String topic, T data) {
if (data == null) {
return null;
}
try {
return objectMapper.writeValueAsBytes(data);
} catch (Exception e) {
throw new RuntimeException("Error serializing value", e);
}
}
}

View File

@ -0,0 +1,126 @@
package com.baeldung.kafka.message.ordering;
import com.baeldung.kafka.message.ordering.payload.UserEvent;
import com.baeldung.kafka.message.ordering.serialization.JacksonDeserializer;
import com.baeldung.kafka.message.ordering.serialization.JacksonSerializer;
import org.apache.kafka.clients.admin.*;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.serialization.LongDeserializer;
import org.apache.kafka.common.serialization.LongSerializer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.KafkaContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.google.common.collect.ImmutableList;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
@Testcontainers
public class ExternalSequenceWithTimeWindowLiveTest {
private static Admin admin;
private static KafkaProducer<Long, UserEvent> producer;
private static KafkaConsumer<Long, UserEvent> consumer;
private static final Duration TIMEOUT_WAIT_FOR_MESSAGES = Duration.ofSeconds(5);
private static final long BUFFER_PERIOD_NS = Duration.ofSeconds(5)
.toNanos();
private static Logger logger = LoggerFactory.getLogger(ExternalSequenceWithTimeWindowLiveTest.class);
@Container
private static final KafkaContainer KAFKA_CONTAINER = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest"));
@BeforeAll
static void setup() throws ExecutionException, InterruptedException {
KAFKA_CONTAINER.addExposedPort(9092);
Properties adminProperties = new Properties();
adminProperties.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
Properties producerProperties = new Properties();
producerProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
producerProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, LongSerializer.class.getName());
producerProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JacksonSerializer.class.getName());
Properties consumerProperties = new Properties();
consumerProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, LongDeserializer.class.getName());
consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JacksonDeserializer.class.getName());
consumerProperties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
consumerProperties.put(Config.CONSUMER_VALUE_DESERIALIZER_SERIALIZED_CLASS, UserEvent.class);
consumerProperties.put(ConsumerConfig.GROUP_ID_CONFIG, "test-group");
admin = Admin.create(adminProperties);
producer = new KafkaProducer<>(producerProperties);
consumer = new KafkaConsumer<>(consumerProperties);
admin.createTopics(ImmutableList.of(new NewTopic(Config.MULTI_PARTITION_TOPIC, Config.MULTIPLE_PARTITIONS, Config.REPLICATION_FACTOR)))
.all()
.get();
}
@AfterAll
static void destroy() {
KAFKA_CONTAINER.stop();
}
@Test
void givenMultiplePartitions_whenPublishedToKafkaAndConsumedWithExtSeqNumberAndTimeWindow_thenCheckForMessageOrder() throws ExecutionException, InterruptedException {
List<UserEvent> sentUserEventList = new ArrayList<>();
List<UserEvent> receivedUserEventList = new ArrayList<>();
for (long sequenceNumber = 1; sequenceNumber <= 10; sequenceNumber++) {
UserEvent userEvent = new UserEvent(UUID.randomUUID()
.toString());
userEvent.setEventNanoTime(System.nanoTime());
userEvent.setGlobalSequenceNumber(sequenceNumber);
Future<RecordMetadata> future = producer.send(new ProducerRecord<>(Config.MULTI_PARTITION_TOPIC, sequenceNumber, userEvent));
sentUserEventList.add(userEvent);
RecordMetadata metadata = future.get();
logger.info("User Event ID: " + userEvent.getUserEventId() + ", Partition : " + metadata.partition());
}
consumer.subscribe(Collections.singletonList(Config.MULTI_PARTITION_TOPIC));
List<UserEvent> buffer = new ArrayList<>();
long lastProcessedTime = System.nanoTime();
ConsumerRecords<Long, UserEvent> records = consumer.poll(TIMEOUT_WAIT_FOR_MESSAGES);
records.forEach(record -> {
buffer.add(record.value());
});
while (!buffer.isEmpty()) {
if (System.nanoTime() - lastProcessedTime > BUFFER_PERIOD_NS) {
processBuffer(buffer, receivedUserEventList);
lastProcessedTime = System.nanoTime();
}
records = consumer.poll(TIMEOUT_WAIT_FOR_MESSAGES);
records.forEach(record -> {
buffer.add(record.value());
});
}
assertThat(receivedUserEventList).isEqualTo(sentUserEventList)
.containsExactlyElementsOf(sentUserEventList);
}
private static void processBuffer(List<UserEvent> buffer, List<UserEvent> receivedUserEventList) {
Collections.sort(buffer);
buffer.forEach(userEvent -> {
receivedUserEventList.add(userEvent);
logger.info("Processing message with Global Sequence number: " + userEvent.getGlobalSequenceNumber() + ", User Event Id: " + userEvent.getUserEventId());
});
buffer.clear();
}
}

View File

@ -0,0 +1,105 @@
package com.baeldung.kafka.message.ordering;
import com.baeldung.kafka.message.ordering.payload.UserEvent;
import com.baeldung.kafka.message.ordering.serialization.JacksonDeserializer;
import com.baeldung.kafka.message.ordering.serialization.JacksonSerializer;
import org.apache.kafka.clients.admin.*;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.serialization.LongDeserializer;
import org.apache.kafka.common.serialization.LongSerializer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.KafkaContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.google.common.collect.ImmutableList;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
@Testcontainers
public class MultiplePartitionLiveTest {
private static Admin admin;
private static KafkaProducer<Long, UserEvent> producer;
private static KafkaConsumer<Long, UserEvent> consumer;
private static final Duration TIMEOUT_WAIT_FOR_MESSAGES = Duration.ofSeconds(5);
private static Logger logger = LoggerFactory.getLogger(MultiplePartitionLiveTest.class);
@Container
private static final KafkaContainer KAFKA_CONTAINER = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest"));
@BeforeAll
static void setup() throws ExecutionException, InterruptedException {
KAFKA_CONTAINER.addExposedPort(9092);
Properties adminProperties = new Properties();
adminProperties.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
Properties producerProperties = new Properties();
producerProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
producerProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, LongSerializer.class.getName());
producerProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JacksonSerializer.class.getName());
Properties consumerProperties = new Properties();
consumerProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, LongDeserializer.class.getName());
consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JacksonDeserializer.class.getName());
consumerProperties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
consumerProperties.put(Config.CONSUMER_VALUE_DESERIALIZER_SERIALIZED_CLASS, UserEvent.class);
consumerProperties.put(ConsumerConfig.GROUP_ID_CONFIG, "test-group");
admin = Admin.create(adminProperties);
producer = new KafkaProducer<>(producerProperties);
consumer = new KafkaConsumer<>(consumerProperties);
admin.createTopics(ImmutableList.of(new NewTopic(Config.MULTI_PARTITION_TOPIC, Config.MULTIPLE_PARTITIONS, Config.REPLICATION_FACTOR)))
.all()
.get();
}
@AfterAll
static void destroy() {
KAFKA_CONTAINER.stop();
}
@Test
void givenMultiplePartitions_whenPublishedToKafkaAndConsumed_thenCheckForMessageOrder() throws ExecutionException, InterruptedException {
List<UserEvent> sentUserEventList = new ArrayList<>();
List<UserEvent> receivedUserEventList = new ArrayList<>();
for (long sequenceNumber = 1; sequenceNumber <= 10; sequenceNumber++) {
UserEvent userEvent = new UserEvent(UUID.randomUUID()
.toString());
userEvent.setGlobalSequenceNumber(sequenceNumber);
userEvent.setEventNanoTime(System.nanoTime());
Future<RecordMetadata> future = producer.send(new ProducerRecord<>(Config.MULTI_PARTITION_TOPIC, sequenceNumber, userEvent));
sentUserEventList.add(userEvent);
RecordMetadata metadata = future.get();
logger.info("User Event ID: " + userEvent.getUserEventId() + ", Partition : " + metadata.partition());
}
consumer.subscribe(Collections.singletonList(Config.MULTI_PARTITION_TOPIC));
ConsumerRecords<Long, UserEvent> records = consumer.poll(TIMEOUT_WAIT_FOR_MESSAGES);
records.forEach(record -> {
UserEvent userEvent = record.value();
receivedUserEventList.add(userEvent);
logger.info("User Event ID: " + userEvent.getUserEventId());
});
assertThat(receivedUserEventList).isNotEqualTo(sentUserEventList)
.containsExactlyInAnyOrderElementsOf(sentUserEventList);
}
}

View File

@ -0,0 +1,109 @@
package com.baeldung.kafka.message.ordering;
import com.baeldung.kafka.message.ordering.payload.UserEvent;
import com.baeldung.kafka.message.ordering.serialization.JacksonDeserializer;
import com.baeldung.kafka.message.ordering.serialization.JacksonSerializer;
import org.apache.kafka.clients.admin.Admin;
import org.apache.kafka.clients.admin.AdminClientConfig;
import org.apache.kafka.clients.admin.NewTopic;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.serialization.LongDeserializer;
import org.apache.kafka.common.serialization.LongSerializer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.KafkaContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.google.common.collect.ImmutableList;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
@Testcontainers
public class SinglePartitionLiveTest {
private static Admin admin;
private static KafkaProducer<Long, UserEvent> producer;
private static KafkaConsumer<Long, UserEvent> consumer;
private static final Duration TIMEOUT_WAIT_FOR_MESSAGES = Duration.ofSeconds(5);
private static Logger logger = LoggerFactory.getLogger(SinglePartitionLiveTest.class);
@Container
private static final KafkaContainer KAFKA_CONTAINER = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest"));
@BeforeAll
static void setup() throws ExecutionException, InterruptedException {
KAFKA_CONTAINER.addExposedPort(9092);
Properties adminProperties = new Properties();
adminProperties.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
Properties producerProperties = new Properties();
producerProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
producerProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, LongSerializer.class.getName());
producerProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JacksonSerializer.class.getName());
Properties consumerProperties = new Properties();
consumerProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, LongDeserializer.class.getName());
consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JacksonDeserializer.class.getName());
consumerProperties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
consumerProperties.put(Config.CONSUMER_VALUE_DESERIALIZER_SERIALIZED_CLASS, UserEvent.class);
consumerProperties.put(ConsumerConfig.GROUP_ID_CONFIG, "test-group");
admin = Admin.create(adminProperties);
producer = new KafkaProducer<>(producerProperties);
consumer = new KafkaConsumer<>(consumerProperties);
admin.createTopics(ImmutableList.of(new NewTopic(Config.SINGLE_PARTITION_TOPIC, Config.SINGLE_PARTITION, Config.REPLICATION_FACTOR)))
.all()
.get();
}
@AfterAll
static void destroy() {
KAFKA_CONTAINER.stop();
}
@Test
void givenASinglePartition_whenPublishedToKafkaAndConsumed_thenCheckForMessageOrder() throws ExecutionException, InterruptedException {
List<UserEvent> sentUserEventList = new ArrayList<>();
List<UserEvent> receivedUserEventList = new ArrayList<>();
for (long sequenceNumber = 1; sequenceNumber <= 10; sequenceNumber++) {
UserEvent userEvent = new UserEvent(UUID.randomUUID()
.toString());
userEvent.setGlobalSequenceNumber(sequenceNumber);
userEvent.setEventNanoTime(System.nanoTime());
ProducerRecord<Long, UserEvent> producerRecord = new ProducerRecord<>(Config.SINGLE_PARTITION_TOPIC, userEvent);
Future<RecordMetadata> future = producer.send(producerRecord);
sentUserEventList.add(userEvent);
RecordMetadata metadata = future.get();
logger.info("User Event ID: " + userEvent.getUserEventId() + ", Partition : " + metadata.partition());
}
consumer.subscribe(Collections.singletonList(Config.SINGLE_PARTITION_TOPIC));
ConsumerRecords<Long, UserEvent> records = consumer.poll(TIMEOUT_WAIT_FOR_MESSAGES);
records.forEach(record -> {
UserEvent userEvent = record.value();
receivedUserEventList.add(userEvent);
logger.info("User Event ID: " + userEvent.getUserEventId());
});
assertThat(receivedUserEventList).isEqualTo(sentUserEventList)
.containsExactlyElementsOf(sentUserEventList);
}
}

View File

@ -0,0 +1,103 @@
package com.baeldung.kafka.multipletopics;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.Duration;
import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.KafkaContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
// This live test needs a Docker Daemon running so that a kafka container can be created
@Testcontainers
public class MultipleTopicsLiveTest {
private final Logger log = LoggerFactory.getLogger(MultipleTopicsLiveTest.class);
private static final String CARD_PAYMENTS_TOPIC = "card-payments";
private static final String BANK_TRANSFERS_TOPIC = "bank-transfers";
private static KafkaProducer<String, String> producer;
private static KafkaConsumer<String, String> consumer;
@Container
private static final KafkaContainer KAFKA_CONTAINER = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest"));
@BeforeAll
static void setup() {
KAFKA_CONTAINER.addExposedPort(9092);
producer = new KafkaProducer<>(getProducerProperties());
consumer = new KafkaConsumer<>(getConsumerProperties());
}
@AfterAll
static void destroy() {
KAFKA_CONTAINER.stop();
}
private static Properties getProducerProperties() {
Properties producerProperties = new Properties();
producerProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
producerProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
producerProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
return producerProperties;
}
private static Properties getConsumerProperties() {
Properties consumerProperties = new Properties();
consumerProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers());
consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
consumerProperties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
consumerProperties.put(ConsumerConfig.GROUP_ID_CONFIG, "payments");
return consumerProperties;
}
@Test
void whenSendingMessagesOnTwoTopics_thenConsumerReceivesMessages() throws Exception {
publishMessages();
consumer.subscribe(Arrays.asList(CARD_PAYMENTS_TOPIC, BANK_TRANSFERS_TOPIC));
int eventsProcessed = 0;
for (ConsumerRecord<String, String> record : consumer.poll(Duration.ofSeconds(10))) {
log.info("Event on topic={}, payload={}", record.topic(), record.value());
eventsProcessed++;
}
assertThat(eventsProcessed).isEqualTo(2);
}
private void publishMessages() throws ExecutionException, InterruptedException {
ProducerRecord<String, String> cardPayment = new ProducerRecord<>(CARD_PAYMENTS_TOPIC, createCardPayment());
producer.send(cardPayment).get();
ProducerRecord<String, String> bankTransfer = new ProducerRecord<>(BANK_TRANSFERS_TOPIC, createBankTransfer());
producer.send(bankTransfer).get();
}
private String createCardPayment() {
return "{\"paymentReference\":\"A184028KM0013790\", \"type\":\"card\", \"amount\":\"275\", \"currency\":\"GBP\"}";
}
private String createBankTransfer() {
return "{\"paymentReference\":\"19ae2-18mk73-009\", \"type\":\"bank\", \"amount\":\"150\", \"currency\":\"EUR\"}";
}
}

View File

@ -0,0 +1,11 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -181,8 +181,9 @@
</build>
<properties>
<jackson.version>2.13.4</jackson.version>
<kafka.version>3.4.0</kafka.version>
<testcontainers-kafka.version>1.15.3</testcontainers-kafka.version>
<testcontainers-kafka.version>1.19.3</testcontainers-kafka.version>
<testcontainers-jupiter.version>1.15.3</testcontainers-jupiter.version>
<flink.version>1.16.1</flink.version>
<awaitility.version>3.0.0</awaitility.version>

View File

@ -29,7 +29,7 @@ import java.util.List;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class BackupCreatorIntegrationTest {
public class BackupCreatorUnitTest {
public static ObjectMapper mapper;
@Before

View File

@ -10,7 +10,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class WordCapitalizerIntegrationTest {
public class WordCapitalizerUnitTest {
@Test
public void givenDataSet_whenExecuteWordCapitalizer_thenReturnCapitalizedWords() throws Exception {

View File

@ -21,8 +21,7 @@ import org.junit.Ignore;
import org.junit.Test;
public class KafkaStreamsLiveTest {
private String bootstrapServers = "localhost:9092";
private Path stateDirectory;
private final String bootstrapServers = "localhost:9092";
@Test
@Ignore("it needs to have kafka broker running on local")
@ -44,8 +43,8 @@ public class KafkaStreamsLiveTest {
// Use a temporary directory for storing state, which will be automatically removed after the test.
try {
this.stateDirectory = Files.createTempDirectory("kafka-streams");
streamsConfiguration.put(StreamsConfig.STATE_DIR_CONFIG, this.stateDirectory.toAbsolutePath()
Path stateDirectory = Files.createTempDirectory("kafka-streams");
streamsConfiguration.put(StreamsConfig.STATE_DIR_CONFIG, stateDirectory.toAbsolutePath()
.toString());
} catch (final IOException e) {
throw new UncheckedIOException("Cannot create temporary directory", e);

View File

@ -191,7 +191,7 @@
<bval.version>2.0.6</bval.version>
<javax.validation.validation-api.version>2.0.1.Final</javax.validation.validation-api.version>
<meecrowave-junit.version>1.2.15</meecrowave-junit.version>
<okhttp.version>3.10.0</okhttp.version>
<okhttp.version>4.12.0</okhttp.version>
<meecrowave-jpa.version>1.2.15</meecrowave-jpa.version>
<meecrowave-core.version>1.2.15</meecrowave-core.version>
<meecrowave-maven-plugin.version>1.2.15</meecrowave-maven-plugin.version>

2
aws-modules/aws-dynamodb/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target/
.idea/

View File

@ -0,0 +1,7 @@
## AWS DYNAMODB
This module contains articles about AWS DynamoDB
### Relevant articles
- [Integration Testing with a Local DynamoDB Instance](https://www.baeldung.com/dynamodb-local-integration-tests)

View File

@ -0,0 +1,71 @@
<?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>aws-dynamodb</artifactId>
<version>0.1.0-SNAPSHOT</version>
<name>aws-dynamodb</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>aws-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>${aws-java-sdk.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>DynamoDBLocal</artifactId>
<version>${dynamodblocal.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven-plugins-version}</version>
<executions>
<execution>
<id>copy</id>
<phase>compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope></includeScope>
<includeTypes>so,dll,dylib</includeTypes>
<outputDirectory>native-libs</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<gson.version>2.10.1</gson.version>
<dynamodblocal.version>1.21.1</dynamodblocal.version>
<maven-plugins-version>3.1.1</maven-plugins-version>
</properties>
</project>

View File

@ -5,6 +5,5 @@ This module contains articles about various Amazon Web Services (AWS) such as EC
### Relevant articles
- [Managing EC2 Instances in Java](https://www.baeldung.com/ec2-java)
- [Integration Testing with a Local DynamoDB Instance](https://www.baeldung.com/dynamodb-local-integration-tests)
- [Managing Amazon SQS Queues in Java](https://www.baeldung.com/aws-queues-java)
- [Guide to AWS Aurora RDS with Java](https://www.baeldung.com/aws-aurora-rds-java)

View File

@ -16,31 +16,9 @@
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>${aws-java-sdk.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>${aws-lambda-java-core.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>${aws-lambda-java-events.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
<groupId>software.amazon.awssdk</groupId>
<artifactId>aws-sdk-java</artifactId>
<version>${aws-java-sdk-v2.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
@ -52,32 +30,10 @@
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>DynamoDBLocal</artifactId>
<version>${dynamodblocal.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
@ -101,11 +57,9 @@
</build>
<properties>
<aws-lambda-java-events.version>1.3.0</aws-lambda-java-events.version>
<aws-lambda-java-core.version>1.1.0</aws-lambda-java-core.version>
<gson.version>2.8.0</gson.version>
<gson.version>2.10.1</gson.version>
<dynamodblocal.version>1.21.1</dynamodblocal.version>
<commons-codec-version>1.10.L001</commons-codec-version>
<commons-codec-version>1.16.0</commons-codec-version>
<jets3t-version>0.9.4.0006L</jets3t-version>
<maven-plugins-version>3.1.1</maven-plugins-version>
</properties>

View File

@ -2,136 +2,148 @@ package com.baeldung.ec2;
import java.util.Arrays;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest;
import com.amazonaws.services.ec2.model.CreateKeyPairRequest;
import com.amazonaws.services.ec2.model.CreateKeyPairResult;
import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.DescribeKeyPairsRequest;
import com.amazonaws.services.ec2.model.DescribeKeyPairsResult;
import com.amazonaws.services.ec2.model.IpPermission;
import com.amazonaws.services.ec2.model.IpRange;
import com.amazonaws.services.ec2.model.MonitorInstancesRequest;
import com.amazonaws.services.ec2.model.RebootInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.StartInstancesRequest;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
import com.amazonaws.services.ec2.model.UnmonitorInstancesRequest;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.AuthorizeSecurityGroupIngressRequest;
import software.amazon.awssdk.services.ec2.model.CreateKeyPairRequest;
import software.amazon.awssdk.services.ec2.model.CreateKeyPairResponse;
import software.amazon.awssdk.services.ec2.model.CreateSecurityGroupRequest;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse;
import software.amazon.awssdk.services.ec2.model.DescribeKeyPairsRequest;
import software.amazon.awssdk.services.ec2.model.DescribeKeyPairsResponse;
import software.amazon.awssdk.services.ec2.model.IpPermission;
import software.amazon.awssdk.services.ec2.model.IpRange;
import software.amazon.awssdk.services.ec2.model.MonitorInstancesRequest;
import software.amazon.awssdk.services.ec2.model.RebootInstancesRequest;
import software.amazon.awssdk.services.ec2.model.RunInstancesRequest;
import software.amazon.awssdk.services.ec2.model.RunInstancesResponse;
import software.amazon.awssdk.services.ec2.model.StartInstancesRequest;
import software.amazon.awssdk.services.ec2.model.StartInstancesResponse;
import software.amazon.awssdk.services.ec2.model.StopInstancesRequest;
import software.amazon.awssdk.services.ec2.model.UnmonitorInstancesRequest;
public class EC2Application {
private static final AWSCredentials credentials;
static {
// put your accesskey and secretkey here
credentials = new BasicAWSCredentials(
"<AWS accesskey>",
"<AWS secretkey>"
);
}
public static void main(String[] args) {
// Set up the client
AmazonEC2 ec2Client = AmazonEC2ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withRegion(Regions.US_EAST_1)
Ec2Client ec2Client = Ec2Client.builder()
.credentialsProvider(ProfileCredentialsProvider.create("default"))
.region(Region.US_EAST_1)
.build();
// Create a security group
CreateSecurityGroupRequest createSecurityGroupRequest = new CreateSecurityGroupRequest().withGroupName("BaeldungSecurityGroup")
.withDescription("Baeldung Security Group");
CreateSecurityGroupRequest createSecurityGroupRequest = CreateSecurityGroupRequest.builder()
.groupName("BaeldungSecurityGroup")
.description("Baeldung Security Group")
.build();
ec2Client.createSecurityGroup(createSecurityGroupRequest);
// Allow HTTP and SSH traffic
IpRange ipRange1 = new IpRange().withCidrIp("0.0.0.0/0");
IpRange ipRange1 = IpRange.builder()
.cidrIp("0.0.0.0/0")
.build();
IpPermission ipPermission1 = new IpPermission().withIpv4Ranges(Arrays.asList(new IpRange[] { ipRange1 }))
.withIpProtocol("tcp")
.withFromPort(80)
.withToPort(80);
IpPermission ipPermission1 = IpPermission.builder()
.ipRanges(Arrays.asList(ipRange1))
.ipProtocol("tcp")
.fromPort(80)
.toPort(80)
.build();
IpPermission ipPermission2 = new IpPermission().withIpv4Ranges(Arrays.asList(new IpRange[] { ipRange1 }))
.withIpProtocol("tcp")
.withFromPort(22)
.withToPort(22);
IpPermission ipPermission2 = IpPermission.builder()
.ipRanges(Arrays.asList(ipRange1))
.ipProtocol("tcp")
.fromPort(22)
.toPort(22)
.build();
AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = new AuthorizeSecurityGroupIngressRequest()
.withGroupName("BaeldungSecurityGroup")
.withIpPermissions(ipPermission1, ipPermission2);
AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = AuthorizeSecurityGroupIngressRequest
.builder()
.groupName("BaeldungSecurityGroup")
.ipPermissions(ipPermission1, ipPermission2)
.build();
ec2Client.authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest);
// Create KeyPair
CreateKeyPairRequest createKeyPairRequest = new CreateKeyPairRequest()
.withKeyName("baeldung-key-pair");
CreateKeyPairResult createKeyPairResult = ec2Client.createKeyPair(createKeyPairRequest);
String privateKey = createKeyPairResult
.getKeyPair()
.getKeyMaterial(); // make sure you keep it, the private key, Amazon doesn't store the private key
CreateKeyPairRequest createKeyPairRequest = CreateKeyPairRequest.builder()
.keyName("baeldung-key-pair")
.build();
CreateKeyPairResponse createKeyPairResponse = ec2Client.createKeyPair(createKeyPairRequest);
String privateKey = createKeyPairResponse.keyMaterial();
// make sure you keep it, the private key, Amazon doesn't store the private key
// See what key-pairs you've got
DescribeKeyPairsRequest describeKeyPairsRequest = new DescribeKeyPairsRequest();
DescribeKeyPairsResult describeKeyPairsResult = ec2Client.describeKeyPairs(describeKeyPairsRequest);
DescribeKeyPairsRequest describeKeyPairsRequest = DescribeKeyPairsRequest.builder()
.build();
DescribeKeyPairsResponse describeKeyPairsResponse = ec2Client.describeKeyPairs(describeKeyPairsRequest);
// Launch an Amazon Instance
RunInstancesRequest runInstancesRequest = new RunInstancesRequest().withImageId("ami-97785bed") // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html | https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/usingsharedamis-finding.html
.withInstanceType("t2.micro") // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html
.withMinCount(1)
.withMaxCount(1)
.withKeyName("baeldung-key-pair") // optional - if not present, can't connect to instance
.withSecurityGroups("BaeldungSecurityGroup");
RunInstancesRequest runInstancesRequest = RunInstancesRequest.builder()
.imageId("ami-97785bed")
.instanceType("t2.micro") // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html
.minCount(1)
.maxCount(1)
.keyName("baeldung-key-pair") // optional - if not present, can't connect to instance
.securityGroups("BaeldungSecurityGroup")
.build();
String yourInstanceId = ec2Client.runInstances(runInstancesRequest).getReservation().getInstances().get(0).getInstanceId();
RunInstancesResponse runInstancesResponse = ec2Client.runInstances(runInstancesRequest);
String yourInstanceId = runInstancesResponse.instances().get(0).instanceId();
// Start an Instance
StartInstancesRequest startInstancesRequest = new StartInstancesRequest()
.withInstanceIds(yourInstanceId);
StartInstancesRequest startInstancesRequest = StartInstancesRequest.builder()
.instanceIds(yourInstanceId)
.build();
StartInstancesResponse startInstancesResponse = ec2Client.startInstances(startInstancesRequest);
ec2Client.startInstances(startInstancesRequest);
// Monitor Instances
MonitorInstancesRequest monitorInstancesRequest = new MonitorInstancesRequest()
.withInstanceIds(yourInstanceId);
MonitorInstancesRequest monitorInstancesRequest = MonitorInstancesRequest.builder()
.instanceIds(yourInstanceId)
.build();
ec2Client.monitorInstances(monitorInstancesRequest);
UnmonitorInstancesRequest unmonitorInstancesRequest = new UnmonitorInstancesRequest()
.withInstanceIds(yourInstanceId);
UnmonitorInstancesRequest unmonitorInstancesRequest = UnmonitorInstancesRequest.builder()
.instanceIds(yourInstanceId)
.build();
ec2Client.unmonitorInstances(unmonitorInstancesRequest);
// Reboot an Instance
RebootInstancesRequest rebootInstancesRequest = new RebootInstancesRequest()
.withInstanceIds(yourInstanceId);
RebootInstancesRequest rebootInstancesRequest = RebootInstancesRequest.builder()
.instanceIds(yourInstanceId)
.build();
ec2Client.rebootInstances(rebootInstancesRequest);
// Stop an Instance
StopInstancesRequest stopInstancesRequest = new StopInstancesRequest()
.withInstanceIds(yourInstanceId);
StopInstancesRequest stopInstancesRequest = StopInstancesRequest.builder()
.instanceIds(yourInstanceId)
.build();
ec2Client.stopInstances(stopInstancesRequest)
.getStoppingInstances()
.stoppingInstances()
.get(0)
.getPreviousState()
.getName();
.previousState()
.name();
// Describe an Instance
DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest();
DescribeInstancesResult response = ec2Client.describeInstances(describeInstancesRequest);
System.out.println(response.getReservations()
DescribeInstancesRequest describeInstancesRequest = DescribeInstancesRequest.builder().build();
DescribeInstancesResponse response = ec2Client.describeInstances(describeInstancesRequest);
System.out.println(response.reservations()
.get(0)
.getInstances()
.instances()
.get(0)
.getKernelId());
.kernelId());
}
}

View File

@ -1,13 +1,5 @@
package com.baeldung.rds;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.rds.AmazonRDS;
import com.amazonaws.services.rds.AmazonRDSClientBuilder;
import com.amazonaws.services.rds.model.*;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
@ -16,12 +8,22 @@ import java.util.Properties;
import java.util.UUID;
import java.util.logging.Logger;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.rds.RdsClient;
import software.amazon.awssdk.services.rds.model.CreateDbInstanceRequest;
import software.amazon.awssdk.services.rds.model.CreateDbInstanceResponse;
import software.amazon.awssdk.services.rds.model.DBInstance;
import software.amazon.awssdk.services.rds.model.DeleteDbInstanceRequest;
import software.amazon.awssdk.services.rds.model.DeleteDbInstanceResponse;
import software.amazon.awssdk.services.rds.model.DescribeDbInstancesResponse;
import software.amazon.awssdk.services.rds.model.Endpoint;
public class AWSRDSService {
final static Logger logger = Logger.getLogger(AWSRDSService.class.getName());
private AWSCredentialsProvider credentials;
private AmazonRDS amazonRDS;
private RdsClient rdsClient;
private String db_username;
private String db_password;
private String db_database;
@ -34,22 +36,17 @@ public class AWSRDSService {
* **/
public AWSRDSService() throws IOException {
//Init RDS client with credentials and region.
credentials = new
AWSStaticCredentialsProvider(new
BasicAWSCredentials("<ACCESS_KEY>",
"<SECRET_KEY>"));
amazonRDS = AmazonRDSClientBuilder.standard().withCredentials(credentials)
.withRegion(Regions.AP_SOUTHEAST_2).build();
Properties prop = new Properties();
InputStream input = AWSRDSService.class.getClassLoader().getResourceAsStream("db.properties");
prop.load(input);
db_username = prop.getProperty("db_username");
db_password = prop.getProperty("db_password");
db_database = prop.getProperty("db_database");
}
public AWSRDSService(AmazonRDS amazonRDS){
this.amazonRDS = amazonRDS;
rdsClient = RdsClient.builder()
.region(Region.AP_SOUTHEAST_2)
.credentialsProvider(ProfileCredentialsProvider.create("default"))
.build();
}
/**
@ -60,29 +57,29 @@ public class AWSRDSService {
public String launchInstance() {
String identifier = "";
CreateDBInstanceRequest request = new CreateDBInstanceRequest();
// RDS instance name
request.setDBInstanceIdentifier("Sydney");
request.setEngine("postgres");
request.setMultiAZ(false);
request.setMasterUsername(db_username);
request.setMasterUserPassword(db_password);
request.setDBName(db_database);
request.setStorageType("gp2");
request.setAllocatedStorage(10);
CreateDbInstanceRequest instanceRequest = CreateDbInstanceRequest.builder()
.dbInstanceIdentifier("Sydney")
.engine("postgres")
.multiAZ(false)
.masterUsername(db_username)
.masterUserPassword(db_password)
.dbName(db_database)
.storageType("gp2")
.allocatedStorage(10)
.build();
DBInstance instance = amazonRDS.createDBInstance(request);
CreateDbInstanceResponse createDbInstanceResponse = rdsClient.createDBInstance(instanceRequest);
// Information about the new RDS instance
identifier = instance.getDBInstanceIdentifier();
String status = instance.getDBInstanceStatus();
Endpoint endpoint = instance.getEndpoint();
String endpoint_url = "Endpoint URL not available yet.";
identifier = createDbInstanceResponse.dbInstance().dbInstanceIdentifier();
String status = createDbInstanceResponse.dbInstance().dbInstanceStatus();
Endpoint endpoint = createDbInstanceResponse.dbInstance().endpoint();
String endpointUrl = "Endpoint URL not available yet.";
if (endpoint != null) {
endpoint_url = endpoint.toString();
endpointUrl = endpoint.toString();
}
logger.info(identifier + "\t" + status);
logger.info(endpoint_url);
logger.info(endpointUrl);
return identifier;
@ -90,44 +87,44 @@ public class AWSRDSService {
// Describe DB instances
public void listInstances() {
DescribeDBInstancesResult result = amazonRDS.describeDBInstances();
List<DBInstance> instances = result.getDBInstances();
DescribeDbInstancesResponse response = rdsClient.describeDBInstances();
List<DBInstance> instances = response.dbInstances();
for (DBInstance instance : instances) {
// Information about each RDS instance
String identifier = instance.getDBInstanceIdentifier();
String engine = instance.getEngine();
String status = instance.getDBInstanceStatus();
Endpoint endpoint = instance.getEndpoint();
String endpoint_url = "Endpoint URL not available yet.";
String identifier = instance.dbInstanceIdentifier();
String engine = instance.engine();
String status = instance.dbInstanceStatus();
Endpoint endpoint = instance.endpoint();
String endpointUrl = "Endpoint URL not available yet.";
if (endpoint != null) {
endpoint_url = endpoint.toString();
endpointUrl = endpoint.toString();
}
logger.info(identifier + "\t" + engine + "\t" + status);
logger.info("\t" + endpoint_url);
logger.info("\t" + endpointUrl);
}
}
//Delete RDS instance
public void terminateInstance(String identifier) {
DeleteDBInstanceRequest request = new DeleteDBInstanceRequest();
request.setDBInstanceIdentifier(identifier);
request.setSkipFinalSnapshot(true);
DeleteDbInstanceRequest request = DeleteDbInstanceRequest.builder()
.dbInstanceIdentifier(identifier)
.skipFinalSnapshot(true)
.build();
// Delete the RDS instance
DBInstance instance = amazonRDS.deleteDBInstance(request);
DeleteDbInstanceResponse response = rdsClient.deleteDBInstance(request);
// Information about the RDS instance being deleted
String status = instance.getDBInstanceStatus();
Endpoint endpoint = instance.getEndpoint();
String endpoint_url = "Endpoint URL not available yet.";
String status = response.dbInstance().dbInstanceStatus();
Endpoint endpoint = response.dbInstance().endpoint();
String endpointUrl = "Endpoint URL not available yet.";
if (endpoint != null) {
endpoint_url = endpoint.toString();
endpointUrl = endpoint.toString();
}
logger.info(identifier + "\t" + status);
logger.info(endpoint_url);
logger.info(endpointUrl);
}

View File

@ -5,140 +5,190 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.CreateQueueRequest;
import com.amazonaws.services.sqs.model.DeleteMessageRequest;
import com.amazonaws.services.sqs.model.GetQueueAttributesRequest;
import com.amazonaws.services.sqs.model.GetQueueAttributesResult;
import com.amazonaws.services.sqs.model.MessageAttributeValue;
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
import com.amazonaws.services.sqs.model.SendMessageBatchRequest;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import com.amazonaws.services.sqs.model.SetQueueAttributesRequest;
import com.amazonaws.services.sqs.model.SendMessageBatchRequestEntry;
import com.amazonaws.services.sqs.model.Message;
import com.amazonaws.services.sqs.AmazonSQS;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.CreateQueueRequest;
import software.amazon.awssdk.services.sqs.model.DeleteMessageRequest;
import software.amazon.awssdk.services.sqs.model.GetQueueAttributesRequest;
import software.amazon.awssdk.services.sqs.model.GetQueueAttributesResponse;
import software.amazon.awssdk.services.sqs.model.GetQueueUrlRequest;
import software.amazon.awssdk.services.sqs.model.GetQueueUrlResponse;
import software.amazon.awssdk.services.sqs.model.Message;
import software.amazon.awssdk.services.sqs.model.MessageAttributeValue;
import software.amazon.awssdk.services.sqs.model.QueueAttributeName;
import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest;
import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequest;
import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequestEntry;
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;
import software.amazon.awssdk.services.sqs.model.SetQueueAttributesRequest;
public class SQSApplication {
private static final AWSCredentials credentials;
static {
// put your accesskey and secretkey here
credentials = new BasicAWSCredentials(
"<AWS accesskey>",
"<AWS secretkey>"
);
}
private static final String STANDARD_QUEUE_NAME = "baeldung-queue";
private static final String FIFO_QUEUE_NAME = "baeldung-queue.fifo";
private static final String DEAD_LETTER_QUEUE_NAME = "baeldung-dead-letter-queue";
public static void main(String[] args) {
// Set up the client
AmazonSQS sqs = AmazonSQSClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withRegion(Regions.US_EAST_1)
SqsClient sqsClient = SqsClient.builder()
.region(Region.US_EAST_1)
.credentialsProvider(ProfileCredentialsProvider.create())
.build();
// Create a standard queue
CreateQueueRequest createStandardQueueRequest = CreateQueueRequest.builder()
.queueName(STANDARD_QUEUE_NAME)
.build();
CreateQueueRequest createStandardQueueRequest = new CreateQueueRequest("baeldung-queue");
String standardQueueUrl = sqs.createQueue(createStandardQueueRequest)
.getQueueUrl();
sqsClient.createQueue(createStandardQueueRequest);
System.out.println("\nGet queue url");
GetQueueUrlResponse getQueueUrlResponse = sqsClient.getQueueUrl(GetQueueUrlRequest.builder()
.queueName(STANDARD_QUEUE_NAME)
.build());
String standardQueueUrl = getQueueUrlResponse.queueUrl();
System.out.println(standardQueueUrl);
// Create a fifo queue
Map<QueueAttributeName, String> queueAttributes = new HashMap<>();
queueAttributes.put(QueueAttributeName.FIFO_QUEUE, "true");
queueAttributes.put(QueueAttributeName.CONTENT_BASED_DEDUPLICATION, "true");
Map<String, String> queueAttributes = new HashMap<String, String>();
queueAttributes.put("FifoQueue", "true");
queueAttributes.put("ContentBasedDeduplication", "true");
CreateQueueRequest createFifoQueueRequest = CreateQueueRequest.builder()
.queueName(FIFO_QUEUE_NAME)
.attributes(queueAttributes)
.build();
CreateQueueRequest createFifoQueueRequest = new CreateQueueRequest("baeldung-queue.fifo").withAttributes(queueAttributes);
String fifoQueueUrl = sqs.createQueue(createFifoQueueRequest)
.getQueueUrl();
sqsClient.createQueue(createFifoQueueRequest);
GetQueueUrlResponse getFifoQueueUrlResponse = sqsClient.getQueueUrl(GetQueueUrlRequest.builder()
.queueName(FIFO_QUEUE_NAME)
.build());
String fifoQueueUrl = getFifoQueueUrlResponse.queueUrl();
System.out.println(fifoQueueUrl);
// Set up a dead letter queue
CreateQueueRequest createDeadLetterQueueRequest = CreateQueueRequest.builder()
.queueName(DEAD_LETTER_QUEUE_NAME)
.build();
String deadLetterQueueUrl = sqs.createQueue("baeldung-dead-letter-queue")
.getQueueUrl();
String deadLetterQueueUrl = sqsClient.createQueue(createDeadLetterQueueRequest)
.queueUrl();
GetQueueAttributesResult deadLetterQueueAttributes = sqs.getQueueAttributes(new GetQueueAttributesRequest(deadLetterQueueUrl).withAttributeNames("QueueArn"));
GetQueueAttributesRequest getQueueAttributesRequest = GetQueueAttributesRequest.builder()
.queueUrl(deadLetterQueueUrl)
.attributeNames(QueueAttributeName.QUEUE_ARN)
.build();
String deadLetterQueueARN = deadLetterQueueAttributes.getAttributes()
GetQueueAttributesResponse deadLetterQueueAttributes = sqsClient.getQueueAttributes(getQueueAttributesRequest);
String deadLetterQueueARN = deadLetterQueueAttributes.attributes()
.get("QueueArn");
SetQueueAttributesRequest queueAttributesRequest = new SetQueueAttributesRequest().withQueueUrl(standardQueueUrl)
.addAttributesEntry("RedrivePolicy", "{\"maxReceiveCount\":\"2\", " + "\"deadLetterTargetArn\":\"" + deadLetterQueueARN + "\"}");
Map<QueueAttributeName, String> attributes = new HashMap<>();
attributes.put(QueueAttributeName.REDRIVE_POLICY, "{\"maxReceiveCount\":\"5\", \"deadLetterTargetArn\":\"" + deadLetterQueueARN + "\"}");
sqs.setQueueAttributes(queueAttributesRequest);
SetQueueAttributesRequest queueAttributesRequest = SetQueueAttributesRequest.builder()
.queueUrl(standardQueueUrl)
.attributes(attributes)
.build();
sqsClient.setQueueAttributes(queueAttributesRequest);
// Send a message to a standard queue
Map<String, MessageAttributeValue> messageAttributes = new HashMap<>();
MessageAttributeValue messageAttributeValue = MessageAttributeValue.builder()
.stringValue("This is an attribute")
.dataType("String")
.build();
messageAttributes.put("AttributeOne", new MessageAttributeValue().withStringValue("This is an attribute")
.withDataType("String"));
messageAttributes.put("AttributeOne", messageAttributeValue);
SendMessageRequest sendMessageStandardQueue = new SendMessageRequest().withQueueUrl(standardQueueUrl)
.withMessageBody("A simple message.")
.withDelaySeconds(30) // Message will arrive in the queue after 30 seconds. We can use this only in standard queues
.withMessageAttributes(messageAttributes);
SendMessageRequest sendMessageStandardQueue = SendMessageRequest.builder()
.queueUrl(standardQueueUrl)
.messageBody("A simple message.")
.delaySeconds(30) // Message will arrive in the queue after 30 seconds. We can use this only in standard queues
.messageAttributes(messageAttributes)
.build();
sqs.sendMessage(sendMessageStandardQueue);
sqsClient.sendMessage(sendMessageStandardQueue);
// Send a message to a fifo queue
SendMessageRequest sendMessageFifoQueue = new SendMessageRequest().withQueueUrl(fifoQueueUrl)
.withMessageBody("FIFO Queue")
.withMessageGroupId("baeldung-group-1")
.withMessageAttributes(messageAttributes);
SendMessageRequest sendMessageFifoQueue = SendMessageRequest.builder()
.queueUrl(fifoQueueUrl)
.messageBody("FIFO Queue")
.messageGroupId("baeldung-group-1")
.messageAttributes(messageAttributes)
.build();
sqs.sendMessage(sendMessageFifoQueue);
sqsClient.sendMessage(sendMessageFifoQueue);
// Send multiple messages
List<SendMessageBatchRequestEntry> messageEntries = new ArrayList<>();
messageEntries.add(new SendMessageBatchRequestEntry().withId("id-1")
.withMessageBody("batch-1")
.withMessageGroupId("baeldung-group-1"));
messageEntries.add(new SendMessageBatchRequestEntry().withId("id-2")
.withMessageBody("batch-2")
.withMessageGroupId("baeldung-group-1"));
SendMessageBatchRequestEntry messageBatchRequestEntry1 = SendMessageBatchRequestEntry.builder()
.id("id-1")
.messageBody("batch-1")
.messageGroupId("baeldung-group-1")
.build();
SendMessageBatchRequest sendMessageBatchRequest = new SendMessageBatchRequest(fifoQueueUrl, messageEntries);
sqs.sendMessageBatch(sendMessageBatchRequest);
SendMessageBatchRequestEntry messageBatchRequestEntry2 = SendMessageBatchRequestEntry.builder()
.id("id-2")
.messageBody("batch-2")
.messageGroupId("baeldung-group-1")
.build();
messageEntries.add(messageBatchRequestEntry1);
messageEntries.add(messageBatchRequestEntry2);
SendMessageBatchRequest sendMessageBatchRequest = SendMessageBatchRequest.builder()
.queueUrl(fifoQueueUrl)
.entries(messageEntries)
.build();
sqsClient.sendMessageBatch(sendMessageBatchRequest);
// Read a message from a queue
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(fifoQueueUrl).withWaitTimeSeconds(10) // Long polling;
.withMaxNumberOfMessages(1); // Max is 10
ReceiveMessageRequest receiveMessageRequest = ReceiveMessageRequest.builder()
.waitTimeSeconds(10)
.maxNumberOfMessages(10)
.build();
List<Message> sqsMessages = sqs.receiveMessage(receiveMessageRequest)
.getMessages();
List<Message> sqsMessages = sqsClient.receiveMessage(receiveMessageRequest)
.messages();
sqsMessages.get(0)
.getAttributes();
.attributes();
sqsMessages.get(0)
.getBody();
.body();
// Delete a message from a queue
DeleteMessageRequest deleteMessageRequest = DeleteMessageRequest.builder()
.queueUrl(fifoQueueUrl)
.receiptHandle(sqsMessages.get(0)
.receiptHandle())
.build();
sqs.deleteMessage(new DeleteMessageRequest().withQueueUrl(fifoQueueUrl)
.withReceiptHandle(sqsMessages.get(0)
.getReceiptHandle()));
sqsClient.deleteMessage(deleteMessageRequest);
// Monitoring
GetQueueAttributesRequest getQueueAttributesRequest = new GetQueueAttributesRequest(standardQueueUrl).withAttributeNames("All");
GetQueueAttributesResult getQueueAttributesResult = sqs.getQueueAttributes(getQueueAttributesRequest);
System.out.println(String.format("The number of messages on the queue: %s", getQueueAttributesResult.getAttributes()
GetQueueAttributesRequest getQueueAttributesRequestForMonitoring = GetQueueAttributesRequest.builder()
.queueUrl(standardQueueUrl)
.build();
GetQueueAttributesResponse attributesResponse = sqsClient.getQueueAttributes(getQueueAttributesRequestForMonitoring);
System.out.println(String.format("The number of messages on the queue: %s", attributesResponse.attributes()
.get("ApproximateNumberOfMessages")));
System.out.println(String.format("The number of messages in flight: %s", getQueueAttributesResult.getAttributes()
System.out.println(String.format("The number of messages in flight: %s", attributesResponse.attributes()
.get("ApproximateNumberOfMessagesNotVisible")));
}

View File

@ -63,6 +63,7 @@
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<version>${reactor.version}</version>
<scope>test</scope>
</dependency>
<dependency>
@ -94,6 +95,7 @@
<spring.version>2.2.1.RELEASE</spring.version>
<awssdk.version>2.17.283</awssdk.version>
<lombok.version>1.18.20</lombok.version>
<reactor.version>3.6.0</reactor.version>
</properties>
</project>

View File

@ -1,43 +0,0 @@
<?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>aws-s3-update-object</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>aws-s3-update-object</name>
<description>Project demonstrating overwriting of S3 objects</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>${aws-java-sdk-version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<properties>
<aws-java-sdk-version>1.12.523</aws-java-sdk-version>
</properties>
</project>

View File

@ -1,13 +0,0 @@
package com.baeldung.awss3updateobject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AwsS3UpdateObjectApplication {
public static void main(String[] args) {
SpringApplication.run(AwsS3UpdateObjectApplication.class, args);
}
}

View File

@ -1,24 +0,0 @@
package com.baeldung.awss3updateobject.controller;
import com.baeldung.awss3updateobject.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("api/v1/file")
public class FileController {
@Autowired
FileService fileService;
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile multipartFile) throws Exception {
return this.fileService.uploadFile(multipartFile);
}
@PostMapping("/update")
public String updateFile(@RequestParam("file") MultipartFile multipartFile, @RequestParam("filePath") String exitingFilePath) throws Exception {
return this.fileService.updateFile(multipartFile, exitingFilePath);
}
}

View File

@ -1,80 +0,0 @@
package com.baeldung.awss3updateobject.service;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@Service
public class FileService {
private static final Logger logger = LoggerFactory.getLogger(FileService.class);
public AmazonS3 amazonS3;
@Value("${aws.s3bucket}")
public String awsS3Bucket;
@PostConstruct
private void init(){
AWSCredentials credentials = new BasicAWSCredentials(
"AWS AccessKey",
"AWS secretKey"
);
this.amazonS3 = AmazonS3ClientBuilder.standard()
.withRegion(Regions.fromName("us-east-1"))
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
}
public String uploadFile(MultipartFile multipartFile) throws Exception {
String key = "/documents/" + multipartFile.getOriginalFilename();
return this.uploadDocument(this.awsS3Bucket, key, multipartFile);
}
public String updateFile(MultipartFile multipartFile, String key) throws Exception {
return this.uploadDocument(this.awsS3Bucket, key, multipartFile);
}
private String uploadDocument(String s3bucket, String key, MultipartFile multipartFile) throws Exception {
try {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(multipartFile.getContentType());
Map<String, String> attributes = new HashMap<>();
attributes.put("document-content-size", String.valueOf(multipartFile.getSize()));
metadata.setUserMetadata(attributes);
InputStream documentStream = multipartFile.getInputStream();
PutObjectResult putObjectResult = this.amazonS3.putObject(new PutObjectRequest(s3bucket, key, documentStream, metadata));
S3Object s3Object = this.amazonS3.getObject(s3bucket, key);
logger.info("Last Modified: " + s3Object.getObjectMetadata().getLastModified());
return key;
} catch (AmazonS3Exception ex) {
if (ex.getErrorCode().equalsIgnoreCase("NoSuchBucket")) {
String msg = String.format("No bucket found with name %s", s3bucket);
throw new Exception(msg);
} else if (ex.getErrorCode().equalsIgnoreCase("AccessDenied")) {
String msg = String.format("Access denied to S3 bucket %s", s3bucket);
throw new Exception(msg);
}
throw ex;
} catch (IOException ex) {
String msg = String.format("Error saving file %s to AWS S3 bucket %s", key, s3bucket);
throw new Exception(msg);
}
}
}

View File

@ -1 +0,0 @@
aws.s3bucket=baeldung-documents;

View File

@ -1,62 +0,0 @@
package com.baeldung.awss3updateobject.controller;
import com.baeldung.awss3updateobject.service.FileService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.multipart.MultipartFile;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
public class FileControllerUnitTest {
private MockMvc mockMvc;
@Mock
private FileService fileService;
@InjectMocks
private FileController fileController;
@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(fileController).build();
}
@Test
public void givenValidMultipartFile_whenUploadedViaEndpoint_thenCorrectPathIsReturned() throws Exception {
MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain", "sample file content".getBytes());
String expectedResult = "File Uploaded Successfully";
when(fileService.uploadFile(multipartFile)).thenReturn(expectedResult);
mockMvc.perform(multipart("/api/v1/file/upload").file(multipartFile))
.andExpect(status().isOk())
.andExpect(content().string(expectedResult));
}
@Test
public void givenValidMultipartFileAndExistingPath_whenUpdatedViaEndpoint_thenSamePathIsReturned() throws Exception {
MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain", "updated file content".getBytes());
String filePath = "some/path/to/file";
String expectedResult = "File Updated Successfully";
when(fileService.updateFile(multipartFile, filePath)).thenReturn(expectedResult);
mockMvc.perform(multipart("/api/v1/file/update")
.file(multipartFile)
.param("filePath", filePath))
.andExpect(status().isOk())
.andExpect(content().string(expectedResult));
}
}

View File

@ -1,99 +0,0 @@
package com.baeldung.awss3updateobject.service;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
public class FileServiceUnitTest {
@Mock
private AmazonS3 amazonS3;
@Mock
private MultipartFile multipartFile;
@InjectMocks
private FileService fileService;
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
fileService = new FileService();
fileService.awsS3Bucket = "test-bucket";
fileService.amazonS3 = amazonS3;
}
@Test
public void givenValidFile_whenUploaded_thenKeyMatchesDocumentPath() throws Exception {
when(multipartFile.getName()).thenReturn("testFile");
when(multipartFile.getOriginalFilename()).thenReturn("testFile");
when(multipartFile.getContentType()).thenReturn("application/pdf");
when(multipartFile.getSize()).thenReturn(1024L);
when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class));
S3Object s3Object = new S3Object();
when(amazonS3.putObject(any())).thenReturn(null);
when(amazonS3.getObject(anyString(), anyString())).thenReturn(s3Object);
String key = fileService.uploadFile(multipartFile);
assertEquals("/documents/testFile", key);
}
@Test
public void givenValidFile_whenUploadFailsDueToNoBucket_thenExceptionIsThrown() throws Exception {
when(multipartFile.getName()).thenReturn("testFile");
when(multipartFile.getOriginalFilename()).thenReturn("testFile");
when(multipartFile.getContentType()).thenReturn("application/pdf");
when(multipartFile.getSize()).thenReturn(1024L);
when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class));
AmazonS3Exception exception = new AmazonS3Exception("Test exception");
exception.setErrorCode("NoSuchBucket");
when(amazonS3.putObject(any(PutObjectRequest.class))).thenThrow(exception);
assertThrows(Exception.class, () -> fileService.uploadFile(multipartFile));
}
@Test
public void givenExistingFile_whenUpdated_thenSameKeyIsReturned() throws Exception {
when(multipartFile.getName()).thenReturn("testFile");
when(multipartFile.getContentType()).thenReturn("application/pdf");
when(multipartFile.getSize()).thenReturn(1024L);
when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class));
S3Object s3Object = new S3Object();
when(amazonS3.putObject(any(PutObjectRequest.class))).thenReturn(null);
when(amazonS3.getObject(anyString(), anyString())).thenReturn(s3Object);
String key = "/documents/existingFile";
String resultKey = fileService.updateFile(multipartFile, key);
assertEquals(key, resultKey);
}
@Test
public void givenFileWithIOException_whenUpdated_thenExceptionIsThrown() throws Exception {
when(multipartFile.getName()).thenReturn("testFile");
when(multipartFile.getContentType()).thenReturn("application/pdf");
when(multipartFile.getSize()).thenReturn(1024L);
when(multipartFile.getInputStream()).thenThrow(new IOException("Test IO Exception"));
assertThrows(Exception.class, () -> fileService.updateFile(multipartFile, "/documents/existingFile"));
}
}

View File

@ -11,3 +11,4 @@ This module contains articles about Simple Storage Service (S3) on AWS
- [Listing All AWS S3 Objects in a Bucket Using Java](https://www.baeldung.com/java-aws-s3-list-bucket-objects)
- [Update an Existing Amazon S3 Object Using Java](https://www.baeldung.com/java-update-amazon-s3-object)
- [How To Rename Files and Folders in Amazon S3](https://www.baeldung.com/java-amazon-s3-rename-files-folders)
- [Update an Existing Amazon S3 Object Using Java](https://www.baeldung.com/java-update-amazon-s3-object)

View File

@ -39,27 +39,6 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<aws.java.sdk.version>2.20.52</aws.java.sdk.version>
<commons-codec-version>1.10.L001</commons-codec-version>

View File

@ -45,6 +45,13 @@ public class S3Application {
new File("/Users/user/Document/hello.txt")
);
s3Service.updateObject(
AWS_BUCKET,
"Document/hello2.txt",
new File("/Users/user/Document/hello2.txt")
);
//listing objects
s3Service.listObjects(AWS_BUCKET);

View File

@ -24,6 +24,7 @@ import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
import software.amazon.awssdk.services.s3.model.ListBucketsResponse;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
@ -99,9 +100,15 @@ class S3Service {
.key(key)
.build();
return s3Client.putObject(request, Path.of(file.toURI()));
}
//updating object
public PutObjectResponse updateObject(String bucketName, String key, java.io.File file) {
return this.putObject(bucketName, key, file);
}
//listing objects
public void listObjects(String bucketName) {
ListObjectsV2Request listObjectsV2Request = ListObjectsV2Request.builder()
@ -110,6 +117,7 @@ class S3Service {
ListObjectsV2Response listObjectsV2Response = s3Client.listObjectsV2(listObjectsV2Request);
for(S3Object os : listObjectsV2Response.contents()) {
System.out.println(os.key());
}
}

View File

@ -11,6 +11,8 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.File;
import java.nio.file.Path;
import java.util.Collections;
import software.amazon.awssdk.services.s3.S3Client;
@ -23,6 +25,7 @@ import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.ListBucketsResponse;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
class S3ServiceIntegrationTest {
@ -38,6 +41,8 @@ class S3ServiceIntegrationTest {
private final String AWS_BUCKET = "baeldung-tutorial-s3";
private File file = new File("/Users/user/Document/hello2.txt");
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
@ -75,6 +80,17 @@ class S3ServiceIntegrationTest {
verify(s3Client).createBucket(bucketRequest);
}
@Test
void whenVerifyingUploadOfS3Object_thenCorrect() {
PutObjectRequest request = PutObjectRequest.builder()
.bucket(BUCKET_NAME)
.key(KEY_NAME)
.build();
s3Service.putObject(BUCKET_NAME, KEY_NAME, file);
verify(s3Client).putObject(request, Path.of(file.toURI()) );
}
@Test
void whenVerifyingListBuckets_thenCorrect() {
when(s3Client.listBuckets()).thenReturn(ListBucketsResponse.builder().buckets(Collections.emptyList()).build());

View File

@ -5,7 +5,6 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>aws-modules</artifactId>
<name>aws-modules</name>
<packaging>pom</packaging>
<parent>
<groupId>com.baeldung</groupId>
@ -13,17 +12,28 @@
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.12.523</version>
<scope>compile</scope>
</dependency>
</dependencies>
<packaging>pom</packaging>
<modules>
<module>aws-app-sync</module>
<module>aws-dynamodb</module>
<module>aws-lambda-modules</module>
<module>aws-miscellaneous</module>
<module>aws-reactive</module>
<module>aws-s3</module>
<module>aws-s3-update-object</module>
</modules>
<properties>
<aws-java-sdk.version>1.12.331</aws-java-sdk.version>
<aws-java-sdk-v2.version>2.20.147</aws-java-sdk-v2.version>
<maven-shade-plugin.version>3.0.0</maven-shade-plugin.version>
</properties>

View File

@ -167,7 +167,6 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<commons-lang3.version>3.9</commons-lang3.version>
<java.version>1.8</java.version>
<logback.version>1.2.3</logback.version>
</properties>
</project>

View File

@ -13,6 +13,13 @@
<version>1.0.0-SNAPSHOT</version>
</parent>
<pluginRepositories>
<pluginRepository>
<id>groovy-plugins-release</id>
<url>https://groovy.jfrog.io/artifactory/plugins-release-local</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
@ -156,8 +163,8 @@
<groovy-wslite.version>1.1.3</groovy-wslite.version>
<assembly.plugin.version>3.4.2</assembly.plugin.version>
<compiler.plugin.version>3.8.1</compiler.plugin.version>
<groovy.compiler.version>3.7.0</groovy.compiler.version>
<groovy-eclipse-batch.version>3.0.8-01</groovy-eclipse-batch.version>
<groovy.compiler.version>3.9.0</groovy.compiler.version>
<groovy-eclipse-batch.version>3.0.9-03</groovy-eclipse-batch.version>
</properties>
</project>

View File

@ -5,7 +5,6 @@ This module contains articles about Java 11 core features
### Relevant articles
- [Guide To Java 8 Optional](https://www.baeldung.com/java-optional)
- [Guide to Java Reflection](http://www.baeldung.com/java-reflection)
- [Guide to Java 8s Collectors](https://www.baeldung.com/java-8-collectors)
- [New Features in Java 11](https://www.baeldung.com/java-11-new-features)
- [Getting the Java Version at Runtime](https://www.baeldung.com/get-java-version-runtime)
- [Invoking a SOAP Web Service in Java](https://www.baeldung.com/java-soap-web-service)

View File

@ -1,237 +0,0 @@
package com.baeldung.collectors;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.junit.Test;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import static com.google.common.collect.Sets.newHashSet;
import static java.util.stream.Collectors.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class Java8CollectorsUnitTest {
private final List<String> givenList = Arrays.asList("a", "bb", "ccc", "dd");
private final List<String> listWithDuplicates = Arrays.asList("a", "bb", "c", "d", "bb");
@Test
public void whenCollectingToList_shouldCollectToList() throws Exception {
final List<String> result = givenList.stream().collect(toList());
assertThat(result).containsAll(givenList);
}
@Test
public void whenCollectingToUnmodifiableList_shouldCollectToUnmodifiableList() {
final List<String> result = givenList.stream().collect(toUnmodifiableList());
assertThatThrownBy(() -> result.add("foo"))
.isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void whenCollectingToSet_shouldCollectToSet() throws Exception {
final Set<String> result = givenList.stream().collect(toSet());
assertThat(result).containsAll(givenList);
}
@Test
public void whenCollectingToUnmodifiableSet_shouldCollectToUnmodifiableSet() {
final Set<String> result = givenList.stream().collect(toUnmodifiableSet());
assertThatThrownBy(() -> result.add("foo"))
.isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void givenContainsDuplicateElements_whenCollectingToSet_shouldAddDuplicateElementsOnlyOnce() throws Exception {
final Set<String> result = listWithDuplicates.stream().collect(toSet());
assertThat(result).hasSize(4);
}
@Test
public void whenCollectingToCollection_shouldCollectToCollection() throws Exception {
final List<String> result = givenList.stream().collect(toCollection(LinkedList::new));
assertThat(result).containsAll(givenList).isInstanceOf(LinkedList.class);
}
@Test
public void whenCollectingToImmutableCollection_shouldThrowException() throws Exception {
assertThatThrownBy(() -> {
givenList.stream().collect(toCollection(ImmutableList::of));
}).isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void whenCollectingToMap_shouldCollectToMap() throws Exception {
final Map<String, Integer> result = givenList.stream().collect(toMap(Function.identity(), String::length));
assertThat(result).containsEntry("a", 1).containsEntry("bb", 2).containsEntry("ccc", 3).containsEntry("dd", 2);
}
@Test
public void whenCollectingToUnmodifiableMap_shouldCollectToUnmodifiableMap() {
final Map<String, Integer> result = givenList.stream()
.collect(toUnmodifiableMap(Function.identity(), String::length));
assertThatThrownBy(() -> result.put("foo", 3))
.isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void whenCollectingToMapwWithDuplicates_shouldCollectToMapMergingTheIdenticalItems() throws Exception {
final Map<String, Integer> result = listWithDuplicates.stream().collect(
toMap(
Function.identity(),
String::length,
(item, identicalItem) -> item
)
);
assertThat(result).containsEntry("a", 1).containsEntry("bb", 2).containsEntry("c", 1).containsEntry("d", 1);
}
@Test
public void givenContainsDuplicateElements_whenCollectingToMap_shouldThrowException() throws Exception {
assertThatThrownBy(() -> {
listWithDuplicates.stream().collect(toMap(Function.identity(), String::length));
}).isInstanceOf(IllegalStateException.class);
}
@Test
public void whenCollectingAndThen_shouldCollect() throws Exception {
final List<String> result = givenList.stream().collect(collectingAndThen(toList(), ImmutableList::copyOf));
assertThat(result).containsAll(givenList).isInstanceOf(ImmutableList.class);
}
@Test
public void whenJoining_shouldJoin() throws Exception {
final String result = givenList.stream().collect(joining());
assertThat(result).isEqualTo("abbcccdd");
}
@Test
public void whenJoiningWithSeparator_shouldJoinWithSeparator() throws Exception {
final String result = givenList.stream().collect(joining(" "));
assertThat(result).isEqualTo("a bb ccc dd");
}
@Test
public void whenJoiningWithSeparatorAndPrefixAndPostfix_shouldJoinWithSeparatorPrePost() throws Exception {
final String result = givenList.stream().collect(joining(" ", "PRE-", "-POST"));
assertThat(result).isEqualTo("PRE-a bb ccc dd-POST");
}
@Test
public void whenPartitioningBy_shouldPartition() throws Exception {
final Map<Boolean, List<String>> result = givenList.stream().collect(partitioningBy(s -> s.length() > 2));
assertThat(result).containsKeys(true, false).satisfies(booleanListMap -> {
assertThat(booleanListMap.get(true)).contains("ccc");
assertThat(booleanListMap.get(false)).contains("a", "bb", "dd");
});
}
@Test
public void whenCounting_shouldCount() throws Exception {
final Long result = givenList.stream().collect(counting());
assertThat(result).isEqualTo(4);
}
@Test
public void whenSummarizing_shouldSummarize() throws Exception {
final DoubleSummaryStatistics result = givenList.stream().collect(summarizingDouble(String::length));
assertThat(result.getAverage()).isEqualTo(2);
assertThat(result.getCount()).isEqualTo(4);
assertThat(result.getMax()).isEqualTo(3);
assertThat(result.getMin()).isEqualTo(1);
assertThat(result.getSum()).isEqualTo(8);
}
@Test
public void whenAveraging_shouldAverage() throws Exception {
final Double result = givenList.stream().collect(averagingDouble(String::length));
assertThat(result).isEqualTo(2);
}
@Test
public void whenSumming_shouldSum() throws Exception {
final Double result = givenList.stream().filter(i -> true).collect(summingDouble(String::length));
assertThat(result).isEqualTo(8);
}
@Test
public void whenMaxingBy_shouldMaxBy() throws Exception {
final Optional<String> result = givenList.stream().collect(maxBy(Comparator.naturalOrder()));
assertThat(result).isPresent().hasValue("dd");
}
@Test
public void whenGroupingBy_shouldGroupBy() throws Exception {
final Map<Integer, Set<String>> result = givenList.stream().collect(groupingBy(String::length, toSet()));
assertThat(result).containsEntry(1, newHashSet("a")).containsEntry(2, newHashSet("bb", "dd")).containsEntry(3, newHashSet("ccc"));
}
@Test
public void whenCreatingCustomCollector_shouldCollect() throws Exception {
final ImmutableSet<String> result = givenList.stream().collect(toImmutableSet());
assertThat(result).isInstanceOf(ImmutableSet.class).contains("a", "bb", "ccc", "dd");
}
private static <T> ImmutableSetCollector<T> toImmutableSet() {
return new ImmutableSetCollector<>();
}
private static class ImmutableSetCollector<T> implements Collector<T, ImmutableSet.Builder<T>, ImmutableSet<T>> {
@Override
public Supplier<ImmutableSet.Builder<T>> supplier() {
return ImmutableSet::builder;
}
@Override
public BiConsumer<ImmutableSet.Builder<T>, T> accumulator() {
return ImmutableSet.Builder::add;
}
@Override
public BinaryOperator<ImmutableSet.Builder<T>> combiner() {
return (left, right) -> left.addAll(right.build());
}
@Override
public Function<ImmutableSet.Builder<T>, ImmutableSet<T>> finisher() {
return ImmutableSet.Builder::build;
}
@Override
public Set<Characteristics> characteristics() {
return Sets.immutableEnumSet(Characteristics.UNORDERED);
}
}
}

View File

@ -45,7 +45,7 @@
<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>
<jackson.version>2.16.0</jackson.version>
<gson.version>2.10</gson.version>
</properties>

View File

@ -8,9 +8,9 @@
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung.core-java-modules</groupId>
<artifactId>core-java-modules</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
@ -21,30 +21,4 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${maven.compiler.source.version}</source>
<target>${maven.compiler.target.version}</target>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.source.version>12</maven.compiler.source.version>
<maven.compiler.target.version>12</maven.compiler.target.version>
</properties>
</project>

View File

@ -19,19 +19,6 @@ public class SwitchUnitTest {
Assert.assertEquals(value, 2);
}
@Test
public void switchLocalVariable(){
var month = Month.AUG;
int i = switch (month){
case JAN,JUN, JUL -> 3;
case FEB,SEP, OCT, NOV, DEC -> 1;
case MAR,MAY, APR, AUG -> {
int j = month.toString().length() * 4;
break j;
}
};
Assert.assertEquals(12, i);
}
enum Month {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC}
}

View File

@ -8,39 +8,9 @@
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung.core-java-modules</groupId>
<artifactId>core-java-modules</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${maven.compiler.source.version}</source>
<target>${maven.compiler.target.version}</target>
<release>13</release>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.plugin.version}</version>
<configuration>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.source.version>13</maven.compiler.source.version>
<maven.compiler.target.version>13</maven.compiler.target.version>
<surefire.plugin.version>3.0.0-M3</surefire.plugin.version>
</properties>
</project>

View File

@ -7,7 +7,6 @@ import org.junit.Test;
public class SwitchExpressionsWithYieldUnitTest {
@Test
@SuppressWarnings("preview")
public void whenSwitchingOnOperationSquareMe_thenWillReturnSquare() {
var me = 4;
var operation = "squareMe";

View File

@ -8,7 +8,6 @@ public class TextBlocksUnitTest {
private static final String JSON_STRING = "{\r\n" + "\"name\" : \"Baeldung\",\r\n" + "\"website\" : \"https://www.%s.com/\"\r\n" + "}";
@SuppressWarnings("preview")
private static final String TEXT_BLOCK_JSON = """
{
"name" : "Baeldung",
@ -25,7 +24,6 @@ public class TextBlocksUnitTest {
}
@SuppressWarnings("removal")
@Test
public void whenTextBlocks_thenFormattedWorksAsFormat() {
assertThat(TEXT_BLOCK_JSON.formatted("baeldung")

View File

@ -13,7 +13,6 @@ import org.junit.Test;
public class SwitchExpressionsUnitTest {
@Test
@SuppressWarnings ("preview")
public void whenSwitchingOverMonthJune_thenWillReturn3() {
var month = JUNE;
@ -29,7 +28,6 @@ public class SwitchExpressionsUnitTest {
}
@Test
@SuppressWarnings ("preview")
public void whenSwitchingOverMonthAugust_thenWillReturn24() {
var month = AUGUST;
@ -47,7 +45,6 @@ public class SwitchExpressionsUnitTest {
}
@Test
@SuppressWarnings ("preview")
public void whenSwitchingOverMonthJanuary_thenWillReturn3() {
Function<Month, Integer> func = (month) -> {
@ -61,7 +58,6 @@ public class SwitchExpressionsUnitTest {
}
@Test
@SuppressWarnings ("preview")
public void whenSwitchingOverMonthAugust_thenWillReturn2() {
var month = AUGUST;

View File

@ -8,10 +8,9 @@
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
<groupId>com.baeldung.core-java-modules</groupId>
<artifactId>core-java-modules</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
@ -27,33 +26,4 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>${maven.compiler.release}</release>
<compilerArgs>--enable-preview</compilerArgs>
<source>14</source>
<target>14</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.plugin.version}</version>
<configuration>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.release>15</maven.compiler.release>
<surefire.plugin.version>3.0.0-M3</surefire.plugin.version>
</properties>
</project>

View File

@ -4,5 +4,4 @@
- [Guide to mapMulti in Stream API](https://www.baeldung.com/java-mapmulti)
- [Collecting Stream Elements into a List in Java](https://www.baeldung.com/java-stream-to-list-collecting)
- [New Features in Java 16](https://www.baeldung.com/java-16-new-features)
- [Guide to Java 8 groupingBy Collector](https://www.baeldung.com/java-groupingby-collector)
- [Value-Based Classes in Java](https://www.baeldung.com/java-value-based-classes)

View File

@ -30,6 +30,11 @@ public final class Point {
return new Point(x, y, z);
}
@Override
public String toString() {
return "Point{" + "x=" + x + ", y=" + y + ", z=" + z + '}';
}
@Override
public boolean equals(Object other) {
if (other == null || getClass() != other.getClass())

View File

@ -1,14 +1,17 @@
package com.baeldung.value_based_class;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
public class ValueBasedClassUnitTest {
@Test
public void givenAutoboxedAndPrimitive_whenCompared_thenReturnEquals() {
int primitive_a = 125;
Integer obj_a = 125; // this is autoboxed
Assert.assertSame(primitive_a, obj_a);
List<Integer> list = new ArrayList<>();
list.add(1); // this is autoboxed
Assert.assertEquals(list.get(0), Integer.valueOf(1));
}
@Test

View File

@ -8,3 +8,5 @@
- [Sealed Classes and Interfaces in Java](https://www.baeldung.com/java-sealed-classes-interfaces)
- [Migrate From Java 8 to Java 17](https://www.baeldung.com/java-migrate-8-to-17)
- [Format Multiple or Conditions in an If Statement in Java](https://www.baeldung.com/java-multiple-or-conditions-if-statement)
- [Get All Record Fields and Its Values via Reflection](https://www.baeldung.com/java-reflection-record-fields-values)
- [Context-Specific Deserialization Filters in Java 17](https://www.baeldung.com/java-context-specific-deserialization-filters)

View File

@ -0,0 +1,47 @@
package com.baeldung.deserializationfilters;
import java.io.ObjectInputFilter;
import java.util.function.BinaryOperator;
import com.baeldung.deserializationfilters.service.DeserializationService;
import com.baeldung.deserializationfilters.service.LimitedArrayService;
import com.baeldung.deserializationfilters.service.LowDepthService;
import com.baeldung.deserializationfilters.service.SmallObjectService;
import com.baeldung.deserializationfilters.utils.FilterUtils;
public class ContextSpecificDeserializationFilterFactory implements BinaryOperator<ObjectInputFilter> {
@Override
public ObjectInputFilter apply(ObjectInputFilter current, ObjectInputFilter next) {
if (current == null) {
Class<?> caller = findInStack(DeserializationService.class);
if (caller == null) {
current = FilterUtils.fallbackFilter();
} else if (caller.equals(SmallObjectService.class)) {
current = FilterUtils.safeSizeFilter(190);
} else if (caller.equals(LowDepthService.class)) {
current = FilterUtils.safeDepthFilter(2);
} else if (caller.equals(LimitedArrayService.class)) {
current = FilterUtils.safeArrayFilter(3);
}
}
return ObjectInputFilter.merge(current, next);
}
private static Class<?> findInStack(Class<?> superType) {
for (StackTraceElement element : Thread.currentThread()
.getStackTrace()) {
try {
Class<?> subType = Class.forName(element.getClassName());
if (superType.isAssignableFrom(subType)) {
return subType;
}
} catch (ClassNotFoundException e) {
return null;
}
}
return null;
}
}

View File

@ -0,0 +1,7 @@
package com.baeldung.deserializationfilters.pojo;
import java.io.Serializable;
public interface ContextSpecific extends Serializable {
}

View File

@ -0,0 +1,19 @@
package com.baeldung.deserializationfilters.pojo;
public class NestedSample implements ContextSpecific {
private static final long serialVersionUID = 1L;
private Sample optional;
public NestedSample(Sample optional) {
this.optional = optional;
}
public Sample getOptional() {
return optional;
}
public void setOptional(Sample optional) {
this.optional = optional;
}
}

View File

@ -0,0 +1,61 @@
package com.baeldung.deserializationfilters.pojo;
public class Sample implements ContextSpecific, Comparable<Sample> {
private static final long serialVersionUID = 1L;
private int[] array;
private String name;
private NestedSample nested;
public Sample(String name) {
this.name = name;
}
public Sample(int[] array) {
this.array = array;
}
public Sample(NestedSample nested) {
this.nested = nested;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int[] getArray() {
return array;
}
public void setArray(int[] array) {
this.array = array;
}
public NestedSample getNested() {
return nested;
}
public void setNested(NestedSample nested) {
this.nested = nested;
}
@Override
public String toString() {
return name;
}
@Override
public int compareTo(Sample o) {
if (name == null)
return -1;
if (o == null || o.getName() == null)
return 1;
return getName().compareTo(o.getName());
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.deserializationfilters.pojo;
public class SampleExploit extends Sample {
private static final long serialVersionUID = 1L;
public SampleExploit() {
super("exploit");
}
public static void maliciousCode() {
System.out.println("exploit executed");
}
@Override
public String toString() {
maliciousCode();
return "exploit";
}
@Override
public int compareTo(Sample o) {
maliciousCode();
return super.compareTo(o);
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.deserializationfilters.service;
import java.io.InputStream;
import java.util.Set;
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
public interface DeserializationService {
Set<ContextSpecific> process(InputStream... inputStreams);
}

View File

@ -0,0 +1,15 @@
package com.baeldung.deserializationfilters.service;
import java.io.InputStream;
import java.util.Set;
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
import com.baeldung.deserializationfilters.utils.DeserializationUtils;
public class LimitedArrayService implements DeserializationService {
@Override
public Set<ContextSpecific> process(InputStream... inputStreams) {
return DeserializationUtils.deserializeIntoSet(inputStreams);
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.deserializationfilters.service;
import java.io.InputStream;
import java.io.ObjectInputFilter;
import java.util.Set;
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
import com.baeldung.deserializationfilters.utils.DeserializationUtils;
public class LowDepthService implements DeserializationService {
public Set<ContextSpecific> process(ObjectInputFilter filter, InputStream... inputStreams) {
return DeserializationUtils.deserializeIntoSet(filter, inputStreams);
}
@Override
public Set<ContextSpecific> process(InputStream... inputStreams) {
return process(null, inputStreams);
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung.deserializationfilters.service;
import java.io.InputStream;
import java.util.Set;
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
import com.baeldung.deserializationfilters.utils.DeserializationUtils;
public class SmallObjectService implements DeserializationService {
@Override
public Set<ContextSpecific> process(InputStream... inputStreams) {
return DeserializationUtils.deserializeIntoSet(inputStreams);
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.deserializationfilters.utils;
import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.ObjectInputFilter;
import java.io.ObjectInputStream;
import java.util.Set;
import java.util.TreeSet;
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
public class DeserializationUtils {
private DeserializationUtils() {
}
public static Object deserialize(InputStream inStream) {
return deserialize(inStream, null);
}
public static Object deserialize(InputStream inStream, ObjectInputFilter filter) {
try (ObjectInputStream in = new ObjectInputStream(inStream)) {
if (filter != null) {
in.setObjectInputFilter(filter);
}
return in.readObject();
} catch (InvalidClassException e) {
return null;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
public static Set<ContextSpecific> deserializeIntoSet(InputStream... inputStreams) {
return deserializeIntoSet(null, inputStreams);
}
public static Set<ContextSpecific> deserializeIntoSet(ObjectInputFilter filter, InputStream... inputStreams) {
Set<ContextSpecific> set = new TreeSet<>();
for (InputStream inputStream : inputStreams) {
Object object = deserialize(inputStream, filter);
if (object != null) {
set.add((ContextSpecific) object);
}
}
return set;
}
}

View File

@ -0,0 +1,32 @@
package com.baeldung.deserializationfilters.utils;
import java.io.ObjectInputFilter;
public class FilterUtils {
private static final String DEFAULT_PACKAGE_PATTERN = "java.base/*;!*";
private static final String POJO_PACKAGE = "com.baeldung.deserializationfilters.pojo";
private FilterUtils() {
}
private static ObjectInputFilter baseFilter(String parameter, int max) {
return ObjectInputFilter.Config.createFilter(String.format("%s=%d;%s.**;%s", parameter, max, POJO_PACKAGE, DEFAULT_PACKAGE_PATTERN));
}
public static ObjectInputFilter fallbackFilter() {
return ObjectInputFilter.Config.createFilter(String.format("%s", DEFAULT_PACKAGE_PATTERN));
}
public static ObjectInputFilter safeSizeFilter(int max) {
return baseFilter("maxbytes", max);
}
public static ObjectInputFilter safeArrayFilter(int max) {
return baseFilter("maxarray", max);
}
public static ObjectInputFilter safeDepthFilter(int max) {
return baseFilter("maxdepth", max);
}
}

View File

@ -0,0 +1,17 @@
package com.baeldung.deserializationfilters.utils;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class SerializationUtils {
private SerializationUtils() {
}
public static void serialize(Object object, OutputStream outStream) throws IOException {
try (ObjectOutputStream objStream = new ObjectOutputStream(outStream)) {
objStream.writeObject(object);
}
}
}

View File

@ -0,0 +1,119 @@
package com.baeldung.deserializationfilters;
import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputFilter;
import java.util.Set;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
import com.baeldung.deserializationfilters.pojo.NestedSample;
import com.baeldung.deserializationfilters.pojo.Sample;
import com.baeldung.deserializationfilters.pojo.SampleExploit;
import com.baeldung.deserializationfilters.service.LimitedArrayService;
import com.baeldung.deserializationfilters.service.LowDepthService;
import com.baeldung.deserializationfilters.service.SmallObjectService;
import com.baeldung.deserializationfilters.utils.DeserializationUtils;
import com.baeldung.deserializationfilters.utils.FilterUtils;
import com.baeldung.deserializationfilters.utils.SerializationUtils;
public class ContextSpecificDeserializationFilterIntegrationTest {
private static ByteArrayOutputStream serialSampleA = new ByteArrayOutputStream();
private static ByteArrayOutputStream serialBigSampleA = new ByteArrayOutputStream();
private static ByteArrayOutputStream serialSampleB = new ByteArrayOutputStream();
private static ByteArrayOutputStream serialBigSampleB = new ByteArrayOutputStream();
private static ByteArrayOutputStream serialSampleC = new ByteArrayOutputStream();
private static ByteArrayOutputStream serialBigSampleC = new ByteArrayOutputStream();
private static ByteArrayInputStream bytes(ByteArrayOutputStream stream) {
return new ByteArrayInputStream(stream.toByteArray());
}
@BeforeAll
static void setup() throws IOException {
ObjectInputFilter.Config.setSerialFilterFactory(new ContextSpecificDeserializationFilterFactory());
SerializationUtils.serialize(new Sample("simple"), serialSampleA);
SerializationUtils.serialize(new SampleExploit(), serialBigSampleA);
SerializationUtils.serialize(new Sample(new int[] { 1, 2, 3 }), serialSampleB);
SerializationUtils.serialize(new Sample(new int[] { 1, 2, 3, 4, 5, 6 }), serialBigSampleB);
SerializationUtils.serialize(new Sample(new NestedSample(null)), serialSampleC);
SerializationUtils.serialize(new Sample(new NestedSample(new Sample("deep"))), serialBigSampleC);
}
@Test
void whenSmallObjectContext_thenCorrectFilterApplied() {
Set<ContextSpecific> result = new SmallObjectService().process( //
bytes(serialSampleA), //
bytes(serialBigSampleA));
assertEquals(1, result.size());
assertEquals("simple", ((Sample) result.iterator()
.next()).getName());
}
@Test
void whenLimitedArrayContext_thenCorrectFilterApplied() {
Set<ContextSpecific> result = new LimitedArrayService().process( //
bytes(serialSampleB), //
bytes(serialBigSampleB));
assertEquals(1, result.size());
}
@Test
void whenLowDepthContext_thenCorrectFilterApplied() {
Set<ContextSpecific> result = new LowDepthService().process( //
bytes(serialSampleC), //
bytes(serialBigSampleC));
assertEquals(1, result.size());
}
@Test
void givenExtraFilter_whenCombinedContext_thenMergedFiltersApplied() {
Set<ContextSpecific> result = new LowDepthService().process( //
FilterUtils.safeSizeFilter(190), //
bytes(serialSampleA), //
bytes(serialBigSampleA), //
bytes(serialSampleC), //
bytes(serialBigSampleC));
assertEquals(1, result.size());
assertEquals("simple", ((Sample) result.iterator()
.next()).getName());
}
@Test
void givenFallbackContext_whenUsingBaseClasses_thenRestrictiveFilterApplied() throws IOException {
String a = new String("a");
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
SerializationUtils.serialize(a, outStream);
String deserializedA = (String) DeserializationUtils.deserialize(bytes(outStream));
assertEquals(a, deserializedA);
}
@Test
void givenFallbackContext_whenUsingAppClasses_thenRejected() throws IOException {
Sample a = new Sample("a");
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
SerializationUtils.serialize(a, outStream);
Sample deserializedA = (Sample) DeserializationUtils.deserialize(bytes(outStream));
assertNull(deserializedA);
}
}

View File

@ -0,0 +1,89 @@
package com.baeldung.recordproperties;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.lang.reflect.Field;
import java.lang.reflect.RecordComponent;
import java.util.ArrayList;
import org.junit.jupiter.api.Test;
record Player(String name, int age, Long score) {
}
public class ReadRecordPropertiesByReflectionUnitTest {
private static final Player ERIC = new Player("Eric", 28, 4242L);
@Test
void whenUsingRecordComponent_thenGetExpectedResult() {
var fields = new ArrayList<Field>();
RecordComponent[] components = Player.class.getRecordComponents();
for (var comp : components) {
try {
Field field = ERIC.getClass()
.getDeclaredField(comp.getName());
field.setAccessible(true);
fields.add(field);
} catch (NoSuchFieldException e) {
// for simplicity, error handling is skipped
}
}
assertEquals(3, fields.size());
var nameField = fields.get(0);
var ageField = fields.get(1);
var scoreField = fields.get(2);
try {
assertEquals("name", nameField.getName());
assertEquals(String.class, nameField.getType());
assertEquals("Eric", nameField.get(ERIC));
assertEquals("age", ageField.getName());
assertEquals(int.class, ageField.getType());
assertEquals(28, ageField.get(ERIC));
assertEquals("score", scoreField.getName());
assertEquals(Long.class, scoreField.getType());
assertEquals(4242L, scoreField.get(ERIC));
} catch (IllegalAccessException exception) {
// for simplicity, error handling is skipped
}
}
@Test
void whenUsingClassGetDeclaredField_thenGetExpectedResult() {
// record has no public fields
assertEquals(0, Player.class.getFields().length);
var fields = new ArrayList<Field>();
for (var field : Player.class.getDeclaredFields()) {
field.setAccessible(true);
fields.add(field);
}
assertEquals(3, fields.size());
var nameField = fields.get(0);
var ageField = fields.get(1);
var scoreField = fields.get(2);
try {
assertEquals("name", nameField.getName());
assertEquals(String.class, nameField.getType());
assertEquals("Eric", nameField.get(ERIC));
assertEquals("age", ageField.getName());
assertEquals(int.class, ageField.getType());
assertEquals(28, ageField.get(ERIC));
assertEquals("score", scoreField.getName());
assertEquals(Long.class, scoreField.getType());
assertEquals(4242L, scoreField.get(ERIC));
} catch (IllegalAccessException ex) {
// for simplicity, error handling is skipped
}
}
}

View File

@ -18,19 +18,19 @@ public class VehicleUnitTest {
}
@Test
public void givenCar_whenUsingReflectionAPI_thenSuperClassIsSealed() {
public void givenCar_whenUsingReflectionAPI_thenSuperClassIsSealed() throws ClassNotFoundException {
Assertions.assertThat(car.getClass().isSealed()).isEqualTo(false);
Assertions.assertThat(car.getClass().getSuperclass().isSealed()).isEqualTo(true);
Assertions.assertThat(car.getClass().getSuperclass().getPermittedSubclasses())
.contains(ClassDesc.of(car.getClass().getCanonicalName()));
.contains(Class.forName(car.getClass().getCanonicalName()));
}
@Test
public void givenTruck_whenUsingReflectionAPI_thenSuperClassIsSealed() {
public void givenTruck_whenUsingReflectionAPI_thenSuperClassIsSealed() throws ClassNotFoundException {
Assertions.assertThat(truck.getClass().isSealed()).isEqualTo(false);
Assertions.assertThat(truck.getClass().getSuperclass().isSealed()).isEqualTo(true);
Assertions.assertThat(truck.getClass().getSuperclass().getPermittedSubclasses())
.contains(ClassDesc.of(truck.getClass().getCanonicalName()));
.contains(Class.forName(truck.getClass().getCanonicalName()));
}
@Test

View File

@ -18,19 +18,19 @@ public class VehicleUnitTest {
}
@Test
public void givenCar_whenUsingReflectionAPI_thenInterfaceIsSealed() {
public void givenCar_whenUsingReflectionAPI_thenInterfaceIsSealed() throws ClassNotFoundException {
Assertions.assertThat(car.getClass().isSealed()).isEqualTo(false);
Assertions.assertThat(car.getClass().getInterfaces()[0].isSealed()).isEqualTo(true);
Assertions.assertThat(car.getClass().getInterfaces()[0].permittedSubclasses())
.contains(ClassDesc.of(car.getClass().getCanonicalName()));
Assertions.assertThat(car.getClass().getInterfaces()[0].getPermittedSubclasses())
.contains(Class.forName(car.getClass().getCanonicalName()));
}
@Test
public void givenTruck_whenUsingReflectionAPI_thenInterfaceIsSealed() {
public void givenTruck_whenUsingReflectionAPI_thenInterfaceIsSealed() throws ClassNotFoundException {
Assertions.assertThat(truck.getClass().isSealed()).isEqualTo(false);
Assertions.assertThat(truck.getClass().getInterfaces()[0].isSealed()).isEqualTo(true);
Assertions.assertThat(truck.getClass().getInterfaces()[0].permittedSubclasses())
.contains(ClassDesc.of(truck.getClass().getCanonicalName()));
Assertions.assertThat(truck.getClass().getInterfaces()[0].getPermittedSubclasses())
.contains(Class.forName(truck.getClass().getCanonicalName()));
}
@Test

View File

@ -0,0 +1,2 @@
## Relevant Articles
- [Deprecate Finalization in Java 18](https://www.baeldung.com/java-18-deprecate-finalization)

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>core-java-18</artifactId>
<name>core-java-18</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../</relativePath>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>${maven.compiler.release}</release>
<compilerArgs>--enable-preview</compilerArgs>
<source>${maven.compiler.source.version}</source>
<target>${maven.compiler.target.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.plugin.version}</version>
<configuration>
<forkCount>1</forkCount>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-api</artifactId>
<version>${surefire.plugin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.source.version>18</maven.compiler.source.version>
<maven.compiler.target.version>18</maven.compiler.target.version>
<maven.compiler.release>18</maven.compiler.release>
<surefire.plugin.version>3.0.0-M5</surefire.plugin.version>
</properties>
</project>

View File

@ -0,0 +1,27 @@
package com.baeldung.finalization_closeable_cleaner;
import java.io.FileInputStream;
import java.io.IOException;
public class FinalizationExamples {
FileInputStream fis = null;
public void readFileOperationWithFinalization() throws IOException {
try {
fis = new FileInputStream("input.txt");
// perform operation on the file
System.out.println(fis.readAllBytes().length);
} finally {
if (fis != null)
fis.close();
}
}
public void readFileOperationWithTryWith() throws IOException {
try (FileInputStream fis = new FileInputStream("input.txt")) {
// perform operations
System.out.println(fis.readAllBytes().length);
}
}
}

View File

@ -0,0 +1,48 @@
package com.baeldung.finalization_closeable_cleaner;
import java.lang.ref.Cleaner;
public class MyCleanerResourceClass implements AutoCloseable {
private static Resource resource;
private static final Cleaner cleaner = Cleaner.create();
private final Cleaner.Cleanable cleanable;
public MyCleanerResourceClass() {
resource = new Resource();
this.cleanable = cleaner.register(this, new CleaningState());
}
public void useResource() {
// using the resource here
resource.use();
}
@Override
public void close() {
// perform actions to close all underlying resources
this.cleanable.clean();
}
static class CleaningState implements Runnable {
CleaningState() {
// constructor
}
@Override
public void run() {
// some cleanup action
System.out.println("Cleanup done");
}
}
static class Resource {
void use() {
System.out.println("Using the resource");
}
void close() {
System.out.println("Cleanup done");
}
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.finalization_closeable_cleaner;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MyCloseableResourceClass implements AutoCloseable {
private final FileInputStream fis;
public MyCloseableResourceClass() throws FileNotFoundException {
this.fis = new FileInputStream("src/main/resources/file.txt");
}
public int getByteLength() throws IOException {
System.out.println("Some operation");
return this.fis.readAllBytes().length;
}
@Override
public void close() throws IOException {
System.out.println("Finalized object");
this.fis.close();
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.finalization_closeable_cleaner;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MyFinalizableResourceClass {
private FileInputStream fis;
public MyFinalizableResourceClass() throws FileNotFoundException {
this.fis = new FileInputStream("src/main/resources/file.txt");
}
public int getByteLength() throws IOException {
System.out.println("Some operation");
return this.fis.readAllBytes().length;
}
@Override
protected void finalize() throws Throwable {
System.out.println("Finalized object");
this.fis.close();
}
}

Some files were not shown because too many files have changed in this diff Show More