Merge branch 'eugenp:master' into JAVA-26380

This commit is contained in:
anuragkumawat 2023-11-03 18:39:01 +05:30 committed by GitHub
commit c7a4c2f623
224 changed files with 3737 additions and 222 deletions

View File

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

View File

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

View File

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

View File

@ -0,0 +1,113 @@
package com.baeldung.rounddate;
import java.time.DayOfWeek;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
public class RoundDate {
public static Date getDate(int year, int month, int day, int hour, int minute) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
public static Date roundToDay(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
public static Date roundToNearestUnit(Date date, int unit) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
switch (unit) {
case Calendar.HOUR:
int minute = calendar.get(Calendar.MINUTE);
if (minute >= 0 && minute < 15) {
calendar.set(Calendar.MINUTE, 0);
} else if (minute >= 15 && minute < 45) {
calendar.set(Calendar.MINUTE, 30);
} else {
calendar.set(Calendar.MINUTE, 0);
calendar.add(Calendar.HOUR_OF_DAY, 1);
}
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
break;
case Calendar.DAY_OF_MONTH:
int hour = calendar.get(Calendar.HOUR_OF_DAY);
if (hour >= 12) {
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
break;
case Calendar.MONTH:
int day = calendar.get(Calendar.DAY_OF_MONTH);
if (day >= 15) {
calendar.add(Calendar.MONTH, 1);
}
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
break;
}
return calendar.getTime();
}
public static LocalDateTime roundToStartOfMonthUsingLocalDateTime(LocalDateTime dateTime) {
return dateTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
}
public static LocalDateTime roundToEndOfWeekUsingLocalDateTime(LocalDateTime dateTime) {
return dateTime.with(TemporalAdjusters.next(DayOfWeek.SATURDAY))
.withHour(23)
.withMinute(59)
.withSecond(59)
.withNano(999);
}
public static ZonedDateTime roundToStartOfMonthUsingZonedDateTime(ZonedDateTime dateTime) {
return dateTime.withDayOfMonth(1)
.withHour(0)
.withMinute(0)
.withSecond(0)
.with(ChronoField.MILLI_OF_SECOND, 0)
.with(ChronoField.MICRO_OF_SECOND, 0)
.with(ChronoField.NANO_OF_SECOND, 0);
}
public static ZonedDateTime roundToEndOfWeekUsingZonedDateTime(ZonedDateTime dateTime) {
return dateTime.with(TemporalAdjusters.next(DayOfWeek.SATURDAY))
.withHour(23)
.withMinute(59)
.withSecond(59)
.with(ChronoField.MILLI_OF_SECOND, 999)
.with(ChronoField.MICRO_OF_SECOND, 999)
.with(ChronoField.NANO_OF_SECOND, 999);
}
}

View File

@ -0,0 +1,63 @@
package com.baeldung.rounddate;
import org.junit.Test;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import static org.junit.Assert.assertEquals;
public class DateRoundingUnitTest {
@Test
public void givenDate_whenRoundToDay_thenBeginningOfDay() {
Date date = RoundDate.getDate(2023, Calendar.JANUARY, 27, 14, 30);
Date result = RoundDate.roundToDay(date);
assertEquals(RoundDate.getDate(2023, Calendar.JANUARY, 27, 0, 0), result);
}
@Test
public void givenDate_whenRoundToNearestUnit_thenNearestUnit() {
Date date = RoundDate.getDate(2023, Calendar.JANUARY, 27, 14, 12);
Date result = RoundDate.roundToNearestUnit(date, Calendar.DAY_OF_MONTH);
Date expected = RoundDate.getDate(2023, Calendar.JANUARY, 28, 0, 0);
assertEquals(expected, result);
}
@Test
public void givenLocalDateTime_whenRoundToStartOfMonth_thenStartOfMonth() {
LocalDateTime dateTime = LocalDateTime.of(2023, 1, 27, 14, 12);
LocalDateTime result = RoundDate.roundToStartOfMonthUsingLocalDateTime(dateTime);
LocalDateTime expected = LocalDateTime.of(2023, 1, 1, 0, 0, 0);
assertEquals(expected, result);
}
@Test
public void givenZonedDateTime_whenRoundToStartOfMonth_thenStartOfMonth() {
ZonedDateTime dateTime = ZonedDateTime.of(2023, 1, 27, 14, 12, 0, 0, ZoneId.systemDefault());
ZonedDateTime result = RoundDate.roundToStartOfMonthUsingZonedDateTime(dateTime);
ZonedDateTime expected = ZonedDateTime.of(2023, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault());
assertEquals(expected, result);
}
@Test
public void givenLocalDateTime_whenRoundToEndOfWeek_thenEndOfWeek() {
LocalDateTime dateTime = LocalDateTime.of(2023, 1, 27, 14, 12);
LocalDateTime result = RoundDate.roundToEndOfWeekUsingLocalDateTime(dateTime);
LocalDateTime expected = LocalDateTime.of(2023, 1, 28, 23, 59, 59, 999);
assertEquals(expected, result);
}
@Test
public void givenZonedDateTime_whenRoundToEndOfWeek_thenEndOfWeek() {
ZonedDateTime dateTime = ZonedDateTime.of(2023, 1, 27, 14, 12, 0, 0, ZoneId.systemDefault());
ZonedDateTime result = RoundDate.roundToEndOfWeekUsingZonedDateTime(dateTime);
ZonedDateTime expected = ZonedDateTime.of(2023, 1, 28, 23, 59, 59, 999, ZoneId.systemDefault());
assertEquals(expected, result);
}
}

View File

@ -0,0 +1,48 @@
package com.baeldung.spliterator;
import java.util.List;
import java.util.Spliterator;
import java.util.function.Consumer;
public class CustomSpliterator implements Spliterator<Integer> {
private final List<Integer> elements;
private int currentIndex;
public CustomSpliterator(List<Integer> elements) {
this.elements = elements;
this.currentIndex = 0;
}
@Override
public boolean tryAdvance(Consumer<? super Integer> action) {
if (currentIndex < elements.size()) {
action.accept(elements.get(currentIndex));
currentIndex++;
return true;
}
return false;
}
@Override
public Spliterator<Integer> trySplit() {
int currentSize = elements.size() - currentIndex;
if (currentSize < 2) {
return null;
}
int splitIndex = currentIndex + currentSize / 2;
CustomSpliterator newSpliterator = new CustomSpliterator(elements.subList(currentIndex, splitIndex));
currentIndex = splitIndex;
return newSpliterator;
}
@Override
public long estimateSize() {
return elements.size() - currentIndex;
}
@Override
public int characteristics() {
return ORDERED | SIZED | SUBSIZED | NONNULL;
}
}

View File

@ -1,12 +0,0 @@
package com.baeldung.spliterator;
import java.util.stream.Stream;
public class Executor {
public static int countAutors(Stream<Author> stream) {
RelatedAuthorCounter wordCounter = stream.reduce(new RelatedAuthorCounter(0, true),
RelatedAuthorCounter::accumulate, RelatedAuthorCounter::combine);
return wordCounter.getCounter();
}
}

View File

@ -1,27 +0,0 @@
package com.baeldung.spliterator;
public class RelatedAuthorCounter {
private final int counter;
private final boolean isRelated;
public RelatedAuthorCounter(int counter, boolean isRelated) {
this.counter = counter;
this.isRelated = isRelated;
}
public RelatedAuthorCounter accumulate(Author author) {
if (author.getRelatedArticleId() == 0) {
return isRelated ? this : new RelatedAuthorCounter(counter, true);
} else {
return isRelated ? new RelatedAuthorCounter(counter + 1, false) : this;
}
}
public RelatedAuthorCounter combine(RelatedAuthorCounter RelatedAuthorCounter) {
return new RelatedAuthorCounter(counter + RelatedAuthorCounter.counter, RelatedAuthorCounter.isRelated);
}
public int getCounter() {
return counter;
}
}

View File

@ -1,49 +0,0 @@
package com.baeldung.spliterator;
import java.util.List;
import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public class RelatedAuthorSpliterator implements Spliterator<Author> {
private final List<Author> list;
AtomicInteger current = new AtomicInteger();
public RelatedAuthorSpliterator(List<Author> list) {
this.list = list;
}
@Override
public boolean tryAdvance(Consumer<? super Author> action) {
action.accept(list.get(current.getAndIncrement()));
return current.get() < list.size();
}
@Override
public Spliterator<Author> trySplit() {
int currentSize = list.size() - current.get();
if (currentSize < 10) {
return null;
}
for (int splitPos = currentSize / 2 + current.intValue(); splitPos < list.size(); splitPos++) {
if (list.get(splitPos).getRelatedArticleId() == 0) {
Spliterator<Author> spliterator = new RelatedAuthorSpliterator(list.subList(current.get(), splitPos));
current.set(splitPos);
return spliterator;
}
}
return null;
}
@Override
public long estimateSize() {
return list.size() - current.get();
}
@Override
public int characteristics() {
return CONCURRENT;
}
}

View File

@ -6,10 +6,10 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Spliterator; import java.util.Spliterator;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -18,22 +18,50 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class ExecutorUnitTest { public class ExecutorUnitTest {
Article article; Article article;
Stream<Author> stream;
Spliterator<Author> spliterator;
@Before @Before
public void init() { public void init() {
article = new Article(Arrays.asList(new Author("Ahmad", 0), new Author("Eugen", 0), new Author("Alice", 1), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), article = new Article(Arrays.asList(new Author("Ahmad", 0), new Author("Eugen", 0), new Author("Alice", 1), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0),
new Author("Alice", 1), new Author("Mike", 0), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Alice", 1), new Author("Mike", 0), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1),
new Author("Mike", 0), new Author("Michał", 0), new Author("Loredana", 1)), 0); new Author("Mike", 0), new Author("Michał", 0), new Author("Loredana", 1)), 0);
spliterator = new RelatedAuthorSpliterator(article.getListOfAuthors());
} }
@Test @Test
public void givenAstreamOfAuthors_whenProcessedInParallelWithCustomSpliterator_coubtProducessRightOutput() { public void givenAStreamOfIntegers_whenProcessedSequentialCustomSpliterator_countProducesRightOutput() {
Stream<Author> stream2 = StreamSupport.stream(spliterator, true); List<Integer> numbers = new ArrayList<>();
assertThat(Executor.countAutors(stream2.parallel())).isEqualTo(9); numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
CustomSpliterator customSpliterator = new CustomSpliterator(numbers);
AtomicInteger sum = new AtomicInteger();
customSpliterator.forEachRemaining(sum::addAndGet);
assertThat(sum.get()).isEqualTo(15);
}
@Test
public void givenAStreamOfIntegers_whenProcessedInParallelWithCustomSpliterator_countProducesRightOutput() {
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
CustomSpliterator customSpliterator = new CustomSpliterator(numbers);
// Create a ForkJoinPool for parallel processing
ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
AtomicInteger sum = new AtomicInteger(0);
// Process elements in parallel using parallelStream
forkJoinPool.submit(() -> customSpliterator.forEachRemaining(sum::addAndGet)).join();
assertThat(sum.get()).isEqualTo(15);
} }
@Test @Test
@ -43,9 +71,7 @@ public class ExecutorUnitTest {
.collect(Collectors.toList()); .collect(Collectors.toList());
Spliterator<Article> spliterator = articles.spliterator(); Spliterator<Article> spliterator = articles.spliterator();
while (spliterator.tryAdvance(article -> article.setName(article.getName() while(spliterator.tryAdvance(article -> article.setName(article.getName().concat("- published by Baeldung"))));
.concat("- published by Baeldung"))))
;
articles.forEach(article -> assertThat(article.getName()).isEqualTo("Java- published by Baeldung")); articles.forEach(article -> assertThat(article.getName()).isEqualTo("Java- published by Baeldung"));
} }

View File

@ -57,5 +57,9 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<properties>
<maven.compiler.release>11</maven.compiler.release>
</properties>
</project> </project>

View File

@ -0,0 +1,29 @@
package com.baeldung.arraycompare;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class ArraysCompareUnitTest {
@Test
void givenSameContents_whenCompare_thenCorrect() {
String[] array1 = new String[] { "A", "B", "C" };
String[] array2 = new String[] { "A", "B", "C" };
assertThat(Arrays.compare(array1, array2)).isEqualTo(0);
}
@Test
void givenDifferentContents_whenCompare_thenDifferent() {
String[] array1 = new String[] { "A", "B", "C" };
String[] array2 = new String[] { "A", "C", "B", "D" };
assertThat(Arrays.compare(array1, array2)).isLessThan(0);
assertThat(Arrays.compare(array2, array1)).isGreaterThan(0);
assertThat(Arrays.compare(array1, null)).isGreaterThan(0);
}
}

