Merge branch 'eugenp:master' into master

This commit is contained in:
Ekatereana 2023-11-21 11:20:09 -08:00 committed by GitHub
commit f2f8e45b96
638 changed files with 8446 additions and 3241 deletions

View File

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

View File

@ -28,7 +28,7 @@
</modules> </modules>
<properties> <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> <commons-math3.version>3.6.1</commons-math3.version>
<cobertura.plugin.version>2.7</cobertura.plugin.version> <cobertura.plugin.version>2.7</cobertura.plugin.version>
<tradukisto.version>1.0.1</tradukisto.version> <tradukisto.version>1.0.1</tradukisto.version>

View File

@ -58,11 +58,16 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.tomakehurst</groupId> <groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId> <artifactId>wiremock</artifactId>
<version>${wiremock.version}</version> <version>${wiremock.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -77,11 +82,12 @@
<properties> <properties>
<mockserver.version>5.6.1</mockserver.version> <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 --> <!-- http client & core 5 -->
<httpcore5.version>5.2</httpcore5.version> <httpcore5.version>5.2</httpcore5.version>
<httpclient5.version>5.2</httpclient5.version> <httpclient5.version>5.2</httpclient5.version>
<httpclient5-fluent.version>5.2</httpclient5-fluent.version> <httpclient5-fluent.version>5.2</httpclient5-fluent.version>
<httpclient.version>4.5.14</httpclient.version>
</properties> </properties>
</project> </project>

View File

@ -8,7 +8,7 @@ import static org.mockserver.model.HttpResponse.response;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; 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.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.mockserver.client.MockServerClient; import org.mockserver.client.MockServerClient;

View File

@ -38,8 +38,6 @@ import org.junit.jupiter.api.Test;
class HttpAsyncClientLiveTest extends GetRequestMockServer { 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_SSL = "https://mms.nw.ru/";
private static final String HOST_WITH_PROXY = "http://httpbin.org/"; 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"; 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";
@ -136,7 +134,7 @@ class HttpAsyncClientLiveTest extends GetRequestMockServer {
client.start(); client.start();
final SimpleHttpRequest request = new SimpleHttpRequest("GET",HOST_WITH_SSL); final SimpleHttpRequest request = new SimpleHttpRequest("GET", HOST_WITH_SSL);
final Future<SimpleHttpResponse> future = client.execute(request, null); final Future<SimpleHttpResponse> future = client.execute(request, null);
final HttpResponse response = future.get(); final HttpResponse response = future.get();
@ -201,7 +199,7 @@ class HttpAsyncClientLiveTest extends GetRequestMockServer {
@Override @Override
public void run() { public void run() {
try { 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(); final HttpResponse response = future.get();
assertThat(response.getCode(), equalTo(200)); assertThat(response.getCode(), equalTo(200));
} catch (final Exception ex) { } catch (final Exception ex) {

View File

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

View File

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

View File

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

View File

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

View File

@ -14,3 +14,4 @@ You can build the project from the command line using: *mvn clean install*, or i
- [Get Partition Count for a Topic in Kafka](https://www.baeldung.com/java-kafka-partition-count-topic) - [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) - [bootstrap-server in Kafka Configuration](https://www.baeldung.com/java-kafka-bootstrap-server)
- [Introduction to Apache Kafka](https://www.baeldung.com/apache-kafka) - [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> <artifactId>slf4j-api</artifactId>
<version>${org.slf4j.version}</version> <version>${org.slf4j.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
@ -57,6 +52,11 @@
<version>${lombok.version}</version> <version>${lombok.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.databind.version} </version>
</dependency>
</dependencies> </dependencies>
<properties> <properties>
@ -64,6 +64,7 @@
<kafka.version>2.8.0</kafka.version> <kafka.version>2.8.0</kafka.version>
<testcontainers-kafka.version>1.15.3</testcontainers-kafka.version> <testcontainers-kafka.version>1.15.3</testcontainers-kafka.version>
<testcontainers-jupiter.version>1.15.3</testcontainers-jupiter.version> <testcontainers-jupiter.version>1.15.3</testcontainers-jupiter.version>
<jackson.databind.version>2.15.2</jackson.databind.version>
</properties> </properties>
</project> </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,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

@ -82,26 +82,11 @@
<artifactId>geronimo-jta_1.0.1B_spec</artifactId> <artifactId>geronimo-jta_1.0.1B_spec</artifactId>
<version>${geronimo.version}</version> <version>${geronimo.version}</version>
</dependency> </dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${validation-api.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.hibernate.validator</groupId> <groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId> <artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version> <version>${hibernate-validator.version}</version>
</dependency> </dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>${javax.el-api.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>${javax.el.version}</version>
</dependency>
</dependencies> </dependencies>
<properties> <properties>
@ -113,10 +98,7 @@
<derby.version>10.8.1.2</derby.version> <derby.version>10.8.1.2</derby.version>
<jta.version>1.1</jta.version> <jta.version>1.1</jta.version>
<geronimo.version>1.0</geronimo.version> <geronimo.version>1.0</geronimo.version>
<validation-api.version>2.0.1.Final</validation-api.version> <hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
<hibernate-validator.version>6.1.2.Final</hibernate-validator.version>
<javax.el-api.version>3.0.0</javax.el-api.version>
<javax.el.version>2.2.4</javax.el.version>
</properties> </properties>
</project> </project>

View File

@ -3,10 +3,10 @@ package com.baeldung.atomikos.spring.jpa;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import javax.validation.ConstraintViolation; import jakarta.validation.ConstraintViolation;
import javax.validation.Validation; import jakarta.validation.Validation;
import javax.validation.Validator; import jakarta.validation.Validator;
import javax.validation.ValidatorFactory; import jakarta.validation.ValidatorFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;

View File

@ -3,7 +3,7 @@ package com.baeldung.atomikos.spring.jpa.order;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import javax.validation.constraints.Max; import jakarta.validation.constraints.Max;
@Entity @Entity
@Table(name = "ORDERS") @Table(name = "ORDERS")

View File

@ -79,7 +79,7 @@
</build> </build>
<properties> <properties>
<gson.version>2.8.0</gson.version> <gson.version>2.10.1</gson.version>
<dynamodblocal.version>1.21.1</dynamodblocal.version> <dynamodblocal.version>1.21.1</dynamodblocal.version>
<maven-plugins-version>3.1.1</maven-plugins-version> <maven-plugins-version>3.1.1</maven-plugins-version>
</properties> </properties>

View File

@ -73,9 +73,9 @@
</build> </build>
<properties> <properties>
<gson.version>2.8.0</gson.version> <gson.version>2.10.1</gson.version>
<dynamodblocal.version>1.21.1</dynamodblocal.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> <jets3t-version>0.9.4.0006L</jets3t-version>
<maven-plugins-version>3.1.1</maven-plugins-version> <maven-plugins-version>3.1.1</maven-plugins-version>
</properties> </properties>

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

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

View File

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

View File

@ -6,4 +6,6 @@
- [How Many Days Are There in a Particular Month of a Given Year?](https://www.baeldung.com/days-particular-month-given-year) - [How Many Days Are There in a Particular Month of a Given Year?](https://www.baeldung.com/days-particular-month-given-year)
- [Difference Between Instant and LocalDateTime](https://www.baeldung.com/java-instant-vs-localdatetime) - [Difference Between Instant and LocalDateTime](https://www.baeldung.com/java-instant-vs-localdatetime)
- [Add Minutes to a Time String in Java](https://www.baeldung.com/java-string-time-add-mins) - [Add Minutes to a Time String in Java](https://www.baeldung.com/java-string-time-add-mins)
- [Round the Date in Java](https://www.baeldung.com/java-round-the-date)
- [Representing Furthest Possible Date in Java](https://www.baeldung.com/java-date-represent-max)
- [[<-- Prev]](/core-java-modules/core-java-datetime-java8-1) - [[<-- Prev]](/core-java-modules/core-java-datetime-java8-1)

View File

@ -55,7 +55,7 @@
<properties> <properties>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<joda-time.version>2.10</joda-time.version> <joda-time.version>2.12.5</joda-time.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,18 @@
package com.baeldung.maxdate;
import java.util.Date;
public class DateComparison {
public int compareTodayWithMaxDate() {
Date today = new Date();
Date maxDate = new Date(Long.MAX_VALUE);
int comparisonResult = today.compareTo(maxDate);
return comparisonResult;
}
public static void main(String[] args) {
DateComparison comparator = new DateComparison();
System.out.println(comparator.compareTodayWithMaxDate());
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.maxdate;
import java.util.Date;
import java.text.SimpleDateFormat;
public class MaxDateDisplay {
public String getMaxDateValue() {
Date maxDate = new Date(Long.MAX_VALUE);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
return "The maximum date value in Java is: " + sdf.format(maxDate);
}
public static void main(String[] args) {
MaxDateDisplay display = new MaxDateDisplay();
System.out.println(display.getMaxDateValue());
}
}

View File

@ -7,7 +7,7 @@ import java.util.List;
public class SimpleParseDate { public class SimpleParseDate {
public Date parseDate(String dateString, List<String> formatStrings) { public static Date parseDate(String dateString, List<String> formatStrings) {
for (String formatString : formatStrings) { for (String formatString : formatStrings) {
try { try {
return new SimpleDateFormat(formatString).parse(dateString); return new SimpleDateFormat(formatString).parse(dateString);

View File

@ -0,0 +1,16 @@
package com.baeldung.maxdate;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
class DateComparisonUnitTest {
@Test
void whenCompareTodayWithMaxDate_thenCorrectResult() {
DateComparison comparator = new DateComparison();
int result = comparator.compareTodayWithMaxDate();
assertTrue(result < 0);
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.maxdate;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class MaxDateDisplayUnitTest {
@Test
void whenGetMaxDate_thenCorrectResult() {
MaxDateDisplay display = new MaxDateDisplay();
String result = display.getMaxDateValue();
assertEquals(
"The maximum date value in Java is: 292278994-08-17 07:12:55.807",
result
);
}
}

View File

@ -1,43 +1,41 @@
package com.baeldung.parsingDates; package com.baeldung.parsingDates;
import com.baeldung.parsingDates.SimpleDateTimeFormat; import static org.junit.jupiter.api.Assertions.assertEquals;
import com.baeldung.parsingDates.SimpleDateTimeFormater; import static org.junit.jupiter.api.Assertions.assertNull;
import com.baeldung.parsingDates.SimpleDateUtils; import static org.junit.jupiter.api.Assertions.assertThrows;
import com.baeldung.parsingDates.SimpleParseDate;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.util.Arrays; import java.util.Arrays;
import org.junit.*;
import static org.junit.Assert.*;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.junit.jupiter.api.Test;
public class SimpleParseDateUnitTest { class SimpleParseDateUnitTest {
@Test @Test
public void whenInvalidInput_thenGettingUnexpectedResult() { void whenInvalidInput_thenGettingUnexpectedResult() {
SimpleParseDate simpleParseDate = new SimpleParseDate();
String date = "2022-40-40"; String date = "2022-40-40";
assertEquals("Sat May 10 00:00:00 UTC 2025", simpleParseDate.parseDate(date, Arrays.asList("MM/dd/yyyy", "dd.MM.yyyy", "yyyy-MM-dd")).toString()); assertEquals("Sat May 10 00:00:00 UTC 2025", SimpleParseDate.parseDate(date, Arrays.asList("MM/dd/yyyy", "dd.MM.yyyy", "yyyy-MM-dd"))
.toString());
} }
@Test @Test
public void whenInvalidDate_thenAssertThrows() { void whenInvalidDate_thenAssertThrows() {
SimpleDateTimeFormater simpleDateTimeFormater = new SimpleDateTimeFormater(); assertEquals(java.time.LocalDate.parse("2022-12-04"), SimpleDateTimeFormater.parseDate("2022-12-04"));
assertEquals(java.time.LocalDate.parse("2022-12-04"), simpleDateTimeFormater.parseDate("2022-12-04")); assertThrows(DateTimeParseException.class, () -> SimpleDateTimeFormater.parseDate("2022-13-04"));
assertThrows(DateTimeParseException.class, () -> simpleDateTimeFormater.parseDate("2022-13-04"));
} }
@Test @Test
public void whenDateIsCorrect_thenParseCorrect() { void whenDateIsCorrect_thenParseCorrect() {
SimpleDateUtils simpleDateUtils = new SimpleDateUtils(); assertNull(SimpleDateUtils.parseDate("53/10/2014"));
assertNull(simpleDateUtils.parseDate("53/10/2014")); assertEquals("Wed Sep 10 00:00:00 UTC 2014", SimpleDateUtils.parseDate("10/09/2014")
assertEquals("Wed Sep 10 00:00:00 UTC 2014", simpleDateUtils.parseDate("10/09/2014").toString()); .toString());
} }
@Test @Test
public void whenDateIsCorrect_thenResultCorrect() { void whenDateIsCorrect_thenResultCorrect() {
SimpleDateTimeFormat simpleDateTimeFormat = new SimpleDateTimeFormat(); assertNull(SimpleDateTimeFormat.parseDate("53/10/2014"));
assertNull(simpleDateTimeFormat.parseDate("53/10/2014")); assertEquals(LocalDate.parse("2014-10-10"), SimpleDateTimeFormat.parseDate("2014-10-10"));
assertEquals(LocalDate.parse("2014-10-10"), simpleDateTimeFormat.parseDate("2014-10-10"));
} }
} }

View File

@ -56,7 +56,7 @@
<properties> <properties>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<joda-time.version>2.10</joda-time.version> <joda-time.version>2.12.5</joda-time.version>
</properties> </properties>
</project> </project>

View File

@ -1,62 +0,0 @@
package com.baeldung.streamreduce.application;
import com.baeldung.streamreduce.entities.User;
import com.baeldung.streamreduce.utilities.NumberUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int result1 = numbers.stream().reduce(0, (a, b) -> a + b);
System.out.println(result1);
int result2 = numbers.stream().reduce(0, Integer::sum);
System.out.println(result2);
List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result3 = letters.stream().reduce("", (a, b) -> a + b);
System.out.println(result3);
String result4 = letters.stream().reduce("", String::concat);
System.out.println(result4);
String result5 = letters.stream().reduce("", (a, b) -> a.toUpperCase() + b.toUpperCase());
System.out.println(result5);
List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
int result6 = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
System.out.println(result6);
String result7 = letters.parallelStream().reduce("", String::concat);
System.out.println(result7);
int result8 = users.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
System.out.println(result8);
List<User> userList = new ArrayList<>();
for (int i = 0; i <= 1000000; i++) {
userList.add(new User("John" + i, i));
}
long t1 = System.currentTimeMillis();
int result9 = userList.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
long t2 = System.currentTimeMillis();
System.out.println(result9);
System.out.println("Sequential stream time: " + (t2 - t1) + "ms");
long t3 = System.currentTimeMillis();
int result10 = userList.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
long t4 = System.currentTimeMillis();
System.out.println(result10);
System.out.println("Parallel stream time: " + (t4 - t3) + "ms");
int result11 = NumberUtils.divideListElements(numbers, 1);
System.out.println(result11);
int result12 = NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 0);
System.out.println(result12);
}
}

View File

@ -1,39 +0,0 @@
package com.baeldung.streamreduce.entities;
import java.util.ArrayList;
import java.util.List;
public class Rating {
double points;
List<Review> reviews = new ArrayList<>();
public Rating() {}
public void add(Review review) {
reviews.add(review);
computeRating();
}
private double computeRating() {
double totalPoints = reviews.stream().map(Review::getPoints).reduce(0, Integer::sum);
this.points = totalPoints / reviews.size();
return this.points;
}
public static Rating average(Rating r1, Rating r2) {
Rating combined = new Rating();
combined.reviews = new ArrayList<>(r1.reviews);
combined.reviews.addAll(r2.reviews);
combined.computeRating();
return combined;
}
public double getPoints() {
return points;
}
public List<Review> getReviews() {
return reviews;
}
}

View File

@ -1,28 +0,0 @@
package com.baeldung.streamreduce.entities;
public class Review {
int points;
String review;
public Review(int points, String review) {
this.points = points;
this.review = review;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
public String getReview() {
return review;
}
public void setReview(String review) {
this.review = review;
}
}

View File

@ -1,30 +0,0 @@
package com.baeldung.streamreduce.entities;
public class User {
private final String name;
private final int age;
private final Rating rating = new Rating();
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Rating getRating() {
return rating;
}
@Override
public String toString() {
return "User{" + "name=" + name + ", age=" + age + '}';
}
}

View File

@ -1,52 +0,0 @@
package com.baeldung.streamreduce.utilities;
import java.util.List;
import java.util.function.BiFunction;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class NumberUtils {
private static final Logger LOGGER = Logger.getLogger(NumberUtils.class.getName());
public static int divideListElements(List<Integer> values, Integer divider) {
return values.stream()
.reduce(0, (a, b) -> {
try {
return a / divider + b / divider;
} catch (ArithmeticException e) {
LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");
}
return 0;
});
}
public static int divideListElementsWithExtractedTryCatchBlock(List<Integer> values, int divider) {
return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider));
}
public static int divideListElementsWithApplyFunctionMethod(List<Integer> values, int divider) {
BiFunction<Integer, Integer, Integer> division = (a, b) -> a / b;
return values.stream().reduce(0, (a, b) -> applyFunction(division, a, divider) + applyFunction(division, b, divider));
}
private static int divide(int value, int factor) {
int result = 0;
try {
result = value / factor;
} catch (ArithmeticException e) {
LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");
}
return result;
}
private static int applyFunction(BiFunction<Integer, Integer, Integer> function, int a, int b) {
try {
return function.apply(a, b);
}
catch(Exception e) {
LOGGER.log(Level.INFO, "Exception occurred!");
}
return 0;
}
}

View File

@ -34,7 +34,6 @@
<properties> <properties>
<commons-lang.version>2.2</commons-lang.version> <commons-lang.version>2.2</commons-lang.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
</properties> </properties>
</project> </project>

View File

@ -8,4 +8,6 @@
- [Difference Between Arrays.sort() and Collections.sort()](https://www.baeldung.com/java-arrays-collections-sort-methods) - [Difference Between Arrays.sort() and Collections.sort()](https://www.baeldung.com/java-arrays-collections-sort-methods)
- [Skipping the First Iteration in Java](https://www.baeldung.com/java-skip-first-iteration) - [Skipping the First Iteration in Java](https://www.baeldung.com/java-skip-first-iteration)
- [Remove Elements From a Queue Using Loop](https://www.baeldung.com/java-remove-elements-queue) - [Remove Elements From a Queue Using Loop](https://www.baeldung.com/java-remove-elements-queue)
- [Intro to Vector Class in Java](https://www.baeldung.com/java-vector-guide)
- [HashSet toArray() Method in Java](https://www.baeldung.com/java-hashset-toarray)
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-4) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-4)

View File

@ -0,0 +1,60 @@
package com.baeldung.collectionssortcomplexity;
import org.openjdk.jmh.annotations.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(value = 1, warmups = 1)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
public class CollectionsSortTimeComplexityJMH {
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
@Benchmark
public void measureCollectionsSortBestCase(BestCaseBenchmarkState state) {
List<Integer> sortedList = new ArrayList<>(state.sortedList);
Collections.sort(sortedList);
}
@Benchmark
public void measureCollectionsSortAverageWorstCase(AverageWorstCaseBenchmarkState state) {
List<Integer> unsortedList = new ArrayList<>(state.unsortedList);
Collections.sort(unsortedList);
}
@State(Scope.Benchmark)
public static class BestCaseBenchmarkState {
List<Integer> sortedList;
@Setup(Level.Trial)
public void setUp() {
sortedList = new ArrayList<>();
for (int i = 1; i <= 1000000; i++) {
sortedList.add(i);
}
}
}
@State(Scope.Benchmark)
public static class AverageWorstCaseBenchmarkState {
List<Integer> unsortedList;
@Setup(Level.Trial)
public void setUp() {
unsortedList = new ArrayList<>();
for (int i = 1000000; i > 0; i--) {
unsortedList.add(i);
}
}
}
}

View File

@ -0,0 +1,33 @@
package com.baeldung.collectionssortcomplexity;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CollectionsSortTimeComplexityMain {
// O(n log n) Time Complexity Example
public static void worstAndAverageCasesTimeComplexity() {
Integer[] sortedArray = {20, 21, 22, 23, 24, 25, 26, 17, 28, 29, 30, 31, 18, 19, 32, 33, 34, 27, 35};
List<Integer> list = Arrays.asList(sortedArray);
Collections.shuffle(list);
long startTime = System.nanoTime();
Collections.sort(list);
long endTime = System.nanoTime();
System.out.println("Execution Time for O(n log n): " + (endTime - startTime) + " nanoseconds");
}
// O(n) Time Complexity Example
public static void bestCaseTimeComplexity() {
Integer[] sortedArray = {19, 22, 19, 22, 24, 25, 17, 11, 22, 23, 28, 23, 0, 1, 12, 9, 13, 27, 15};
List<Integer> list = Arrays.asList(sortedArray);
long startTime = System.nanoTime();
Collections.sort(list);
long endTime = System.nanoTime();
System.out.println("Execution Time for O(n): " + (endTime - startTime) + " nanoseconds");
}
public static void main(String[] args) {
worstAndAverageCasesTimeComplexity();
bestCaseTimeComplexity();
}
}

View File

@ -0,0 +1,87 @@
package com.baeldung.vectors;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;
import org.junit.Test;
public class VectorOperationsUnitTest {
private static Vector<String> getVector() {
Vector<String> vector = new Vector<String>();
vector.add("Today");
vector.add("is");
vector.add("a");
vector.add("great");
vector.add("day!");
return vector;
}
@Test
public void givenAVector_whenAddElementsUsingAddMethod_thenElementsGetAddedAtEnd() {
Vector<String> vector = getVector();
vector.add("Hello");
assertEquals(6, vector.size());
}
@Test
public void givenAVector_whenUpdateElementAtIndex_thenElementAtIndexGetsUpdated() {
Vector<String> vector = getVector();
assertEquals(5, vector.size());
assertEquals("great", vector.get(3));
vector.set(3, "good");
assertEquals("good", vector.get(3));
}
@Test
public void givenAVector_whenRemoveAnElement_thenElementGetsRemovedFromTheVector() {
Vector<String> vector = getVector();
assertEquals(5, vector.size());
// remove a specific element
vector.remove("a");
assertEquals(4, vector.size());
// remove at specific index
vector.remove(2);
assertEquals("day!", vector.get(2));
assertEquals(3, vector.size());
assertEquals(false, vector.remove("SomethingThatDoesn'tExist"));
}
@Test(expected = ArrayIndexOutOfBoundsException.class)
public void givenAVector_whenIndexIsBeyondRange_thenRemoveMethodThrowsArrayIndexOutOfBoundsException() {
Vector<String> vector = getVector();
assertEquals(5, vector.size());
vector.remove(10);
}
@Test
public void givenAVector_whenGetElementWithinARange_thenGetMethodGetsAnElementFromTheVector() {
Vector<String> vector = getVector();
String fourthElement = vector.get(3);
assertEquals("great", fourthElement);
}
@Test(expected = ArrayIndexOutOfBoundsException.class)
public void givenAVector_whenGetElementBeyondARange_thenGetMethodThrowsArrayIndexOutOfBoundsException() {
Vector<String> vector = getVector();
assertEquals(5, vector.size());
vector.get(10);
}
@Test
public void givenAVector_whenAddElementFromACollection_thenAllElementsGetAdeddToTheVector() {
Vector<String> vector = getVector();
assertEquals(5, vector.size());
ArrayList<String> words = new ArrayList<>(Arrays.asList("Baeldung", "is", "cool!"));
vector.addAll(words);
assertEquals(8, vector.size());
assertEquals("cool!", vector.get(7));
}
}

View File

@ -0,0 +1,51 @@
package com.baeldung.toarraymethod;
import org.junit.Test;
import java.util.HashSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class ConvertingHashSetToArrayUnitTest {
@Test
public void givenStringHashSet_whenConvertedToArray_thenArrayContainsStringElements() {
HashSet<String> stringSet = new HashSet<>();
stringSet.add("Apple");
stringSet.add("Banana");
stringSet.add("Cherry");
// Convert the HashSet of Strings to an array of Strings
String[] stringArray = stringSet.toArray(new String[0]);
// Test that the array is of the correct length
assertEquals(3, stringArray.length);
for (String str : stringArray) {
assertTrue(stringSet.contains(str));
}
}
@Test
public void givenIntegerHashSet_whenConvertedToArray_thenArrayContainsIntegerElements() {
HashSet<Integer> integerSet = new HashSet<>();
integerSet.add(5);
integerSet.add(10);
integerSet.add(15);
// Convert the HashSet of Integers to an array of Integers
Integer[] integerArray = integerSet.toArray(new Integer[0]);
// Test that the array is of the correct length
assertEquals(3, integerArray.length);
for (Integer num : integerArray) {
assertTrue(integerSet.contains(num));
}
assertTrue(integerSet.contains(5));
assertTrue(integerSet.contains(10));
assertTrue(integerSet.contains(15));
}
}

View File

@ -44,6 +44,6 @@
<properties> <properties>
<vavr.version>0.10.3</vavr.version> <vavr.version>0.10.3</vavr.version>
<java.version>11</java.version> <java.version>11</java.version>
<modelmapper.version>3.1.1</modelmapper.version> <modelmapper.version>3.2.0</modelmapper.version>
</properties> </properties>
</project> </project>

View File

@ -1,8 +1,9 @@
package com.baeldung.modelmapper; package com.baeldung.modelmapper;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.modelmapper.ModelMapper; import org.modelmapper.ModelMapper;
import org.modelmapper.TypeMap; import org.modelmapper.TypeMap;
import org.modelmapper.TypeToken; import org.modelmapper.TypeToken;
@ -10,11 +11,10 @@ import org.modelmapper.TypeToken;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.hasProperty;
import static org.junit.Assert.assertThat;
/** /**
* This class has test methods of mapping Integer to Character list, * This class has test methods of mapping Integer to Character list,
@ -22,12 +22,12 @@ import static org.junit.Assert.assertThat;
* *
* @author Sasa Milenkovic * @author Sasa Milenkovic
*/ */
public class UsersListMappingUnitTest { class UsersListMappingUnitTest {
private ModelMapper modelMapper; private ModelMapper modelMapper;
private List<User> users; private List<User> users;
@Before @BeforeEach
public void init() { public void init() {
modelMapper = new ModelMapper(); modelMapper = new ModelMapper();
@ -35,18 +35,16 @@ public class UsersListMappingUnitTest {
TypeMap<UserList, UserListDTO> typeMap = modelMapper.createTypeMap(UserList.class, UserListDTO.class); TypeMap<UserList, UserListDTO> typeMap = modelMapper.createTypeMap(UserList.class, UserListDTO.class);
typeMap.addMappings(mapper -> mapper.using(new UsersListConverter()) typeMap.addMappings(mapper -> mapper.using(new UsersListConverter())
.map(UserList::getUsers, UserListDTO::setUsernames)); .map(UserList::getUsers, UserListDTO::setUsernames));
users = new ArrayList(); users = new ArrayList<>();
users.add(new User("b100", "user1", "user1@baeldung.com", "111-222", "USER")); users.add(new User("b100", "user1", "user1@baeldung.com", "111-222", "USER"));
users.add(new User("b101", "user2", "user2@baeldung.com", "111-333", "USER")); users.add(new User("b101", "user2", "user2@baeldung.com", "111-333", "USER"));
users.add(new User("b102", "user3", "user3@baeldung.com", "111-444", "ADMIN")); users.add(new User("b102", "user3", "user3@baeldung.com", "111-444", "ADMIN"));
} }
@Test @Test
public void whenInteger_thenMapToCharacter() { void whenInteger_thenMapToCharacter() {
List<Integer> integers = new ArrayList<Integer>(); List<Integer> integers = new ArrayList<Integer>();
integers.add(1); integers.add(1);
@ -57,36 +55,27 @@ public class UsersListMappingUnitTest {
}.getType()); }.getType());
assertThat(characters, hasItems('1', '2', '3')); assertThat(characters, hasItems('1', '2', '3'));
} }
@Test @Test
public void givenUsersList_whenUseGenericType_thenMapToUserDTO() { void givenUsersList_whenUseGenericType_thenMapToUserDTO() {
// Mapping lists using custom (generic) type mapping // Mapping lists using custom (generic) type mapping
List<UserDTO> userDtoList = MapperUtil.mapList(users, UserDTO.class); List<UserDTO> userDtoList = MapperUtil.mapList(users, UserDTO.class);
assertThat(userDtoList, Matchers.<UserDTO>hasItem( assertThat(userDtoList, Matchers.<UserDTO> hasItem(Matchers.both(hasProperty("userId", equalTo("b100")))
Matchers.both(hasProperty("userId", equalTo("b100"))) .and(hasProperty("email", equalTo("user1@baeldung.com")))
.and(hasProperty("email", equalTo("user1@baeldung.com"))) .and(hasProperty("username", equalTo("user1")))));
.and(hasProperty("username", equalTo("user1")))));
} }
@Test @Test
public void givenUsersList_whenUseConverter_thenMapToUsernames() { void givenUsersList_whenUseConverter_thenMapToUsernames() {
// Mapping lists using property mapping and converter // Mapping lists using property mapping and converter
UserList userList = new UserList(); UserList userList = new UserList();
userList.setUsers(users); userList.setUsers(users);
UserListDTO dtos = new UserListDTO(); UserListDTO dtos = new UserListDTO();
modelMapper.map(userList, dtos); modelMapper.map(userList, dtos);
assertThat(dtos.getUsernames(), hasItems("user1", "user2", "user3")); assertThat(dtos.getUsernames(), hasItems("user1", "user2", "user3"));
} }
} }

View File

@ -66,7 +66,6 @@
<properties> <properties>
<jmh.version>1.21</jmh.version> <jmh.version>1.21</jmh.version>
<commons-lang.version>2.2</commons-lang.version> <commons-lang.version>2.2</commons-lang.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
<gson.version>2.10.1</gson.version> <gson.version>2.10.1</gson.version>
<jackson.version>2.15.2</jackson.version> <jackson.version>2.15.2</jackson.version>
<org.json.version>20230618</org.json.version> <org.json.version>20230618</org.json.version>

View File

@ -1,3 +1,7 @@
## Relevant Articles ## Relevant Articles:
- [Difference Between putIfAbsent() and computeIfAbsent() in Javas Map](https://www.baeldung.com/java-map-putifabsent-computeifabsent) - [Difference Between putIfAbsent() and computeIfAbsent() in Javas Map](https://www.baeldung.com/java-map-putifabsent-computeifabsent)
- [How to Write and Read a File with a Java HashMap](https://www.baeldung.com/how-to-write-and-read-a-file-with-a-java-hashmap/)
- [How to Write Hashmap to CSV File](https://www.baeldung.com/java-write-hashmap-csv) - [How to Write Hashmap to CSV File](https://www.baeldung.com/java-write-hashmap-csv)
- [How to Get First or Last Entry From a LinkedHashMap in Java](https://www.baeldung.com/java-linkedhashmap-first-last-key-value-pair)
- [How to Write and Read a File with a Java HashMap](https://www.baeldung.com/java-hashmap-write-read-file)
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-6)

View File

@ -1,11 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <modelVersion>4.0.0</modelVersion>
<artifactId>core-java-collections-maps-7</artifactId> <artifactId>core-java-collections-maps-7</artifactId>
<name>core-java-collections-maps-7</name> <name>core-java-collections-maps-7</name>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties>
<gson.version>2.10.1</gson.version>
<csv.version>1.5</csv.version>
</properties>
<parent> <parent>
<artifactId>core-java-modules</artifactId> <artifactId>core-java-modules</artifactId>
@ -13,72 +17,29 @@
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
</parent> </parent>
<properties>
<spring.version>5.2.5.RELEASE</spring.version>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<version>2.12.4</version> <version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.36</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
<version>2.8.9</version> <version>${gson.version}</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20230227</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId> <artifactId>commons-csv</artifactId>
<version>1.5</version> <version>${csv.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
@ -92,5 +53,4 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -0,0 +1,70 @@
package com.baeldung.map;
import java.util.HashMap;
import java.util.Map;
public class BenchmarkMapMethods {
public static void main(String[] args) {
BenchmarkMapMethods bmm = new BenchmarkMapMethods();
Map<String, Long> map = new HashMap<>();
map.put("Guava", bmm.benchMarkGuavaMap());
map.put("ContainsKey", bmm.benchContainsKeyMap());
map.put("MergeMethod", bmm.benchMarkMergeMethod());
map.put("ComputeMethod", bmm.benchMarComputeMethod());
map.put("GetOrDefault", bmm.benchMarkGetOrDefaultMethod());
}
private long benchMarkGuavaMap() {
long startTime = System.nanoTime();
IncrementMapValueWays im = new IncrementMapValueWays();
im.charFrequencyUsingAtomicMap(getString());
long endTime = System.nanoTime();
return endTime - startTime;
}
private long benchContainsKeyMap() {
long startTime = System.nanoTime();
IncrementMapValueWays im = new IncrementMapValueWays();
im.charFrequencyUsingContainsKey(getString());
long endTime = System.nanoTime();
return endTime - startTime;
}
private long benchMarComputeMethod() {
long startTime = System.nanoTime();
IncrementMapValueWays im = new IncrementMapValueWays();
im.charFrequencyUsingCompute(getString());
long endTime = System.nanoTime();
return endTime - startTime;
}
private long benchMarkMergeMethod() {
long startTime = System.nanoTime();
IncrementMapValueWays im = new IncrementMapValueWays();
im.charFrequencyUsingMerge(getString());
long endTime = System.nanoTime();
return endTime - startTime;
}
private long benchMarkGetOrDefaultMethod() {
long startTime = System.nanoTime();
IncrementMapValueWays im = new IncrementMapValueWays();
im.charFrequencyUsingGetOrDefault(getString());
long endTime = System.nanoTime();
return endTime - startTime;
}
private String getString() {
return
"Once upon a time in a quaint village nestled between rolling hills and whispering forests, there lived a solitary storyteller named Elias. Elias was known for spinning tales that transported listeners to magical realms and awakened forgotten dreams.\n"
+ "\n"
+ "His favorite spot was beneath an ancient oak tree, its sprawling branches offering shade to those who sought refuge from the bustle of daily life. Villagers of all ages would gather around Elias, their faces illuminated by the warmth of his stories.\n"
+ "\n" + "One evening, as dusk painted the sky in hues of orange and purple, a curious young girl named Lily approached Elias. Her eyes sparkled with wonder as she asked for a tale unlike any other.\n" + "\n"
+ "Elias smiled, sensing her thirst for adventure, and began a story about a forgotten kingdom veiled by mist, guarded by mystical creatures and enchanted by ancient spells. With each word, the air grew thick with anticipation, and the listeners were transported into a world where magic danced on the edges of reality.\n"
+ "\n" + "As Elias weaved the story, Lily's imagination took flight. She envisioned herself as a brave warrior, wielding a shimmering sword against dark forces, her heart fueled by courage and kindness.\n" + "\n"
+ "The night wore on, but the spell of the tale held everyone captive. The villagers laughed, gasped, and held their breaths, journeying alongside the characters through trials and triumphs.\n" + "\n"
+ "As the final words lingered in the air, a sense of enchantment settled upon the listeners. They thanked Elias for the gift of his storytelling, each carrying a piece of the magical kingdom within their hearts.\n" + "\n"
+ "Lily, inspired by the story, vowed to cherish the spirit of adventure and kindness in her own life. With a newfound spark in her eyes, she bid Elias goodnight, already dreaming of the countless adventures awaiting her.\n" + "\n"
+ "Under the star-studded sky, Elias remained beneath the ancient oak, his heart aglow with the joy of sharing tales that ignited imagination and inspired dreams. And as the night embraced the village, whispers of the enchanted kingdom lingered in the breeze, promising endless possibilities to those who dared to believe.";
}
}

View File

@ -0,0 +1,80 @@
package com.baeldung.map;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import com.google.common.util.concurrent.AtomicLongMap;
public class IncrementMapValueWays {
public Map<Character, Integer> charFrequencyUsingContainsKey(String sentence) {
Map<Character, Integer> charMap = new HashMap<>();
for (int c = 0; c < sentence.length(); c++) {
int count = 0;
if (charMap.containsKey(sentence.charAt(c))) {
count = charMap.get(sentence.charAt(c));
}
charMap.put(sentence.charAt(c), count + 1);
}
return charMap;
}
public Map<Character, Integer> charFrequencyUsingGetOrDefault(String sentence) {
Map<Character, Integer> charMap = new HashMap<>();
for (int c = 0; c < sentence.length(); c++) {
charMap.put(sentence.charAt(c), charMap.getOrDefault(sentence.charAt(c), 0) + 1);
}
return charMap;
}
public Map<Character, Integer> charFrequencyUsingMerge(String sentence) {
Map<Character, Integer> charMap = new HashMap<>();
for (int c = 0; c < sentence.length(); c++) {
charMap.merge(sentence.charAt(c), 1, Integer::sum);
}
return charMap;
}
public Map<Character, Integer> charFrequencyUsingCompute(String sentence) {
Map<Character, Integer> charMap = new HashMap<>();
for (int c = 0; c < sentence.length(); c++) {
charMap.compute(sentence.charAt(c), (key, value) -> (value == null) ? 1 : value + 1);
}
return charMap;
}
public Map<Character, Long> charFrequencyUsingAtomicMap(String sentence) {
AtomicLongMap<Character> map = AtomicLongMap.create();
for (int c = 0; c < sentence.length(); c++) {
map.getAndIncrement(sentence.charAt(c));
}
return map.asMap();
}
public Map<Character, Integer> charFrequencyWithConcurrentMap(String sentence, Map<Character, Integer> charMap) {
for (int c = 0; c < sentence.length(); c++) {
charMap.compute(sentence.charAt(c), (key, value) -> (value == null) ? 1 : value + 1);
}
return charMap;
}
public Map<Character, AtomicInteger> charFrequencyWithGetAndIncrement(String sentence) {
Map<Character, AtomicInteger> charMap = new HashMap<>();
for (int c = 0; c < sentence.length(); c++) {
charMap.putIfAbsent(sentence.charAt(c), new AtomicInteger(0));
charMap.get(sentence.charAt(c))
.incrementAndGet();
}
return charMap;
}
public Map<Character, AtomicInteger> charFrequencyWithGetAndIncrementComputeIfAbsent(String sentence) {
Map<Character, AtomicInteger> charMap = new HashMap<>();
for (int c = 0; c < sentence.length(); c++) {
charMap.computeIfAbsent(sentence.charAt(c), k -> new AtomicInteger(0))
.incrementAndGet();
}
return charMap;
}
}

View File

@ -0,0 +1,51 @@
package com.baeldung.map.readandwritefile;
import java.io.Serializable;
import java.util.Objects;
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String firstName;
private String lastName;
/** Default constructor for JSON serialization */
public Student() {
}
public Student(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Student student = (Student) o;
return Objects.equals(firstName, student.firstName) && Objects.equals(lastName, student.lastName);
}
@Override
public int hashCode() {
return super.hashCode();
}
}

View File

@ -0,0 +1,103 @@
package com.baeldung.map;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Assert;
import org.junit.Test;
public class IncrementMapValueUnitTest {
@Test
public void givenString_whenUsingContainsKey_thenReturnFreqMap() {
String string = "the quick brown fox jumps over the lazy dog";
IncrementMapValueWays ic = new IncrementMapValueWays();
Map<Character, Integer> actualMap = ic.charFrequencyUsingContainsKey(string);
Map<Character, Integer> expectedMap = getExpectedMap();
Assert.assertEquals(expectedMap, actualMap);
}
@Test
public void givenString_whenUsingGetOrDefault_thenReturnFreqMap() {
String string = "the quick brown fox jumps over the lazy dog";
IncrementMapValueWays ic = new IncrementMapValueWays();
Map<Character, Integer> actualMap = ic.charFrequencyUsingGetOrDefault(string);
Map<Character, Integer> expectedMap = getExpectedMap();
Assert.assertEquals(expectedMap, actualMap);
}
@Test
public void givenString_whenUsingMapMerge_thenReturnFreqMap() {
String string = "the quick brown fox jumps over the lazy dog";
IncrementMapValueWays ic = new IncrementMapValueWays();
Map<Character, Integer> actualMap = ic.charFrequencyUsingMerge(string);
Map<Character, Integer> expectedMap = getExpectedMap();
Assert.assertEquals(expectedMap, actualMap);
}
@Test
public void givenString_whenUsingMapCompute_thenReturnFreqMap() {
String string = "the quick brown fox jumps over the lazy dog";
IncrementMapValueWays ic = new IncrementMapValueWays();
Map<Character, Integer> actualMap = ic.charFrequencyUsingCompute(string);
Map<Character, Integer> expectedMap = getExpectedMap();
Assert.assertEquals(expectedMap, actualMap);
}
@Test
public void givenString_whenUsingGuava_thenReturnFreqMap() {
String string = "the quick brown fox jumps over the lazy dog";
IncrementMapValueWays ic = new IncrementMapValueWays();
Map<Character, Long> actualMap = ic.charFrequencyUsingAtomicMap(string);
Map<Character, Integer> expectedMap = getExpectedMap();
Assert.assertEquals(expectedMap.keySet(), actualMap.keySet());
}
@Test
public void givenString_whenUsingIncrementAndGet_thenReturnFreqMap() {
String string = "the quick brown fox jumps over the lazy dog";
IncrementMapValueWays ic = new IncrementMapValueWays();
Map<Character, AtomicInteger> actualMap = ic.charFrequencyWithGetAndIncrement(string);
Assert.assertEquals(getExpectedMap().keySet(), actualMap.keySet());
}
@Test
public void givenString_whenUsingIncrementAndGetAndComputeIfAbsent_thenReturnFreqMap() {
String string = "the quick brown fox jumps over the lazy dog";
IncrementMapValueWays ic = new IncrementMapValueWays();
Map<Character, AtomicInteger> actualMap = ic.charFrequencyWithGetAndIncrementComputeIfAbsent(string);
Assert.assertEquals(getExpectedMap().keySet(), actualMap.keySet());
}
@Test
public void givenString_whenUsingConcurrentMapCompute_thenReturnFreqMap() throws InterruptedException {
Map<Character, Integer> charMap = new ConcurrentHashMap<>();
Thread thread1 = new Thread(() -> {
IncrementMapValueWays ic = new IncrementMapValueWays();
ic.charFrequencyWithConcurrentMap("the quick brown", charMap);
});
Thread thread2 = new Thread(() -> {
IncrementMapValueWays ic = new IncrementMapValueWays();
ic.charFrequencyWithConcurrentMap(" fox jumps over the lazy dog", charMap);
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
Map<Character, Integer> expectedMap = getExpectedMap();
Assert.assertEquals(expectedMap, charMap);
}
private Map<Character, Integer> getExpectedMap() {
return Stream.of(
new Object[][] { { ' ', 8 }, { 'a', 1 }, { 'b', 1 }, { 'c', 1 }, { 'd', 1 }, { 'e', 3 }, { 'f', 1 }, { 'g', 1 }, { 'h', 2 }, { 'i', 1 }, { 'j', 1 }, { 'k', 1 }, { 'l', 1 }, { 'm', 1 }, { 'n', 1 }, { 'o', 4 }, { 'p', 1 }, { 'q', 1 }, { 'r', 2 },
{ 's', 1 }, { 't', 2 }, { 'u', 2 }, { 'v', 1 }, { 'w', 1 }, { 'x', 1 }, { 'y', 1 }, { 'z', 1 } })
.collect(Collectors.toMap(data -> (Character) data[0], data -> (Integer) data[1]));
}
}

View File

@ -0,0 +1,135 @@
package com.baeldung.map.readandwritefile;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.junit.After;
import org.junit.Test;
import org.junit.Before;
public class ReadAndWriteFileWithHashMapUnitTest {
private static final Map<Integer, Student> STUDENT_DATA = new HashMap<>();
static {
STUDENT_DATA.put(1234, new Student("Henry", "Winter"));
STUDENT_DATA.put(5678, new Student("Richard", "Papen"));
}
private File file;
@Before
public void createFile() throws IOException {
file = File.createTempFile("student", ".data");
}
@After
public void deleteFile() {
file.delete();
}
@Test
public void givenHashMap_whenWrittenAsPropertiesFile_thenReloadedMapIsIdentical() throws IOException {
// Given a map containing student data
Map<String, String> studentData = new HashMap<>();
studentData.put("student.firstName", "Henry");
studentData.put("student.lastName", "Winter");
// When converting to a Properties object and writing to a file
Properties props = new Properties();
props.putAll(studentData);
try (OutputStream output = Files.newOutputStream(file.toPath())) {
props.store(output, null);
}
// Then the map resulting from loading the Properties file is identical
Properties propsFromFile = new Properties();
try (InputStream input = Files.newInputStream(file.toPath())) {
propsFromFile.load(input);
}
Map<String, String> studentDataFromProps = propsFromFile.stringPropertyNames()
.stream()
.collect(Collectors.toMap(key -> key, props::getProperty));
assertThat(studentDataFromProps).isEqualTo(studentData);
}
@Test
public void givenHashMap_whenSerializedToFile_thenDeserializedMapIsIdentical() throws IOException, ClassNotFoundException {
// Given a map containing student data (STUDENT_DATA)
// When serializing the map to a file
try (FileOutputStream fileOutput = new FileOutputStream(file); ObjectOutputStream objectStream = new ObjectOutputStream(fileOutput)) {
objectStream.writeObject(STUDENT_DATA);
}
// Then read the file back into a map and check the contents
Map<Integer, Student> studentsFromFile;
try (FileInputStream fileReader = new FileInputStream(file); ObjectInputStream objectStream = new ObjectInputStream(fileReader)) {
studentsFromFile = (HashMap<Integer, Student>) objectStream.readObject();
}
assertThat(studentsFromFile).isEqualTo(STUDENT_DATA);
}
@Test
public void givenHashMap_whenSerializedToFileWithJackson_thenDeserializedMapIsIdentical() throws IOException {
// Given a map containing student data (STUDENT_DATA)
// When converting to JSON with Jackson and writing to a file
ObjectMapper mapper = new ObjectMapper();
try (FileOutputStream fileOutput = new FileOutputStream(file)) {
mapper.writeValue(fileOutput, STUDENT_DATA);
}
// Then deserialize the file back into a map and check that it's identical
Map<Integer, Student> mapFromFile;
try (FileInputStream fileInput = new FileInputStream(file)) {
// Create a TypeReference so we can deserialize the parameterized type
TypeReference<HashMap<Integer, Student>> mapType = new TypeReference<HashMap<Integer, Student>>() {
};
mapFromFile = mapper.readValue(fileInput, mapType);
}
assertThat(mapFromFile).isEqualTo(STUDENT_DATA);
}
@Test
public void givenHashMap_whenSerializedToFileWithGson_thenDeserializedMapIsIdentical() throws IOException {
// Given a map containing student data (STUDENT_DATA)
// When converting to JSON using Gson and writing to a file
Gson gson = new Gson();
try (FileWriter writer = new FileWriter(file)) {
gson.toJson(STUDENT_DATA, writer);
}
// Then deserialize the file back into a map and check that it's identical
Map<Integer, Student> studentsFromFile;
try (FileReader reader = new FileReader(file)) {
Type mapType = new TypeToken<HashMap<Integer, Student>>() {
}.getType();
studentsFromFile = gson.fromJson(reader, mapType);
}
assertThat(studentsFromFile).isEqualTo(STUDENT_DATA);
}
}

View File

@ -85,12 +85,12 @@
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<jcabi-aspects.version>0.22.6</jcabi-aspects.version> <jcabi-aspects.version>0.22.6</jcabi-aspects.version>
<aspectjrt.version>1.9.5</aspectjrt.version> <aspectjrt.version>1.9.20.1</aspectjrt.version>
<cactoos.version>0.43</cactoos.version> <cactoos.version>0.43</cactoos.version>
<ea-async.version>1.2.3</ea-async.version> <ea-async.version>1.2.3</ea-async.version>
<jcabi-maven-plugin.version>0.14.1</jcabi-maven-plugin.version> <jcabi-maven-plugin.version>0.14.1</jcabi-maven-plugin.version>
<aspectjtools.version>1.9.1</aspectjtools.version> <aspectjtools.version>1.9.20.1</aspectjtools.version>
<aspectjweaver.version>1.9.1</aspectjweaver.version> <aspectjweaver.version>1.9.20.1</aspectjweaver.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,126 @@
package com.baeldung.exceptions_completablefuture;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
public class CompletableFutureExceptionsHandlingUnitTest {
@ParameterizedTest
@MethodSource("parametersSource_handle")
void whenCompletableFutureIsScheduled_thenHandleStageIsAlwaysInvoked(int radius, long expected)
throws ExecutionException, InterruptedException {
long actual = CompletableFuture
.supplyAsync(() -> {
if (radius <= 0) {
throw new IllegalArgumentException("Supplied with non-positive radius '%d'");
}
return Math.round(Math.pow(radius, 2) * Math.PI);
})
.handle((result, ex) -> {
if (ex == null) {
return result;
} else {
return -1L;
}
})
.get();
Assertions.assertThat(actual).isEqualTo(expected);
}
@ParameterizedTest
@MethodSource("parametersSource_exceptionally")
void whenCompletableFutureIsScheduled_thenExceptionallyExecutedOnlyOnFailure(int a, int b, int c, long expected)
throws ExecutionException, InterruptedException {
long actual = CompletableFuture
.supplyAsync(() -> {
if (a <= 0 || b <= 0 || c <= 0) {
throw new IllegalArgumentException(String.format("Supplied with incorrect edge length [%s]", List.of(a, b, c)));
}
return a * b * c;
})
.exceptionally((ex) -> -1)
.get();
Assertions.assertThat(actual).isEqualTo(expected);
}
@ParameterizedTest
@MethodSource("parametersSource_exceptionally")
void givenCompletableFutureIsScheduled_whenHandleIsAlreadyPresent_thenExceptionallyIsNotExecuted(int a, int b, int c, long expected)
throws ExecutionException, InterruptedException {
long actual = CompletableFuture
.supplyAsync(() -> {
if (a <= 0 || b <= 0 || c <= 0) {
throw new IllegalArgumentException(String.format("Supplied with incorrect edge length [%s]", List.of(a, b, c)));
}
return a * b * c;
})
.handle((result, throwable) -> {
if (throwable != null) {
return -1;
}
return result;
})
.exceptionally((ex) -> {
System.exit(1);
return 0;
})
.get();
Assertions.assertThat(actual).isEqualTo(expected);
}
@ParameterizedTest
@MethodSource("parametersSource_whenComplete")
void whenCompletableFutureIsScheduled_thenWhenCompletedExecutedAlways(Double a, long expected, Class<Exception> ifAny) {
try {
CountDownLatch countDownLatch = new CountDownLatch(1);
long actual = CompletableFuture
.supplyAsync(() -> {
if (a.isNaN()) {
throw new IllegalArgumentException("Supplied value is NaN");
}
return Math.round(Math.pow(a, 2));
})
.whenComplete((result, exception) -> countDownLatch.countDown())
.get();
Assertions.assertThat(countDownLatch.await(20L, java.util.concurrent.TimeUnit.SECONDS));
Assertions.assertThat(actual).isEqualTo(expected);
} catch (Exception e) {
Assertions.assertThat(e.getClass()).isSameAs(ExecutionException.class);
Assertions.assertThat(e.getCause().getClass()).isSameAs(ifAny);
}
}
static Stream<Arguments> parametersSource_handle() {
return Stream.of(
Arguments.of(1, 3),
Arguments.of(-1, -1)
);
}
static Stream<Arguments> parametersSource_exceptionally() {
return Stream.of(
Arguments.of(1, 5, 5, 25),
Arguments.of(-1, 10, 15, -1)
);
}
static Stream<Arguments> parametersSource_whenComplete() {
return Stream.of(
Arguments.of(2d, 4, null),
Arguments.of(Double.NaN, 1, IllegalArgumentException.class)
);
}
}

View File

@ -11,4 +11,6 @@ This module contains articles about basic Java concurrency.
- [CompletableFuture and ThreadPool in Java](https://www.baeldung.com/java-completablefuture-threadpool) - [CompletableFuture and ThreadPool in Java](https://www.baeldung.com/java-completablefuture-threadpool)
- [CompletableFuture allOf().join() vs. CompletableFuture.join()](https://www.baeldung.com/java-completablefuture-allof-join) - [CompletableFuture allOf().join() vs. CompletableFuture.join()](https://www.baeldung.com/java-completablefuture-allof-join)
- [Retry Logic with CompletableFuture](https://www.baeldung.com/java-completablefuture-retry-logic) - [Retry Logic with CompletableFuture](https://www.baeldung.com/java-completablefuture-retry-logic)
- [Convert From List of CompletableFuture to CompletableFuture List](https://www.baeldung.com/java-completablefuture-list-convert)
- [Synchronize a Static Variable Among Different Threads](https://www.baeldung.com/java-synchronize-static-variable-different-threads)
- [[<-- Prev]](../core-java-concurrency-basic-2) - [[<-- Prev]](../core-java-concurrency-basic-2)

View File

@ -0,0 +1,30 @@
package com.baeldung.concurrent.synchronizestatic.atomicinteger;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Synchronizing static variable with AtomicInteger.
*/
public class Employee {
private static final AtomicInteger count = new AtomicInteger(0);
int id;
String name;
String title;
public Employee(int id, String name, String title) {
incrementCount();
this.id = id;
this.name = name;
this.title = title;
}
private static void incrementCount() {
count.incrementAndGet();
}
public static int getCount() {
return count.get();
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.concurrent.synchronizestatic.none;
/**
* No synchronization.
*/
public class Employee {
static int count;
int id;
String name;
String title;
public Employee(int id, String name, String title) {
incrementCount();
this.id = id;
this.name = name;
this.title = title;
}
private static void incrementCount() {
System.out.println("Count = " + ++count);
}
public static Integer getCount() {
return count;
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.concurrent.synchronizestatic.reentrantlock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Synchronizing static variable with a Reenatrant Lock.
*/
public class Employee {
private static final ReentrantLock lock = new ReentrantLock();
static int count;
int id;
String name;
String title;
public Employee(int id, String name, String title) {
incrementCount();
this.id = id;
this.name = name;
this.title = title;
}
private static void incrementCount() {
lock.lock();
try {
System.out.println("Count = " + ++count);
}
finally {
lock.unlock();
}
}
public static int getCount() {
lock.lock();
try {
return count;
}
finally {
lock.unlock();
}
}
}

View File

@ -0,0 +1,33 @@
package com.baeldung.concurrent.synchronizestatic.synchronizedblock;
/**
* Synchronizing static variable with a synchronized block.
*/
public class Employee {
private static final Object lock = new Object();
static int count;
int id;
String name;
String title;
public Employee(int id, String name, String title) {
incrementCount();
this.id = id;
this.name = name;
this.title = title;
}
private static void incrementCount() {
synchronized(lock) {
System.out.println("Count = " + ++count);
}
}
public static int getCount() {
synchronized(lock) {
return count;
}
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.concurrent.synchronizestatic.synchronizedclass;
/**
* Synchronizing static variable with a synchronized block.
*/
public class Employee
{
static int count;
int id;
String name;
String title;
public Employee(int id, String name, String title) {
incrementCount();
this.id = id;
this.name = name;
this.title = title;
}
private static void incrementCount() {
synchronized(Employee.class) {
System.out.println("Count = " + ++count);
}
}
public static int getCount() {
synchronized(Employee.class) {
return count;
}
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.concurrent.synchronizestatic.synchronizedmethod;
/**
* Synchronizing static variable with a synchronized method.
*/
public class Employee {
static int count;
int id;
String name;
String title;
public Employee(int id, String name, String title)
{
incrementCount();
this.id = id;
this.name = name;
this.title = title;
}
private static synchronized void incrementCount() {
System.out.println("Count = " + ++count);
}
public static synchronized int getCount() {
return count;
}
}

View File

@ -0,0 +1,90 @@
package com.baeldung.concurrent.synchronizestatic;
import org.junit.Test;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* The tests in this class show the output of creating multiple
* types of Employee classes in the <code>synchronizedstatic</code>
* package. When not synchronized the out will not be sequential;
* when it is synchronized the output will be in sequential.
*/
public class SychronizeStaticDataUnitTest {
private final Executor pool = Executors.newFixedThreadPool(4);
private final int numberToTest = 100;
@Test
public void whenNotSynchronized_thenDataOutOfOrder() {
System.out.println("No synchronization");
for(int i = 0; i < numberToTest; i++) {
int finalI = i;
pool.execute(() -> {
new com.baeldung.concurrent.synchronizestatic.none.Employee(finalI, "John", "Smith");
});
}
}
@Test
public void whenSynchronizedMethod_thenDataInOrder() {
System.out.println("Synchronization with synchronized method");
for(int i = 0; i < numberToTest; i++) {
int finalI = i;
pool.execute(() -> {
new com.baeldung.concurrent.synchronizestatic.synchronizedmethod.Employee(finalI, "John", "Smith");
});
}
}
@Test
public void whenSynchronizedClass_thenDataInOrder() {
System.out.println("Synchronization with synchronized block on class");
for(int i = 0; i < numberToTest; i++) {
int finalI = i;
pool.execute(() -> {
new com.baeldung.concurrent.synchronizestatic.synchronizedclass.Employee(finalI, "John", "Smith");
});
}
}
@Test
public void whenSynchronizedBlock_thenDataInOrder() {
System.out.println("Synchronization with synchronized block on a private object");
for(int i = 0; i < numberToTest; i++) {
int finalI = i;
pool.execute(() -> {
new com.baeldung.concurrent.synchronizestatic.synchronizedblock.Employee(finalI, "John", "Smith");
});
}
}
@Test
public void whenAtomicInteger_thenDataInOrder() {
// Not straight forward to test this because we cannot log/print
// and increment values in a synchronized fashion like other
// tests
}
@Test
public void whenReentrantLock_thenDataInOrder() {
System.out.println("Synchronization with ReentrantLock");
for(int i = 0; i < numberToTest; i++) {
int finalI = i;
pool.execute(() -> {
new com.baeldung.concurrent.synchronizestatic.reentrantlock.Employee(finalI, "John", "Smith");
});
}
}
}

View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>core-java-conditionals</artifactId> <artifactId>core-java-conditionals</artifactId>
<version>0.1.0-SNAPSHOT</version> <version>0.1.0-SNAPSHOT</version>
<name>core-java-compiler</name> <name>core-java-conditionals</name>
<packaging>jar</packaging> <packaging>jar</packaging>
<parent> <parent>

View File

@ -7,3 +7,4 @@
- [ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java) - [ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java)
- [System.console() vs. System.out](https://www.baeldung.com/java-system-console-vs-system-out) - [System.console() vs. System.out](https://www.baeldung.com/java-system-console-vs-system-out)
- [How to Log to the Console in Color](https://www.baeldung.com/java-log-console-in-color) - [How to Log to the Console in Color](https://www.baeldung.com/java-log-console-in-color)
- [Create Table Using ASCII in a Console in Java](https://www.baeldung.com/java-console-ascii-make-table)

View File

@ -29,6 +29,11 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>de.vandermeer</groupId>
<artifactId>asciitable</artifactId>
<version>${ascii.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -157,6 +162,7 @@
<maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version> <maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version>
<source.version>1.8</source.version> <source.version>1.8</source.version>
<target.version>1.8</target.version> <target.version>1.8</target.version>
<ascii.version>0.3.2</ascii.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,44 @@
package com.baeldung.consoletableoutput;
public class BodyMassIndex {
private String name;
private double height;
private double weight;
public BodyMassIndex(String name, double height, double weight) {
this.name = name;
this.height = height;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double calculate() {
double bmi = weight / (height * height);
String formattedBmi = String.format("%.2f", bmi);
return Double.parseDouble(formattedBmi);
}
}

View File

@ -0,0 +1,62 @@
package com.baeldung.consoletableoutput;
import java.util.ArrayList;
import java.util.List;
import de.vandermeer.asciitable.AsciiTable;
import de.vandermeer.skb.interfaces.transformers.textformat.TextAlignment;
public class BodyMassIndexApplication {
public static void main(String[] args) {
stringFormat();
asciiTable();
}
public static void stringFormat() {
List<BodyMassIndex> bodyMassIndices = new ArrayList<>();
bodyMassIndices.add(new BodyMassIndex("Tom", 1.8, 80));
bodyMassIndices.add(new BodyMassIndex("Elton", 1.9, 90));
bodyMassIndices.add(new BodyMassIndex("Harry", 1.9, 90));
bodyMassIndices.add(new BodyMassIndex("Hannah", 1.9, 90));
String leftAlignment = "| %-7s | %-7.2f | %-7.2f | %-5.2f |%n";
System.out.format("+---------+---------+---------+-------+%n");
System.out.format("| Name | Height | Weight | BMI |%n");
System.out.format("+---------+---------+---------+-------+%n");
for (BodyMassIndex bodyMassIndex : bodyMassIndices) {
System.out.format(leftAlignment, bodyMassIndex.getName(), bodyMassIndex.getHeight(), bodyMassIndex.getWeight(), bodyMassIndex.calculate());
System.out.format("+---------+---------+---------+-------+%n");
}
}
public static void asciiTable() {
List<BodyMassIndex> bodyMassIndices = new ArrayList<>();
bodyMassIndices.add(new BodyMassIndex("Tom", 1.8, 80));
bodyMassIndices.add(new BodyMassIndex("Elton", 1.9, 90));
bodyMassIndices.add(new BodyMassIndex("Harry", 1.9, 90));
bodyMassIndices.add(new BodyMassIndex("Hannah", 1.9, 90));
AsciiTable asciiTable = new AsciiTable();
asciiTable.addRule();
asciiTable.addRow("Name", "Height", "Weight", "BMI");
asciiTable.addRule();
for (BodyMassIndex bodyMassIndex : bodyMassIndices) {
asciiTable.addRow(bodyMassIndex.getName(), bodyMassIndex.getHeight(), bodyMassIndex.getWeight(), bodyMassIndex.calculate());
asciiTable.addRule();
}
asciiTable.setTextAlignment(TextAlignment.CENTER);
String render = asciiTable.render();
System.out.println(render);
}
}

View File

@ -54,7 +54,7 @@
</build> </build>
<properties> <properties>
<joda-time.version>2.10</joda-time.version> <joda-time.version>2.12.5</joda-time.version>
<hirondelle-date4j.version>RELEASE</hirondelle-date4j.version> <hirondelle-date4j.version>RELEASE</hirondelle-date4j.version>
<maven.compiler.source>1.9</maven.compiler.source> <maven.compiler.source>1.9</maven.compiler.source>
<maven.compiler.target>1.9</maven.compiler.target> <maven.compiler.target>1.9</maven.compiler.target>

View File

@ -47,7 +47,7 @@
</dependencies> </dependencies>
<properties> <properties>
<joda-time.version>2.10</joda-time.version> <joda-time.version>2.12.5</joda-time.version>
<hirondelle-date4j.version>1.5.1</hirondelle-date4j.version> <hirondelle-date4j.version>1.5.1</hirondelle-date4j.version>
<prettytime.version>3.2.7.Final</prettytime.version> <prettytime.version>3.2.7.Final</prettytime.version>
<time4j-base.version>5.9</time4j-base.version> <time4j-base.version>5.9</time4j-base.version>

View File

@ -11,4 +11,6 @@ This module contains articles about date operations in Java.
- [Getting Yesterdays Date in Java](https://www.baeldung.com/java-find-yesterdays-date) - [Getting Yesterdays Date in Java](https://www.baeldung.com/java-find-yesterdays-date)
- [How to Get the Start and End Dates of a Year Using Java](https://www.baeldung.com/java-date-year-start-end) - [How to Get the Start and End Dates of a Year Using Java](https://www.baeldung.com/java-date-year-start-end)
- [Convert Between Java LocalDate and Epoch](https://www.baeldung.com/java-localdate-epoch) - [Convert Between Java LocalDate and Epoch](https://www.baeldung.com/java-localdate-epoch)
- [Get First Date of Current Month in Java](https://www.baeldung.com/java-current-month-start-date)
- [Time Conversions Using TimeUnit](https://www.baeldung.com/java-timeunit-conversion)
- [[<-- Prev]](/core-java-modules/core-java-date-operations-2) - [[<-- Prev]](/core-java-modules/core-java-date-operations-2)

View File

@ -28,7 +28,6 @@
<properties> <properties>
<joda-time.version>2.12.5</joda-time.version> <joda-time.version>2.12.5</joda-time.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,105 @@
package com.baeldung.timeunitconversions;
import org.junit.jupiter.api.Test;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
class TimeUnitConversionsUnitTest {
@Test
void givenSeconds_whenConvertToMinutes_thenCorrect() {
int input = 60;
long minutes = TimeUnit.MINUTES.convert(input, TimeUnit.SECONDS);
assertThat(minutes).isEqualTo(1);
}
@Test
void givenMinutes_whenConvertToSeconds_thenCorrect() {
int input = 1;
long seconds = TimeUnit.SECONDS.convert(input, TimeUnit.MINUTES);
assertThat(seconds).isEqualTo(60);
}
@Test
void givenSeconds_whenToMinutes_thenCorrect() {
int input = 60;
long minutes = TimeUnit.SECONDS.toMinutes(input);
assertThat(minutes).isEqualTo(1);
}
@Test
void givenMinutes_whenToSeconds_thenCorrect() {
int input = 1;
long seconds = TimeUnit.MINUTES.toSeconds(input);
assertThat(seconds).isEqualTo(60);
}
@Test
void givenNegativeInput_whenToMinutes_thenCorrect() {
int input = -60;
long minutes = TimeUnit.SECONDS.toMinutes(input);
assertThat(minutes).isEqualTo(-1);
}
@Test
void givenNonTotalInput_whenToMinutes_thenCorrectTotalResultWithDecimalTruncate() {
long positiveUnder = TimeUnit.SECONDS.toMinutes(59);
long positiveAbove = TimeUnit.SECONDS.toMinutes(61);
assertThat(positiveUnder).isEqualTo(0);
assertThat(positiveAbove).isEqualTo(1);
}
@Test
void givenNonTotalNegativeInput_whenToMinutes_thenCorrectTotalResultWithDecimalTruncate() {
long negativeUnder = TimeUnit.SECONDS.toMinutes(-59);
long negativeAbove = TimeUnit.SECONDS.toMinutes(-61);
assertThat(negativeUnder).isEqualTo(0);
assertThat(negativeAbove).isEqualTo(-1);
}
@Test
void givenOverflowInput_whenToMillis_thenTruncatedToLimit() {
long maxMillis = TimeUnit.DAYS.toMillis(Long.MAX_VALUE);
long minMillis = TimeUnit.DAYS.toMillis(Long.MIN_VALUE);
assertThat(maxMillis).isEqualTo(Long.MAX_VALUE);
assertThat(minMillis).isEqualTo(Long.MIN_VALUE);
}
@Test
void givenInput_whenExtractFineTimeUnits_thenCorrect() {
long inputSeconds = 3672;
long hours = TimeUnit.SECONDS.toHours(inputSeconds);
long secondsRemainingAfterHours = inputSeconds - TimeUnit.HOURS.toSeconds(hours);
long minutes = TimeUnit.SECONDS.toMinutes(secondsRemainingAfterHours);
long seconds = secondsRemainingAfterHours - TimeUnit.MINUTES.toSeconds(minutes);
assertThat(hours).isEqualTo(1);
assertThat(minutes).isEqualTo(1);
assertThat(seconds).isEqualTo(12);
assertThat(inputSeconds).isEqualTo(
(hours * 60 * 60) +
(minutes * 60) +
(seconds)
);
}
}

View File

@ -54,7 +54,7 @@
</build> </build>
<properties> <properties>
<joda-time.version>2.10</joda-time.version> <joda-time.version>2.12.5</joda-time.version>
<maven.compiler.source>1.9</maven.compiler.source> <maven.compiler.source>1.9</maven.compiler.source>
<maven.compiler.target>1.9</maven.compiler.target> <maven.compiler.target>1.9</maven.compiler.target>
</properties> </properties>

View File

@ -0,0 +1,31 @@
package com.baeldung.timestamptolong;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
public class TimestampToLong {
public long usingSimpleDateFormat(String timestampString) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(timestampString);
String currentDateString = sdf.format(date);
return sdf.parse(currentDateString).getTime();
}
public long usingInstantClass(String timestampString) {
Instant instant = LocalDateTime.parse(timestampString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
.atZone(ZoneId.systemDefault())
.toInstant();
return instant.toEpochMilli();
}
public long usingJava8DateTime(String timestampString) {
LocalDateTime localDateTime = LocalDateTime.parse(timestampString.replace(" ", "T"));
return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
}

View File

@ -0,0 +1,42 @@
package com.baeldung.timestamptolocaldatetime;
import org.joda.time.DateTimeZone;
import org.junit.Test;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import static org.junit.Assert.assertEquals;
public class TimeToLocalDateTimeUnitTest {
private static final long timestampInMillis = 1700010123000L;
private static final String expectedTimestampString = "2023-11-15 01:02:03";
@Test
public void givenTimestamp_whenConvertingToLocalDateTime_thenConvertSuccessfully() {
Instant instant = Instant.ofEpochMilli(timestampInMillis);
LocalDateTime localDateTime =
LocalDateTime.ofInstant(instant, ZoneId.of("UTC"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = localDateTime.format(formatter);
assertEquals(expectedTimestampString, formattedDateTime);
}
@Test
public void givenJodaTime_whenGettingTimestamp_thenConvertToLong() {
DateTime dateTime = new DateTime(timestampInMillis, DateTimeZone.UTC);
org.joda.time.LocalDateTime localDateTime = dateTime.toLocalDateTime();
org.joda.time.format.DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
String actualTimestamp = formatter.print(localDateTime);
assertEquals(expectedTimestampString, actualTimestamp);
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.timestamptolong;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import static org.junit.Assert.assertEquals;
public class TimestampToLongUnitTest {
private static final String timestampString = "2023-11-15 01:02:03";
@Test
public void givenSimpleDateFormat_whenFormattingDate_thenConvertToLong() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(timestampString);
String currentDateString = sdf.format(date);
long actualTimestamp = sdf.parse(currentDateString).getTime();
assertEquals(1700010123000L, actualTimestamp);
}
@Test
public void givenInstantClass_whenGettingTimestamp_thenConvertToLong() {
Instant instant = LocalDateTime.parse(timestampString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
.atZone(ZoneId.systemDefault())
.toInstant();
long actualTimestamp = instant.toEpochMilli();
assertEquals(1700010123000L, actualTimestamp);
}
@Test
public void givenJava8DateTime_whenGettingTimestamp_thenConvertToLong() {
LocalDateTime localDateTime = LocalDateTime.parse(timestampString.replace(" ", "T"));
long actualTimestamp = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
assertEquals(1700010123000L, actualTimestamp);
}
}

View File

@ -64,7 +64,7 @@
</build> </build>
<properties> <properties>
<commons-validator.version>1.6</commons-validator.version> <commons-validator.version>1.7</commons-validator.version>
<joda-time.version>2.12.5</joda-time.version> <joda-time.version>2.12.5</joda-time.version>
<hirondelle-date4j.version>RELEASE</hirondelle-date4j.version> <hirondelle-date4j.version>RELEASE</hirondelle-date4j.version>
<maven.compiler.source>1.9</maven.compiler.source> <maven.compiler.source>1.9</maven.compiler.source>

View File

@ -6,6 +6,7 @@ import java.time.Instant;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.TimeZone;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.junit.Test; import org.junit.Test;
@ -17,7 +18,7 @@ public class FormatInstantUnitTest {
@Test @Test
public void givenInstant_whenUsingDateTimeFormatter_thenFormat() { public void givenInstant_whenUsingDateTimeFormatter_thenFormat() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_FORMAT) DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_FORMAT)
.withZone(ZoneId.systemDefault()); .withZone(TimeZone.getTimeZone("UTC").toZoneId());
Instant instant = Instant.parse("2022-02-15T18:35:24.00Z"); Instant instant = Instant.parse("2022-02-15T18:35:24.00Z");
String formattedInstant = formatter.format(instant); String formattedInstant = formatter.format(instant);

View File

@ -4,3 +4,4 @@
- [Introduction to Javadoc](http://www.baeldung.com/javadoc) - [Introduction to Javadoc](http://www.baeldung.com/javadoc)
- [Code Snippets in Java API Documentation](https://www.baeldung.com/java-doc-code-snippets) - [Code Snippets in Java API Documentation](https://www.baeldung.com/java-doc-code-snippets)
- [How to Document Generic Type Parameters in Javadoc](https://www.baeldung.com/java-javadoc-generic-type-parameters)

View File

@ -51,7 +51,6 @@
<properties> <properties>
<mockito-inline.version>3.8.0</mockito-inline.version> <mockito-inline.version>3.8.0</mockito-inline.version>
<assertj.version>3.22.0</assertj.version> <assertj.version>3.22.0</assertj.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
<vavr.version>0.10.4</vavr.version> <vavr.version>0.10.4</vavr.version>
</properties> </properties>

View File

@ -35,7 +35,6 @@
<properties> <properties>
<mockito-inline.version>3.8.0</mockito-inline.version> <mockito-inline.version>3.8.0</mockito-inline.version>
<assertj.version>3.22.0</assertj.version> <assertj.version>3.22.0</assertj.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
<vavr.version>0.10.4</vavr.version> <vavr.version>0.10.4</vavr.version>
</properties> </properties>

View File

@ -1,2 +1,3 @@
## Relevant Articles ## Relevant Articles
- [Convert Hex to RGB Using Java](https://www.baeldung.com/java-convert-hex-to-rgb) - [Convert Hex to RGB Using Java](https://www.baeldung.com/java-convert-hex-to-rgb)
- [Convert a Hex String to an Integer in Java](https://www.baeldung.com/java-convert-hex-string-to-integer)

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