Merge branch 'eugenp:master' into JAVA-26280

This commit is contained in:
anuragkumawat 2023-11-03 18:39:24 +05:30 committed by GitHub
commit ef027438e9
67 changed files with 1661 additions and 93 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,3 @@
FROM openjdk:8-jdk-alpine
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"]

View File

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

View File

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

View File

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

View File

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

View File

@ -91,6 +91,10 @@
<artifactId>aspectjweaver</artifactId>
<version>${aspectjweaver.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>

View File

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

View File

@ -0,0 +1,38 @@
package com.baeldung.restvalidation.config;
import javax.validation.MessageInterpolator;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MessageSourceResourceBundleLocator;
@Configuration
public class MessageConfig {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:CustomValidationMessages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
@Bean
public MessageInterpolator getMessageInterpolator(MessageSource messageSource) {
MessageSourceResourceBundleLocator resourceBundleLocator = new MessageSourceResourceBundleLocator(messageSource);
ResourceBundleMessageInterpolator messageInterpolator = new ResourceBundleMessageInterpolator(resourceBundleLocator);
return new RecursiveLocaleContextMessageInterpolator(messageInterpolator);
}
@Bean
public LocalValidatorFactoryBean getValidator(MessageInterpolator messageInterpolator) {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setMessageInterpolator(messageInterpolator);
return bean;
}
}

View File

@ -0,0 +1,36 @@
package com.baeldung.restvalidation.config;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.validation.MessageInterpolator;
import org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
public class RecursiveLocaleContextMessageInterpolator extends AbstractMessageInterpolator {
private static final Pattern PATTERN_PLACEHOLDER = Pattern.compile("\\{([^}]+)\\}");
private final MessageInterpolator interpolator;
public RecursiveLocaleContextMessageInterpolator(ResourceBundleMessageInterpolator interpolator) {
this.interpolator = interpolator;
}
@Override
public String interpolate(MessageInterpolator.Context context, Locale locale, String message) {
int level = 0;
while (containsPlaceholder(message) && (level++ < 2)) {
message = this.interpolator.interpolate(message, context, locale);
}
return message;
}
private boolean containsPlaceholder(String code) {
Matcher matcher = PATTERN_PLACEHOLDER.matcher(code);
return matcher.find();
}
}

View File

@ -0,0 +1,12 @@
package com.baeldung.restvalidation.response;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class InputFieldError {
private String field;
private String message;
}

View File

@ -0,0 +1,17 @@
package com.baeldung.restvalidation.response;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UpdateUserResponse {
private List<InputFieldError> fieldErrors;
}

View File

@ -0,0 +1,15 @@
package com.baeldung.restvalidation.service1;
import javax.validation.constraints.NotEmpty;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@NotEmpty
private String email;
}

View File