View File

@ -3,3 +3,4 @@
This module contains articles about Java array fundamentals. They assume no previous background knowledge on working with arrays. This module contains articles about Java array fundamentals. They assume no previous background knowledge on working with arrays.
### Relevant Articles: ### Relevant Articles:
- [Arrays mismatch() Method in Java](https://www.baeldung.com/java-arrays-mismatch)

View File

@ -7,4 +7,5 @@
- [Creating Custom Iterator in Java](https://www.baeldung.com/java-creating-custom-iterator) - [Creating Custom Iterator in Java](https://www.baeldung.com/java-creating-custom-iterator)
- [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)
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-4) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-4)

View File

@ -1,2 +1,3 @@
## 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 Hashmap to CSV File](https://www.baeldung.com/java-write-hashmap-csv)

View File

@ -79,5 +79,18 @@
<version>1.5</version> <version>1.5</version>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
--add-opens java.base/java.util=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project> </project>

View File

@ -0,0 +1,85 @@
package com.baeldung.map.linkedhashmapfirstandlastentry;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class GetFirstAndLastEntryFromLinkedHashMapUnitTest {
private static final LinkedHashMap<String, String> THE_MAP = new LinkedHashMap<>();
static {
THE_MAP.put("key one", "a1 b1 c1");
THE_MAP.put("key two", "a2 b2 c2");
THE_MAP.put("key three", "a3 b3 c3");
THE_MAP.put("key four", "a4 b4 c4");
}
@Test
void whenIteratingEntrySet_thenGetExpectedResult() {
Entry<String, String> firstEntry = THE_MAP.entrySet().iterator().next();
assertEquals("key one", firstEntry.getKey());
assertEquals("a1 b1 c1", firstEntry.getValue());
Entry<String, String> lastEntry = null;
Iterator<Entry<String, String>> it = THE_MAP.entrySet().iterator();
while (it.hasNext()) {
lastEntry = it.next();
}
assertNotNull(lastEntry);
assertEquals("key four", lastEntry.getKey());
assertEquals("a4 b4 c4", lastEntry.getValue());
}
@Test
void whenConvertingEntriesToArray_thenGetExpectedResult() {
Entry<String, String>[] theArray = new Entry[THE_MAP.size()];
THE_MAP.entrySet().toArray(theArray);
Entry<String, String> firstEntry = theArray[0];
assertEquals("key one", firstEntry.getKey());
assertEquals("a1 b1 c1", firstEntry.getValue());
Entry<String, String> lastEntry = theArray[THE_MAP.size() - 1];
assertEquals("key four", lastEntry.getKey());
assertEquals("a4 b4 c4", lastEntry.getValue());
}
@Test
void whenUsingStreamAPI_thenGetExpectedResult() {
Entry<String, String> firstEntry = THE_MAP.entrySet().stream().findFirst().get();
assertEquals("key one", firstEntry.getKey());
assertEquals("a1 b1 c1", firstEntry.getValue());
Entry<String, String> lastEntry = THE_MAP.entrySet().stream().skip(THE_MAP.size() - 1).findFirst().get();
assertNotNull(lastEntry);
assertEquals("key four", lastEntry.getKey());
assertEquals("a4 b4 c4", lastEntry.getValue());
}
@Test
void whenUsingReflection_thenGetExpectedResult() throws NoSuchFieldException, IllegalAccessException {
Field head = THE_MAP.getClass().getDeclaredField("head");
head.setAccessible(true);
Entry<String, String> firstEntry = (Entry<String, String>) head.get(THE_MAP);
assertEquals("key one", firstEntry.getKey());
assertEquals("a1 b1 c1", firstEntry.getValue());
Field tail = THE_MAP.getClass().getDeclaredField("tail");
tail.setAccessible(true);
Entry<String, String> lastEntry = (Entry<String, String>) tail.get(THE_MAP);
assertEquals("key four", lastEntry.getKey());
assertEquals("a4 b4 c4", lastEntry.getValue());
}
}

View File

@ -10,4 +10,5 @@ This module contains articles about basic Java concurrency.
- [Returning a Value After Finishing Threads Job in Java](https://www.baeldung.com/java-return-value-after-thread-finish) - [Returning a Value After Finishing Threads Job in Java](https://www.baeldung.com/java-return-value-after-thread-finish)
- [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)
- [[<-- Prev]](../core-java-concurrency-basic-2) - [[<-- Prev]](../core-java-concurrency-basic-2)

View File

@ -0,0 +1,100 @@
package com.baeldung.concurrent.completablefuturelist;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;
public class Application {
ScheduledExecutorService asyncOperationEmulation;
Application initialize() {
asyncOperationEmulation = Executors.newScheduledThreadPool(10);
return this;
}
CompletableFuture<String> asyncOperation(String operationId) {
CompletableFuture<String> cf = new CompletableFuture<>();
asyncOperationEmulation.submit(() -> {
// The following lines simulate an exception happening on the 567th operation
// if (operationId.endsWith("567")) {
// cf.completeExceptionally(new Exception("Error on operation " + operationId));
// return;
// }
try {
Thread.sleep(100);
cf.complete(operationId);
} catch (InterruptedException e) {
System.err.println("Thread interrupted error");
cf.completeExceptionally(e);
}
});
return cf;
}
void startNaive() {
List<CompletableFuture<String>> futures = new ArrayList<>();
for (int i = 1; i <= 1000; i++) {
String operationId = "Naive-Operation-" + i;
futures.add(asyncOperation(operationId));
}
CompletableFuture<List<String>> aggregate = CompletableFuture.completedFuture(new ArrayList<>());
for (CompletableFuture<String> future : futures) {
aggregate = aggregate.thenCompose(list -> {
try {
list.add(future.get());
return CompletableFuture.completedFuture(list);
} catch (Exception e) {
final CompletableFuture<List<String>> excFuture = new CompletableFuture<>();
excFuture.completeExceptionally(e);
return excFuture;
}
});
}
try {
final List<String> results = aggregate.join();
System.out.println("Printing first 10 results");
for (int i = 0; i < 10; i++) {
System.out.println("Finished " + results.get(i));
}
} finally {
close();
}
}
void start() {
List<CompletableFuture<String>> futures = new ArrayList<>();
for (int i = 1; i <= 1000; i++) {
String operationId = "Operation-" + i;
futures.add(asyncOperation(operationId));
}
CompletableFuture<?>[] futuresArray = futures.toArray(new CompletableFuture<?>[0]);
CompletableFuture<List<String>> listFuture = CompletableFuture.allOf(futuresArray).thenApply(v -> futures.stream().map(CompletableFuture::join).collect(Collectors.toList()));
try {
final List<String> results = listFuture.join();
System.out.println("Printing first 10 results");
for (int i = 0; i < 10; i++) {
System.out.println("Finished " + results.get(i));
}
} finally {
close();
}
}
void close() {
asyncOperationEmulation.shutdownNow();
}
public static void main(String[] args) {
new Application().initialize()
// Switch between .startNaive() and .start() to test both implementations
// .startNaive();
.start();
}
}

View File

@ -12,6 +12,7 @@ This module contains articles about Java Concurrency that are also part of an Eb
- [Guide to the Volatile Keyword in Java](https://www.baeldung.com/java-volatile) - [Guide to the Volatile Keyword in Java](https://www.baeldung.com/java-volatile)
- [A Guide to the Java ExecutorService](https://www.baeldung.com/java-executor-service-tutorial) - [A Guide to the Java ExecutorService](https://www.baeldung.com/java-executor-service-tutorial)
- [Guide To CompletableFuture](https://www.baeldung.com/java-completablefuture) - [Guide To CompletableFuture](https://www.baeldung.com/java-completablefuture)
- [How To Manage Timeout for CompletableFuture](https://www.baeldung.com/java-completablefuture-timeout)
### NOTE: ### NOTE:

View File

@ -12,6 +12,15 @@
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
</parent> </parent>
<dependencies>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build> <build>
<finalName>core-java-concurrency-simple</finalName> <finalName>core-java-concurrency-simple</finalName>
<resources> <resources>

View File

@ -0,0 +1,182 @@
package com.baeldung.concurrent.completablefuture;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.*;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class CompletableFutureTimeoutUnitTest {
private WireMockServer wireMockServer;
private ScheduledExecutorService executorService;
private static final int DEFAULT_TIMEOUT = 1000; //1 seconds
private static final String DEFAULT_PRODUCT = """
{
"products": [
{
"id": 2,
"title": "iPhone X",
"description": "SIM-Free, Model A19211 6.5-inch Super Retina HD display with OLED technology A12 Bionic chip with ...",
"price": 899,
"discountPercentage": 0.0,
"rating": 4.44,
"stock": 34,
"brand": "Apple",
"category": "smartphones"
},
{
"id": 3,
"title": "Samsung Universe 9",
"description": "Samsung's new variant which goes beyond Galaxy to the Universe",
"price": 1249,
"discountPercentage": 0.0,
"rating": 4.09,
"stock": 36,
"brand": "Samsung",
"category": "smartphones"
}
],
"total": 2
}""";
private static final String PRODUCT_OFFERS = """
{
"products": [
{
"id": 1,
"title": "iPhone 9",
"description": "An apple mobile which is nothing like apple",
"price": 549,
"discountPercentage": 12.96,
"rating": 4.69,
"stock": 94,
"brand": "Apple",
"category": "smartphones"
},
{
"id": 2,
"title": "iPhone X",
"description": "SIM-Free, Model A19211 6.5-inch Super Retina HD display with OLED technology A12 Bionic chip with ...",
"price": 899,
"discountPercentage": 17.94,
"rating": 4.44,
"stock": 34,
"brand": "Apple",
"category": "smartphones"
},
{
"id": 3,
"title": "Samsung Universe 9",
"description": "Samsung's new variant which goes beyond Galaxy to the Universe",
"price": 1249,
"discountPercentage": 15.46,
"rating": 4.09,
"stock": 36,
"brand": "Samsung",
"category": "smartphones"
},
{
"id": 4,
"title": "OPPOF19",
"description": "OPPO F19 is officially announced on April 2021.",
"price": 280,
"discountPercentage": 17.91,
"rating": 4.3,
"stock": 123,
"brand": "OPPO",
"category": "smartphones"
},
{
"id": 5,
"title": "Huawei P30",
"description": "Huaweis re-badged P30 Pro New Edition was officially unveiled yesterday in Germany and now the device has made its way to the UK.",
"price": 499,
"discountPercentage": 10.58,
"rating": 4.09,
"stock": 32,
"brand": "Huawei",
"category": "smartphones"
}
],
"total": 5
}""";
@BeforeAll
void setUp() {
wireMockServer = new WireMockServer(8080);
wireMockServer.start();
WireMock.configureFor("localhost", 8080);
stubFor(get(urlEqualTo("/api/dummy"))
.willReturn(aResponse()
.withFixedDelay(5000) // must be > DEFAULT_TIMEOUT for a timeout to occur.
.withBody(PRODUCT_OFFERS)));
executorService = Executors.newScheduledThreadPool(1);
}
@AfterAll
void tearDown() {
executorService.shutdown();
wireMockServer.stop();
}
private CompletableFuture<String> fetchProductData() {
return CompletableFuture.supplyAsync(() -> {
try {
URL url = new URL("http://localhost:8080/api/dummy");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
return response.toString();
} finally {
connection.disconnect();
}
} catch (IOException e) {
return "";
}
});
}
@Test
void whenorTimeout_thenGetThrow() {
CompletableFuture<String> productDataFuture = fetchProductData();
productDataFuture.orTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
assertThrows(ExecutionException.class, productDataFuture::get);
}
@Test
void whencompleteOnTimeout_thenReturnValue() throws ExecutionException, InterruptedException {
CompletableFuture<String> productDataFuture = fetchProductData();
productDataFuture.completeOnTimeout(DEFAULT_PRODUCT, DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
assertEquals(DEFAULT_PRODUCT, productDataFuture.get());
}
@Test
void whencompleteExceptionally_thenGetThrow() {
CompletableFuture<String> productDataFuture = fetchProductData();
executorService.schedule(() -> productDataFuture
.completeExceptionally(new TimeoutException("Timeout occurred")), DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
assertThrows(ExecutionException.class, productDataFuture::get);
}
}

View File

@ -0,0 +1,61 @@
package com.baeldung.firstdaymonth;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.junit.jupiter.api.Test;
public class FirstDayOfMonthUnitTest {
@Test
void givenMonth_whenUsingCalendar_thenReturnFirstDay() {
Date currentDate = new GregorianCalendar(2023, Calendar.NOVEMBER, 23).getTime();
Date expectedDate = new GregorianCalendar(2023, Calendar.NOVEMBER, 1).getTime();
Calendar cal = Calendar.getInstance();
cal.setTime(currentDate);
cal.set(Calendar.DAY_OF_MONTH, 1);
assertEquals(expectedDate, cal.getTime());
}
@Test
void givenMonth_whenUsingLocalDate_thenReturnFirstDay() {
LocalDate currentDate = LocalDate.of(2023, 9, 6);
LocalDate expectedDate = LocalDate.of(2023, 9, 1);
assertEquals(expectedDate, currentDate.withDayOfMonth(1));
}
@Test
void givenMonth_whenUsingTemporalAdjusters_thenReturnFirstDay() {
LocalDate currentDate = LocalDate.of(2023, 7, 19);
LocalDate expectedDate = LocalDate.of(2023, 7, 1);
assertEquals(expectedDate, currentDate.with(TemporalAdjusters.firstDayOfMonth()));
}
@Test
void givenMonth_whenUsingYearMonth_thenReturnFirstDay() {
YearMonth currentDate = YearMonth.of(2023, 4);
LocalDate expectedDate = LocalDate.of(2023, 4, 1);
assertEquals(expectedDate, currentDate.atDay(1));
}
@Test
void givenMonth_whenUsingJodaTime_thenReturnFirstDay() {
org.joda.time.LocalDate currentDate = org.joda.time.LocalDate.parse("2023-5-10");
org.joda.time.LocalDate expectedDate = org.joda.time.LocalDate.parse("2023-5-1");
assertEquals(expectedDate, currentDate.dayOfMonth()
.withMinimumValue());
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.generictype;
/**
* @param <T> The type of the first value in the {@code Pair<T,S>}.
* @param <S> The type of the second value in the {@code Pair<T,S>}.
*/
public class Pair<T, S> {
public T first;
public S second;
/**
* Constructs a new Pair object with the specified values.
*
* @param a The first value.
* @param b The second value.
*/
public Pair(T a, S b) {
first = a;
second = b;
}
}

View File

@ -35,6 +35,21 @@
<artifactId>simplemagic</artifactId> <artifactId>simplemagic</artifactId>
<version>${simplemagic.version}</version> <version>${simplemagic.version}</version>
</dependency> </dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -62,5 +77,6 @@
<jmime-magic.version>0.1.5</jmime-magic.version> <jmime-magic.version>0.1.5</jmime-magic.version>
<jodd-util.version>6.2.1</jodd-util.version> <jodd-util.version>6.2.1</jodd-util.version>
<simplemagic.version>1.17</simplemagic.version> <simplemagic.version>1.17</simplemagic.version>
<jmh.version>1.37</jmh.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,112 @@
package com.baeldung.zip;
import java.io.*;
import java.util.concurrent.TimeUnit;
import java.util.*;
import java.util.zip.*;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 1, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(value = 1)
public class ZipBenchmark {
public static final int NUM_OF_FILES = 10;
public static final int DATA_SIZE = 204800;
@State(Scope.Thread)
public static class SourceState {
public File compressedFile;
@Setup(Level.Trial)
public void setup() throws IOException {
ZipSampleFileStore sampleFileStore = new ZipSampleFileStore(NUM_OF_FILES, DATA_SIZE);
compressedFile = sampleFileStore.getFile();
}
@TearDown(Level.Trial)
public void cleanup() {
if (compressedFile.exists()) {
compressedFile.delete();
}
}
}
@Benchmark
public static void readAllEntriesByZipFile(SourceState sourceState, Blackhole blackhole) throws IOException {
try (ZipFile zipFile = new ZipFile(sourceState.compressedFile)) {
Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
while (zipEntries.hasMoreElements()) {
ZipEntry zipEntry = zipEntries.nextElement();
try (InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry))) {
blackhole.consume(ZipSampleFileStore.getString(inputStream));
}
}
}
}
@Benchmark
public static void readAllEntriesByZipInputStream(SourceState sourceState, Blackhole blackhole) throws IOException {
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceState.compressedFile));
ZipInputStream zipInputStream = new ZipInputStream(bis)
) {
ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) {
blackhole.consume(ZipSampleFileStore.getString(zipInputStream));
}
}
}
@Benchmark
public static void readLastEntryByZipFile(SourceState sourceState, Blackhole blackhole) throws IOException {
try (ZipFile zipFile = new ZipFile(sourceState.compressedFile)) {
ZipEntry zipEntry = zipFile.getEntry(getLastEntryName());
try (InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry))) {
blackhole.consume(ZipSampleFileStore.getString(inputStream));
}
}
}
@Benchmark
public static void readLastEntryByZipInputStream(SourceState sourceState, Blackhole blackhole) throws IOException {
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceState.compressedFile));
ZipInputStream zipInputStream = new ZipInputStream(bis)
) {
ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) {
if (Objects.equals(entry.getName(), getLastEntryName())){
blackhole.consume(ZipSampleFileStore.getString(zipInputStream));
}
}
}
}
private static String getLastEntryName() {
return String.format(ZipSampleFileStore.ENTRY_NAME_PATTERN, NUM_OF_FILES);
}
public static void main(String[] args) throws Exception {
Options options = new OptionsBuilder()
.include(ZipBenchmark.class.getSimpleName()).threads(1)
.shouldFailOnError(true)
.shouldDoGC(true)
.jvmArgs("-server").build();
new Runner(options).run();
}
}

