Merge branch 'eugenp:master' into danielmcnally285_return_first_non_null
This commit is contained in:
+113
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.baeldung.vectors;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class VectorOperationsUnitTest {
|
||||
|
||||
private static Vector<String> getVector() {
|
||||
Vector<String> vector = new Vector<String>();
|
||||
vector.add("Today");
|
||||
vector.add("is");
|
||||
vector.add("a");
|
||||
vector.add("great");
|
||||
vector.add("day!");
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenAddElementsUsingAddMethod_thenElementsGetAddedAtEnd() {
|
||||
Vector<String> vector = getVector();
|
||||
vector.add("Hello");
|
||||
assertEquals(6, vector.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenUpdateElementAtIndex_thenElementAtIndexGetsUpdated() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
assertEquals("great", vector.get(3));
|
||||
vector.set(3, "good");
|
||||
assertEquals("good", vector.get(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenRemoveAnElement_thenElementGetsRemovedFromTheVector() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
|
||||
// remove a specific element
|
||||
vector.remove("a");
|
||||
assertEquals(4, vector.size());
|
||||
|
||||
// remove at specific index
|
||||
vector.remove(2);
|
||||
assertEquals("day!", vector.get(2));
|
||||
assertEquals(3, vector.size());
|
||||
|
||||
assertEquals(false, vector.remove("SomethingThatDoesn'tExist"));
|
||||
}
|
||||
|
||||
@Test(expected = ArrayIndexOutOfBoundsException.class)
|
||||
public void givenAVector_whenIndexIsBeyondRange_thenRemoveMethodThrowsArrayIndexOutOfBoundsException() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
vector.remove(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenGetElementWithinARange_thenGetMethodGetsAnElementFromTheVector() {
|
||||
Vector<String> vector = getVector();
|
||||
String fourthElement = vector.get(3);
|
||||
assertEquals("great", fourthElement);
|
||||
}
|
||||
|
||||
@Test(expected = ArrayIndexOutOfBoundsException.class)
|
||||
public void givenAVector_whenGetElementBeyondARange_thenGetMethodThrowsArrayIndexOutOfBoundsException() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
vector.get(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenAddElementFromACollection_thenAllElementsGetAdeddToTheVector() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
ArrayList<String> words = new ArrayList<>(Arrays.asList("Baeldung", "is", "cool!"));
|
||||
vector.addAll(words);
|
||||
assertEquals(8, vector.size());
|
||||
assertEquals("cool!", vector.get(7));
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
+85
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+23
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@
|
||||
<source.version>11</source.version>
|
||||
<target.version>11</target.version>
|
||||
<json.version>20200518</json.version>
|
||||
<opencsv.version>4.1</opencsv.version>
|
||||
<opencsv.version>5.8</opencsv.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+72
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+122
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package com.baeldung.optionalsasparameterrecords;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record Product(String name, double price, Optional<String> description) {
|
||||
}
|
||||
+17
@@ -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));
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.baeldung.streamtomapandmultimap;
|
||||
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class StreamToMapAndMultiMapUnitTest {
|
||||
@Test
|
||||
public void givenStringStream_whenConvertingToMapWithMerge_thenExpectedMapIsGenerated() {
|
||||
Stream<String> stringStream = Stream.of("one", "two", "three", "two");
|
||||
|
||||
Map<String, String> mergedMap = stringStream.collect(
|
||||
Collectors.toMap(s -> s, s -> s, (s1, s2) -> s1 + ", " + s2)
|
||||
);
|
||||
|
||||
// Define the expected map
|
||||
Map<String, String> expectedMap = Map.of(
|
||||
"one", "one",
|
||||
"two", "two, two",
|
||||
"three", "three"
|
||||
);
|
||||
|
||||
assertEquals(expectedMap, mergedMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringStream_whenConvertingToMultimap_thenExpectedMultimapIsGenerated() {
|
||||
Stream<String> stringStream = Stream.of("one", "two", "three", "two");
|
||||
|
||||
LinkedHashMultimap<Object, Object> multimap = LinkedHashMultimap.create();
|
||||
|
||||
stringStream.collect(Collectors.groupingBy(
|
||||
s -> s,
|
||||
Collectors.mapping(s -> s, Collectors.toList())
|
||||
)).forEach((key, value) -> multimap.putAll(key, value));
|
||||
|
||||
LinkedHashMultimap<Object, Object> expectedMultimap = LinkedHashMultimap.create();
|
||||
expectedMultimap.put("one", "one");
|
||||
expectedMultimap.put("two", "two");
|
||||
expectedMultimap.put("three", "three");
|
||||
|
||||
assertEquals(expectedMultimap, multimap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringStream_whenConvertingToMultimapWithStreamReduce_thenExpectedMultimapIsGenerated() {
|
||||
Stream<String> stringStream = Stream.of("one", "two", "three", "two");
|
||||
|
||||
Map<String, List<String>> multimap = stringStream.reduce(
|
||||
new HashMap<>(),
|
||||
(map, element) -> {
|
||||
map.computeIfAbsent(element, k -> new ArrayList<>()).add(element);
|
||||
return map;
|
||||
},
|
||||
(map1, map2) -> {
|
||||
map2.forEach((key, value) -> map1.merge(key, value, (list1, list2) -> {
|
||||
list1.addAll(list2);
|
||||
return list1;
|
||||
}));
|
||||
return map1;
|
||||
}
|
||||
);
|
||||
|
||||
Map<String, List<String>> expectedMultimap = new HashMap<>();
|
||||
expectedMultimap.put("one", Collections.singletonList("one"));
|
||||
expectedMultimap.put("two", Arrays.asList("two", "two"));
|
||||
expectedMultimap.put("three", Collections.singletonList("three"));
|
||||
|
||||
assertEquals(expectedMultimap, multimap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringStream_whenConvertingToMapWithStreamReduce_thenExpectedMapIsGenerated() {
|
||||
Stream<String> stringStream = Stream.of("one", "two", "three", "two");
|
||||
|
||||
Map<String, String> resultMap = stringStream.reduce(
|
||||
new HashMap<>(),
|
||||
(map, element) -> {
|
||||
map.put(element, element);
|
||||
return map;
|
||||
},
|
||||
(map1, map2) -> {
|
||||
map1.putAll(map2);
|
||||
return map1;
|
||||
}
|
||||
);
|
||||
|
||||
Map<String, String> expectedMap = new HashMap<>();
|
||||
expectedMap.put("one", "one");
|
||||
expectedMap.put("two", "two");
|
||||
expectedMap.put("three", "three");
|
||||
|
||||
assertEquals(expectedMap, resultMap);
|
||||
}
|
||||
}
|
||||
+38
-23
@@ -1,7 +1,11 @@
|
||||
package com.baeldung.streams;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@@ -11,14 +15,12 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
class Java8StreamsUnitTest {
|
||||
|
||||
public class Java8StreamsUnitTest {
|
||||
private static List<String> list;
|
||||
|
||||
private List<String> list;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
@BeforeAll
|
||||
public static void init() {
|
||||
list = new ArrayList<>();
|
||||
list.add("One");
|
||||
list.add("OneAndOnly");
|
||||
@@ -42,60 +44,73 @@ public class Java8StreamsUnitTest {
|
||||
Stream<String> streamOf = Stream.of("a", "b", "c");
|
||||
assertEquals(streamOf.count(), 3);
|
||||
|
||||
long count = list.stream().distinct().count();
|
||||
long count = list.stream()
|
||||
.distinct()
|
||||
.count();
|
||||
assertEquals(count, 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkStreamCount_whenOperationFilter_thanCorrect() {
|
||||
Stream<String> streamFilter = list.stream().filter(element -> element.isEmpty());
|
||||
void checkStreamCount_whenOperationFilter_thanCorrect() {
|
||||
Stream<String> streamFilter = list.stream()
|
||||
.filter(element -> element.isEmpty());
|
||||
assertEquals(streamFilter.count(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkStreamCount_whenOperationMap_thanCorrect() {
|
||||
void checkStreamCount_whenOperationMap_thanCorrect() {
|
||||
List<String> uris = new ArrayList<>();
|
||||
uris.add("C:\\My.txt");
|
||||
Stream<Path> streamMap = uris.stream().map(uri -> Paths.get(uri));
|
||||
Stream<Path> streamMap = uris.stream()
|
||||
.map(uri -> Paths.get(uri));
|
||||
assertEquals(streamMap.count(), 1);
|
||||
|
||||
List<Detail> details = new ArrayList<>();
|
||||
details.add(new Detail());
|
||||
details.add(new Detail());
|
||||
Stream<String> streamFlatMap = details.stream().flatMap(detail -> detail.getParts().stream());
|
||||
Stream<String> streamFlatMap = details.stream()
|
||||
.flatMap(detail -> detail.getParts()
|
||||
.stream());
|
||||
assertEquals(streamFlatMap.count(), 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkStreamCount_whenOperationMatch_thenCorrect() {
|
||||
boolean isValid = list.stream().anyMatch(element -> element.contains("h"));
|
||||
boolean isValidOne = list.stream().allMatch(element -> element.contains("h"));
|
||||
boolean isValidTwo = list.stream().noneMatch(element -> element.contains("h"));
|
||||
void checkStreamCount_whenOperationMatch_thenCorrect() {
|
||||
boolean isValid = list.stream()
|
||||
.anyMatch(element -> element.contains("h"));
|
||||
boolean isValidOne = list.stream()
|
||||
.allMatch(element -> element.contains("h"));
|
||||
boolean isValidTwo = list.stream()
|
||||
.noneMatch(element -> element.contains("h"));
|
||||
assertTrue(isValid);
|
||||
assertFalse(isValidOne);
|
||||
assertFalse(isValidTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkStreamReducedValue_whenOperationReduce_thenCorrect() {
|
||||
void checkStreamReducedValue_whenOperationReduce_thenCorrect() {
|
||||
List<Integer> integers = new ArrayList<>();
|
||||
integers.add(1);
|
||||
integers.add(1);
|
||||
integers.add(1);
|
||||
Integer reduced = integers.stream().reduce(23, (a, b) -> a + b);
|
||||
Integer reduced = integers.stream()
|
||||
.reduce(23, (a, b) -> a + b);
|
||||
assertTrue(reduced == 26);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkStreamContains_whenOperationCollect_thenCorrect() {
|
||||
List<String> resultList = list.stream().map(element -> element.toUpperCase()).collect(Collectors.toList());
|
||||
void checkStreamContains_whenOperationCollect_thenCorrect() {
|
||||
List<String> resultList = list.stream()
|
||||
.map(element -> element.toUpperCase())
|
||||
.collect(Collectors.toList());
|
||||
assertEquals(resultList.size(), list.size());
|
||||
assertTrue(resultList.contains(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkParallelStream_whenDoWork() {
|
||||
list.parallelStream().forEach(element -> doWork(element));
|
||||
list.parallelStream()
|
||||
.forEach(element -> doWork(element));
|
||||
}
|
||||
|
||||
private void doWork(String string) {
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<opencsv.version>4.1</opencsv.version>
|
||||
<opencsv.version>5.8</opencsv.version>
|
||||
<spring-core.version>5.3.13</spring-core.version>
|
||||
<apache-commons-lang3.version>3.12.0</apache-commons-lang3.version>
|
||||
<apache-commons-text.version>1.10.0</apache-commons-text.version>
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@ import com.opencsv.CSVParser;
|
||||
import com.opencsv.CSVParserBuilder;
|
||||
import com.opencsv.CSVReader;
|
||||
import com.opencsv.CSVReaderBuilder;
|
||||
import com.opencsv.exceptions.CsvException;
|
||||
|
||||
public class SplitCommaSeparatedString {
|
||||
|
||||
@@ -50,7 +51,7 @@ public class SplitCommaSeparatedString {
|
||||
return splitter.splitToList(input);
|
||||
}
|
||||
|
||||
public static List<String[]> splitMultiLineWithOpenCSV(String input) throws IOException {
|
||||
public static List<String[]> splitMultiLineWithOpenCSV(String input) throws IOException, CsvException {
|
||||
CSVParser parser = new CSVParserBuilder().withSeparator(',')
|
||||
.build();
|
||||
|
||||
|
||||
+3
-1
@@ -14,6 +14,8 @@ import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.opencsv.exceptions.CsvException;
|
||||
|
||||
public class SplitCommaSeparatedStringUnitTest {
|
||||
|
||||
@Test
|
||||
@@ -27,7 +29,7 @@ public class SplitCommaSeparatedStringUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultiLineInput_whenParsing_shouldIgnoreCommasInsideDoubleQuotes() throws IOException {
|
||||
public void givenMultiLineInput_whenParsing_shouldIgnoreCommasInsideDoubleQuotes() throws IOException, CsvException {
|
||||
String input = "baeldung,tutorial,splitting,text,\"ignoring this comma,\"" + System.lineSeparator()
|
||||
+ "splitting,a,regular,line,no double quotes";
|
||||
|
||||
|
||||
+34
@@ -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();
|
||||
}
|
||||
}
|
||||
+65
@@ -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");
|
||||
}
|
||||
}
|
||||
+24
@@ -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);
|
||||
}
|
||||
}
|
||||
+17
@@ -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);
|
||||
}
|
||||
}
|
||||
+24
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
+42
@@ -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();
|
||||
}
|
||||
}
|
||||
+39
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
## JNI
|
||||
|
||||
This module contains articles about the Java Native Interface (JNI).
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Guide to JNI (Java Native Interface)](https://www.baeldung.com/jni)
|
||||
- [Using JNA to Access Native Dynamic Libraries](https://www.baeldung.com/java-jna-dynamic-libraries)
|
||||
- [Check if a Java Program Is Running in 64-Bit or 32-Bit JVM](https://www.baeldung.com/java-detect-jvm-64-or-32-bit)
|
||||
- [How to use JNI’s RegisterNatives() method?](https://www.baeldung.com/jni-registernatives)
|
||||
- [Custom DLL Load – Fixing the “java.lang.UnsatisfiedLinkError” Error](https://www.baeldung.com/java-custom-dll-load-fixing-the-java-lang-unsatisfiedlinkerror-error)
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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>java-native</artifactId>
|
||||
<name>java-native</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna-platform</artifactId>
|
||||
<version>${jna.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- we don't want to reuse JVMs here ! -->
|
||||
<reuseForks>false</reuseForks>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<jna.version>5.6.0</jna.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "com_baeldung_jni_ExampleObjectsJNI.h"
|
||||
#include <iostream>
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_jni_ExampleObjectsJNI
|
||||
* Method: createUser
|
||||
* Signature: (Ljava/lang/String;D)Lcom/baeldung/jni/UserData;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_baeldung_jni_ExampleObjectsJNI_createUser
|
||||
(JNIEnv *env, jobject thisObject, jstring name, jdouble balance){
|
||||
|
||||
// Create the object of the class UserData
|
||||
jclass userDataClass = env->FindClass("com/baeldung/jni/UserData");
|
||||
jobject newUserData = env->AllocObject(userDataClass);
|
||||
|
||||
// Get UserData fields to set
|
||||
jfieldID nameField = env->GetFieldID(userDataClass , "name", "Ljava/lang/String;");
|
||||
jfieldID balanceField = env->GetFieldID(userDataClass , "balance", "D");
|
||||
|
||||
// Set the values of the new object
|
||||
env->SetObjectField(newUserData, nameField, name);
|
||||
env->SetDoubleField(newUserData, balanceField, balance);
|
||||
|
||||
// Return the created object
|
||||
return newUserData;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_jni_ExampleObjectsJNI
|
||||
* Method: printUserData
|
||||
* Signature: (Lcom/baeldung/jni/UserData;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_jni_ExampleObjectsJNI_printUserData
|
||||
(JNIEnv *env, jobject thisObject, jobject userData){
|
||||
|
||||
// Find the class method id
|
||||
jclass userDataClass = env->GetObjectClass(userData);
|
||||
jmethodID methodId = env->GetMethodID(userDataClass, "getUserInfo", "()Ljava/lang/String;");
|
||||
|
||||
// Call the object method and get the result
|
||||
jstring result = (jstring)env->CallObjectMethod(userData, methodId);
|
||||
|
||||
// Print the result
|
||||
std::cout << "C++: User data is: " << env->GetStringUTFChars(result, NULL) << std::endl;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_baeldung_jni_ExampleObjectsJNI */
|
||||
|
||||
#ifndef _Included_com_baeldung_jni_ExampleObjectsJNI
|
||||
#define _Included_com_baeldung_jni_ExampleObjectsJNI
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_baeldung_jni_ExampleObjectsJNI
|
||||
* Method: createUser
|
||||
* Signature: (Ljava/lang/String;D)Lcom/baeldung/jni/UserData;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_baeldung_jni_ExampleObjectsJNI_createUser
|
||||
(JNIEnv *, jobject, jstring, jdouble);
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_jni_ExampleObjectsJNI
|
||||
* Method: printUserData
|
||||
* Signature: (Lcom/baeldung/jni/UserData;)V
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_jni_ExampleObjectsJNI_printUserData
|
||||
(JNIEnv *, jobject, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "com_baeldung_jni_ExampleParametersJNI.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_jni_ExampleParametersJNI
|
||||
* Method: sumIntegers
|
||||
* Signature: (II)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_com_baeldung_jni_ExampleParametersJNI_sumIntegers (JNIEnv* env, jobject thisObject, jint first, jint second){
|
||||
std::cout << "C++: The numbers received are : " << first << " and " << second << std::endl;
|
||||
return (long)first + (long)second;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_jni_ExampleParametersJNI
|
||||
* Method: sayHelloToMe
|
||||
* Signature: (Ljava/lang/String;Z)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_jni_ExampleParametersJNI_sayHelloToMe (JNIEnv* env, jobject thisObject, jstring name, jboolean isFemale){
|
||||
const char* nameCharPointer = env->GetStringUTFChars(name, NULL);
|
||||
std::cout << "C++: The string received is: " << nameCharPointer << std::endl;
|
||||
std::string title;
|
||||
if(isFemale){
|
||||
title = "Ms. ";
|
||||
}
|
||||
else{
|
||||
title = "Mr. ";
|
||||
}
|
||||
|
||||
std::string fullName = title + nameCharPointer;
|
||||
return env->NewStringUTF(fullName.c_str());
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_baeldung_jni_ExampleParametersJNI */
|
||||
|
||||
#ifndef _Included_com_baeldung_jni_ExampleParametersJNI
|
||||
#define _Included_com_baeldung_jni_ExampleParametersJNI
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_baeldung_jni_ExampleParametersJNI
|
||||
* Method: sumIntegers
|
||||
* Signature: (II)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_com_baeldung_jni_ExampleParametersJNI_sumIntegers
|
||||
(JNIEnv*, jobject, jint, jint);
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_jni_ExampleParametersJNI
|
||||
* Method: sayHelloToMe
|
||||
* Signature: (Ljava/lang/String;Z)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_jni_ExampleParametersJNI_sayHelloToMe
|
||||
(JNIEnv*, jobject, jstring, jboolean);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "com_baeldung_jni_HelloWorldJNI.h"
|
||||
#include <iostream>
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_jni_HelloWorldJNI
|
||||
* Method: sayHello
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_jni_HelloWorldJNI_sayHello (JNIEnv* env, jobject thisObject) {
|
||||
std::string hello = "Hello from C++ !!";
|
||||
std::cout << hello << std::endl;
|
||||
return env->NewStringUTF(hello.c_str());
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_baeldung_jni_HelloWorldJNI */
|
||||
|
||||
#ifndef _Included_com_baeldung_jni_HelloWorldJNI
|
||||
#define _Included_com_baeldung_jni_HelloWorldJNI
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_baeldung_jni_HelloWorldJNI
|
||||
* Method: sayHello
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_jni_HelloWorldJNI_sayHello
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
#include "com_baeldung_jni_RegisterNativesHelloWorldJNI.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
JNIEXPORT jstring JNICALL hello (JNIEnv* env, jobject thisObject) {
|
||||
std::string hello = "Hello from registered native C++ !!";
|
||||
std::cout << hello << std::endl;
|
||||
return env->NewStringUTF(hello.c_str());
|
||||
}
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
{"sayHello", "()Ljava/lang/String;", (void*) &hello },
|
||||
};
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_register (JNIEnv* env, jobject thsObject) {
|
||||
jclass clazz = env->FindClass("com/baeldung/jni/RegisterNativesHelloWorldJNI");
|
||||
|
||||
(env)->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(methods[0]));
|
||||
}
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_baeldung_jni_RegisterNativesHelloWorldJNI */
|
||||
|
||||
#ifndef _Included_com_baeldung_jni_RegisterNativesHelloWorldJNI
|
||||
#define _Included_com_baeldung_jni_RegisterNativesHelloWorldJNI
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_baeldung_jni_RegisterNativesHelloWorldJNI
|
||||
* Method: sayHello
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_sayHello
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_jni_RegisterNativesHelloWorldJNI
|
||||
* Method: register
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_register
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
REM Create the header with javac -h . ClassName.java
|
||||
REM Remember to set your JAVA_HOME env var
|
||||
g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
|
||||
g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 com_baeldung_jni_ExampleParametersJNI.cpp -o com_baeldung_jni_ExampleParametersJNI.o
|
||||
g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 com_baeldung_jni_ExampleObjectsJNI.cpp -o com_baeldung_jni_ExampleObjectsJNI.o
|
||||
g++ -shared -o ..\..\..\native\win32\native.dll com_baeldung_jni_HelloWorldJNI.o com_baeldung_jni_ExampleParametersJNI.o com_baeldung_jni_ExampleObjectsJNI.o -Wl,--add-stdcall-alias
|
||||
@@ -0,0 +1,7 @@
|
||||
# Create the header with javac -h . ClassName.java
|
||||
# Remember to set your JAVA_HOME env var
|
||||
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
|
||||
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux com_baeldung_jni_ExampleParametersJNI.cpp -o com_baeldung_jni_ExampleParametersJNI.o
|
||||
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux com_baeldung_jni_ExampleObjectsJNI.cpp -o com_baeldung_jni_ExampleObjectsJNI.o
|
||||
g++ -shared -fPIC -o ../../../native/linux_x86_64/libnative.so com_baeldung_jni_HelloWorldJNI.o com_baeldung_jni_ExampleParametersJNI.o com_baeldung_jni_ExampleObjectsJNI.o -lc
|
||||
# Don't forget to set java.library.path to point to the folder where you have the libnative you're loading.
|
||||
@@ -0,0 +1,7 @@
|
||||
# Create the header with javac -h . ClassName.java
|
||||
# Remember to set your JAVA_HOME env var
|
||||
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
|
||||
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_ExampleParametersJNI.cpp -o com_baeldung_jni_ExampleParametersJNI.o
|
||||
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_ExampleObjectsJNI.cpp -o com_baeldung_jni_ExampleObjectsJNI.o
|
||||
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_RegisterNativesHelloWorldJNI.cpp -o com_baeldung_jni_RegisterNativesHelloWorldJNI.o
|
||||
g++ -dynamiclib -o ../../../native/macos/libnative.dylib com_baeldung_jni_HelloWorldJNI.o com_baeldung_jni_ExampleParametersJNI.o com_baeldung_jni_ExampleObjectsJNI.o com_baeldung_jni_RegisterNativesHelloWorldJNI.o -lc
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#include "com_baeldung_unsatisfiedlink_JniUnsatisfiedLink.h"
|
||||
#include <iostream>
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
* Method: test
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_unsatisfiedlink_JniUnsatisfiedLink_test (JNIEnv* env, jobject thisObject) {
|
||||
std::string test = "Test OK";
|
||||
std::cout << test << std::endl;
|
||||
return env->NewStringUTF(test.c_str());
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_baeldung_unsatisfiedlink_JniUnsatisfiedLink */
|
||||
|
||||
#ifndef _Included_com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
#define _Included_com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
* Method: test
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_unsatisfiedlink_JniUnsatisfiedLink_test
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
# Create the header with javac -h . ClassName.java
|
||||
# Remember to set your JAVA_HOME env var
|
||||
# Don't forget to set java.library.path to point to the folder where you have the lib you're loading.
|
||||
MYSELF="$(readlink -f "$0")"
|
||||
MYDIR="${MYSELF%/*}"
|
||||
|
||||
cd "$MYDIR"
|
||||
class_name=com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
lib_name=test
|
||||
|
||||
g++ -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" ${class_name}.cpp -o ${class_name}.o
|
||||
g++ -shared -fPIC -o lib${lib_name}.so ${class_name}.o -lc
|
||||
|
||||
# 32-bit version
|
||||
g++ -m32 -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" ${class_name}.cpp -o ${class_name}32.o
|
||||
g++ -m32 -shared -fPIC -o lib${lib_name}32.so ${class_name}32.o -lc
|
||||
|
||||
# dummy version
|
||||
touch ${class_name}-dummy.o
|
||||
|
||||
ls lib*
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.baeldung.jna;
|
||||
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Platform;
|
||||
|
||||
public interface CMath extends Library {
|
||||
CMath INSTANCE = Native.load(Platform.isWindows() ? "msvcrt" : "c", CMath.class);
|
||||
double cosh(double value);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.baeldung.jna;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.baeldung.jna;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.FunctionMapper;
|
||||
import com.sun.jna.LastErrorException;
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.NativeLong;
|
||||
import com.sun.jna.Platform;
|
||||
import com.sun.jna.Structure;
|
||||
import com.sun.jna.Structure.FieldOrder;
|
||||
|
||||
public interface NativeFS extends Library {
|
||||
|
||||
FunctionMapper mapper = (library,method) -> {
|
||||
if (Platform.isWindows()) {
|
||||
return "_" + method.getName();
|
||||
}
|
||||
else {
|
||||
return "__x" + method.getName(); // On Linux, stat is actually _xstat
|
||||
}
|
||||
};
|
||||
|
||||
public NativeFS INSTANCE = Native.load(Platform.isWindows() ? "msvcrt" : "c",
|
||||
NativeFS.class,
|
||||
Collections.singletonMap(Library.OPTION_FUNCTION_MAPPER, mapper));
|
||||
|
||||
int stat(String path, Stat stat) throws LastErrorException;
|
||||
|
||||
@FieldOrder({"st_dev","st_ino","st_mode","st_nlink","st_uid","st_gid","st_rdev","st_size","st_atime","st_mtime","st_ctime"})
|
||||
public class Stat extends Structure {
|
||||
public int st_dev;
|
||||
public int st_ino;
|
||||
public short st_mode;
|
||||
public short st_nlink;
|
||||
public short st_uid;
|
||||
public short st_gid;
|
||||
public int st_rdev;
|
||||
public NativeLong st_size;
|
||||
public NativeLong st_atime;
|
||||
public NativeLong st_mtime;
|
||||
public NativeLong st_ctime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.jna;
|
||||
|
||||
import com.sun.jna.LastErrorException;
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Platform;
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
public interface StdC extends Library {
|
||||
StdC INSTANCE = Native.load(Platform.isWindows() ? "msvcrt" : "c", StdC.class );
|
||||
Pointer malloc(long n);
|
||||
void free(Pointer p);
|
||||
Pointer memset(Pointer p, int c, long n);
|
||||
int open(String path, int flags) throws LastErrorException;
|
||||
int close(int fd) throws LastErrorException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.jni;
|
||||
|
||||
public class ExampleObjectsJNI {
|
||||
|
||||
static {
|
||||
System.loadLibrary("native");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
ExampleObjectsJNI instance = new ExampleObjectsJNI();
|
||||
UserData newUser = instance.createUser("John Doe", 450.67);
|
||||
instance.printUserData(newUser);
|
||||
}
|
||||
|
||||
public native UserData createUser(String name, double balance);
|
||||
|
||||
public native String printUserData(UserData user);
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.baeldung.jni;
|
||||
|
||||
public class ExampleParametersJNI {
|
||||
|
||||
static {
|
||||
System.loadLibrary("native");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Java: My full name: " + new ExampleParametersJNI().sayHelloToMe("Martin", false));
|
||||
long sumFromNative = new ExampleParametersJNI().sumIntegers(456, 44);
|
||||
System.out.println("Java: The sum coming from native code is: " + sumFromNative);
|
||||
}
|
||||
|
||||
// Declare another method sumIntegers that receives two integers and return a long with the sum
|
||||
public native long sumIntegers(int first, int second);
|
||||
|
||||
// Declare another method sayHelloToMe that receives the name and gender and returns the proper salutation
|
||||
public native String sayHelloToMe(String name, boolean isFemale);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.baeldung.jni;
|
||||
|
||||
public class HelloWorldJNI {
|
||||
|
||||
static {
|
||||
System.loadLibrary("native");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new HelloWorldJNI().sayHello();
|
||||
}
|
||||
|
||||
// Declare a native method sayHello() that receives no arguments and returns void
|
||||
public native String sayHello();
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.jni;
|
||||
|
||||
public class RegisterNativesHelloWorldJNI {
|
||||
|
||||
static {
|
||||
System.loadLibrary("native");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
RegisterNativesHelloWorldJNI helloWorldJNI = new RegisterNativesHelloWorldJNI();
|
||||
helloWorldJNI.register();
|
||||
helloWorldJNI.sayHello();
|
||||
}
|
||||
|
||||
public native String sayHello();
|
||||
|
||||
public native void register();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.jni;
|
||||
|
||||
public class UserData {
|
||||
|
||||
public String name;
|
||||
public double balance;
|
||||
|
||||
public String getUserInfo() {
|
||||
return "[name]=" + name + ", [balance]=" + balance;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.jvmbitversion;
|
||||
|
||||
import com.sun.jna.Platform;
|
||||
|
||||
public class JVMBitVersion {
|
||||
|
||||
public String getUsingSystemClass() {
|
||||
return System.getProperty("sun.arch.data.model") + "-bit";
|
||||
}
|
||||
|
||||
public String getUsingNativeClass() {
|
||||
if (com.sun.jna.Native.POINTER_SIZE == 8) {
|
||||
return "64-bit";
|
||||
} else if (com.sun.jna.Native.POINTER_SIZE == 4) {
|
||||
return "32-bit";
|
||||
} else
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
public boolean getUsingPlatformClass() {
|
||||
return (Platform.is64Bit());
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.baeldung.unsatisfiedlink;
|
||||
|
||||
public class JniUnsatisfiedLink {
|
||||
|
||||
public static final String LIB_NAME = "test";
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.loadLibrary(LIB_NAME);
|
||||
new JniUnsatisfiedLink().test();
|
||||
}
|
||||
|
||||
public native String test();
|
||||
|
||||
public native String nonexistentDllMethod();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,3 @@
|
||||
grant {
|
||||
permission java.lang.RuntimePermission "loadLibrary.test";
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.jna;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Platform;
|
||||
|
||||
class CMathUnitTest {
|
||||
@Test
|
||||
void whenCallNative_thenSuccess() {
|
||||
CMath lib = Native.load(Platform.isWindows() ? "msvcrt" : "c", CMath.class);
|
||||
double result = lib.cosh(0);
|
||||
assertEquals(1.0,result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.jna;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.jna.NativeFS.Stat;
|
||||
import com.sun.jna.LastErrorException;
|
||||
import com.sun.jna.Platform;
|
||||
|
||||
public class NativeFSUnitTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void whenCallNative_thenSuccess() throws IOException {
|
||||
NativeFS lib = NativeFS.INSTANCE;
|
||||
|
||||
File f = Files.createTempFile("junit", ".bin").toFile();
|
||||
f.deleteOnExit();
|
||||
Stat stat = new Stat();
|
||||
try {
|
||||
if (Platform.isWindows()) {
|
||||
int rc = lib.stat(f.getAbsolutePath(), stat);
|
||||
assertEquals(0, rc);
|
||||
assertEquals(0,stat.st_size.longValue());
|
||||
}
|
||||
}
|
||||
catch(LastErrorException error) {
|
||||
fail("stat failed: error code=" + error.getErrorCode());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.baeldung.jna;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Platform;
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
class StdCUnitTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setupProtectedMode() {
|
||||
Native.setProtected(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMalloc_thenSuccess() {
|
||||
StdC lib = StdC.INSTANCE;
|
||||
Pointer p = lib.malloc(1024);
|
||||
p.setMemory(0l, 1024l, (byte) 0);
|
||||
lib.free(p);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAccessViolation_thenShouldThrowError() {
|
||||
// Running this test on Linux requires additional setup using libjsig.so
|
||||
// Details here: http://java-native-access.github.io/jna/5.6.0/javadoc/overview-summary.html#crash-protection
|
||||
// IMPORTANT NOTICE: Code for illustration purposes only. DON'T DO THIS IN YOUR OWN CODE
|
||||
if ( Platform.isWindows()) {
|
||||
Error e = null;
|
||||
Pointer p = new Pointer(0l);
|
||||
|
||||
try {
|
||||
p.setMemory(0, 100*1024, (byte) 0);
|
||||
}
|
||||
catch(Error err) {
|
||||
e = err;
|
||||
}
|
||||
|
||||
assertNotNull(e, "Should throw Error");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.baeldung.jni;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class JNINativeManualTest {
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
System.loadLibrary("native");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNativeHelloWorld_thenOutputIsAsExpected() {
|
||||
HelloWorldJNI helloWorld = new HelloWorldJNI();
|
||||
String helloFromNative = helloWorld.sayHello();
|
||||
assertTrue(!helloFromNative.isEmpty() && helloFromNative.equals("Hello from C++ !!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSumNative_thenResultIsArithmeticallyCorrect() {
|
||||
ExampleParametersJNI parametersNativeMethods = new ExampleParametersJNI();
|
||||
assertTrue(parametersNativeMethods.sumIntegers(200, 400) == 600L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSayingNativeHelloToMe_thenResultIsAsExpected() {
|
||||
ExampleParametersJNI parametersNativeMethods = new ExampleParametersJNI();
|
||||
assertEquals(parametersNativeMethods.sayHelloToMe("Orange", true), "Ms. Orange");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCreatingNativeObject_thenObjectIsNotNullAndHasCorrectData() {
|
||||
String name = "Iker Casillas";
|
||||
double balance = 2378.78;
|
||||
ExampleObjectsJNI objectsNativeMethods = new ExampleObjectsJNI();
|
||||
UserData userFromNative = objectsNativeMethods.createUser(name, balance);
|
||||
assertNotNull(userFromNative);
|
||||
assertEquals(userFromNative.name, name);
|
||||
assertTrue(userFromNative.balance == balance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNativeCallingObjectMethod_thenResultIsAsExpected() {
|
||||
String name = "Sergio Ramos";
|
||||
double balance = 666.77;
|
||||
ExampleObjectsJNI objectsNativeMethods = new ExampleObjectsJNI();
|
||||
UserData userData = new UserData();
|
||||
userData.name = name;
|
||||
userData.balance = balance;
|
||||
assertEquals(objectsNativeMethods.printUserData(userData), "[name]=" + name + ", [balance]=" + balance);
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.jni.registernatives;
|
||||
|
||||
import com.baeldung.jni.RegisterNativesHelloWorldJNI;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class JNIRegisterNativesManualTest {
|
||||
@Before
|
||||
public void setup() {
|
||||
System.loadLibrary("native");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenRegisteredNativeHelloWorld_thenOutputIsAsExpected() {
|
||||
RegisterNativesHelloWorldJNI helloWorld = new RegisterNativesHelloWorldJNI();
|
||||
helloWorld.register();
|
||||
|
||||
String helloFromNative = helloWorld.sayHello();
|
||||
|
||||
assertNotNull(helloFromNative);
|
||||
assertTrue(helloFromNative.equals("Hello from registered native C++ !!"));
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.baeldung.jvmbitversion;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sun.jna.Platform;
|
||||
|
||||
public class JVMBitVersionUnitTest {
|
||||
|
||||
private JVMBitVersion jvmVersion;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
jvmVersion = new JVMBitVersion();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUsingSystemClass_thenOutputIsAsExpected() {
|
||||
if ("64".equals(System.getProperty("sun.arch.data.model"))) {
|
||||
assertEquals("64-bit", jvmVersion.getUsingSystemClass());
|
||||
} else if ("32".equals(System.getProperty("sun.arch.data.model"))) {
|
||||
assertEquals("32-bit", jvmVersion.getUsingSystemClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUsingNativeClass_thenResultIsAsExpected() {
|
||||
if (com.sun.jna.Native.POINTER_SIZE == 8) {
|
||||
assertEquals("64-bit", jvmVersion.getUsingNativeClass());
|
||||
} else if (com.sun.jna.Native.POINTER_SIZE == 4) {
|
||||
assertEquals("32-bit", jvmVersion.getUsingNativeClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUsingPlatformClass_thenResultIsAsExpected() {
|
||||
if (Platform.is64Bit() == Boolean.TRUE) {
|
||||
assertEquals(Boolean.TRUE, jvmVersion.getUsingPlatformClass());
|
||||
} else if (com.sun.jna.Native.POINTER_SIZE == 4) {
|
||||
assertEquals(Boolean.FALSE, jvmVersion.getUsingPlatformClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.baeldung.unsatisfiedlink;
|
||||
|
||||
import static com.baeldung.unsatisfiedlink.JniUnsatisfiedLink.LIB_NAME;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class JniUnsatisfiedLinkManualTest {
|
||||
|
||||
static String osLibPrefix = "";
|
||||
static String osLibSuffix = "";
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
String osName = System.getProperty("os.name")
|
||||
.toLowerCase();
|
||||
|
||||
if (osName.contains("win")) {
|
||||
osLibSuffix = ".dll";
|
||||
} else if (osName.contains("nix") || osName.contains("nux") || osName.contains("mac")) {
|
||||
osLibPrefix = "lib";
|
||||
osLibSuffix = ".so";
|
||||
if (osName.contains("mac")) {
|
||||
osLibPrefix = "lib";
|
||||
osLibSuffix = ".dylib";
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported operating system: " + osName);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCorrectLibName_thenLibLoaded() {
|
||||
assertDoesNotThrow(() -> {
|
||||
System.loadLibrary(LIB_NAME);
|
||||
new JniUnsatisfiedLink().test();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenIncorrectLibName_thenLibNotFound() {
|
||||
String libName = osLibPrefix + LIB_NAME + osLibSuffix;
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(libName));
|
||||
|
||||
assertEquals(String.format("no %s in java.library.path", libName), error.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenLoadLibraryContainsPathSeparator_thenErrorThrown() {
|
||||
String libName = "/" + LIB_NAME;
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(libName));
|
||||
|
||||
assertEquals(String.format("Directory separator should not appear in library name: %s", libName), error.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenLoadWithoutAbsolutePath_thenErrorThrown() {
|
||||
String libName = LIB_NAME;
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.load(libName));
|
||||
|
||||
assertEquals(String.format("Expecting an absolute path of the library: %s", libName), error.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUnlinkedMethod_thenErrorThrown() {
|
||||
System.loadLibrary(LIB_NAME);
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> new JniUnsatisfiedLink().nonexistentDllMethod());
|
||||
|
||||
assertTrue(error.getMessage()
|
||||
.contains("JniUnsatisfiedLink.nonexistentDllMethod"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenIncompatibleArchitecture_thenErrorThrown() {
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(LIB_NAME + "32"));
|
||||
|
||||
assertTrue(error.getMessage()
|
||||
.contains("wrong ELF class: ELFCLASS32"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCorruptedFile_thenErrorThrown() {
|
||||
String libPath = System.getProperty("java.library.path");
|
||||
assertNotNull(libPath);
|
||||
|
||||
String dummyLib = LIB_NAME + "-dummy";
|
||||
assertTrue(new File(libPath, osLibPrefix + dummyLib + osLibSuffix).isFile());
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(dummyLib));
|
||||
|
||||
assertTrue(error.getMessage()
|
||||
.contains("file too short"));
|
||||
}
|
||||
}
|
||||
@@ -199,6 +199,7 @@
|
||||
<module>core-java-date-operations-1</module>
|
||||
<!--<module>core-java-datetime-conversion</module>--> <!--JAVA-25433-->
|
||||
<module>core-java-httpclient</module>
|
||||
<module>java-native</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
Reference in New Issue
Block a user