@ -0,0 +1,36 @@
package com.baeldung.restvalidation.service1;
import org.springframework.http.*;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.Valid;
import com.baeldung.restvalidation.response.InputFieldError;
import com.baeldung.restvalidation.response.UpdateUserResponse;
@RestController
public class UserService1 {
@PutMapping(value = "/user1", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UpdateUserResponse> updateUser(@RequestBody @Valid User user,
BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<InputFieldError> fieldErrorList = bindingResult.getFieldErrors().stream()
.map(error -> new InputFieldError(error.getField(), error.getDefaultMessage()))
.collect(Collectors.toList());
UpdateUserResponse updateResponse = new UpdateUserResponse(fieldErrorList);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(updateResponse);
}
else {
// Update logic...
return ResponseEntity.status(HttpStatus.OK).build();
}
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung.restvalidation.service2;
import javax.validation.constraints.NotEmpty;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@NotEmpty(message = "{validation.email.notEmpty}")
private String email;
}

View File

@ -0,0 +1,40 @@
package com.baeldung.restvalidation.service2;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.baeldung.restvalidation.response.InputFieldError;
import com.baeldung.restvalidation.response.UpdateUserResponse;
@RestController
public class UserService2 {
@PutMapping(value = "/user2", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UpdateUserResponse> updateUser(@RequestBody @Valid User user,
BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<InputFieldError> fieldErrorList = bindingResult.getFieldErrors().stream()
.map(error -> new InputFieldError(error.getField(), error.getDefaultMessage()))
.collect(Collectors.toList());
UpdateUserResponse updateResponse = new UpdateUserResponse(fieldErrorList);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(updateResponse);
}
else {
// Update logic...
return ResponseEntity.status(HttpStatus.OK).build();
}
}
}

View File

@ -0,0 +1,32 @@
package com.baeldung.restvalidation.service3;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Documented
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Constraint(validatedBy = { FieldNotEmptyValidator.class })
public @interface FieldNotEmpty {
String message() default "{validation.notEmpty}";
String field() default "Field";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,16 @@
package com.baeldung.restvalidation.service3;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class FieldNotEmptyValidator implements ConstraintValidator<FieldNotEmpty, Object> {
private String message;
private String field;
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
return (value != null && !value.toString().trim().isEmpty());
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.restvalidation.service3;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@FieldNotEmpty(message = "{validation.notEmpty}", field = "{field.personalEmail}")
private String email;
}

View File

@ -0,0 +1,40 @@
package com.baeldung.restvalidation.service3;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.baeldung.restvalidation.response.InputFieldError;
import com.baeldung.restvalidation.response.UpdateUserResponse;
@RestController
public class UserService3 {
@PutMapping(value = "/user3", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UpdateUserResponse> updateUser(@RequestBody @Valid User user,
BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<InputFieldError> fieldErrorList = bindingResult.getFieldErrors().stream()
.map(error -> new InputFieldError(error.getField(), error.getDefaultMessage()))
.collect(Collectors.toList());
UpdateUserResponse updateResponse = new UpdateUserResponse(fieldErrorList);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(updateResponse);
}
else {
// Update logic...
return ResponseEntity.status(HttpStatus.OK).build();
}
}
}

View File

@ -0,0 +1,3 @@
field.personalEmail=Personal Email
validation.notEmpty={field} cannot be empty
validation.email.notEmpty=Email cannot be empty

View File

@ -0,0 +1,3 @@
field.personalEmail=個人電郵
validation.notEmpty={field}不能是空白
validation.email.notEmpty=電郵不能留空

View File

@ -0,0 +1 @@
javax.validation.constraints.NotEmpty.message=The field cannot be empty

View File

@ -0,0 +1 @@
javax.validation.constraints.NotEmpty.message=本欄不能留空

View File

@ -0,0 +1,75 @@
package com.baeldung.restvalidation.service1;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Objects;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.baeldung.restvalidation.RestValidationApplication;
import com.baeldung.restvalidation.response.InputFieldError;
import com.baeldung.restvalidation.response.UpdateUserResponse;
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RestValidationApplication.class)
class UserService1IntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void whenUpdateValidEmail_thenReturnsOK() {
// When
ResponseEntity<UpdateUserResponse> responseEntity = updateUser(new User("test@email.com"), null);
// Then
assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
}
@Test
void whenUpdateEmptyEmail_thenReturnsErrorMessageInEnglish() {
// When
ResponseEntity<UpdateUserResponse> responseEntity = updateUser(new User(""), null);
// Then
InputFieldError error = responseEntity.getBody().getFieldErrors().get(0);
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
assertEquals("The field cannot be empty", error.getMessage());
}
@Test
void whenUpdateEmptyEmailWithLanguageHeaderEqualsToZh_thenReturnsErrorMessageInChinese() {
// When
ResponseEntity<UpdateUserResponse> responseEntity = updateUser(new User(""), "zh-tw");
// Then
InputFieldError error = responseEntity.getBody().getFieldErrors().get(0);
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
assertEquals("本欄不能留空", error.getMessage());
}
private ResponseEntity<UpdateUserResponse> updateUser(User user, String language) {
HttpHeaders headers = new HttpHeaders();
if (Objects.nonNull(language)) {
headers.set(HttpHeaders.ACCEPT_LANGUAGE, language);
}
return restTemplate.exchange(
"/user1",
HttpMethod.PUT,
new HttpEntity<>(user, headers),
UpdateUserResponse.class
);
}
}

View File