View File

@ -0,0 +1,70 @@
package com.baeldung.zip;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
public class ZipSampleFileStore {
public static final String ENTRY_NAME_PATTERN = "str-data-%s.txt";
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
private final File file;
private final List<String> dataList;
public ZipSampleFileStore(int numOfFiles, int fileSize) throws IOException {
dataList = new ArrayList<>(numOfFiles);
file = File.createTempFile("zip-sample", "");
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(file))) {
for (int idx=0; idx<=numOfFiles; idx++) {
byte[] data = createRandomStringInByte(fileSize);
dataList.add(new String(data, DEFAULT_ENCODING));
ZipEntry entry = new ZipEntry(String.format(ENTRY_NAME_PATTERN, idx));
zos.putNextEntry(entry);
zos.write(data);
zos.closeEntry();
}
}
}
public static byte[] createRandomStringInByte(int size) {
Random random = new Random();
byte[] data = new byte[size];
for (int n = 0; n < data.length; n++) {
char randomChar;
int choice = random.nextInt(2); // 0 for uppercase, 1 for lowercase
if (choice == 0) {
randomChar = (char) ('A' + random.nextInt(26)); // 'A' to 'Z'
} else {
randomChar = (char) ('a' + random.nextInt(26)); // 'a' to 'z'
}
data[n] = (byte) randomChar;
}
return data;
}
public File getFile() {
return file;
}
public List<String> getDataList() {
return dataList;
}
public static String getString(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
IOUtils.copy(inputStream, byteArrayOutputStream);
return byteArrayOutputStream.toString(DEFAULT_ENCODING);
}
}

View File

@ -0,0 +1,83 @@
package com.baeldung.zip;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import org.junit.*;
public class ZipUnitTest {
private static File compressedFile;
private static List<String> dataList = new ArrayList<>();
@BeforeClass
public static void prepareData() throws IOException {
ZipSampleFileStore sampleFileStore = new ZipSampleFileStore(ZipBenchmark.NUM_OF_FILES, ZipBenchmark.DATA_SIZE);
compressedFile = sampleFileStore.getFile();
dataList = sampleFileStore.getDataList();
}
@Test
public void whenCreateZipFile_thenCompressedSizeShouldBeLessThanOriginal() throws IOException {
byte[] data = ZipSampleFileStore.createRandomStringInByte(10240);
File file = File.createTempFile("zip-temp", "");
try (
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
ZipOutputStream zos = new ZipOutputStream(bos)
) {
ZipEntry zipEntry = new ZipEntry("zip-entry.txt");
zos.putNextEntry(zipEntry);
zos.write(data);
zos.closeEntry();
assertThat(file.length()).isLessThan(data.length);
}
finally {
file.delete();
}
}
@Test
public void whenReadAllEntriesViaZipFile_thenDataIsEqualtoTheSource() throws IOException {
try (ZipFile zipFile = new ZipFile(compressedFile)) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
List<? extends ZipEntry> entryList = Collections.list(entries);
for (int idx=0; idx<entryList.size(); idx++) {
ZipEntry zipEntry = entryList.get(idx);
try (InputStream inputStream = zipFile.getInputStream(zipEntry)) {
String actual = ZipSampleFileStore.getString(inputStream);
assertThat(actual).as("Data for ZIP entry: " + zipEntry.getName()).isEqualTo(dataList.get(idx));
}
}
}
}
@Test
public void whenReadAllEntriesViaZipInputStream_thenDataIsEqualtoTheSource() throws IOException {
int idx = 0;
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(compressedFile));
ZipInputStream zipInputStream = new ZipInputStream(bis)
) {
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
String actual = ZipSampleFileStore.getString(zipInputStream);
assertThat(actual).as("Data for ZIP entry: " + zipEntry.getName()).isEqualTo(dataList.get(idx++));
}
}
}
@AfterClass
public static void cleanup() {
if (compressedFile.exists()) {
compressedFile.delete();
}
}
}

View File

@ -0,0 +1,2 @@
I'm going to Alabama
Alabama is a state in the US

View File

@ -0,0 +1 @@
Dreams from My Father by Barack Obama

View File

@ -0,0 +1 @@
Harry Potter and the Chamber of Secrets

View File

@ -0,0 +1,64 @@
package com.baeldung.printwritervsfilewriter;
import static org.junit.jupiter.api.Assertions.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import org.junit.jupiter.api.Test;
public class PrintWriterVsFilePrinterUnitTest {
@Test
public void whenWritingToTextFileUsingFileWriter_thenTextMatches() throws IOException {
String result = "Harry Potter and the Chamber of Secrets";
File file = new File("potter.txt");
try (FileWriter fw = new FileWriter(file);) {
fw.write("Harry Potter and the Chamber of Secrets");
}
try (BufferedReader reader = new BufferedReader(new FileReader(file));) {
String actualData = reader.readLine();
assertEquals(result, actualData);
}
}
@Test
public void whenWritingToTextFileUsingPrintWriterPrintf_thenTextMatches() throws IOException {
String result = "Dreams from My Father by Barack Obama";
File file = new File("dream.txt");
try (PrintWriter pw = new PrintWriter(file);) {
String author = "Barack Obama";
pw.printf("Dreams from My Father by %s", author);
assertTrue(!pw.checkError());
}
try (BufferedReader reader = new BufferedReader(new FileReader(file));) {
String actualData = reader.readLine();
assertEquals(result, actualData);
}
}
@Test
public void whenWritingToTextFileUsingPrintWriterPrintln_thenTextMatches() throws IOException {
String result = "I'm going to Alabama\nAlabama is a state in the US\n";
try (PrintWriter pw = new PrintWriter("alabama.txt");) {
pw.println("I'm going to Alabama");
pw.println("Alabama is a state in the US");
}
Path path = Paths.get("alabama.txt");
String actualData = new String(Files.readAllBytes(path));
assertEquals(result, actualData);
}
}

View File

