Merge branch 'eugenp:master' into JAVA-26380
This commit is contained in:
commit
c7a4c2f623
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.baeldung.algorithms.connect4;
|
||||
|
||||
public enum Piece {
|
||||
PLAYER_1,
|
||||
PLAYER_2
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -6,10 +6,10 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -18,22 +18,50 @@ import lombok.extern.slf4j.Slf4j;
|
|||
@Slf4j
|
||||
public class ExecutorUnitTest {
|
||||
Article article;
|
||||
Stream<Author> stream;
|
||||
Spliterator<Author> spliterator;
|
||||
|
||||
@Before
|
||||
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),
|
||||
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);
|
||||
|
||||
spliterator = new RelatedAuthorSpliterator(article.getListOfAuthors());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAstreamOfAuthors_whenProcessedInParallelWithCustomSpliterator_coubtProducessRightOutput() {
|
||||
Stream<Author> stream2 = StreamSupport.stream(spliterator, true);
|
||||
assertThat(Executor.countAutors(stream2.parallel())).isEqualTo(9);
|
||||
public void givenAStreamOfIntegers_whenProcessedSequentialCustomSpliterator_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);
|
||||
|
||||
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
|
||||
|
@ -43,9 +71,7 @@ public class ExecutorUnitTest {
|
|||
.collect(Collectors.toList());
|
||||
|
||||
Spliterator<Article> spliterator = articles.spliterator();
|
||||
while (spliterator.tryAdvance(article -> article.setName(article.getName()
|
||||
.concat("- published by Baeldung"))))
|
||||
;
|
||||
while(spliterator.tryAdvance(article -> article.setName(article.getName().concat("- published by Baeldung"))));
|
||||
|
||||
articles.forEach(article -> assertThat(article.getName()).isEqualTo("Java- published by Baeldung"));
|
||||
}
|
||||
|
|
|
@ -58,4 +58,8 @@
|
|||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,3 +3,4 @@
|
|||
This module contains articles about Java array fundamentals. They assume no previous background knowledge on working with arrays.
|
||||
|
||||
### Relevant Articles:
|
||||
- [Arrays mismatch() Method in Java](https://www.baeldung.com/java-arrays-mismatch)
|
||||
|
|
|
@ -7,4 +7,5 @@
|
|||
- [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)
|
||||
- [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)
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
## Relevant Articles
|
||||
- [Difference Between putIfAbsent() and computeIfAbsent() in Java’s Map](https://www.baeldung.com/java-map-putifabsent-computeifabsent)
|
||||
- [How to Write Hashmap to CSV File](https://www.baeldung.com/java-write-hashmap-csv)
|
||||
|
|
|
@ -79,5 +79,18 @@
|
|||
<version>1.5</version>
|
||||
</dependency>
|
||||
</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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -10,4 +10,5 @@ This module contains articles about basic Java concurrency.
|
|||
- [Returning a Value After Finishing Thread’s 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 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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
- [A Guide to the Java ExecutorService](https://www.baeldung.com/java-executor-service-tutorial)
|
||||
- [Guide To CompletableFuture](https://www.baeldung.com/java-completablefuture)
|
||||
- [How To Manage Timeout for CompletableFuture](https://www.baeldung.com/java-completablefuture-timeout)
|
||||
|
||||
### NOTE:
|
||||
|
||||
|
|
|
@ -12,6 +12,15 @@
|
|||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.wiremock</groupId>
|
||||
<artifactId>wiremock</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>core-java-concurrency-simple</finalName>
|
||||
<resources>
|
||||
|
|
|
@ -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": "Huawei’s 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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -35,6 +35,21 @@
|
|||
<artifactId>simplemagic</artifactId>
|
||||
<version>${simplemagic.version}</version>
|
||||
</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>
|
||||
|
||||
<build>
|
||||
|
@ -62,5 +77,6 @@
|
|||
<jmime-magic.version>0.1.5</jmime-magic.version>
|
||||
<jodd-util.version>6.2.1</jodd-util.version>
|
||||
<simplemagic.version>1.17</simplemagic.version>
|
||||
<jmh.version>1.37</jmh.version>
|
||||
</properties>
|
||||
</project>
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
I'm going to Alabama
|
||||
Alabama is a state in the US
|
|
@ -0,0 +1 @@
|
|||
Dreams from My Father by Barack Obama
|
|
@ -0,0 +1 @@
|
|||
Harry Potter and the Chamber of Secrets
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.baeldung.optionalsasparameterrecords;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record Product(String name, double price, Optional<String> description) {
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -85,7 +85,7 @@ public class AlphanumericPerformanceBenchmark {
|
|||
|
||||
public boolean isAlphanumeric(final int codePoint) {
|
||||
return (codePoint >= 65 && codePoint <= 90) ||
|
||||
(codePoint >= 97 && codePoint <= 172) ||
|
||||
(codePoint >= 97 && codePoint <= 122) ||
|
||||
(codePoint >= 48 && codePoint <= 57);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
- [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)
|
||||
- [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)
|
||||
|
|
|
@ -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)
|
||||
- [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)
|
||||
- [Wrapping a String After a Number of Characters Word-Wise](https://www.baeldung.com/java-wrap-string-number-characters-word-wise)
|
||||
|
|
|
@ -3,3 +3,5 @@
|
|||
- [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)
|
||||
- [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)
|
||||
|
|
|
@ -54,6 +54,11 @@
|
|||
<artifactId>commons-codec</artifactId>
|
||||
<version>${commons-codec.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${spring-core.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -95,6 +100,7 @@
|
|||
<javax.el-api.version>3.0.0</javax.el-api.version>
|
||||
<javax.el.version>2.2.6</javax.el.version>
|
||||
<commons-codec.version>1.14</commons-codec.version>
|
||||
<spring-core.version>5.3.0</spring-core.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -3,6 +3,7 @@ package com.baeldung.emptystrings;
|
|||
import com.google.common.base.Strings;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Test;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
|
@ -109,6 +110,24 @@ public class EmptyStringsUnitTest {
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
- [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)
|
||||
- [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)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
### 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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 Multi-line String](https://www.baeldung.com/java-multiline-string)
|
||||
- [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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -42,17 +42,17 @@ public class AVLTree {
|
|||
return root == null ? -1 : root.height;
|
||||
}
|
||||
|
||||
private Node insert(Node node, int key) {
|
||||
if (node == null) {
|
||||
private Node insert(Node root, int key) {
|
||||
if (root == null) {
|
||||
return new Node(key);
|
||||
} else if (node.key > key) {
|
||||
node.left = insert(node.left, key);
|
||||
} else if (node.key < key) {
|
||||
node.right = insert(node.right, key);
|
||||
} else if (root.key > key) {
|
||||
root.left = insert(root.left, key);
|
||||
} else if (root.key < key) {
|
||||
root.right = insert(root.right, key);
|
||||
} else {
|
||||
throw new RuntimeException("duplicate Key!");
|
||||
}
|
||||
return rebalance(node);
|
||||
return rebalance(root);
|
||||
}
|
||||
|
||||
private Node delete(Node node, int key) {
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
|
||||
- [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 CSV File from POJO with Custom Column Headers and Positions](https://www.baeldung.com/java-create-csv-pojo-customize-columns)
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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>";
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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.
|
|
@ -22,6 +22,7 @@ public class EditorUnitTest {
|
|||
loadAndVerifyTestData(entityManagerFactory, editor);
|
||||
}
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void givenNeo4j_WhenEntitiesCreated_thenCanBeRetrieved() throws Exception {
|
||||
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("ogm-neo4j");
|
||||
|
|
|
@ -106,6 +106,7 @@
|
|||
<module>spring-jpa</module>
|
||||
<module>spring-jpa-2</module>
|
||||
<module>spring-jdbc</module>
|
||||
<module>spring-jdbc-2</module>
|
||||
<module>spring-jooq</module>
|
||||
<module>spring-mybatis</module>
|
||||
<module>spring-persistence-simple</module>
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
DROP TABLE student;
|
|
@ -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');
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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>
|
8
pom.xml
8
pom.xml
|
@ -349,7 +349,6 @@
|
|||
|
||||
<!-- <module>ethereum</module> --> <!-- JAVA-6001 -->
|
||||
<!-- <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>lagom</module> --> <!-- Not a maven project -->
|
||||
|
@ -362,7 +361,7 @@
|
|||
<module>muleesb</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/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>java-nashorn</module>
|
||||
<module>jeromq</module>
|
||||
|
@ -523,7 +522,6 @@
|
|||
|
||||
<!-- <module>ethereum</module> --> <!-- JAVA-6001 -->
|
||||
<!-- <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>lagom</module> --> <!-- Not a maven project -->
|
||||
|
@ -534,7 +532,7 @@
|
|||
<module>muleesb</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/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>java-nashorn</module>
|
||||
<module>jeromq</module>
|
||||
|
@ -932,6 +930,7 @@
|
|||
<module>spring-di-4</module>
|
||||
<module>spring-kafka-2</module>
|
||||
<!--<module>java-panama</module> Java-19 module-->
|
||||
<module>libraries-llms</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
@ -1214,6 +1213,7 @@
|
|||
<module>spring-di-4</module>
|
||||
<module>spring-kafka-2</module>
|
||||
<!--<module>java-panama</module> Java-19 module-->
|
||||
<module>libraries-llms</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
|
|
@ -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
|
|
@ -1,3 +1,3 @@
|
|||
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"]
|
|
@ -1,3 +1,3 @@
|
|||
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"]
|
|
@ -1,3 +1,3 @@
|
|||
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"]
|
|
@ -26,6 +26,11 @@
|
|||
<version>${reactor.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.addons</groupId>
|
||||
<artifactId>reactor-extra</artifactId>
|
||||
<version>${reactor.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
@ -35,7 +40,7 @@
|
|||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<reactor.version>3.4.17</reactor.version>
|
||||
<reactor.version>3.5.1</reactor.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
## Relevant Articles
|
||||
- [Spring Boot 3.1’s ConnectionDetails Abstraction](https://www.baeldung.com/spring-boot-3-1-connectiondetails-abstraction)
|
|
@ -15,6 +15,14 @@
|
|||
<relativePath>../../parent-boot-3</relativePath>
|
||||
</parent>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>repository.spring.release</id>
|
||||
<name>Spring GA Repository</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
@ -94,6 +102,17 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<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>
|
||||
<groupId>org.postgresql</groupId>
|
||||
|
@ -175,6 +194,18 @@
|
|||
</dependency>
|
||||
</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>
|
||||
|
||||
<profile>
|
||||
|
@ -244,9 +275,6 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgs>--enable-preview</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -8,3 +8,4 @@
|
|||
- [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)
|
||||
- [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)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [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)
|
||||
- [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)
|
||||
|
|
|
@ -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)
|
||||
- [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)
|
||||
- [Spring Boot: Customize the Jackson ObjectMapper](https://www.baeldung.com/spring-boot-customize-jackson-objectmapper)
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package com.baeldung.boot.jackson.config;
|
||||
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
|
||||
public class CoffeeConstants {
|
||||
|
||||
public static final String DATETIME_FORMAT = "dd-MM-yyyy HH:mm";
|
|
@ -1,11 +1,12 @@
|
|||
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.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@Configuration
|
||||
public class CoffeeCustomizerConfig {
|
|
@ -1,12 +1,13 @@
|
|||
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.Configuration;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
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
|
||||
public class CoffeeHttpConverterConfiguration {
|
|
@ -1,12 +1,13 @@
|
|||
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.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
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
|
||||
public class CoffeeJacksonBuilderConfig {
|
|
@ -1,13 +1,14 @@
|
|||
package com.baeldung.boot.jackson.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
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
|
||||
public class CoffeeObjectMapperConfig {
|
|
@ -1,19 +1,19 @@
|
|||
package com.baeldung.boot.jackson.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
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
|
||||
@PropertySource("classpath:coffee.properties")
|
||||
public class CoffeeRegisterModuleConfig {
|
||||
|
||||
@Bean
|
||||
public Module javaTimeModule() {
|
||||
public JavaTimeModule javaTimeModule() {
|
||||
JavaTimeModule module = new JavaTimeModule();
|
||||
module.addSerializer(LOCAL_DATETIME_SERIALIZER);
|
||||
return module;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue