Merge branch 'master' of https://github.com/eugenp/tutorials into BAEL_3301_testing_@ConfigurationProperties
This commit is contained in:
@@ -11,5 +11,5 @@ This module contains articles about core Java input and output (IO)
|
||||
- [List Files in a Directory in Java](https://www.baeldung.com/java-list-directory-files)
|
||||
- [Java – Append Data to a File](https://www.baeldung.com/java-append-to-file)
|
||||
- [How to Copy a File with Java](https://www.baeldung.com/java-copy-file)
|
||||
- [Create a Directory in Java](https://www.baeldung.com/java-create-directory)
|
||||
- [Create a Directory in Java](https://www.baeldung.com/java-create-directory)
|
||||
- [[<-- Prev]](/core-java-modules/core-java-io)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
package com.baeldung.lock;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.nio.channels.NonReadableChannelException;
|
||||
import java.nio.channels.NonWritableChannelException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
public class FileLocks {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FileLocks.class);
|
||||
|
||||
// Write locks
|
||||
|
||||
/**
|
||||
* Trying to get an exclusive lock on a read-only FileChannel won't work.
|
||||
*/
|
||||
static void getExclusiveLockFromInputStream() throws IOException {
|
||||
Path path = Files.createTempFile("foo", "txt");
|
||||
try (FileInputStream fis = new FileInputStream(path.toFile());
|
||||
FileLock lock = fis.getChannel()
|
||||
.lock()) {
|
||||
LOG.debug("This won't happen");
|
||||
} catch (NonWritableChannelException e) {
|
||||
LOG.error("The channel obtained through a FileInputStream isn't writable. You can't obtain an exclusive lock on it!");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an exclusive lock from a RandomAccessFile. Works because the file is writable.
|
||||
* @param from beginning of the locked region
|
||||
* @param size how many bytes to lock
|
||||
* @return A lock object representing the newly-acquired lock
|
||||
* @throws IOException if there is a problem creating the temporary file
|
||||
*/
|
||||
static FileLock getExclusiveLockFromRandomAccessFile(long from, long size) throws IOException {
|
||||
Path path = Files.createTempFile("foo", "txt");
|
||||
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "rw");
|
||||
FileLock lock = file.getChannel()
|
||||
.lock(from, size, false)) {
|
||||
if (lock.isValid()) {
|
||||
LOG.debug("This is a valid exclusive lock");
|
||||
return lock;
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires an exclusive lock on a file region.
|
||||
* @param from beginning of the locked region
|
||||
* @param size how many bytes to lock
|
||||
* @return A lock object representing the newly-acquired lock
|
||||
* @throws IOException if there is a problem creating the temporary file
|
||||
*/
|
||||
static FileLock getExclusiveLockFromFileChannelOpen(long from, long size) throws IOException {
|
||||
Path path = Files.createTempFile("foo", "txt");
|
||||
try (FileChannel channel = FileChannel.open(path, StandardOpenOption.APPEND); FileLock lock = channel.lock(from, size, false)) {
|
||||
String text = "Hello, world.";
|
||||
ByteBuffer buffer = ByteBuffer.allocate(text.length() + System.lineSeparator()
|
||||
.length());
|
||||
buffer.put((text + System.lineSeparator()).getBytes(StandardCharsets.UTF_8));
|
||||
buffer.flip();
|
||||
while (buffer.hasRemaining()) {
|
||||
channel.write(buffer, channel.size());
|
||||
}
|
||||
LOG.debug("This was written to the file");
|
||||
Files.lines(path)
|
||||
.forEach(LOG::debug);
|
||||
return lock;
|
||||
}
|
||||
}
|
||||
|
||||
// Read locks
|
||||
|
||||
/**
|
||||
* Trying to get a shared lock on a write-only FileChannel won't work.
|
||||
*/
|
||||
static void getReadLockFromOutputStream() throws IOException {
|
||||
Path path = Files.createTempFile("foo", "txt");
|
||||
try (FileOutputStream fis = new FileOutputStream(path.toFile());
|
||||
FileLock lock = fis.getChannel()
|
||||
.lock(0, Long.MAX_VALUE, true)) {
|
||||
LOG.debug("This won't happen");
|
||||
} catch (NonReadableChannelException e) {
|
||||
LOG.error("The channel obtained through a FileOutputStream isn't readable. " + "You can't obtain an shared lock on it!");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a lock from an <tt>InputStream</tt>.
|
||||
* @param from beginning of the locked region
|
||||
* @param size how many bytes to lock
|
||||
* @return A lock object representing the newly-acquired lock
|
||||
* @throws IOException if there is a problem creating the temporary file
|
||||
*/
|
||||
static FileLock getReadLockFromInputStream(long from, long size) throws IOException {
|
||||
Path path = Files.createTempFile("foo", "txt");
|
||||
try (FileInputStream fis = new FileInputStream(path.toFile());
|
||||
FileLock lock = fis.getChannel()
|
||||
.lock(from, size, true)) {
|
||||
if (lock.isValid()) {
|
||||
LOG.debug("This is a valid shared lock");
|
||||
return lock;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an exclusive lock from a RandomAccessFile. Works because the file is readable.
|
||||
* @param from beginning of the locked region
|
||||
* @param size how many bytes to lock
|
||||
* @return A lock object representing the newly-acquired lock
|
||||
* @throws IOException if there is a problem creating the temporary file
|
||||
*/
|
||||
static FileLock getReadLockFromRandomAccessFile(long from, long size) throws IOException {
|
||||
Path path = Files.createTempFile("foo", "txt");
|
||||
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "r"); // could also be "rw", but "r" is sufficient for reading
|
||||
FileLock lock = file.getChannel()
|
||||
.lock(from, size, true)) {
|
||||
if (lock.isValid()) {
|
||||
LOG.debug("This is a valid shared lock");
|
||||
return lock;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.baeldung.lock;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.nio.channels.NonReadableChannelException;
|
||||
import java.nio.channels.NonWritableChannelException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FileLocksUnitTest {
|
||||
|
||||
@Test
|
||||
void givenAnInputStream_whenGetWriteLock_thenThrowNonWritableChannelException() {
|
||||
assertThrows(NonWritableChannelException.class, () -> FileLocks.getExclusiveLockFromInputStream());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenARandomAccessFileWithReadWriteAccess_whenGetWriteLock_thenLock() throws IOException {
|
||||
FileLock lock = FileLocks.getExclusiveLockFromRandomAccessFile(0, 10);
|
||||
assertNotNull(lock);
|
||||
assertFalse(lock.isShared());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenAPath_whenGetExclusiveLock_thenLock() throws IOException {
|
||||
FileLock lock = FileLocks.getExclusiveLockFromFileChannelOpen(0, 10);
|
||||
assertNotNull(lock);
|
||||
assertFalse(lock.isShared());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenAFileOutputStream_whenGetSharedLock_thenThrowNonReadableChannelException() {
|
||||
assertThrows(NonReadableChannelException.class, FileLocks::getReadLockFromOutputStream);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenAnInputStream_whenGetSharedLock_thenLock() throws IOException {
|
||||
FileLock lock = FileLocks.getReadLockFromInputStream(0, 10);
|
||||
assertNotNull(lock);
|
||||
assertTrue(lock.isShared());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenARandomAccessFile_whenGetSharedLock_thenLock() throws IOException {
|
||||
FileLock lock = FileLocks.getReadLockFromRandomAccessFile(0, 10);
|
||||
assertNotNull(lock);
|
||||
assertTrue(lock.isShared());
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
- [Introduction to Java Serialization](http://www.baeldung.com/java-serialization)
|
||||
- [Guide to UUID in Java](http://www.baeldung.com/java-uuid)
|
||||
- [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin)
|
||||
- [Quick Guide to Java Stack](http://www.baeldung.com/java-stack)
|
||||
- [Quick Guide to the Java Stack](http://www.baeldung.com/java-stack)
|
||||
- [Compiling Java *.class Files with javac](http://www.baeldung.com/javac)
|
||||
- [Introduction to Javadoc](http://www.baeldung.com/javadoc)
|
||||
- [Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.baeldung;
|
||||
package com.baeldung.timer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
@@ -5,4 +5,5 @@ This module contains articles about Kotlin core features.
|
||||
### Relevant articles:
|
||||
- [Working with Dates in Kotlin](https://www.baeldung.com/kotlin-dates)
|
||||
- [Kotlin Ternary Conditional Operator](https://www.baeldung.com/kotlin-ternary-operator)
|
||||
- [Sequences in Kotlin](https://www.baeldung.com/kotlin/sequences)
|
||||
- [[<-- Prev]](/core-kotlin-modules/core-kotlin)
|
||||
|
||||
@@ -13,4 +13,7 @@ This module contains articles about Kotlin core features.
|
||||
- [Implementing a Binary Tree in Kotlin](https://www.baeldung.com/kotlin-binary-tree)
|
||||
- [JUnit 5 for Kotlin Developers](https://www.baeldung.com/junit-5-kotlin)
|
||||
- [Converting Kotlin Data Class from JSON using GSON](https://www.baeldung.com/kotlin-json-convert-data-class)
|
||||
- [Fuel HTTP Library with Kotlin](https://www.baeldung.com/kotlin-fuel)
|
||||
- [Introduction to Kovenant Library for Kotlin](https://www.baeldung.com/kotlin-kovenant)
|
||||
- [Dependency Injection for Kotlin with Injekt](https://www.baeldung.com/kotlin-dependency-injection-with-injekt)
|
||||
- [[More --> ]](/core-kotlin-modules/core-kotlin-2)
|
||||
|
||||
@@ -5,3 +5,4 @@ This module contains articles about Scala's core features
|
||||
### Relevant Articles:
|
||||
|
||||
- [Introduction to Scala](https://www.baeldung.com/scala-intro)
|
||||
- [Regular Expressions in Scala](https://www.baeldung.com/scala/regular-expressions)
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package com.baeldung.scala
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
|
||||
class HigherOrderFunctionsExamplesUnitTest {
|
||||
|
||||
@Test
|
||||
def whenCallingMapWithAnonymousFunction_thenTransformationIsApplied() = {
|
||||
val expected = Seq("sir Alex Ferguson", "sir Bobby Charlton", "sir Frank Lampard")
|
||||
|
||||
val names = Seq("Alex Ferguson", "Bobby Charlton", "Frank Lampard")
|
||||
val sirNames = names.map(name => "sir " + name)
|
||||
|
||||
assertEquals(expected, sirNames)
|
||||
}
|
||||
|
||||
@Test
|
||||
def whenCallingMapWithDefined_thenTransformationIsApplied() = {
|
||||
val expected = Seq("sir Alex Ferguson", "sir Bobby Charlton", "sir Frank Lampard")
|
||||
|
||||
val names = Seq("Alex Ferguson", "Bobby Charlton", "Frank Lampard")
|
||||
|
||||
def prefixWithSir(name: String) = "sir " + name
|
||||
val sirNames = names.map(prefixWithSir)
|
||||
|
||||
assertEquals(expected, sirNames)
|
||||
}
|
||||
|
||||
@Test
|
||||
def whenCallingFilter_thenUnecessaryElementsAreRemoved() = {
|
||||
val expected = Seq("John O'Shea", "John Hartson")
|
||||
|
||||
val names = Seq("John O'Shea", "Aiden McGeady", "John Hartson")
|
||||
val johns = names.filter(name => name.matches("^John .*"))
|
||||
|
||||
assertEquals(expected, johns)
|
||||
}
|
||||
|
||||
@Test
|
||||
def whenCallingReduce_thenProperSumIsCalculated() = {
|
||||
val expected = 2750
|
||||
|
||||
val earnings = Seq(1000, 1300, 450)
|
||||
val sumEarnings = earnings.reduce((acc, x) => acc + x)
|
||||
|
||||
assertEquals(expected, sumEarnings)
|
||||
}
|
||||
|
||||
@Test
|
||||
def whenCallingFold_thenNumberOfWordsShouldBeCalculated() = {
|
||||
val expected = 6
|
||||
|
||||
val strings = Seq("bunch of words", "just me", "it")
|
||||
val sumEarnings = strings.foldLeft(0)((acc, x) => acc + x.split(" ").size)
|
||||
|
||||
assertEquals(expected, sumEarnings)
|
||||
}
|
||||
|
||||
@Test
|
||||
def whenCallingOwnHigherOrderFunction_thenProperFunctionIsReturned() = {
|
||||
def mathOperation(name: String): (Int, Int) => Int = (x: Int, y: Int) => {
|
||||
name match {
|
||||
case "addition" => x + y
|
||||
case "multiplication" => x * y
|
||||
case "division" => x/y
|
||||
case "subtraction" => x - y
|
||||
}
|
||||
}
|
||||
|
||||
def add: (Int, Int) => Int = mathOperation("addition")
|
||||
def mul: (Int, Int) => Int = mathOperation("multiplication")
|
||||
def div: (Int, Int) => Int = mathOperation("division")
|
||||
def sub: (Int, Int) => Int = mathOperation("subtraction")
|
||||
|
||||
assertEquals(15, add(10, 5))
|
||||
assertEquals(50, mul(10, 5))
|
||||
assertEquals(2, div(10, 5))
|
||||
assertEquals(5, sub(10, 5))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.baeldung.scala
|
||||
package com.baeldung.scala.regex
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.Assert.assertEquals
|
||||
+23
-3
@@ -12,15 +12,32 @@
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-java</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>it.unimi.dsi</groupId>
|
||||
<artifactId>dsiutils</artifactId>
|
||||
<version>${dsiutils.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vavr</groupId>
|
||||
<artifactId>vavr</artifactId>
|
||||
<version>${vavr.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<finalName>java-numbers-3</finalName>
|
||||
<resources>
|
||||
@@ -33,6 +50,9 @@
|
||||
|
||||
<properties>
|
||||
<dsiutils.version>2.6.0</dsiutils.version>
|
||||
<vavr.version>0.10.2</vavr.version>
|
||||
<commons.version>3.9</commons.version>
|
||||
<assertj.version>3.6.1</assertj.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package com.baeldung.parsedouble;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.primitives.Doubles;
|
||||
|
||||
import io.vavr.control.Try;
|
||||
|
||||
public class StringToDoubleParserUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenNullValue_whenParseStringToDouble_thenDefaultNaNValueIsReturned() {
|
||||
assertThat(parseStringToDouble(null)).isNaN();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStringValue_whenParseStringToDouble_thenDefaultNaNValueIsReturned() {
|
||||
assertThat(parseStringToDouble("")).isNaN();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringValue_whenParseStringToDouble_thenDoubleValueIsReturned() {
|
||||
assertThat(parseStringToDouble("1")).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringValue_whenParseStringToDoubleWithDefault_thenDoubleValueIsReturned() {
|
||||
assertThat(parseStringToDouble("1", 2.0d)).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStringValue_whenParseStringToDoubleWithDefault_thenDefaultValueIsReturned() {
|
||||
assertThat(parseStringToDouble("", 1.0d)).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNullValue_whenParseStringToDoubleWithDefault_thenDefaultValueIsReturned() {
|
||||
assertThat(parseStringToDouble(null, 1.0d)).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringValue_whenParseStringToOptionalDouble_thenOptionalValueIsReturned() {
|
||||
assertThat(parseStringToOptionalDouble("1")).isEqualTo(Optional.of(1.0d));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNullValue_whenParseStringToOptionalDouble_thenOptionalValueIsEmpty() {
|
||||
assertThat(parseStringToOptionalDouble(null)).isEqualTo(Optional.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStringValue_whenParseStringToOptionalDouble_thenOptionalValueIsEmpty() {
|
||||
assertThat(parseStringToOptionalDouble("")).isEqualTo(Optional.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStringValue_whenParseStringToOptionalDouble_thenDefaulOptionalValueIsReturned() {
|
||||
assertThat(parseStringToOptionalDouble("").orElse(1.0d)).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNullValue_whenParseStringToOptionalDouble_thenDefaulOptionalValueIsReturned() {
|
||||
assertThat(parseStringToOptionalDouble(null).orElse(1.0d)).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringValue_whenTryStringToDouble_thenDoubleValueIsReturned() {
|
||||
assertThat(tryStringToDouble("1", 2.0d)).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNullValue_whenTryStringToDoubleWithDefault_thenDoubleValueIsReturned() {
|
||||
assertThat(tryStringToDouble(null, 2.0d)).isEqualTo(2.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStringValue_whenTryStringToDoubleWithDefault_thenDoubleValueIsReturned() {
|
||||
assertThat(tryStringToDouble("", 2.0d)).isEqualTo(2.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTwoStringValues_whenTryParseFirstNonNull_thenDoubleValueIsReturned() {
|
||||
assertThat(Doubles.tryParse(MoreObjects.firstNonNull("1.0", "2.0"))).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNullStringValue_whenTryParseFirstNonNull_thenSecondDoubleValueIsReturned() {
|
||||
assertThat(Doubles.tryParse(MoreObjects.firstNonNull(null, "2.0"))).isEqualTo(2.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStringValue_whenTryParseFirstNonNull_thenNullIsReturned() {
|
||||
assertThat(Doubles.tryParse(MoreObjects.firstNonNull("", "2.0"))).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringValue_whenToDouble_thenDoubleValueIsReturned() {
|
||||
assertThat(NumberUtils.toDouble("1.0")).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNullValue_whenToDouble_thenLibraryDefaultDoubleValueIsReturned() {
|
||||
String nullString = null;
|
||||
assertThat(NumberUtils.toDouble(nullString)).isEqualTo(0.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStringValue_whenToDouble_thenLibraryDefaultDoubleValueIsReturned() {
|
||||
assertThat(NumberUtils.toDouble("")).isEqualTo(0.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStringValue_whenToDoubleWithDefault_thenDoubleValueIsReturned() {
|
||||
assertThat(NumberUtils.toDouble("", 2.0d)).isEqualTo(2.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNullValue_whenToDoubleWithDefault_thenDoubleValueIsReturned() {
|
||||
String nullString = null;
|
||||
assertThat(NumberUtils.toDouble(nullString, 2.0d)).isEqualTo(2.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringValue_whenToDoubleWithDefault_thenDoubleValueIsReturned() {
|
||||
assertThat(NumberUtils.toDouble("1.0", 2.0d)).isEqualTo(1.0d);
|
||||
}
|
||||
|
||||
private static Optional<Double> parseStringToOptionalDouble(String value) {
|
||||
return value == null || value.isEmpty() ? Optional.empty() : Optional.of(Double.valueOf(value));
|
||||
}
|
||||
|
||||
private static double parseStringToDouble(String value) {
|
||||
return value == null || value.isEmpty() ? Double.NaN : Double.parseDouble(value);
|
||||
}
|
||||
|
||||
private static double parseStringToDouble(String value, double defaultValue) {
|
||||
return value == null || value.isEmpty() ? defaultValue : Double.parseDouble(value);
|
||||
}
|
||||
|
||||
private static double tryStringToDouble(String value, double defaultValue) {
|
||||
return Try.of(() -> Double.parseDouble(value)).getOrElse(defaultValue);
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,28 @@
|
||||
<version>${cache2k.version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.moshi</groupId>
|
||||
<artifactId>moshi</artifactId>
|
||||
<version>${moshi.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.moshi</groupId>
|
||||
<artifactId>moshi-adapters</artifactId>
|
||||
<version>${moshi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.jcabi</groupId>
|
||||
<artifactId>jcabi-aspects</artifactId>
|
||||
<version>${jcabi-aspects.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>${aspectjrt.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
@@ -81,6 +103,36 @@
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<finalName>libraries-3</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.jcabi</groupId>
|
||||
<artifactId>jcabi-maven-plugin</artifactId>
|
||||
<version>${jcabi-maven-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>ajc</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjtools</artifactId>
|
||||
<version>${aspectjtools.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>${aspectjweaver.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<jcommander.version>1.78</jcommander.version>
|
||||
@@ -93,5 +145,11 @@
|
||||
<cactoos.version>0.43</cactoos.version>
|
||||
<airline.version>2.7.2</airline.version>
|
||||
<cache2k.version>1.2.3.Final</cache2k.version>
|
||||
<moshi.version>1.9.2</moshi.version>
|
||||
<jcabi-aspects.version>0.22.6</jcabi-aspects.version>
|
||||
<aspectjrt.version>1.9.2</aspectjrt.version>
|
||||
<jcabi-maven-plugin.version>0.14.1</jcabi-maven-plugin.version>
|
||||
<aspectjtools.version>1.9.2</aspectjtools.version>
|
||||
<aspectjweaver.version>1.9.2</aspectjweaver.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
@@ -4,38 +4,33 @@ import java.util.Objects;
|
||||
|
||||
import org.cache2k.Cache;
|
||||
import org.cache2k.Cache2kBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ProductHelper {
|
||||
|
||||
final Logger LOGGER = LoggerFactory.getLogger(ProductHelper.class);
|
||||
|
||||
private Cache<String, Integer> cachedDiscounts;
|
||||
|
||||
private int cacheMissCount = 0;
|
||||
|
||||
public ProductHelper() {
|
||||
cachedDiscounts = Cache2kBuilder.of(String.class, Integer.class)
|
||||
.name("discount")
|
||||
.eternal(true)
|
||||
.entryCapacity(100)
|
||||
.build();
|
||||
|
||||
initDiscountCache("Sports", 20);
|
||||
}
|
||||
|
||||
public void initDiscountCache(String productType, Integer value) {
|
||||
cachedDiscounts.put(productType, value);
|
||||
}
|
||||
|
||||
public Integer getDiscount(String productType) {
|
||||
Integer discount = cachedDiscounts.get(productType);
|
||||
if (Objects.isNull(discount)) {
|
||||
LOGGER.info("Discount for {} not found.", productType);
|
||||
discount = 0;
|
||||
} else {
|
||||
LOGGER.info("Discount for {} found.", productType);
|
||||
cacheMissCount++;
|
||||
discount = "Sports".equalsIgnoreCase(productType) ? 20 : 10;
|
||||
cachedDiscounts.put(productType, discount);
|
||||
}
|
||||
return discount;
|
||||
}
|
||||
|
||||
public int getCacheMissCount() {
|
||||
return cacheMissCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.baeldung.cache2k;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.cache2k.Cache;
|
||||
@@ -14,28 +13,26 @@ public class ProductHelperUsingLoader {
|
||||
|
||||
private Cache<String, Integer> cachedDiscounts;
|
||||
|
||||
private int cacheMissCount = 0;
|
||||
|
||||
public ProductHelperUsingLoader() {
|
||||
cachedDiscounts = Cache2kBuilder.of(String.class, Integer.class)
|
||||
.name("discount-loader")
|
||||
.eternal(false)
|
||||
.expireAfterWrite(10, TimeUnit.MILLISECONDS)
|
||||
.entryCapacity(100)
|
||||
.loader((key) -> {
|
||||
LOGGER.info("Calculating discount for {}.", key);
|
||||
cacheMissCount++;
|
||||
return "Sports".equalsIgnoreCase(key) ? 20 : 10;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public Integer getDiscount(String productType) {
|
||||
Integer discount = cachedDiscounts.get(productType);
|
||||
if (Objects.isNull(discount)) {
|
||||
LOGGER.info("Discount for {} not found.", productType);
|
||||
discount = 0;
|
||||
} else {
|
||||
LOGGER.info("Discount for {} found.", productType);
|
||||
}
|
||||
return discount;
|
||||
return cachedDiscounts.get(productType);
|
||||
}
|
||||
|
||||
public int getCacheMissCount() {
|
||||
return cacheMissCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.baeldung.cache2k;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.cache2k.Cache;
|
||||
@@ -16,14 +15,15 @@ public class ProductHelperWithEventListener {
|
||||
|
||||
private Cache<String, Integer> cachedDiscounts;
|
||||
|
||||
private int cacheMissCount = 0;
|
||||
|
||||
public ProductHelperWithEventListener() {
|
||||
cachedDiscounts = Cache2kBuilder.of(String.class, Integer.class)
|
||||
.name("discount-listener")
|
||||
.eternal(false)
|
||||
.expireAfterWrite(10, TimeUnit.MILLISECONDS)
|
||||
.entryCapacity(100)
|
||||
.loader((key) -> {
|
||||
LOGGER.info("Calculating discount for {}.", key);
|
||||
cacheMissCount++;
|
||||
return "Sports".equalsIgnoreCase(key) ? 20 : 10;
|
||||
})
|
||||
.addListener(new CacheEntryCreatedListener<String, Integer>() {
|
||||
@@ -36,14 +36,11 @@ public class ProductHelperWithEventListener {
|
||||
}
|
||||
|
||||
public Integer getDiscount(String productType) {
|
||||
Integer discount = cachedDiscounts.get(productType);
|
||||
if (Objects.isNull(discount)) {
|
||||
LOGGER.info("Discount for {} not found.", productType);
|
||||
discount = 0;
|
||||
} else {
|
||||
LOGGER.info("Discount for {} found.", productType);
|
||||
}
|
||||
return discount;
|
||||
return cachedDiscounts.get(productType);
|
||||
}
|
||||
|
||||
public int getCacheMissCount() {
|
||||
return cacheMissCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,39 +5,34 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.cache2k.Cache;
|
||||
import org.cache2k.Cache2kBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ProductHelperWithExpiry {
|
||||
|
||||
final Logger LOGGER = LoggerFactory.getLogger(ProductHelperWithExpiry.class);
|
||||
|
||||
private Cache<String, Integer> cachedDiscounts;
|
||||
|
||||
private int cacheMissCount = 0;
|
||||
|
||||
public ProductHelperWithExpiry() {
|
||||
cachedDiscounts = Cache2kBuilder.of(String.class, Integer.class)
|
||||
.name("discount-expiry")
|
||||
.eternal(false)
|
||||
.expireAfterWrite(5, TimeUnit.MILLISECONDS)
|
||||
.entryCapacity(100)
|
||||
.build();
|
||||
|
||||
initDiscountCache("Sports", 20);
|
||||
}
|
||||
|
||||
public void initDiscountCache(String productType, Integer value) {
|
||||
cachedDiscounts.put(productType, value);
|
||||
}
|
||||
|
||||
public Integer getDiscount(String productType) {
|
||||
Integer discount = cachedDiscounts.get(productType);
|
||||
if (Objects.isNull(discount)) {
|
||||
LOGGER.info("Discount for {} not found.", productType);
|
||||
discount = 0;
|
||||
} else {
|
||||
LOGGER.info("Discount for {} found.", productType);
|
||||
cacheMissCount++;
|
||||
discount = "Sports".equalsIgnoreCase(productType) ? 20 : 10;
|
||||
cachedDiscounts.put(productType, discount);
|
||||
}
|
||||
return discount;
|
||||
}
|
||||
|
||||
public int getCacheMissCount() {
|
||||
return cacheMissCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.baeldung.jcabi;
|
||||
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.jcabi.aspects.Async;
|
||||
import com.jcabi.aspects.Cacheable;
|
||||
import com.jcabi.aspects.LogExceptions;
|
||||
import com.jcabi.aspects.Loggable;
|
||||
import com.jcabi.aspects.Quietly;
|
||||
import com.jcabi.aspects.RetryOnFailure;
|
||||
import com.jcabi.aspects.UnitedThrow;
|
||||
|
||||
public class JcabiAspectJ {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
displayFactorial(10);
|
||||
getFactorial(10).get();
|
||||
|
||||
String result = cacheExchangeRates();
|
||||
if (result != cacheExchangeRates()) {
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
divideByZero();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
divideByZeroQuietly();
|
||||
try {
|
||||
processFile();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Loggable
|
||||
@Async
|
||||
public static void displayFactorial(int number) {
|
||||
long result = factorial(number);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
@Loggable
|
||||
@Async
|
||||
public static Future<Long> getFactorial(int number) {
|
||||
Future<Long> factorialFuture = CompletableFuture.supplyAsync(() -> factorial(number));
|
||||
return factorialFuture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds factorial of a number
|
||||
* @param number
|
||||
* @return
|
||||
*/
|
||||
public static long factorial(int number) {
|
||||
long result = 1;
|
||||
for(int i=number;i>0;i--) {
|
||||
result *= i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Loggable
|
||||
@Cacheable(lifetime = 2, unit = TimeUnit.SECONDS)
|
||||
public static String cacheExchangeRates() {
|
||||
String result = null;
|
||||
try {
|
||||
URL exchangeRateUrl = new URL("https://api.exchangeratesapi.io/latest");
|
||||
URLConnection con = exchangeRateUrl.openConnection();
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
result = in.readLine();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@LogExceptions
|
||||
public static void divideByZero() {
|
||||
int x = 1/0;
|
||||
}
|
||||
|
||||
@RetryOnFailure(attempts = 2, types = {java.lang.NumberFormatException.class})
|
||||
@Quietly
|
||||
public static void divideByZeroQuietly() {
|
||||
int x = 1/0;
|
||||
}
|
||||
|
||||
@UnitedThrow(IllegalStateException.class)
|
||||
public static void processFile() throws IOException, InterruptedException {
|
||||
BufferedReader reader = new BufferedReader(new FileReader("baeldung.txt"));
|
||||
reader.readLine();
|
||||
|
||||
Thread thread = new Thread();
|
||||
thread.wait(2000);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,12 +6,13 @@ import org.junit.Test;
|
||||
|
||||
public class ProductHelperUnitTest {
|
||||
|
||||
ProductHelper productHelper = new ProductHelper();
|
||||
|
||||
@Test
|
||||
public void whenInvokedGetDiscount_thenGetItFromCache() {
|
||||
public void whenInvokedGetDiscountTwice_thenGetItFromCache() {
|
||||
ProductHelper productHelper = new ProductHelper();
|
||||
assertTrue(productHelper.getCacheMissCount() == 0);
|
||||
assertTrue(productHelper.getDiscount("Sports") == 20);
|
||||
assertTrue(productHelper.getDiscount("Electronics") == 0);
|
||||
assertTrue(productHelper.getDiscount("Sports") == 20);
|
||||
assertTrue(productHelper.getCacheMissCount() == 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-3
@@ -6,12 +6,16 @@ import org.junit.Test;
|
||||
|
||||
public class ProductHelperUsingLoaderUnitTest {
|
||||
|
||||
ProductHelperUsingLoader productHelper = new ProductHelperUsingLoader();
|
||||
|
||||
@Test
|
||||
public void whenInvokedGetDiscount_thenPopulateCache() {
|
||||
public void whenInvokedGetDiscount_thenPopulateCacheUsingLoader() {
|
||||
ProductHelperUsingLoader productHelper = new ProductHelperUsingLoader();
|
||||
assertTrue(productHelper.getCacheMissCount() == 0);
|
||||
|
||||
assertTrue(productHelper.getDiscount("Sports") == 20);
|
||||
assertTrue(productHelper.getCacheMissCount() == 1);
|
||||
|
||||
assertTrue(productHelper.getDiscount("Electronics") == 10);
|
||||
assertTrue(productHelper.getCacheMissCount() == 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-2
@@ -6,10 +6,9 @@ import org.junit.Test;
|
||||
|
||||
public class ProductHelperWithEventListenerUnitTest {
|
||||
|
||||
ProductHelperWithEventListener productHelper = new ProductHelperWithEventListener();
|
||||
|
||||
@Test
|
||||
public void whenEntryAddedInCache_thenEventListenerCalled() {
|
||||
ProductHelperWithEventListener productHelper = new ProductHelperWithEventListener();
|
||||
assertTrue(productHelper.getDiscount("Sports") == 20);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,13 +6,17 @@ import org.junit.Test;
|
||||
|
||||
public class ProductHelperWithExpiryUnitTest {
|
||||
|
||||
ProductHelperWithExpiry productHelper = new ProductHelperWithExpiry();
|
||||
|
||||
@Test
|
||||
public void whenInvokedGetDiscountForExpiredProduct_thenNoDiscount() throws InterruptedException {
|
||||
public void whenInvokedGetDiscountAfterExpiration_thenDiscountCalculatedAgain() throws InterruptedException {
|
||||
ProductHelperWithExpiry productHelper = new ProductHelperWithExpiry();
|
||||
assertTrue(productHelper.getCacheMissCount() == 0);
|
||||
assertTrue(productHelper.getDiscount("Sports") == 20);
|
||||
assertTrue(productHelper.getCacheMissCount() == 1);
|
||||
|
||||
Thread.sleep(20);
|
||||
assertTrue(productHelper.getDiscount("Sports") == 0);
|
||||
|
||||
assertTrue(productHelper.getDiscount("Sports") == 20);
|
||||
assertTrue(productHelper.getCacheMissCount() == 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.time.Instant;
|
||||
|
||||
import com.squareup.moshi.FromJson;
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.JsonQualifier;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import com.squareup.moshi.ToJson;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AlternativeAdapterUnitTest {
|
||||
@Test
|
||||
public void whenSerializing_thenAlternativeAdapterUsed() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new EpochMillisAdapter())
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
String json = jsonAdapter.toJson(new Post("Introduction to Moshi Json", "Baeldung", Instant.now()));
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeserializing_thenAlternativeAdapterUsed() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new EpochMillisAdapter())
|
||||
.build();
|
||||
JsonAdapter<Post> jsonAdapter = moshi.adapter(Post.class);
|
||||
|
||||
String json = "{\"author\":\"Baeldung\",\"posted\":1582095269204,\"title\":\"Introduction to Moshi Json\"}";
|
||||
Post post = jsonAdapter.fromJson(json);
|
||||
System.out.println(post);
|
||||
|
||||
}
|
||||
|
||||
public static class Post {
|
||||
String title;
|
||||
String author;
|
||||
@EpochMillis Instant posted;
|
||||
|
||||
public Post() {
|
||||
}
|
||||
|
||||
public Post(String title, String author, Instant posted) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.posted = posted;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Instant getPosted() {
|
||||
return posted;
|
||||
}
|
||||
|
||||
public void setPosted(Instant posted) {
|
||||
this.posted = posted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("title", title).append("author", author).append("posted", posted)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
|
||||
@JsonQualifier
|
||||
public @interface EpochMillis {
|
||||
}
|
||||
|
||||
public static class EpochMillisAdapter {
|
||||
@ToJson
|
||||
public Long toJson(@EpochMillis Instant input) {
|
||||
return input.toEpochMilli();
|
||||
}
|
||||
@FromJson
|
||||
@EpochMillis
|
||||
public Instant fromJson(Long input) {
|
||||
return Instant.ofEpochMilli(input);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import com.squareup.moshi.Types;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ArrayUnitTest {
|
||||
@Test
|
||||
public void whenSerializingList_thenJsonArrayProduced() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
Type type = Types.newParameterizedType(List.class, String.class);
|
||||
JsonAdapter<List<String>> jsonAdapter = moshi.adapter(type);
|
||||
|
||||
String json = jsonAdapter.toJson(Arrays.asList("One", "Two", "Three"));
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeserializingJsonArray_thenListProduced() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.build();
|
||||
Type type = Types.newParameterizedType(List.class, String.class);
|
||||
JsonAdapter<List<String>> jsonAdapter = moshi.adapter(type);
|
||||
|
||||
String json = "[\"One\",\"Two\",\"Three\"]";
|
||||
List<String> result = jsonAdapter.fromJson(json);
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.baeldung.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import com.squareup.moshi.FromJson;
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import com.squareup.moshi.ToJson;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ComplexAdapterUnitTest {
|
||||
@Test
|
||||
public void whenSerializing_thenCorrectJsonProduced() {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new JsonDateTimeAdapter())
|
||||
.build();
|
||||
JsonAdapter<ZonedDateTime> jsonAdapter = moshi.adapter(ZonedDateTime.class);
|
||||
|
||||
String json = jsonAdapter.toJson(ZonedDateTime.now());
|
||||
System.out.println(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeserializing_thenCorrectJsonConsumed() throws IOException {
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(new JsonDateTimeAdapter())
|
||||
.build();
|
||||
JsonAdapter<ZonedDateTime> jsonAdapter = moshi.adapter(ZonedDateTime.class);
|
||||
|
||||
String json = "{\"date\":\"2020-02-17\",\"time\":\"07:53:27.064\",\"timezone\":\"Europe/London\"}";
|
||||
ZonedDateTime now = jsonAdapter.fromJson(json);
|
||||
System.out.println(now);
|
||||
|
||||
}
|
||||
|
||||
public static class JsonDateTimeAdapter {
|
||||
@ToJson
|
||||
public JsonDateTime toJson(ZonedDateTime input) {
|
||||
String date = input.toLocalDate().toString();
|
||||
String time = input.toLocalTime().toString();
|
||||
String timezone = input.getZone().toString();
|
||||
return new JsonDateTime(date, time, timezone);
|
||||
}
|
||||
@FromJson
|
||||
public ZonedDateTime fromJson(JsonDateTime input) {
|
||||
LocalDate date = LocalDate.parse(input.getDate());
|
||||
LocalTime time = LocalTime.parse(input.getTime());
|
||||
ZoneId timezone = ZoneId.of(input.getTimezone());
|
||||
return ZonedDateTime.of(date, time, timezone);
|
||||
}
|
||||
}
|
||||
public static class JsonDateTime {
|
||||
private String date;
|
||||
private String time;
|
||||
private String timezone;
|
||||
|
||||
public JsonDateTime() {
|
||||
}
|
||||
|
||||
public JsonDateTime(String date, String time, String timezone) {
|
||||
this.date = date;
|
||||
this.time = time;
|
||||
this.timezone = timezone;
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(String time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getTimezone() {
|
||||
return timezone;
|
||||
}
|
||||
|
||||
public void setTimezone(String timezone) {
|
||||
this.timezone = timezone;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user