@ -0,0 +1,72 @@
package com.baeldung.jndi;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jndi.JndiTemplate;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
import javax.naming.*;
import javax.sql.DataSource;
import java.util.Enumeration;
import static org.junit.jupiter.api.Assertions.*;
class JndiNamingUnitTest {
private static InitialContext context;
private static DriverManagerDataSource dataSource;
@BeforeAll
static void setUp() throws Exception {
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
dataSource = new DriverManagerDataSource("jdbc:h2:mem:mydb");
builder.activate();
JndiTemplate jndiTemplate = new JndiTemplate();
context = (InitialContext) jndiTemplate.getContext();
dataSource.setDriverClassName("org.h2.Driver");
context.bind("java:comp/env/jdbc/datasource", dataSource);
}
@Test
void givenACompositeName_whenAddingAnElement_thenNameIsAdded() throws Exception {
Name objectName = new CompositeName("java:comp/env/jdbc");
Enumeration<String> items = objectName.getAll();
while(items.hasMoreElements()) {
System.out.println(items.nextElement());
}
objectName.add("New Name");
assertEquals("env", objectName.get(1));
assertEquals("New Name", objectName.get(objectName.size() - 1));
}
@Test
void givenContext_whenLookupByName_thenReturnsValidObject() throws Exception {
DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/datasource");
assertNotNull(ds);
assertNotNull(ds.getConnection());
}
@Test
void givenSubContext_whenLookupByName_thenReturnsValidObject() throws Exception {
Context subContext = (Context) context.lookup("java:comp/env");
DataSource ds = (DataSource) subContext.lookup("jdbc/datasource");
assertNotNull(ds);
assertNotNull(ds.getConnection());
}
@AfterAll
static void tearDown() throws Exception {
context.close();
}
}

View File

@ -0,0 +1,122 @@
package com.baeldung.genericnumberscomparator;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import org.junit.jupiter.api.Test;
class GenericNumbersComparatorUnitTest {
public int compareDouble(Number num1, Number num2) {
return Double.compare(num1.doubleValue(), num2.doubleValue());
}
@Test
void givenNumbers_whenUseCompareDouble_thenWillExecuteComparison() {
assertEquals(0, compareDouble(5, 5.0));
}
public int compareTo(Integer int1, Integer int2) {
return int1.compareTo(int2);
}
@Test
void givenNumbers_whenUseCompareTo_thenWillExecuteComparison() {
assertEquals(-1, compareTo(5, 7));
}
Map<Class<? extends Number>, BiFunction<Number, Number, Integer>> comparisonMap = new HashMap<>();
public int compareUsingMap(Number num1, Number num2) {
comparisonMap.put(Integer.class, (a, b) -> ((Integer) num1).compareTo((Integer) num2));
return comparisonMap.get(num1.getClass())
.apply(num1, num2);
}
@Test
void givenNumbers_whenUseCompareUsingMap_thenWillExecuteComparison() {
assertEquals(-1, compareUsingMap(5, 7));
}
public interface NumberComparator {
int compare(Number num1, Number num2);
}
@Test
void givenNumbers_whenUseProxy_thenWillExecuteComparison() {
NumberComparator proxy = (NumberComparator) Proxy.newProxyInstance(NumberComparator.class.getClassLoader(), new Class[] { NumberComparator.class },
(p, method, args) -> Double.compare(((Number) args[0]).doubleValue(), ((Number) args[1]).doubleValue()));
assertEquals(0, proxy.compare(5, 5.0));
}
public int compareUsingReflection(Number num1, Number num2) throws Exception {
Method method = num1.getClass()
.getMethod("compareTo", num1.getClass());
return (int) method.invoke(num1, num2);
}
@Test
void givenNumbers_whenUseCompareUsingReflection_thenWillExecuteComparison() throws Exception {
assertEquals(-1, compareUsingReflection(5, 7));
}
interface NumberComparatorFactory {
Comparator<Number> getComparator();
}
class IntegerComparatorFactory implements NumberComparatorFactory {
@Override
public Comparator<Number> getComparator() {
return (num1, num2) -> ((Integer) num1).compareTo((Integer) num2);
}
}
@Test
void givenNumbers_whenUseComparatorFactory_thenWillExecuteComparison() {
NumberComparatorFactory factory = new IntegerComparatorFactory();
Comparator<Number> comparator = factory.getComparator();
assertEquals(-1, comparator.compare(5, 7));
}
Function<Number, Double> toDouble = Number::doubleValue;
BiPredicate<Number, Number> isEqual = (num1, num2) -> toDouble.apply(num1)
.equals(toDouble.apply(num2));
@Test
void givenNumbers_whenUseIsEqual_thenWillExecuteComparison() {
assertEquals(true, isEqual.test(5, 5.0));
}
private Number someNumber = 5;
private Number anotherNumber = 5.0;
Optional<Number> optNum1 = Optional.ofNullable(someNumber);
Optional<Number> optNum2 = Optional.ofNullable(anotherNumber);
int comparisonResult = optNum1.flatMap(n1 -> optNum2.map(n2 -> Double.compare(n1.doubleValue(), n2.doubleValue())))
.orElse(0);
@Test
void givenNumbers_whenUseComparisonResult_thenWillExecuteComparison() {
assertEquals(0, comparisonResult);
}
private boolean someCondition = true;
Function<Number, ?> dynamicFunction = someCondition ? Number::doubleValue : Number::intValue;
Comparator<Number> dynamicComparator = (num1, num2) -> ((Comparable) dynamicFunction.apply(num1)).compareTo(dynamicFunction.apply(num2));
@Test
void givenNumbers_whenUseDynamicComparator_thenWillExecuteComparison() {
assertEquals(0, dynamicComparator.compare(5, 5.0));
}
}

View File

@ -0,0 +1,6 @@
package com.baeldung.optionalsasparameterrecords;
import java.util.Optional;
public record Product(String name, double price, Optional<String> description) {
}

View File

@ -0,0 +1,17 @@
package com.baeldung.optionalsasparameterrecords;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Optional;
public class OptionalAsRecordParameterUnitTest {
@Test
public void givenRecordCreationWithOptional_thenCreateItProperly() {
var emptyDescriptionProduct = new Product("television", 1699.99, Optional.empty());
Assertions.assertEquals("television", emptyDescriptionProduct.name());
Assertions.assertEquals(1699.99, emptyDescriptionProduct.price());
Assertions.assertNull(emptyDescriptionProduct.description().orElse(null));
}
}

View File

@ -85,7 +85,7 @@ public class AlphanumericPerformanceBenchmark {
public boolean isAlphanumeric(final int codePoint) { public boolean isAlphanumeric(final int codePoint) {
return (codePoint >= 65 && codePoint <= 90) || return (codePoint >= 65 && codePoint <= 90) ||
(codePoint >= 97 && codePoint <= 172) || (codePoint >= 97 && codePoint <= 122) ||
(codePoint >= 48 && codePoint <= 57); (codePoint >= 48 && codePoint <= 57);
} }
} }

View File