@ -0,0 +1,75 @@
package com.baeldung.restvalidation.service2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Objects;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.baeldung.restvalidation.RestValidationApplication;
import com.baeldung.restvalidation.response.InputFieldError;
import com.baeldung.restvalidation.response.UpdateUserResponse;
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RestValidationApplication.class)
class UserService2IntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void whenUpdateValidEmail_thenReturnsOK() {
// When
ResponseEntity<UpdateUserResponse> responseEntity = updateUser(new User("test@email.com"), null);
// Then
assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
}
@Test
void whenUpdateEmptyEmail_thenReturnsErrorMessageInEnglish() {
// When
ResponseEntity<UpdateUserResponse> responseEntity = updateUser(new User(""), null);
// Then
InputFieldError error = responseEntity.getBody().getFieldErrors().get(0);
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
assertEquals("Email cannot be empty", error.getMessage());
}
@Test
void whenUpdateEmptyEmailWithLanguageHeaderEqualsToZh_thenReturnsErrorMessageInChinese() {
// When
ResponseEntity<UpdateUserResponse> responseEntity = updateUser(new User(""), "zh-tw");
// Then
InputFieldError error = responseEntity.getBody().getFieldErrors().get(0);
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
assertEquals("電郵不能留空", error.getMessage());
}
private ResponseEntity<UpdateUserResponse> updateUser(User user, String language) {
HttpHeaders headers = new HttpHeaders();
if (Objects.nonNull(language)) {
headers.set(HttpHeaders.ACCEPT_LANGUAGE, language);
}
return restTemplate.exchange(
"/user2",
HttpMethod.PUT,
new HttpEntity<>(user, headers),
UpdateUserResponse.class
);
}
}

View File

@ -0,0 +1,75 @@
package com.baeldung.restvalidation.service3;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Objects;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.baeldung.restvalidation.RestValidationApplication;
import com.baeldung.restvalidation.response.InputFieldError;
import com.baeldung.restvalidation.response.UpdateUserResponse;
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RestValidationApplication.class)
class UserService3IntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void whenUpdateValidEmail_thenReturnsOK() {
// When
ResponseEntity<UpdateUserResponse> responseEntity = updateUser(new User("test@email.com"), null);
// Then
assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
}
@Test
void whenUpdateEmptyEmail_thenReturnsErrorMessageInEnglish() {
// When
ResponseEntity<UpdateUserResponse> responseEntity = updateUser(new User(""), null);
// Then
InputFieldError error = responseEntity.getBody().getFieldErrors().get(0);
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
assertEquals("Personal Email cannot be empty", error.getMessage());
}
@Test
void whenUpdateEmptyEmailWithLanguageHeaderEqualsToZh_thenReturnsErrorMessageInChinese() {
// When
ResponseEntity<UpdateUserResponse> responseEntity = updateUser(new User(""), "zh-tw");
// Then
InputFieldError error = responseEntity.getBody().getFieldErrors().get(0);
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
assertEquals("個人電郵不能是空白", error.getMessage());
}
private ResponseEntity<UpdateUserResponse> updateUser(User user, String language) {
HttpHeaders headers = new HttpHeaders();
if (Objects.nonNull(language)) {
headers.set(HttpHeaders.ACCEPT_LANGUAGE, language);
}
return restTemplate.exchange(
"/user3",
HttpMethod.PUT,
new HttpEntity<>(user, headers),
UpdateUserResponse.class
);
}
}

View File

@ -16,10 +16,12 @@
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
@ -30,16 +32,25 @@
<artifactId>spring-cloud-contract-wiremock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-stub-runner</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud-contract-producer</artifactId>
<version>${project.parent.version}</version>
<classifier>stubs</classifier>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>

View File