@ -4,3 +4,4 @@
- [Aggregate Runtime Exceptions in Java Streams](https://www.baeldung.com/java-streams-aggregate-exceptions) - [Aggregate Runtime Exceptions in Java Streams](https://www.baeldung.com/java-streams-aggregate-exceptions)
- [Streams vs. Loops in Java](https://www.baeldung.com/java-streams-vs-loops) - [Streams vs. Loops in Java](https://www.baeldung.com/java-streams-vs-loops)
- [Partition a Stream in Java](https://www.baeldung.com/java-partition-stream) - [Partition a Stream in Java](https://www.baeldung.com/java-partition-stream)
- [Taking Every N-th Element from Finite and Infinite Streams in Java](https://www.baeldung.com/java-nth-element-finite-infinite-streams)

View File

@ -13,3 +13,4 @@ This module contains articles about string-related algorithms.
- [Find the Most Frequent Characters in a String](https://www.baeldung.com/java-string-find-most-frequent-characters) - [Find the Most Frequent Characters in a String](https://www.baeldung.com/java-string-find-most-frequent-characters)
- [Checking If a String Is a Repeated Substring](https://www.baeldung.com/java-repeated-substring) - [Checking If a String Is a Repeated Substring](https://www.baeldung.com/java-repeated-substring)
- [Check if Letter Is Emoji With Java](https://www.baeldung.com/java-check-letter-emoji) - [Check if Letter Is Emoji With Java](https://www.baeldung.com/java-check-letter-emoji)
- [Wrapping a String After a Number of Characters Word-Wise](https://www.baeldung.com/java-wrap-string-number-characters-word-wise)

View File

@ -3,3 +3,5 @@
- [Convert String to Int Using Encapsulation](https://www.baeldung.com/java-encapsulation-convert-string-to-int) - [Convert String to Int Using Encapsulation](https://www.baeldung.com/java-encapsulation-convert-string-to-int)
- [HashMap with Multiple Values for the Same Key](https://www.baeldung.com/java-hashmap-multiple-values-per-key) - [HashMap with Multiple Values for the Same Key](https://www.baeldung.com/java-hashmap-multiple-values-per-key)
- [Split Java String Into Key-Value Pairs](https://www.baeldung.com/java-split-string-map) - [Split Java String Into Key-Value Pairs](https://www.baeldung.com/java-split-string-map)
- [How to Center Text Output in Java](https://www.baeldung.com/java-center-text-output)
- [How to Convert an Object to String](https://www.baeldung.com/java-object-string-representation)

View File

@ -54,6 +54,11 @@
<artifactId>commons-codec</artifactId> <artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version> <version>${commons-codec.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-core.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -95,6 +100,7 @@
<javax.el-api.version>3.0.0</javax.el-api.version> <javax.el-api.version>3.0.0</javax.el-api.version>
<javax.el.version>2.2.6</javax.el.version> <javax.el.version>2.2.6</javax.el.version>
<commons-codec.version>1.14</commons-codec.version> <commons-codec.version>1.14</commons-codec.version>
<spring-core.version>5.3.0</spring-core.version>
</properties> </properties>
</project> </project>

View File

@ -3,6 +3,7 @@ package com.baeldung.emptystrings;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.junit.Test; import org.junit.Test;
import org.springframework.util.ObjectUtils;
import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolation;
import javax.validation.Validation; import javax.validation.Validation;
@ -109,6 +110,24 @@ public class EmptyStringsUnitTest {
assertFalse(Strings.isNullOrEmpty(blankString)); assertFalse(Strings.isNullOrEmpty(blankString));
} }
/*
* Spring Core ObjectUtils
*/
@Test
public void givenSomeEmptyString_thenObjectUtilsIsEmptyReturnsTrue() {
assertTrue(ObjectUtils.isEmpty(emptyString));
}
@Test
public void givenSomeNonEmptyString_thenObjectUtilsIsEmptyReturnsFalse() {
assertFalse(ObjectUtils.isEmpty(nonEmptyString));
}
@Test
public void givenSomeBlankString_thenObjectUtilsIsEmptyReturnsFalse() {
assertFalse(ObjectUtils.isEmpty(blankString));
}
/* /*
* Bean Validation * Bean Validation
*/ */

View File

@ -11,4 +11,4 @@
- [Check if a String Has All Unique Characters in Java](https://www.baeldung.com/java-check-string-all-unique-chars) - [Check if a String Has All Unique Characters in Java](https://www.baeldung.com/java-check-string-all-unique-chars)
- [Performance Comparison Between Different Java String Concatenation Methods](https://www.baeldung.com/java-string-concatenation-methods) - [Performance Comparison Between Different Java String Concatenation Methods](https://www.baeldung.com/java-string-concatenation-methods)
- [Replacing Single Quote with \ in Java String](https://www.baeldung.com/java-replacing-single-quote-string) - [Replacing Single Quote with \ in Java String](https://www.baeldung.com/java-replacing-single-quote-string)
- [Check if a String Contains a Number Value in Java](https://www.baeldung.com/java-string-number-presence)

View File

@ -1,3 +1,4 @@
### Relevant Articles: ### Relevant Articles:
[How to Center Text Output in Java](https://www.baeldung.com/java-center-text-output) - [How to Center Text Output in Java](https://www.baeldung.com/java-center-text-output)
- [Capitalize the First Letter of Each Word in a String](https://www.baeldung.com/java-string-initial-capital-letter-every-word)

View File

@ -0,0 +1,34 @@
package com.baeldung.mutablestrings;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
public class CharsetUsageExample {
public ByteBuffer encodeString(String inputString) {
Charset charset = Charset.forName("UTF-8");
CharsetEncoder encoder = charset.newEncoder();
CharBuffer charBuffer = CharBuffer.wrap(inputString);
ByteBuffer byteBuffer = ByteBuffer.allocate(50);
encoder.encode(charBuffer, byteBuffer, true); // true indicates the end of input
byteBuffer.flip();
return byteBuffer;
}
public String decodeString(ByteBuffer byteBuffer) {
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
CharBuffer decodedCharBuffer = CharBuffer.allocate(50);
decoder.decode(byteBuffer, decodedCharBuffer, true);
decodedCharBuffer.flip();
return decodedCharBuffer.toString();
}
}

View File

@ -0,0 +1,65 @@
package com.baeldung.mutablestrings;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.concurrent.atomic.AtomicReference;
public class MutableStringUsingCharset {
private final AtomicReference<CharBuffer> cbRef = new AtomicReference<>();
private final Charset myCharset = new Charset("mycharset", null) {
@Override
public boolean contains(Charset cs) {
return false;
}
@Override
public CharsetDecoder newDecoder() {
return new CharsetDecoder(this, 1.0f, 1.0f) {
@Override
protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
cbRef.set(out);
while (in.remaining() > 0) {
out.append((char) in.get());
}
return CoderResult.UNDERFLOW;
}
};
}
@Override
public CharsetEncoder newEncoder() {
CharsetEncoder cd = new CharsetEncoder(this, 1.0f, 1.0f) {
@Override
protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
while (in.hasRemaining()) {
if (!out.hasRemaining()) {
return CoderResult.OVERFLOW;
}
char currentChar = in.get();
if (currentChar > 127) {
return CoderResult.unmappableForLength(1);
}
out.put((byte) currentChar);
}
return CoderResult.UNDERFLOW;
}
};
return cd;
}
};
public String createModifiableString(String s) {
return new String(s.getBytes(), myCharset);
}
public void modifyString() {
CharBuffer cb = cbRef.get();
cb.position(0);
cb.put("xyz");
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.mutablestrings;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import com.google.errorprone.annotations.DoNotCall;
public class MutableStrings {
/**
* This involves using Reflection to change String fields and it is not encouraged to use this in programs.
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
@DoNotCall
public void mutableUsingReflection() throws NoSuchFieldException, IllegalAccessException {
String myString = "Hello World";
String otherString = new String("Hello World");
Field f = String.class.getDeclaredField("value");
f.setAccessible(true);
f.set(myString, "Hi World".toCharArray());
System.out.println(otherString);
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.unicode;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
public class UnicodeLetterChecker {
public boolean characterClassCheck(String input) {
for (char c : input.toCharArray()) {
if (!Character.isLetter(c)) {
return false;
}
}
return true;
}
public boolean regexCheck(String input) {
Pattern pattern = Pattern.compile("^\\p{L}+$");
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
public boolean isAlphaCheck(String input) {
return StringUtils.isAlpha(input);
}
public boolean StreamsCheck(String input) {
return input.codePoints().allMatch(Character::isLetter);
}
}

View File

@ -0,0 +1,17 @@
package com.baeldung.mutablestring;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.baeldung.mutablestrings.CharsetUsageExample;
public class CharsetUsageUnitTest {
@Test
public void givenCharset_whenStringIsEncodedAndDecoded_thenGivesCorrectResult() {
CharsetUsageExample ch = new CharsetUsageExample();
String inputString = "hello दुनिया";
String result = ch.decodeString(ch.encodeString(inputString));
Assertions.assertEquals(inputString, result);
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.mutablestring;
import org.junit.Assert;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import com.baeldung.mutablestrings.MutableStringUsingCharset;
public class MutableStringUsingCharsetUnitTest {
@Test
@Disabled
/**
* This test is disabled as it works well for Java 8 and below
*/
public void givenCustomCharSet_whenStringUpdated_StringGetsMutated() throws Exception {
MutableStringUsingCharset ms = new MutableStringUsingCharset();
String s = ms.createModifiableString("Hello");
Assert.assertEquals("Hello", s);
ms.modifyString();
Assert.assertEquals("something", s);
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.unicode;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class UnicodeLetterCheckerUnitTest {
@Test
public void givenString_whenUsingIsLetter_thenReturnTrue() {
UnicodeLetterChecker checker = new UnicodeLetterChecker();
boolean isUnicodeLetter = checker.characterClassCheck("HelloWorld");
assertTrue(isUnicodeLetter);
}
@Test
public void givenString_whenUsingRegex_thenReturnTrue() {
UnicodeLetterChecker checker = new UnicodeLetterChecker();
boolean isUnicodeLetter = checker.regexCheck("HelloWorld");
assertTrue(isUnicodeLetter);
}
@Test
public void givenString_whenUsingIsAlpha_thenReturnTrue() {
UnicodeLetterChecker checker = new UnicodeLetterChecker();
boolean isUnicodeLetter = checker.isAlphaCheck("HelloWorld");
assertTrue(isUnicodeLetter);
}
@Test
public void givenString_whenUsingStreams_thenReturnTrue() {
UnicodeLetterChecker checker = new UnicodeLetterChecker();
boolean isUnicodeLetter = checker.StreamsCheck("HelloWorld");
assertTrue(isUnicodeLetter);
}
}

View File

@ -14,3 +14,4 @@ Listed here there are only those articles that does not fit into other core-java
- [Java String Interview Questions and Answers](https://www.baeldung.com/java-string-interview-questions) - [Java String Interview Questions and Answers](https://www.baeldung.com/java-string-interview-questions)
- [Java Multi-line String](https://www.baeldung.com/java-multiline-string) - [Java Multi-line String](https://www.baeldung.com/java-multiline-string)
- [Reuse StringBuilder for Efficiency](https://www.baeldung.com/java-reuse-stringbuilder-for-efficiency) - [Reuse StringBuilder for Efficiency](https://www.baeldung.com/java-reuse-stringbuilder-for-efficiency)
- [How to Iterate Over the String Characters in Java](https://www.baeldung.com/java-iterate-string-characters)

View File

@ -0,0 +1,42 @@
package com.baeldung.stringIterator;
import java.text.*;
import java.util.*;
public class StringIterator {
public static String javaCharArray(String str){
StringBuilder result = new StringBuilder();
for (char c : str.toCharArray()) {
result.append(c);
}
return result.toString();
}
public static String javaforLoop(String str) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
result.append(c);
}
return result.toString();
}
public static String java8forEach(String str){
StringBuilder result = new StringBuilder();
str.chars().forEach(name -> {
result.append((char) name);
});
return result.toString();
}
public static String javaCharacterIterator(String str){
StringBuilder result = new StringBuilder();
CharacterIterator it = new StringCharacterIterator(str);
while (it.current() != CharacterIterator.DONE) {
result.append(it.current());
it.next();
}
return result.toString();
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.passstringbyreference;
public class Dummy {
String dummyString;
public String getDummyString() {
return dummyString;
}
public void setDummyString(String dummyString) {
this.dummyString = dummyString;
}
}

View File

@ -0,0 +1,85 @@
package com.baeldung.passstringbyreference;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import org.junit.jupiter.api.Test;
class PassStringUnitTest {
@Test
void givenAString_whenPassedToVoidMethod_thenStringIsNotModified() {
String s = "hello";
concatStringWithNoReturn(s);
assertEquals("hello", s);
}
void concatStringWithNoReturn(String input) {
input += " world";
assertEquals("hello world", input);
}
@Test
void givenAString_whenPassedToMethodAndReturnNewString_thenStringIsModified() {
String s = "hello";
assertEquals("hello world", concatStringWithReturn(s));
}
String concatStringWithReturn(String input) {
return input + " world";
}
@Test
void givenAString_whenPassStringBuilderToVoidMethod_thenConcatNewStringOk() {
StringBuilder builder = new StringBuilder("hello");
concatWithStringBuilder(builder);
assertEquals("hello world", builder.toString());
}
void concatWithStringBuilder(StringBuilder input) {
input.append(" world");
}
@Test
void givenAString_whenPassStringBufferToVoidMethod_thenConcatNewStringOk() {
StringBuffer builder = new StringBuffer("hello");
concatWithStringBuffer(builder);
assertEquals("hello world", builder.toString());
}
void concatWithStringBuffer(StringBuffer input) {
input.append(" world");
}
@Test
void givenObjectWithStringField_whenSetDifferentValue_thenObjectIsModified() {
Dummy dummy = new Dummy();
assertNull(dummy.getDummyString());
modifyStringValueInInputObject(dummy, "hello world");
assertEquals("hello world", dummy.getDummyString());
}
void modifyStringValueInInputObject(Dummy dummy, String dummyString) {
dummy.setDummyString(dummyString);
}
@Test
void givenObjectWithStringField_whenSetDifferentValueWithStringBuilder_thenSetStringInNewObject() {
assertEquals("hello world", getDummy("hello", "world").getDummyString());
}
Dummy getDummy(String hello, String world) {
StringBuilder builder = new StringBuilder();
builder.append(hello)
.append(" ")
.append(world);
Dummy dummy = new Dummy();
dummy.setDummyString(builder.toString());
return dummy;
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.stringIterator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class StringIteratorTest {
@Test
public void whenUseCharArrayMethod_thenIterate() {
String input = "Hello, Baeldung!";
String expectedOutput = "Hello, Baeldung!";
String result = StringIterator.javaCharArray(input);
assertEquals(expectedOutput, result);
}
@Test
public void whenUseJavaForLoop_thenIterate() {
String input = "Hello, Baeldung!";
String expectedOutput = "Hello, Baeldung!";
String result = StringIterator.javaForLoop(input);
assertEquals(expectedOutput, result);
}
@Test
public void whenUseForEachMethod_thenIterate() {
String input = "Hello, Baeldung!";
String expectedOutput = "Hello, Baeldung!";
String result = StringIterator.java8ForEach(input);
assertEquals(expectedOutput, result);
}
@Test
public void whenUseCharacterIterator_thenIterate() {
String input = "Hello, Baeldung!";
String expectedOutput = "Hello, Baeldung!";
String result = StringIterator.javaCharacterIterator(input);
assertEquals(expectedOutput, result);
}
}

View File

@ -42,17 +42,17 @@ public class AVLTree {
return root == null ? -1 : root.height; return root == null ? -1 : root.height;
} }
private Node insert(Node node, int key) { private Node insert(Node root, int key) {
if (node == null) { if (root == null) {
return new Node(key); return new Node(key);
} else if (node.key > key) { } else if (root.key > key) {
node.left = insert(node.left, key); root.left = insert(root.left, key);
} else if (node.key < key) { } else if (root.key < key) {
node.right = insert(node.right, key); root.right = insert(root.right, key);
} else { } else {
throw new RuntimeException("duplicate Key!"); throw new RuntimeException("duplicate Key!");
} }
return rebalance(node); return rebalance(root);
} }
private Node delete(Node node, int key) { private Node delete(Node node, int key) {

View File

@ -3,4 +3,4 @@
- [Transferring a File Through SFTP in Java](https://www.baeldung.com/java-file-sftp) - [Transferring a File Through SFTP in Java](https://www.baeldung.com/java-file-sftp)
- [How to Create Password-Protected Zip Files and Unzip Them in Java](https://www.baeldung.com/java-password-protected-zip-unzip) - [How to Create Password-Protected Zip Files and Unzip Them in Java](https://www.baeldung.com/java-password-protected-zip-unzip)
- [How to Create CSV File from POJO with Custom Column Headers and Positions](https://www.baeldung.com/java-create-csv-pojo-customize-columns)

43
libraries-llms/pom.xml Normal file
View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>libraries-llms</artifactId>
<name>libraries-llms</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<!-- dependencies for langchain4j -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-embeddings</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-embeddings-all-minilm-l6-v2</artifactId>
<version>${langchain4j.version}</version>
</dependency>
</dependencies>
<properties>
<langchain4j.version>0.23.0</langchain4j.version>
</properties>
</project>

View File

@ -0,0 +1,65 @@
package com.baeldung.langchain;
import static dev.langchain4j.data.document.FileSystemDocumentLoader.loadDocument;
import static java.time.Duration.ofSeconds;
import static org.junit.Assert.assertNotNull;
import java.nio.file.Paths;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.langchain4j.chain.ConversationalRetrievalChain;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.embedding.AllMiniLmL6V2EmbeddingModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.input.PromptTemplate;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.retriever.EmbeddingStoreRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
public class ChainWithDocumentLiveTest {
private static final Logger logger = LoggerFactory.getLogger(ChainWithDocumentLiveTest.class);
@Test
public void givenChainWithDocument_whenPrompted_thenValidResponse() {
EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.documentSplitter(DocumentSplitters.recursive(500, 0))
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
Document document = loadDocument(Paths.get("src/test/resources/example-files/simpson's_adventures.txt"));
ingestor.ingest(document);
ChatLanguageModel chatModel = OpenAiChatModel.builder()
.apiKey(Constants.OPENAI_API_KEY)
.timeout(ofSeconds(60))
.build();
ConversationalRetrievalChain chain = ConversationalRetrievalChain.builder()
.chatLanguageModel(chatModel)
.retriever(EmbeddingStoreRetriever.from(embeddingStore, embeddingModel))
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.promptTemplate(PromptTemplate.from("Answer the following question to the best of your ability: {{question}}\n\nBase your answer on the following information:\n{{information}}"))
.build();
String answer = chain.execute("Who is Simpson?");
logger.info(answer);
assertNotNull(answer);
}
}

View File

@ -0,0 +1,81 @@
package com.baeldung.langchain;
import static dev.langchain4j.data.document.FileSystemDocumentLoader.loadDocument;
import static dev.langchain4j.model.openai.OpenAiModelName.GPT_3_5_TURBO;
import static java.time.Duration.ofSeconds;
import static java.util.stream.Collectors.joining;
import static org.junit.Assert.assertNotNull;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.embedding.AllMiniLmL6V2EmbeddingModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiTokenizer;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
public class ChatWithDocumentLiveTest {
private static final Logger logger = LoggerFactory.getLogger(ChatWithDocumentLiveTest.class);
@Test
public void givenDocument_whenPrompted_thenValidResponse() {
Document document = loadDocument(Paths.get("src/test/resources/example-files/simpson's_adventures.txt"));
DocumentSplitter splitter = DocumentSplitters.recursive(100, 0, new OpenAiTokenizer(GPT_3_5_TURBO));
List<TextSegment> segments = splitter.split(document);
EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
List<Embedding> embeddings = embeddingModel.embedAll(segments)
.content();
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
embeddingStore.addAll(embeddings, segments);
String question = "Who is Simpson?";
Embedding questionEmbedding = embeddingModel.embed(question)
.content();
int maxResults = 3;
double minScore = 0.7;
List<EmbeddingMatch<TextSegment>> relevantEmbeddings = embeddingStore.findRelevant(questionEmbedding, maxResults, minScore);
PromptTemplate promptTemplate = PromptTemplate.from("Answer the following question to the best of your ability:\n" + "\n" + "Question:\n" + "{{question}}\n" + "\n" + "Base your answer on the following information:\n" + "{{information}}");
String information = relevantEmbeddings.stream()
.map(match -> match.embedded()
.text())
.collect(joining("\n\n"));
Map<String, Object> variables = new HashMap<>();
variables.put("question", question);
variables.put("information", information);
Prompt prompt = promptTemplate.apply(variables);
ChatLanguageModel chatModel = OpenAiChatModel.builder()
.apiKey(Constants.OPENAI_API_KEY)
.timeout(ofSeconds(60))
.build();
AiMessage aiMessage = chatModel.generate(prompt.toUserMessage())
.content();
logger.info(aiMessage.text());
assertNotNull(aiMessage.text());
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.langchain;
import static dev.langchain4j.data.message.UserMessage.userMessage;
import static dev.langchain4j.model.openai.OpenAiModelName.GPT_3_5_TURBO;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiTokenizer;
public class ChatWithMemoryLiveTest {
private static final Logger logger = LoggerFactory.getLogger(ChatWithMemoryLiveTest.class);
@Test
public void givenMemory_whenPrompted_thenValidResponse() {
ChatLanguageModel model = OpenAiChatModel.withApiKey(Constants.OPENAI_API_KEY);
ChatMemory chatMemory = TokenWindowChatMemory.withMaxTokens(300, new OpenAiTokenizer(GPT_3_5_TURBO));
chatMemory.add(userMessage("Hello, my name is Kumar"));
AiMessage answer = model.generate(chatMemory.messages())
.content();
logger.info(answer.text());
chatMemory.add(answer);
assertNotNull(answer.text());
chatMemory.add(userMessage("What is my name?"));
AiMessage answerWithName = model.generate(chatMemory.messages())
.content();
logger.info(answerWithName.text());
chatMemory.add(answerWithName);
assertThat(answerWithName.text()).contains("Kumar");
}
}

View File

@ -0,0 +1,12 @@
package com.baeldung.langchain;
public class Constants {
/**
* A limited access key for access to OpenAI language models can be generated by first
* registering for free at (https://platform.openai.com/signup) and then by navigating
* to "Create new secret key" page at (https://platform.openai.com/account/api-keys).
*/
public static String OPENAI_API_KEY = "<OPENAI_API_KEY>";
}

View File

@ -0,0 +1,41 @@
package com.baeldung.langchain;
import static dev.langchain4j.model.openai.OpenAiModelName.GPT_3_5_TURBO;
import static org.junit.Assert.assertNotNull;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;
import dev.langchain4j.model.openai.OpenAiChatModel;
public class PromptTemplatesLiveTest {
private static final Logger logger = LoggerFactory.getLogger(PromptTemplatesLiveTest.class);
@Test
public void givenPromptTemplate_whenSuppliedInput_thenValidResponse() {
PromptTemplate promptTemplate = PromptTemplate.from("Tell me a {{adjective}} joke about {{content}}..");
Map<String, Object> variables = new HashMap<>();
variables.put("adjective", "funny");
variables.put("content", "humans");
Prompt prompt = promptTemplate.apply(variables);
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey(Constants.OPENAI_API_KEY)
.modelName(GPT_3_5_TURBO)
.temperature(0.3)
.build();
String response = model.generate(prompt.text());
logger.info(response);
assertNotNull(response);
}
}

View File

@ -0,0 +1,49 @@
package com.baeldung.langchain;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
public class ServiceWithToolsLiveTest {
private static final Logger logger = LoggerFactory.getLogger(ServiceWithToolsLiveTest.class);
static class Calculator {
@Tool("Calculates the length of a string")
int stringLength(String s) {
return s.length();
}
@Tool("Calculates the sum of two numbers")
int add(int a, int b) {
return a + b;
}
}
interface Assistant {
String chat(String userMessage);
}
@Test
public void givenServiceWithTools_whenPrompted_thenValidResponse() {
Assistant assistant = AiServices.builder(Assistant.class)
.chatLanguageModel(OpenAiChatModel.withApiKey(Constants.OPENAI_API_KEY))
.tools(new Calculator())
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.build();
String question = "What is the sum of the numbers of letters in the words \"language\" and \"model\"?";
String answer = assistant.chat(question);
logger.info(answer);
assertThat(answer).contains("13");
}
}

View File

@ -0,0 +1,28 @@
Once upon a time in the town of VeggieVille, there lived a cheerful carrot named Simpson.
Simpson was a radiant carrot, always beaming with joy and positivity.
His vibrant orange skin and lush green top were a sight to behold, but it was his infectious laughter and warm personality that really set him apart.
Simpson had a diverse group of friends, each a vegetable with their own unique characteristics.
There was Bella the blushing beetroot, always ready with a riddle or two; Timmy the timid tomato, a gentle soul with a heart of gold; and Percy the prankster potato, whose jokes always brought a smile to everyone's faces.
Despite their differences, they shared a close bond, their friendship as robust as their natural goodness.
Their lives were filled with delightful adventures, from playing hide-and-seek amidst the leafy lettuce to swimming in the dewy droplets that pooled on the cabbage leaves.
Their favorite place, though, was the sunlit corner of the vegetable patch, where they would bask in the warmth of the sun, share stories, and have hearty laughs.
One day, a bunch of pesky caterpillars invaded VeggieVille.
The vegetables were terrified, fearing they would be nibbled to nothingness.
But Simpson, with his usual sunny disposition, had an idea.
He proposed they host a grand feast for the caterpillars, with the juiciest leaves from the outskirts of the town.
Simpson's optimism was contagious, and his friends eagerly joined in to prepare the feast.
When the caterpillars arrived, they were pleasantly surprised.
They enjoyed the feast and were so impressed with the vegetables' hospitality that they promised not to trouble VeggieVille again.
In return, they agreed to help pollinate the flowers, contributing to a more lush and vibrant VeggieVille.
Simpson's idea had saved the day, but he humbly attributed the success to their teamwork and friendship.
They celebrated their victory with a grand party, filled with laughter, dance, and merry games.
That night, under the twinkling stars, they made a pact to always stand by each other, come what may.
From then on, the story of the happy carrot and his friends spread far and wide, a tale of friendship, unity, and positivity.
Simpson, Bella, Timmy, and Percy continued to live their joyful lives, their laughter echoing through VeggieVille.
And so, the tale of the happy carrot and his friends serves as a reminder that no matter the challenge, with optimism, teamwork, and a bit of creativity, anything is possible.

View File

@ -22,6 +22,7 @@ public class EditorUnitTest {
loadAndVerifyTestData(entityManagerFactory, editor); loadAndVerifyTestData(entityManagerFactory, editor);
} }
*/ */
@Test @Test
public void givenNeo4j_WhenEntitiesCreated_thenCanBeRetrieved() throws Exception { public void givenNeo4j_WhenEntitiesCreated_thenCanBeRetrieved() throws Exception {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("ogm-neo4j"); EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("ogm-neo4j");

View File

@ -106,6 +106,7 @@
<module>spring-jpa</module> <module>spring-jpa</module>
<module>spring-jpa-2</module> <module>spring-jpa-2</module>
<module>spring-jdbc</module> <module>spring-jdbc</module>
<module>spring-jdbc-2</module>
<module>spring-jooq</module> <module>spring-jooq</module>
<module>spring-mybatis</module> <module>spring-mybatis</module>
<module>spring-persistence-simple</module> <module>spring-persistence-simple</module>

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring-jdbc-2</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring-jdbc-2</name>
<description>Demo project for Spring Jdbc</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
<properties>
<spring-boot.version>3.2.0-SNAPSHOT</spring-boot.version>
<junit-jupiter.version>5.10.0</junit-jupiter.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@ -0,0 +1,14 @@
package com.baeldung.jdbcclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = "com.baledung.jdbcclient")
public class JdbcClientDemoApplication {
public static void main(String[] args) {
SpringApplication.run(JdbcClientDemoApplication.class, args);
}
}

View File

@ -0,0 +1,95 @@
package com.baeldung.jdbcclient.dao;
import com.baeldung.jdbcclient.model.Student;
import com.baeldung.jdbcclient.model.StudentResultExtractor;
import com.baeldung.jdbcclient.model.StudentRowMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowCountCallbackHandler;
import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.stereotype.Repository;
import java.sql.Types;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Repository
public class StudentDao {
private static final Logger logger = LoggerFactory.getLogger(StudentDao.class);
@Autowired
private JdbcClient jdbcClient;
public Integer insertWithSetParamWithNamedParamAndSqlType(Student student) {
String sql = "INSERT INTO student (student_name, age, grade, gender, state)"
+ "VALUES (:name, :age, :grade, :gender, :state)";
Integer noOfrowsAffected = this.jdbcClient.sql(sql)
.param("name", student.getStudentName(), Types.VARCHAR)
.param("age", student.getAge(), Types.INTEGER)
.param("grade", student.getGrade(), Types.INTEGER)
.param("gender", student.getStudentGender(), Types.VARCHAR)
.param("state", student.getState(), Types.VARCHAR)
.update();
logger.info("No. of rows affected: " + noOfrowsAffected);
return noOfrowsAffected;
}
public List<Student> getStudentsOfGradeStateAndGenderWithPositionalParams(int grade, String state, String gender) {
String sql = "select student_id, student_name, age, grade, gender, state from student"
+ " where grade = ? and state = ? and gender = ?";
return jdbcClient.sql(sql)
.param(grade)
.param(state)
.param(gender)
.query(new StudentRowMapper()).list();
}
public List<Student> getStudentsOfGradeStateAndGenderWithParamIndex(int grade, String state, String gender) {
String sql = "select student_id, student_name, age, grade, gender, state from student"
+ " where grade = ? and state = ? and gender = ?";
return jdbcClient.sql(sql)
.param(1,grade)
.param(2, state)
.param(3, gender)
.query(new StudentResultExtractor());
}
public Student getStudentsOfGradeStateAndGenderWithParamsInVarargs(int grade, String state, String gender) {
String sql = "select student_id, student_name, age, grade, gender, state from student"
+ " where grade = ? and state = ? and gender = ? limit 1";
return jdbcClient.sql(sql)
.params(grade, state, gender)
.query(new StudentRowMapper()).single();
}
public Optional<Student> getStudentsOfGradeStateAndGenderWithParamsInList(List params) {
String sql = "select student_id, student_name, age, grade, gender, state from student"
+ " where grade = ? and state = ? and gender = ? limit 1";
return jdbcClient.sql(sql)
.params(params)
.query(new StudentRowMapper()).optional();
}
public int getCountOfStudentsOfGradeStateAndGenderWithNamedParam(int grade, String state, String gender) {
String sql = "select student_id, student_name, age, grade, gender, state from student"
+ " where grade = :grade and state = :state and gender = :gender";
RowCountCallbackHandler countCallbackHandler = new RowCountCallbackHandler();
jdbcClient.sql(sql)
.param("grade", grade)
.param("state", state)
.param("gender", gender)
.query(countCallbackHandler);
return countCallbackHandler.getRowCount();
}
public List<Student> getStudentsOfGradeStateAndGenderWithParamMap(Map<String, ?> paramMap) {
String sql = "select student_id, student_name, age, grade, gender, state from student"
+ " where grade = :grade and state = :state and gender = :gender";
return jdbcClient.sql(sql)
.params(paramMap)
.query(new StudentRowMapper()).list();
}
}

View File

@ -0,0 +1,60 @@
package com.baeldung.jdbcclient.model;
public class Student {
private Integer studentId;
private String studentName;
private String studentGender;
private Integer age;
private Integer grade;
public Integer getStudentId() {
return studentId;
}
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public String getStudentGender() {
return studentGender;
}
public void setStudentGender(String studentGender) {
this.studentGender = studentGender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getGrade() {
return grade;
}
public void setGrade(Integer grade) {
this.grade = grade;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
private String state;
}

View File

@ -0,0 +1,26 @@
package com.baeldung.jdbcclient.model;
import org.springframework.jdbc.core.ResultSetExtractor;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class StudentResultExtractor implements ResultSetExtractor<List<Student>> {
@Override
public List<Student> extractData(ResultSet rs) throws SQLException {
List<Student> students = new ArrayList<Student>();
while(rs.next()) {
Student student = new Student();
student.setStudentId(rs.getInt("student_id"));
student.setStudentName(rs.getString("student_name"));
student.setAge(rs.getInt("age"));
student.setStudentGender(rs.getString("gender"));
student.setGrade(rs.getInt("grade"));
student.setState(rs.getString("state"));
students.add(student);
}
return students;
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.jdbcclient.model;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
public class StudentRowMapper implements RowMapper<Student> {
@Override
public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
Student student = new Student();
student.setStudentId(rs.getInt("student_id"));
student.setStudentName(rs.getString("student_name"));
student.setAge(rs.getInt("age"));
student.setStudentGender(rs.getString("gender"));
student.setGrade(rs.getInt("grade"));
student.setState(rs.getString("state"));
return student;
}
}

View File

@ -0,0 +1,5 @@
# DataSource Configuration
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=user
spring.datasource.password= # Leave this empty

View File

@ -0,0 +1 @@
DROP TABLE student;

View File

@ -0,0 +1,98 @@
CREATE TABLE student (
student_id INT AUTO_INCREMENT PRIMARY KEY,
student_name VARCHAR(255) NOT NULL,
age INT,
grade INT NOT NULL,
gender VARCHAR(10) NOT NULL,
state VARCHAR(100) NOT NULL
);
-- Student 1
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('John Smith', 18, 3, 'Male', 'California');
-- Student 2
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emily Johnson', 17, 2, 'Female', 'New York');
-- Student 3
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Michael Davis', 4, 1, 'Male', 'Texas');
-- Student 4
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Sophia Martinez', 2, 1, 'Female', 'Florida');
-- Student 5
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('William Brown', 5, 5, 'Male', 'California');
-- Student 6
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Garcia', 4, 2, 'Female', 'Texas');
-- Student 7
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ethan Rodriguez', 3, 1, 'Male', 'New York');
-- Student 8
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ava Hernandez', 2, 1, 'Female', 'Florida');
-- Student 9
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('James Wilson', 5, 4, 'Male', 'Texas');
-- Student 10
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emma Miller', 3, 1, 'Female', 'California');
-- Student 11
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Benjamin Brown', 4, 1, 'Male', 'New York');
-- Student 12
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Mia Smith', 2, 1, 'Female', 'Florida');
-- Student 13
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Daniel Johnson', 5, 4, 'Male', 'California');
-- Student 14
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ava Davis', 4, 2, 'Female', 'Texas');
-- Student 15
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Matthew Martinez', 3, 1, 'Male', 'New York');
-- Student 16
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Sophia Taylor', 2, 1, 'Female', 'Florida');
-- Student 17
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Alexander White', 5, 4, 'Male', 'California');
-- Student 18
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Johnson', 4, 2, 'Female', 'Texas');
-- Student 19
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Christopher Lee', 3, 1, 'Male', 'New York');
-- Student 20
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emma Wilson', 2, 1, 'Female', 'Florida');
-- Student 21
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Elijah Smith', 5, 3, 'Male', 'Texas');
-- Student 22
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Isabella Davis', 4, 2, 'Female', 'California');
-- Student 23
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Liam Johnson', 3, 1, 'Male', 'New York');
-- Student 24
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Garcia', 2, 1, 'Female', 'Florida');
-- Student 25
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Noah Rodriguez', 5, 3, 'Male', 'Texas');
-- Student 26
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Sophia Hernandez', 4, 2, 'Female', 'California');
-- Student 27
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Mason Smith', 3, 1, 'Male', 'New York');
-- Student 28
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ava Taylor', 2, 1, 'Female', 'Florida');
-- Student 29
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('William Brown', 5, 5, 'Male', 'Texas');
-- Student 30
INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Martinez', 4, 4, 'Female', 'California');

View File

@ -0,0 +1,104 @@
package com.baeldung.jdbcclient;
import com.baeldung.jdbcclient.dao.StudentDao;
import com.baeldung.jdbcclient.model.Student;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.jdbc.Sql;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
@Sql(value = "/jdbcclient/student.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(value = "/jdbcclient/drop_student.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
@SpringBootTest(classes = JdbcClientDemoApplication.class)
@TestPropertySource(locations = {"classpath:jdbcclient/application.properties"})
public class JdbcClientUnitTest {
private static final Logger logger = LoggerFactory.getLogger(JdbcClientUnitTest.class);
@Autowired
private StudentDao studentDao;
@Test
void givenJdbcClient_whenInsertWithNamedParamAndSqlType_thenSuccess() {
logger.info("testing invoked successfully");
Student student = getSampleStudent("Johny Dep", 8, 4, "Male", "New York");
assertEquals(1, studentDao.insertWithSetParamWithNamedParamAndSqlType(student));
}
@Test
void givenJdbcClient_whenQueryWithPositionalParams_thenSuccess() {
logger.info("testing invoked successfully");
List<Student> students = studentDao.getStudentsOfGradeStateAndGenderWithPositionalParams(
1, "New York", "Male");
logger.info("number of students fetched " + students.size());
assertEquals(6, students.size());
}
@Test
void givenJdbcClient_whenQueryWithParamsInVarargs_thenSuccess() {
logger.info("testing invoked successfully");
Student student = studentDao.getStudentsOfGradeStateAndGenderWithParamsInVarargs(
1, "New York", "Male");
assertNotNull(student);
}
@Test
void givenJdbcClient_whenQueryWithParamsInList_thenSuccess() {
logger.info("testing invoked successfully");
List params = List.of(1, "New York", "Male");
Optional<Student> optional = studentDao.getStudentsOfGradeStateAndGenderWithParamsInList(params);
if(optional.isPresent()) {
assertNotNull(optional.get());
} else {
assertThrows(NoSuchElementException.class, () -> optional.get());
}
}
@Test
void givenJdbcClient_whenQueryWithParamsIndex_thenSuccess() {
logger.info("testing invoked successfully");
List<Student> students = studentDao.getStudentsOfGradeStateAndGenderWithParamIndex(
1, "New York", "Male");
assertEquals(6, students.size());
}
@Test
void givenJdbcClient_whenQueryWithNamedParam_thenSuccess() {
logger.info("testing invoked successfully");
Integer count = studentDao.getCountOfStudentsOfGradeStateAndGenderWithNamedParam(
1, "New York", "Male");
logger.info("number of students fetched " + count);
assertEquals(6, count);
}
@Test
void givenJdbcClient_whenQueryWithParamMap_thenSuccess() {
logger.info("testing invoked successfully");
Map<String, ?> paramMap = Map.of(
"grade", 1,
"gender", "Male",
"state", "New York"
);
List<Student> students = studentDao.getStudentsOfGradeStateAndGenderWithParamMap(paramMap);
logger.info("number of students fetched " + students.size());
assertEquals(6, students.size());
}
private Student getSampleStudent(String name, int age, int grade, String gender, String state) {
Student student = new Student();
student.setStudentName(name);
student.setStudentGender(gender);
student.setAge(age);
student.setGrade(grade);
student.setState(state);
return student;
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="15 seconds" debug="false">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%d{ISO8601}]-[%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -349,7 +349,6 @@
<!-- <module>ethereum</module> --> <!-- JAVA-6001 --> <!-- <module>ethereum</module> --> <!-- JAVA-6001 -->
<!-- <module>gradle-modules</module> --> <!-- Not a maven project --> <!-- <module>gradle-modules</module> --> <!-- Not a maven project -->
<!-- <module>grails</module> --> <!-- Not a maven project -->
<!-- <module>guest</module> --> <!-- not to be built as its for guest articles --> <!-- <module>guest</module> --> <!-- not to be built as its for guest articles -->
<!-- <module>lagom</module> --> <!-- Not a maven project --> <!-- <module>lagom</module> --> <!-- Not a maven project -->
@ -362,7 +361,7 @@
<module>muleesb</module> <module>muleesb</module>
<module>web-modules/java-lite</module> <module>web-modules/java-lite</module>
<module>persistence-modules/deltaspike</module> <!-- delta spike it doesn't support yet the jakarta API--> <module>persistence-modules/deltaspike</module> <!-- delta spike it doesn't support yet the jakarta API-->
<module>persistence-modules/hibernate-ogm</module> <!-- hibernate-ogm wasn't updated because it doesn't support jakarta API --> <module>persistence-modules/hibernate-ogm</module> <!-- hibernate-ogm wasn't updated because a workaround for jakarta namespace wasn't found JAVA-20557 -->
<module>persistence-modules/spring-data-cassandra-reactive</module> <!--JAVA-21844--> <module>persistence-modules/spring-data-cassandra-reactive</module> <!--JAVA-21844-->
<module>java-nashorn</module> <module>java-nashorn</module>
<module>jeromq</module> <module>jeromq</module>
@ -523,7 +522,6 @@
<!-- <module>ethereum</module> --> <!-- JAVA-6001 --> <!-- <module>ethereum</module> --> <!-- JAVA-6001 -->
<!-- <module>gradle-modules</module> --> <!-- Not a maven project --> <!-- <module>gradle-modules</module> --> <!-- Not a maven project -->
<!-- <module>grails</module> --> <!-- Not a maven project -->
<!-- <module>guest</module> --> <!-- not to be built as its for guest articles --> <!-- <module>guest</module> --> <!-- not to be built as its for guest articles -->
<!-- <module>lagom</module> --> <!-- Not a maven project --> <!-- <module>lagom</module> --> <!-- Not a maven project -->
@ -534,7 +532,7 @@
<module>muleesb</module> <module>muleesb</module>
<module>web-modules/java-lite</module> <module>web-modules/java-lite</module>
<module>persistence-modules/deltaspike</module> <!-- delta spike it doesn't support yet the jakarta API--> <module>persistence-modules/deltaspike</module> <!-- delta spike it doesn't support yet the jakarta API-->
<module>persistence-modules/hibernate-ogm</module> <!-- hibernate-ogm wasn't updated because it doesn't support jakarta API --> <module>persistence-modules/hibernate-ogm</module> <!-- hibernate-ogm wasn't updated because a workaround for jakarta namespace wasn't found JAVA-20557 -->
<module>persistence-modules/spring-data-cassandra-reactive</module> <!--JAVA-21844--> <module>persistence-modules/spring-data-cassandra-reactive</module> <!--JAVA-21844-->
<module>java-nashorn</module> <module>java-nashorn</module>
<module>jeromq</module> <module>jeromq</module>
@ -932,6 +930,7 @@
<module>spring-di-4</module> <module>spring-di-4</module>
<module>spring-kafka-2</module> <module>spring-kafka-2</module>
<!--<module>java-panama</module> Java-19 module--> <!--<module>java-panama</module> Java-19 module-->
<module>libraries-llms</module>
</modules> </modules>
<properties> <properties>
@ -1214,6 +1213,7 @@
<module>spring-di-4</module> <module>spring-di-4</module>
<module>spring-kafka-2</module> <module>spring-kafka-2</module>
<!--<module>java-panama</module> Java-19 module--> <!--<module>java-panama</module> Java-19 module-->
<module>libraries-llms</module>
</modules> </modules>
<properties> <properties>

View File

@ -0,0 +1,57 @@
version: '3'
services:
frontend:
build: ./frontend
ports:
- "80:80"
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
ports:
- 22181:2181
kafka:
image: confluentinc/cp-kafka:latest
container_name: kafka-broker
depends_on:
- zookeeper
ports:
- 29092:29092
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka-broker:9092,PLAINTEXT_HOST://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
mongodb:
container_name: mongo-db
image: mongo:6.0
volumes:
- ~/mongo:/data/db
ports:
- "27017:27017"
healthcheck:
test: exit 0
order-service:
build: ./order-service
ports:
- "8080:8080"
depends_on:
mongodb:
condition: service_healthy
inventory-service:
build: ./inventory-service
ports:
- "8081:8081"
depends_on:
mongodb:
condition: service_healthy
shipping-service:
build: ./shipping-service
ports:
- "8082:8082"
depends_on:
mongodb:
condition: service_healthy

View File

@ -1,3 +1,3 @@
FROM openjdk:8-jdk-alpine FROM openjdk:8-jdk-alpine
COPY target/inventory-service-async-0.0.1-SNAPSHOT.jar app.jar COPY target/inventory-service-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=docker","/app.jar"] ENTRYPOINT ["java","-jar","-Dspring.profiles.active=docker","/app.jar"]

View File

@ -1,3 +1,3 @@
FROM openjdk:8-jdk-alpine FROM openjdk:8-jdk-alpine
COPY target/order-service-async-0.0.1-SNAPSHOT.jar app.jar COPY target/order-service-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=docker","/app.jar"] ENTRYPOINT ["java","-jar","-Dspring.profiles.active=docker","/app.jar"]

View File

@ -1,3 +1,3 @@
FROM openjdk:8-jdk-alpine FROM openjdk:8-jdk-alpine
COPY target/shipping-service-async-0.0.1-SNAPSHOT.jar app.jar COPY target/shipping-service-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=docker","/app.jar"] ENTRYPOINT ["java","-jar","-Dspring.profiles.active=docker","/app.jar"]

View File

@ -26,6 +26,11 @@
<version>${reactor.version}</version> <version>${reactor.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>io.projectreactor.addons</groupId>
<artifactId>reactor-extra</artifactId>
<version>${reactor.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
@ -35,7 +40,7 @@
</dependencies> </dependencies>
<properties> <properties>
<reactor.version>3.4.17</reactor.version> <reactor.version>3.5.1</reactor.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,48 @@
package com.baeldung.math;
import org.junit.Test;
import reactor.math.MathFlux;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
public class MathFluxOperationsUnitTest {
@Test
public void givenFluxOfNumbers_whenCalculatingSum_thenExpectCorrectResult() {
Flux<Integer> numbers = Flux.just(1, 2, 3, 4, 5);
Mono<Integer> sumMono = MathFlux.sumInt(numbers);
StepVerifier.create(sumMono)
.expectNext(15)
.verifyComplete();
}
@Test
public void givenFluxOfNumbers_whenCalculatingAverage_thenExpectCorrectResult() {
Flux<Integer> numbers = Flux.just(1, 2, 3, 4, 5);
Mono<Double> averageMono = MathFlux.averageDouble(numbers);
StepVerifier.create(averageMono)
.expectNext(3.0)
.verifyComplete();
}
@Test
public void givenFluxOfNumbers_whenFindingMinElement_thenExpectCorrectResult() {
Flux<Integer> numbers = Flux.just(3, 1, 5, 2, 4);
Mono<Integer> minMono = MathFlux.min(numbers);
StepVerifier.create(minMono)
.expectNext(1)
.verifyComplete();
}
@Test
public void givenFluxOfNumbers_whenFindingMaxElement_thenExpectCorrectResult() {
Flux<Integer> numbers = Flux.just(3, 1, 5, 2, 4);
Mono<Integer> maxMono = MathFlux.max(numbers);
StepVerifier.create(maxMono)
.expectNext(5)
.verifyComplete();
}
}

View File

@ -1,18 +0,0 @@
package com.baeldung.activitiwithspring;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ActivitiWithSpringApplication.class)
@AutoConfigureTestDatabase
public class ActivitiWithSpringApplicationIntegrationTest {
@Test
public void contextLoads() {
}
}

View File

@ -0,0 +1,2 @@
## Relevant Articles
- [Spring Boot 3.1s ConnectionDetails Abstraction](https://www.baeldung.com/spring-boot-3-1-connectiondetails-abstraction)

View File

@ -15,6 +15,14 @@
<relativePath>../../parent-boot-3</relativePath> <relativePath>../../parent-boot-3</relativePath>
</parent> </parent>
<repositories>
<repository>
<id>repository.spring.release</id>
<name>Spring GA Repository</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -94,6 +102,17 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<version>3.2.0-M2</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>
@ -175,6 +194,18 @@
</dependency> </dependency>
</dependencies> </dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.0-M2</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<profiles> <profiles>
<profile> <profile>
@ -244,9 +275,6 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -0,0 +1,70 @@
package com.baeldung.conditionalonthreading;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;
import org.springframework.boot.autoconfigure.thread.Threading;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class ConditionalOnThreadingUnitTest {
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withUserConfiguration(CurrentConfig.class);
@Configuration
static class CurrentConfig {
@Bean
@ConditionalOnThreading(Threading.PLATFORM)
ThreadingType platformBean() {
return ThreadingType.PLATFORM;
}
@Bean
@ConditionalOnThreading(Threading.VIRTUAL)
ThreadingType virtualBean() {
return ThreadingType.VIRTUAL;
}
}
enum ThreadingType {
PLATFORM, VIRTUAL
}
@Test
@EnabledForJreRange(max = JRE.JAVA_20)
public void whenJava20AndVirtualThreadsEnabled_thenThreadingIsPlatform() {
applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=true").run(context -> {
Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.PLATFORM);
});
}
@Test
@EnabledForJreRange(max = JRE.JAVA_20)
public void whenJava20AndVirtualThreadsDisabled_thenThreadingIsPlatform() {
applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=false").run(context -> {
Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.PLATFORM);
});
}
@Test
@EnabledForJreRange(min = JRE.JAVA_21)
public void whenJava21AndVirtualThreadsEnabled_thenThreadingIsVirtual() {
applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=true").run(context -> {
Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.VIRTUAL);
});
}
@Test
@EnabledForJreRange(min = JRE.JAVA_21)
public void whenJava21AndVirtualThreadsDisabled_thenThreadingIsPlatform() {
applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=false").run(context -> {
Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.PLATFORM);
});
}
}

View File

@ -8,3 +8,4 @@
- [HTTP Interface in Spring 6](https://www.baeldung.com/spring-6-http-interface) - [HTTP Interface in Spring 6](https://www.baeldung.com/spring-6-http-interface)
- [Working with Virtual Threads in Spring 6](https://www.baeldung.com/spring-6-virtual-threads) - [Working with Virtual Threads in Spring 6](https://www.baeldung.com/spring-6-virtual-threads)
- [Docker Compose Support in Spring Boot 3](https://www.baeldung.com/ops/docker-compose-support-spring-boot) - [Docker Compose Support in Spring Boot 3](https://www.baeldung.com/ops/docker-compose-support-spring-boot)
- [A Guide to RestClient in Spring Boot](https://www.baeldung.com/spring-boot-restclient)

View File

@ -1,7 +1,6 @@
### Relevant Articles: ### Relevant Articles:
- [HttpMessageNotWritableException: No Converter for [class …] With Preset Content-Type](https://www.baeldung.com/spring-no-converter-with-preset) - [HttpMessageNotWritableException: No Converter for [class …] With Preset Content-Type](https://www.baeldung.com/spring-no-converter-with-preset)
- [Spring Boot: Customize the Jackson ObjectMapper](https://www.baeldung.com/spring-boot-customize-jackson-objectmapper)
- [“HttpMessageNotWritableException: No converter found for return value of type”](https://www.baeldung.com/spring-no-converter-found) - [“HttpMessageNotWritableException: No converter found for return value of type”](https://www.baeldung.com/spring-no-converter-found)
- [Creating a Read-Only Repository with Spring Data](https://www.baeldung.com/spring-data-read-only-repository) - [Creating a Read-Only Repository with Spring Data](https://www.baeldung.com/spring-data-read-only-repository)
- [Using JaVers for Data Model Auditing in Spring Data](https://www.baeldung.com/spring-data-javers-audit) - [Using JaVers for Data Model Auditing in Spring Data](https://www.baeldung.com/spring-data-javers-audit)

View File

@ -11,4 +11,5 @@ This module contains articles about Spring Boot with Spring Data
- [Spring Custom Property Editor](https://www.baeldung.com/spring-mvc-custom-property-editor) - [Spring Custom Property Editor](https://www.baeldung.com/spring-mvc-custom-property-editor)
- [Using @JsonComponent in Spring Boot](https://www.baeldung.com/spring-boot-jsoncomponent) - [Using @JsonComponent in Spring Boot](https://www.baeldung.com/spring-boot-jsoncomponent)
- [Guide To Running Logic on Startup in Spring](https://www.baeldung.com/running-setup-logic-on-startup-in-spring) - [Guide To Running Logic on Startup in Spring](https://www.baeldung.com/running-setup-logic-on-startup-in-spring)
- [Spring Boot: Customize the Jackson ObjectMapper](https://www.baeldung.com/spring-boot-customize-jackson-objectmapper)

View File

@ -1,10 +1,10 @@
package com.baeldung.boot.jackson.config; package com.baeldung.boot.jackson.config;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
public class CoffeeConstants { public class CoffeeConstants {
public static final String DATETIME_FORMAT = "dd-MM-yyyy HH:mm"; public static final String DATETIME_FORMAT = "dd-MM-yyyy HH:mm";

View File

@ -1,11 +1,12 @@
package com.baeldung.boot.jackson.config; package com.baeldung.boot.jackson.config;
import com.fasterxml.jackson.annotation.JsonInclude; import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; import com.fasterxml.jackson.annotation.JsonInclude;
@Configuration @Configuration
public class CoffeeCustomizerConfig { public class CoffeeCustomizerConfig {

View File

@ -1,12 +1,13 @@
package com.baeldung.boot.jackson.config; package com.baeldung.boot.jackson.config;
import com.fasterxml.jackson.annotation.JsonInclude; import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; import com.fasterxml.jackson.annotation.JsonInclude;
@Configuration @Configuration
public class CoffeeHttpConverterConfiguration { public class CoffeeHttpConverterConfiguration {

View File

@ -1,12 +1,13 @@
package com.baeldung.boot.jackson.config; package com.baeldung.boot.jackson.config;
import com.fasterxml.jackson.annotation.JsonInclude; import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; import com.fasterxml.jackson.annotation.JsonInclude;
@Configuration @Configuration
public class CoffeeJacksonBuilderConfig { public class CoffeeJacksonBuilderConfig {

View File

@ -1,13 +1,14 @@
package com.baeldung.boot.jackson.config; package com.baeldung.boot.jackson.config;
import com.fasterxml.jackson.annotation.JsonInclude; import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
@Configuration @Configuration
public class CoffeeObjectMapperConfig { public class CoffeeObjectMapperConfig {

View File

@ -1,19 +1,19 @@
package com.baeldung.boot.jackson.config; package com.baeldung.boot.jackson.config;
import com.fasterxml.jackson.databind.Module; import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.PropertySource;
import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
@Configuration @Configuration
@PropertySource("classpath:coffee.properties") @PropertySource("classpath:coffee.properties")
public class CoffeeRegisterModuleConfig { public class CoffeeRegisterModuleConfig {
@Bean @Bean
public Module javaTimeModule() { public JavaTimeModule javaTimeModule() {
JavaTimeModule module = new JavaTimeModule(); JavaTimeModule module = new JavaTimeModule();
module.addSerializer(LOCAL_DATETIME_SERIALIZER); module.addSerializer(LOCAL_DATETIME_SERIALIZER);
return module; return module;

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