@ -1,24 +1,18 @@
package com.baeldung.spring.cloud.springcloudcontractconsumer.controller;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.cloud.contract.stubrunner.junit.StubRunnerRule;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -26,42 +20,16 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
@AutoConfigureJsonTesters
@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.LOCAL,
ids = "com.baeldung.spring.cloud:spring-cloud-contract-producer:+:stubs:8090")
public class BasicMathControllerIntegrationTest {
@Rule
public StubRunnerRule rule = new StubRunnerRule().downloadStub(
"com.baeldung.spring.cloud",
"spring-cloud-contract-producer")
.withPort(8090).failOnNoStubs(true);
@Autowired
private MockMvc mockMvc;
private static WireMockServer wireMockServer;
@BeforeClass
public static void setupClass() {
WireMockConfiguration wireMockConfiguration = WireMockConfiguration.options().port(8090); // Use the same port as in your code
wireMockServer = new WireMockServer(wireMockConfiguration);
wireMockServer.start();
}
@AfterClass
public static void teardownClass() {
wireMockServer.stop();
}
@Before
public void setup() {
wireMockServer.stubFor(get(urlEqualTo("/validate/prime-number?number=1"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("Odd")));
wireMockServer.stubFor(get(urlEqualTo("/validate/prime-number?number=2"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("Even")));
}
@Test
public void given_WhenPassEvenNumberInQueryParam_ThenReturnEven() throws Exception {

View File

@ -9,9 +9,9 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-spring-5</artifactId>
<artifactId>parent-spring-6</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-spring-5</relativePath>
<relativePath>../parent-spring-6</relativePath>
</parent>
<dependencyManagement>
@ -46,11 +46,6 @@
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>${javax.inject.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@ -84,9 +79,8 @@
</build>
<properties>
<spring-boot.version>2.6.1</spring-boot.version>
<spring-boot.version>3.1.2</spring-boot.version>
<aspectj-plugin.version>1.14.0</aspectj-plugin.version>
<javax.inject.version>1</javax.inject.version>
<log4j2.version>2.17.1</log4j2.version>
</properties>

View File

@ -3,9 +3,9 @@ package com.baeldung.di.aspectj;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Transient;
@Entity
@Configurable(preConstruction = true)

View File

@ -3,8 +3,8 @@ package com.baeldung.wiring.configuration.inject;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import javax.inject.Inject;
import javax.inject.Named;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -3,7 +3,7 @@ package com.baeldung.wiring.configuration.inject;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import javax.inject.Inject;
import jakarta.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -3,7 +3,7 @@ package com.baeldung.wiring.configuration.inject;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import javax.inject.Inject;
import jakarta.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -5,7 +5,7 @@ import static org.junit.Assert.assertNotNull;
import java.io.File;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -9,7 +9,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.baeldung.wiring.configuration.ApplicationContextTestResourceQualifier;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.io.File;
import static org.junit.Assert.assertEquals;

View File

@ -8,7 +8,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.baeldung.wiring.configuration.ApplicationContextTestResourceNameType;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.io.File;
import static org.junit.Assert.assertEquals;

View File

@ -8,7 +8,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.baeldung.wiring.configuration.ApplicationContextTestResourceNameType;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.io.File;
import static org.junit.Assert.assertEquals;

View File

@ -8,7 +8,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.baeldung.wiring.configuration.ApplicationContextTestResourceNameType;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.io.File;
import static org.junit.Assert.assertEquals;

View File

@ -9,7 +9,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.baeldung.wiring.configuration.ApplicationContextTestResourceQualifier;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.io.File;
import static org.junit.Assert.assertEquals;

View File

@ -8,7 +8,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.baeldung.wiring.configuration.ApplicationContextTestResourceNameType;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.io.File;
import static org.junit.Assert.assertEquals;

View File

@ -9,9 +9,9 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-spring-5</artifactId>
<artifactId>parent-spring-6</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-spring-5</relativePath>
<relativePath>../parent-spring-6</relativePath>
</parent>
<dependencyManagement>
@ -45,8 +45,10 @@
</dependencies>
<properties>
<spring-boot.version>2.6.1</spring-boot.version>
<spring-boot.version>3.1.2</spring-boot.version>
<log4j2.version>2.17.1</log4j2.version>
<org.slf4j.version>2.0.9</org.slf4j.version>
<logback.version>1.4.11</logback.version>
</properties>
</project>

View File

@ -7,7 +7,7 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DynamicAutowireConfig.class)

View File

@ -9,9 +9,9 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-2</relativePath>
<relativePath>../parent-boot-3</relativePath>
</parent>
<dependencies>

View File

@ -2,7 +2,7 @@ package com.baeldung.sampleabstract;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
public abstract class BallService {

View File

@ -10,9 +10,9 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-spring-5</artifactId>
<artifactId>parent-spring-6</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-spring-5</relativePath>
<relativePath>../parent-spring-6</relativePath>
</parent>
<dependencyManagement>
@ -48,11 +48,6 @@
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>${javax.inject.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
@ -71,7 +66,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>${mockito.spring.boot.version}</version>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
@ -89,11 +84,6 @@
<!-- <groupId>org.springframework</groupId> -->
<!-- <artifactId>spring-context</artifactId> -->
<!-- </dependency> -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>${annotation-api.version}</version>
</dependency>
<!-- &lt;!&ndash; test scoped &ndash;&gt; -->
<!-- <dependency> -->
<!-- <groupId>org.springframework</groupId> -->
@ -143,11 +133,7 @@
<properties>
<start-class>org.baeldung.org.baeldung.sample.App</start-class>
<!-- Spring -->
<annotation-api.version>1.3.2</annotation-api.version>
<mockito.spring.boot.version>1.4.4.RELEASE</mockito.spring.boot.version>
<javax.inject.version>1</javax.inject.version>
<spring-boot.version>1.5.2.RELEASE</spring-boot.version>
<mockito.version>1.10.19</mockito.version>
<spring-boot.version>3.1.2</spring-boot.version>
<aspectjweaver.version>1.9.5</aspectjweaver.version>
</properties>