diff --git a/core-java-modules/core-java-10/README.md b/core-java-modules/core-java-10/README.md index 23f598b902..38b1db1c05 100644 --- a/core-java-modules/core-java-10/README.md +++ b/core-java-modules/core-java-10/README.md @@ -10,3 +10,4 @@ This module contains articles about Java 10 core features - [Deep Dive Into the New Java JIT Compiler – Graal](https://www.baeldung.com/graal-java-jit-compiler) - [Copying Sets in Java](https://www.baeldung.com/java-copy-sets) - [Converting between a List and a Set in Java](https://www.baeldung.com/convert-list-to-set-and-set-to-list) +- [Java IndexOutOfBoundsException “Source Does Not Fit in Dest”](https://www.baeldung.com/java-indexoutofboundsexception) diff --git a/core-java-modules/core-java-exceptions-3/README.md b/core-java-modules/core-java-exceptions-3/README.md index f136a73daf..f93e1a9943 100644 --- a/core-java-modules/core-java-exceptions-3/README.md +++ b/core-java-modules/core-java-exceptions-3/README.md @@ -4,3 +4,5 @@ - [IllegalArgumentException or NullPointerException for a Null Parameter?](https://www.baeldung.com/java-illegalargumentexception-or-nullpointerexception) - [IllegalMonitorStateException in Java](https://www.baeldung.com/java-illegalmonitorstateexception) - [AbstractMethodError in Java](https://www.baeldung.com/java-abstractmethoderror) +- [Java IndexOutOfBoundsException “Source Does Not Fit in Dest”](https://www.baeldung.com/java-indexoutofboundsexception) +- [Localizing Exception Messages in Java](https://www.baeldung.com/java-localize-exception-messages) diff --git a/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingAddAllMethodDemo.java b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingAddAllMethodDemo.java new file mode 100644 index 0000000000..34e6f1c998 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingAddAllMethodDemo.java @@ -0,0 +1,14 @@ +package com.baeldung.exception.indexoutofbounds; + +import java.util.ArrayList; +import java.util.List; + +public class CopyListUsingAddAllMethodDemo { + static List copyList(List source) { + List destination = new ArrayList<>(); + + destination.addAll(source); + + return destination; + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingCollectionsCopyMethodDemo.java b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingCollectionsCopyMethodDemo.java new file mode 100644 index 0000000000..664e2152d8 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingCollectionsCopyMethodDemo.java @@ -0,0 +1,10 @@ +package com.baeldung.exception.indexoutofbounds; + +import java.util.Collections; +import java.util.List; + +public class CopyListUsingCollectionsCopyMethodDemo { + static void copyList(List source, List destination) { + Collections.copy(destination, source); + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingConstructorDemo.java b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingConstructorDemo.java new file mode 100644 index 0000000000..493031ba0a --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingConstructorDemo.java @@ -0,0 +1,10 @@ +package com.baeldung.exception.indexoutofbounds; + +import java.util.ArrayList; +import java.util.List; + +public class CopyListUsingConstructorDemo { + static List copyList(List source) { + return new ArrayList<>(source); + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingJava8StreamDemo.java b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingJava8StreamDemo.java new file mode 100644 index 0000000000..d9d0247d2f --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/CopyListUsingJava8StreamDemo.java @@ -0,0 +1,12 @@ +package com.baeldung.exception.indexoutofbounds; + +import java.util.List; +import java.util.stream.Collectors; + +public class CopyListUsingJava8StreamDemo { + static List copyList(List source) { + return source + .stream() + .collect(Collectors.toList()); + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/IndexOutOfBoundsExceptionDemo.java b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/IndexOutOfBoundsExceptionDemo.java new file mode 100644 index 0000000000..78b7b03bc1 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exception/indexoutofbounds/IndexOutOfBoundsExceptionDemo.java @@ -0,0 +1,13 @@ +package com.baeldung.exception.indexoutofbounds; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class IndexOutOfBoundsExceptionDemo { + static List copyList(List source) { + List destination = new ArrayList<>(source.size()); + Collections.copy(destination, source); + return destination; + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exceptions/localization/LocalizedException.java b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exceptions/localization/LocalizedException.java new file mode 100644 index 0000000000..c3f9980b99 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exceptions/localization/LocalizedException.java @@ -0,0 +1,47 @@ +package com.baeldung.exceptions.localization; + +import java.util.Locale; + +public class LocalizedException extends Exception { + + private static final long serialVersionUID = 1L; + + private final String messageKey; + private final Locale locale; + + public LocalizedException(String messageKey) { + this(messageKey, Locale.getDefault()); + } + + public LocalizedException(String messageKey, Locale locale) { + this.messageKey = messageKey; + this.locale = locale; + } + + /** + * @return a localized message based on the messageKey provided at instantiation. + */ + public String getMessage() { + + /* + * This is a deliberate role reversal of the default implementation of getLocalizedMessage. + * some logging frameworks like Log4J 1 & 2 and Logback will use getMessage instead of + * getLocalizedMessage when logging Throwables. If we want to use these frameworks in client + * applications to log localized messages, then we'll need to override getMessage in a + * similar fashion to return the appropriate content. Or, you can call getLocalizedMessage + * on your own to create the log content. + */ + return getLocalizedMessage(); + } + + /** + * @return a localized message based on the messageKey provided at instantiation. + */ + public String getLocalizedMessage() { + + /* + * java.util.logging uses getLocalizedMessage when logging Throwables. + */ + return Messages.getMessageForLocale(messageKey, locale); + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exceptions/localization/Messages.java b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exceptions/localization/Messages.java new file mode 100644 index 0000000000..1079bedd1a --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/main/java/com/baeldung/exceptions/localization/Messages.java @@ -0,0 +1,27 @@ +package com.baeldung.exceptions.localization; + +import java.util.Locale; +import java.util.ResourceBundle; + +public class Messages { + + /** + * Retrieves the value for the messageKey from the locale-specific messages.properties, or from + * the base messages.properties for unsupported locales. + * + * @param messageKey The key for the message in the messages.properties ResourceBundle. + * @param locale The locale to search the message key. + * @return The value defined for the messageKey in the provided locale. + */ + public static String getMessageForLocale(String messageKey, Locale locale) { + + /* + * For more complex implementations, you will want a var-args parameter for MessageFormat + * substitutions. Then we can read the value from the bundle and pass the value with the + * substitutions to MessageFormat to create the final message value. + */ + return ResourceBundle.getBundle("messages", locale) + .getString(messageKey); + } + +} diff --git a/core-java-modules/core-java-exceptions-3/src/main/resources/messages.properties b/core-java-modules/core-java-exceptions-3/src/main/resources/messages.properties new file mode 100644 index 0000000000..b6122d7f21 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/main/resources/messages.properties @@ -0,0 +1 @@ +message.exception = I am an exception. \ No newline at end of file diff --git a/core-java-modules/core-java-exceptions-3/src/main/resources/messages_fr.properties b/core-java-modules/core-java-exceptions-3/src/main/resources/messages_fr.properties new file mode 100644 index 0000000000..f28e0d54ff --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/main/resources/messages_fr.properties @@ -0,0 +1 @@ +message.exception = Je suis une exception. \ No newline at end of file diff --git a/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingAddAllMethodDemoUnitTest.java b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingAddAllMethodDemoUnitTest.java new file mode 100644 index 0000000000..204bbff696 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingAddAllMethodDemoUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.exception.indexoutofbounds; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class CopyListUsingAddAllMethodDemoUnitTest { + + @Test + void whenPassValidArrayList_thenCopyListUsingAddAllMethod() { + List source = Arrays.asList(11, 22, 33); + + assertEquals(source, CopyListUsingAddAllMethodDemo.copyList(source)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingCollectionsCopyMethodDemoUnitTest.java b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingCollectionsCopyMethodDemoUnitTest.java new file mode 100644 index 0000000000..7ebf7461a6 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingCollectionsCopyMethodDemoUnitTest.java @@ -0,0 +1,31 @@ +package com.baeldung.exception.indexoutofbounds; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class CopyListUsingCollectionsCopyMethodDemoUnitTest { + @Test + void whenCopyListUsingCollectionsCopy_thenOverrideAllDestinationListValues() { + List source = Arrays.asList(11, 22, 33); + List destination = Arrays.asList(1, 2, 3); + + CopyListUsingCollectionsCopyMethodDemo.copyList(source, destination); + + assertEquals(source, destination); + } + + @Test + void whenCopyListUsingCollectionsCopy_thenOverrideInitialDestinationValuesAndOthersShouldBeUnchanged(){ + List source = Arrays.asList(11, 22, 33); + List destination = Arrays.asList(1, 2, 3, 4, 5); + List expectedList = Arrays.asList(11, 22, 33, 4, 5); + + CopyListUsingCollectionsCopyMethodDemo.copyList(source, destination); + + assertEquals(expectedList, destination); + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingConstructorDemoUnitTest.java b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingConstructorDemoUnitTest.java new file mode 100644 index 0000000000..cd15c5055c --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingConstructorDemoUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.exception.indexoutofbounds; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class CopyListUsingConstructorDemoUnitTest { + + @Test + void whenCopyListUsingConstructor_thenMakeACopyOfList() { + List source = Arrays.asList(11, 22, 33); + + assertEquals(source, CopyListUsingConstructorDemo.copyList(source)); + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingJava8StreamDemoUnitTest.java b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingJava8StreamDemoUnitTest.java new file mode 100644 index 0000000000..9fb8e16b2a --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/CopyListUsingJava8StreamDemoUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.exception.indexoutofbounds; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class CopyListUsingJava8StreamDemoUnitTest { + + @Test + void whenCopyListUsingStream_thenMakeACopyOfArrayList() { + List source = Arrays.asList(11, 22, 33); + + assertEquals(source, CopyListUsingJava8StreamDemo.copyList(source)); + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/IndexOutOfBoundsExceptionDemoUnitTest.java b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/IndexOutOfBoundsExceptionDemoUnitTest.java new file mode 100644 index 0000000000..9929fa78d3 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exception/indexoutofbounds/IndexOutOfBoundsExceptionDemoUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.exception.indexoutofbounds; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + + +class IndexOutOfBoundsExceptionDemoUnitTest { + + @Test + void givenDestinationArrayListSizeIsZero_whenCopySourceArrayListToDestination_thenShouldThrowIndexOutOfBoundsException() { + List source = Arrays.asList(1, 2, 3, 4, 5); + + assertThrows(IndexOutOfBoundsException.class, () -> IndexOutOfBoundsExceptionDemo.copyList(source)); + } + + @Test + void givenSourceAndDestinationListSizeIsEqual_whenCopySourceArrayListToDestination_thenShouldNotThrowIndexOutOfBoundsException() { + List source = Collections.emptyList(); + + assertEquals(source, IndexOutOfBoundsExceptionDemo.copyList(source)); + } +} diff --git a/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/localization/LocalizedExceptionUnitTest.java b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/localization/LocalizedExceptionUnitTest.java new file mode 100644 index 0000000000..a46ca05d23 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/localization/LocalizedExceptionUnitTest.java @@ -0,0 +1,61 @@ +package com.baeldung.exceptions.localization; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LocalizedExceptionUnitTest { + + private Locale originalDefaultLocale; + + @Before + public void saveOriginalDefaultLocale() { + originalDefaultLocale = Locale.getDefault(); + } + + @After + public void restoreOriginalDefaultLocale() { + Locale.setDefault(originalDefaultLocale); + } + + @Test + public void givenUsEnglishDefaultLocale_whenLocalizingMessage_thenMessageComesFromDefaultMessages() { + Locale.setDefault(Locale.US); + + LocalizedException localizedException = new LocalizedException("message.exception"); + String usEnglishLocalizedExceptionMessage = localizedException.getLocalizedMessage(); + + assertThat(usEnglishLocalizedExceptionMessage).isEqualTo("I am an exception."); + } + + @Test + public void givenFranceFrenchDefaultLocale_whenLocalizingMessage_thenMessageComesFromFrenchTranslationMessages() { + Locale.setDefault(Locale.FRANCE); + + LocalizedException localizedException = new LocalizedException("message.exception"); + String franceFrenchLocalizedExceptionMessage = localizedException.getLocalizedMessage(); + + assertThat(franceFrenchLocalizedExceptionMessage).isEqualTo("Je suis une exception."); + } + + @Test + public void givenUsEnglishProvidedLocale_whenLocalizingMessage_thenMessageComesFromDefaultMessage() { + LocalizedException localizedException = new LocalizedException("message.exception", Locale.US); + String usEnglishLocalizedExceptionMessage = localizedException.getLocalizedMessage(); + + assertThat(usEnglishLocalizedExceptionMessage).isEqualTo("I am an exception."); + } + + @Test + public void givenFranceFrenchProvidedLocale_whenLocalizingMessage_thenMessageComesFromFrenchTranslationMessages() { + LocalizedException localizedException = new LocalizedException("message.exception", Locale.FRANCE); + String franceFrenchLocalizedExceptionMessage = localizedException.getLocalizedMessage(); + + assertThat(franceFrenchLocalizedExceptionMessage).isEqualTo("Je suis une exception."); + } + +} diff --git a/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/localization/MessagesUnitTest.java b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/localization/MessagesUnitTest.java new file mode 100644 index 0000000000..7a6cb8ed32 --- /dev/null +++ b/core-java-modules/core-java-exceptions-3/src/test/java/com/baeldung/exceptions/localization/MessagesUnitTest.java @@ -0,0 +1,25 @@ +package com.baeldung.exceptions.localization; + +import org.junit.Test; + +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MessagesUnitTest { + + @Test + public void givenUsEnglishLocale_whenRetrievingMessage_thenEnglishTranslationIsReturned() { + String translatedMessage = Messages.getMessageForLocale("message.exception", Locale.US); + + assertThat(translatedMessage).isEqualTo("I am an exception."); + } + + @Test + public void givenFranceFrenchLocale_whenRetrievingMessage_thenFrenchTranslationIsReturned() { + String translatedMessage = Messages.getMessageForLocale("message.exception", Locale.FRANCE); + + assertThat(translatedMessage).isEqualTo("Je suis une exception."); + } + +} diff --git a/core-java-modules/core-java-functional/README.md b/core-java-modules/core-java-functional/README.md index ff12555376..5891b4a943 100644 --- a/core-java-modules/core-java-functional/README.md +++ b/core-java-modules/core-java-functional/README.md @@ -1 +1,3 @@ ## Relevant articles: + +- [Functional Programming in Java](https://www.baeldung.com/java-functional-programming) diff --git a/core-java-modules/core-java-lang-3/README.md b/core-java-modules/core-java-lang-3/README.md index 0707d0de98..78491e5bfa 100644 --- a/core-java-modules/core-java-lang-3/README.md +++ b/core-java-modules/core-java-lang-3/README.md @@ -8,4 +8,5 @@ This module contains articles about core features in the Java language - [Checking if a Class Exists in Java](https://www.baeldung.com/java-check-class-exists) - [The Difference Between a.getClass() and A.class in Java](https://www.baeldung.com/java-getclass-vs-class) - [Constants in Java: Patterns and Anti-Patterns](https://www.baeldung.com/java-constants-good-practices) +- [The transient Keyword in Java](https://www.baeldung.com/java-transient-keyword) - [[<-- Prev]](/core-java-modules/core-java-lang-2) diff --git a/core-java-modules/core-java-lang-oop-types/README.md b/core-java-modules/core-java-lang-oop-types/README.md index 459352c490..6c649877b3 100644 --- a/core-java-modules/core-java-lang-oop-types/README.md +++ b/core-java-modules/core-java-lang-oop-types/README.md @@ -12,3 +12,4 @@ This module contains articles about types in Java - [Attaching Values to Java Enum](https://www.baeldung.com/java-enum-values) - [A Guide to Java Enums](https://www.baeldung.com/a-guide-to-java-enums) - [Determine if an Object is of Primitive Type](https://www.baeldung.com/java-object-primitive-type) +- [Extending Enums in Java](https://www.baeldung.com/java-extending-enums) diff --git a/core-java-modules/core-java-string-operations-3/README.md b/core-java-modules/core-java-string-operations-3/README.md index 4e46849c11..7f391ee056 100644 --- a/core-java-modules/core-java-string-operations-3/README.md +++ b/core-java-modules/core-java-string-operations-3/README.md @@ -1,3 +1,4 @@ ### Relevant Articles: - [Version Comparison in Java](https://www.baeldung.com/java-comparing-versions) +- [Java (String) or .toString()?](https://www.baeldung.com/java-string-casting-vs-tostring) diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/BufferedChannel.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/BufferedChannel.kt similarity index 95% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/BufferedChannel.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/BufferedChannel.kt index 6cfaf5b496..5fefc2f95e 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/BufferedChannel.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/BufferedChannel.kt @@ -1,4 +1,4 @@ -package com.baeldung.channles +package com.baeldung.channels import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.channels.Channel diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/ConflatedChannel.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/ConflatedChannel.kt similarity index 95% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/ConflatedChannel.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/ConflatedChannel.kt index 63b0b967c1..6225eeb107 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/ConflatedChannel.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/ConflatedChannel.kt @@ -1,4 +1,4 @@ -package com.baeldung.channles +package com.baeldung.channels import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.channels.Channel diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/PizzaPipeline.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/PizzaPipeline.kt similarity index 94% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/PizzaPipeline.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/PizzaPipeline.kt index ff4dcb2d32..abc8be4d18 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/PizzaPipeline.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/PizzaPipeline.kt @@ -1,6 +1,6 @@ -package com.baeldung.channles +package com.baeldung.channels -import com.baeldung.channles.OrderStatus.* +import com.baeldung.channels.OrderStatus.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.produce diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/ProducerConsumer.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/ProducerConsumer.kt similarity index 95% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/ProducerConsumer.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/ProducerConsumer.kt index 50687b909a..37f3c7d7bb 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/ProducerConsumer.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/ProducerConsumer.kt @@ -1,4 +1,4 @@ -package com.baeldung.channles +package com.baeldung.channels import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/RendezvousChannel.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/RendezvousChannel.kt similarity index 94% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/RendezvousChannel.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/RendezvousChannel.kt index e046e86e29..d4b554bced 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/RendezvousChannel.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/RendezvousChannel.kt @@ -1,4 +1,4 @@ -package com.baeldung.channles +package com.baeldung.channels import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/SeveralProducersOneConsumer.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/SeveralProducersOneConsumer.kt similarity index 96% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/SeveralProducersOneConsumer.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/SeveralProducersOneConsumer.kt index fd2c046f97..5ed95debe8 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/SeveralProducersOneConsumer.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/SeveralProducersOneConsumer.kt @@ -1,4 +1,4 @@ -package com.baeldung.channles +package com.baeldung.channels import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.channels.Channel diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/SingleProducerSeveralConsumers.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/SingleProducerSeveralConsumers.kt similarity index 95% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/SingleProducerSeveralConsumers.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/SingleProducerSeveralConsumers.kt index bff1609b35..f8f7b4b23b 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/SingleProducerSeveralConsumers.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/SingleProducerSeveralConsumers.kt @@ -1,4 +1,4 @@ -package com.baeldung.channles +package com.baeldung.channels import kotlinx.coroutines.* import kotlinx.coroutines.channels.ReceiveChannel diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/TickerChannel.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/TickerChannel.kt similarity index 94% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/TickerChannel.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/TickerChannel.kt index febcbd1534..85c0dc8d04 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/TickerChannel.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/TickerChannel.kt @@ -1,4 +1,4 @@ -package com.baeldung.channles +package com.baeldung.channels import kotlinx.coroutines.channels.ticker import kotlinx.coroutines.delay diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/UnlimitedChannel.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/UnlimitedChannel.kt similarity index 95% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/UnlimitedChannel.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/UnlimitedChannel.kt index 9b01bcee54..e4725ca903 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/UnlimitedChannel.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/UnlimitedChannel.kt @@ -1,4 +1,4 @@ -package com.baeldung.channles +package com.baeldung.channels import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.channels.Channel diff --git a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/logger.kt b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/logger.kt similarity index 82% rename from core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/logger.kt rename to core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/logger.kt index fdc4c295f8..036a6a4504 100644 --- a/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channles/logger.kt +++ b/core-kotlin-modules/core-kotlin-concurrency/src/main/kotlin/com/baeldung/channels/logger.kt @@ -1,4 +1,4 @@ -package com.baeldung.channles +package com.baeldung.channels import java.text.SimpleDateFormat import java.util.* diff --git a/discord4j/.gitignore b/discord4j/.gitignore new file mode 100644 index 0000000000..b56f1dd0d0 --- /dev/null +++ b/discord4j/.gitignore @@ -0,0 +1,33 @@ +README.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/discord4j/pom.xml b/discord4j/pom.xml new file mode 100644 index 0000000000..7687f63ad5 --- /dev/null +++ b/discord4j/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.5.RELEASE + + + com.baeldung + discord4j-bot + 0.0.1-SNAPSHOT + discord4j-bot + Demo Discord bot using Discord4J + Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + com.discord4j + discord4j-core + 3.1.1 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + diff --git a/discord4j/src/main/java/com/baeldung/discordbot/BotConfiguration.java b/discord4j/src/main/java/com/baeldung/discordbot/BotConfiguration.java new file mode 100644 index 0000000000..a60005e9b5 --- /dev/null +++ b/discord4j/src/main/java/com/baeldung/discordbot/BotConfiguration.java @@ -0,0 +1,48 @@ +package com.baeldung.discordbot; + +import com.baeldung.discordbot.events.EventListener; +import discord4j.core.DiscordClientBuilder; +import discord4j.core.GatewayDiscordClient; +import discord4j.core.event.domain.Event; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +@Configuration +public class BotConfiguration { + + private static final Logger log = LoggerFactory.getLogger( BotConfiguration.class ); + + @Value("${token}") + private String token; + + @Bean + public GatewayDiscordClient gatewayDiscordClient(List> eventListeners) { + GatewayDiscordClient client = null; + + try { + client = DiscordClientBuilder.create(token) + .build() + .login() + .block(); + + for(EventListener listener : eventListeners) { + client.on(listener.getEventType()) + .flatMap(listener::execute) + .onErrorResume(listener::handleError) + .subscribe(); + } + + client.onDisconnect().block(); + } + catch ( Exception exception ) { + log.error( "Be sure to use a valid bot token!", exception ); + } + + return client; + } +} diff --git a/discord4j/src/main/java/com/baeldung/discordbot/DiscordBotApplication.java b/discord4j/src/main/java/com/baeldung/discordbot/DiscordBotApplication.java new file mode 100644 index 0000000000..069a36635c --- /dev/null +++ b/discord4j/src/main/java/com/baeldung/discordbot/DiscordBotApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.discordbot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DiscordBotApplication { + + public static void main(String[] args) { + SpringApplication.run(DiscordBotApplication.class, args); + } +} diff --git a/discord4j/src/main/java/com/baeldung/discordbot/events/EventListener.java b/discord4j/src/main/java/com/baeldung/discordbot/events/EventListener.java new file mode 100644 index 0000000000..ca4c79de0d --- /dev/null +++ b/discord4j/src/main/java/com/baeldung/discordbot/events/EventListener.java @@ -0,0 +1,19 @@ +package com.baeldung.discordbot.events; + +import discord4j.core.event.domain.Event; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +public interface EventListener { + + Logger LOG = LoggerFactory.getLogger(EventListener.class); + + Class getEventType(); + Mono execute(T event); + + default Mono handleError(Throwable error) { + LOG.error("Unable to process " + getEventType().getSimpleName(), error); + return Mono.empty(); + } +} diff --git a/discord4j/src/main/java/com/baeldung/discordbot/events/MessageCreateListener.java b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageCreateListener.java new file mode 100644 index 0000000000..f545489804 --- /dev/null +++ b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageCreateListener.java @@ -0,0 +1,19 @@ +package com.baeldung.discordbot.events; + +import discord4j.core.event.domain.message.MessageCreateEvent; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class MessageCreateListener extends MessageListener implements EventListener { + + @Override + public Class getEventType() { + return MessageCreateEvent.class; + } + + @Override + public Mono execute(MessageCreateEvent event) { + return processCommand(event.getMessage()); + } +} diff --git a/discord4j/src/main/java/com/baeldung/discordbot/events/MessageListener.java b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageListener.java new file mode 100644 index 0000000000..e1f48468be --- /dev/null +++ b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageListener.java @@ -0,0 +1,19 @@ +package com.baeldung.discordbot.events; + +import discord4j.core.object.entity.Message; +import reactor.core.publisher.Mono; + +public abstract class MessageListener { + + public Mono processCommand(Message eventMessage) { + return Mono.just(eventMessage) + .filter(message -> message.getAuthor().map(user -> !user.isBot()).orElse(false)) + .filter(message -> message.getContent().equalsIgnoreCase("!todo")) + .flatMap(Message::getChannel) + .flatMap(channel -> channel.createMessage("Things to do today:\n" + + " - write a bot\n" + + " - eat lunch\n" + + " - play a game")) + .then(); + } +} diff --git a/discord4j/src/main/java/com/baeldung/discordbot/events/MessageUpdateListener.java b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageUpdateListener.java new file mode 100644 index 0000000000..62802d4903 --- /dev/null +++ b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageUpdateListener.java @@ -0,0 +1,22 @@ +package com.baeldung.discordbot.events; + +import discord4j.core.event.domain.message.MessageUpdateEvent; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class MessageUpdateListener extends MessageListener implements EventListener { + + @Override + public Class getEventType() { + return MessageUpdateEvent.class; + } + + @Override + public Mono execute(MessageUpdateEvent event) { + return Mono.just(event) + .filter(MessageUpdateEvent::isContentChanged) + .flatMap(MessageUpdateEvent::getMessage) + .flatMap(super::processCommand); + } +} diff --git a/discord4j/src/main/resources/application.yml b/discord4j/src/main/resources/application.yml new file mode 100644 index 0000000000..e2079e33b4 --- /dev/null +++ b/discord4j/src/main/resources/application.yml @@ -0,0 +1 @@ +token: 'our-token-here' diff --git a/discord4j/src/test/java/com/baeldung/discordbot/DiscordBotLiveTest.java b/discord4j/src/test/java/com/baeldung/discordbot/DiscordBotLiveTest.java new file mode 100644 index 0000000000..8d9a285748 --- /dev/null +++ b/discord4j/src/test/java/com/baeldung/discordbot/DiscordBotLiveTest.java @@ -0,0 +1,12 @@ +package com.baeldung.discordbot; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class DiscordBotLiveTest { + + @Test + public void contextTest() { + } +} diff --git a/java-native/README.md b/java-native/README.md index 2e2047924b..4f85342a38 100644 --- a/java-native/README.md +++ b/java-native/README.md @@ -6,3 +6,4 @@ This module contains articles about the Java Native Interface (JNI). - [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) diff --git a/persistence-modules/java-jpa-3/README.md b/persistence-modules/java-jpa-3/README.md index dce9c4e711..504c7ccdd0 100644 --- a/persistence-modules/java-jpa-3/README.md +++ b/persistence-modules/java-jpa-3/README.md @@ -5,3 +5,4 @@ This module contains articles about the Java Persistence API (JPA) in Java. ### Relevant Articles: - [JPA Entity Equality](https://www.baeldung.com/jpa-entity-equality) +- [Ignoring Fields With the JPA @Transient Annotation](https://www.baeldung.com/jpa-transient-ignore-field) diff --git a/persistence-modules/java-jpa-3/pom.xml b/persistence-modules/java-jpa-3/pom.xml index da18ae3046..7c02cc6c8e 100644 --- a/persistence-modules/java-jpa-3/pom.xml +++ b/persistence-modules/java-jpa-3/pom.xml @@ -27,7 +27,21 @@ h2 ${h2.version} - + + mysql + mysql-connector-java + 8.0.21 + + + com.fasterxml.jackson.core + jackson-databind + 2.11.3 + + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate5 + 2.9.8 + javax.persistence diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/HibernateConfig.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/HibernateConfig.java new file mode 100644 index 0000000000..9285c23dfa --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/HibernateConfig.java @@ -0,0 +1,37 @@ +package com.baeldung.ignorable.fields; + +import java.util.Properties; + +import org.hibernate.SessionFactory; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.service.ServiceRegistry; + +public class HibernateConfig { + private static SessionFactory sessionFactory; + + public static SessionFactory getSessionFactory() { + if (sessionFactory == null) { + Configuration configuration = new Configuration(); + + Properties settings = new Properties(); + settings.put(Environment.DRIVER, "com.mysql.cj.jdbc.Driver"); + settings.put(Environment.URL, "jdbc:mysql://localhost:3306/app_db?useSSL=false"); + settings.put(Environment.USER, "root"); + settings.put(Environment.PASS, "password"); + settings.put(Environment.DIALECT, "org.hibernate.dialect.MySQL5Dialect"); + settings.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread"); + configuration.setProperties(settings); + + configuration.addAnnotatedClass(User.class); + + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySettings(configuration.getProperties()) + .build(); + + sessionFactory = configuration.buildSessionFactory(serviceRegistry); + } + return sessionFactory; + } +} \ No newline at end of file diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/User.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/User.java new file mode 100644 index 0000000000..8d1812605d --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/User.java @@ -0,0 +1,80 @@ +package com.baeldung.ignorable.fields; + +import java.io.Serializable; +import java.util.StringJoiner; + +import javax.persistence.*; + +@Entity +@Table(name = "Users") +public class User implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + private String email; + private String password; + @Transient + private String currentDevice; + + // Needed for Hibernate mapping + public User() { + } + + public User(String email, String password, String currentDevice) { + this.email = email; + this.password = password; + this.currentDevice = currentDevice; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getCurrentDevice() { + return currentDevice; + } + + public void setCurrentDevice(String currentDevice) { + this.currentDevice = currentDevice; + } + + @Override + public String toString() { + return new StringJoiner(", ", User.class.getSimpleName() + "[", "]").add("id=" + id) + .add("email='" + email + "'") + .add("password='" + password + "'") + .add("currentDevice='" + currentDevice + "'") + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof User)) + return false; + User user = (User) o; + return email.equals(user.email); + } +} \ No newline at end of file diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/UserDao.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/UserDao.java new file mode 100644 index 0000000000..45e491e42e --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/UserDao.java @@ -0,0 +1,28 @@ +package com.baeldung.ignorable.fields; + +import java.util.List; + +import org.hibernate.Session; +import org.hibernate.Transaction; + +public class UserDao { + + public void saveUser(User user) { + Transaction transaction = null; + try (Session session = HibernateConfig.getSessionFactory().openSession()) { + transaction = session.beginTransaction(); + session.save(user); + transaction.commit(); + } catch (Exception e) { + if (transaction != null) { + transaction.rollback(); + } + } + } + + public List getUsers() { + try (Session session = HibernateConfig.getSessionFactory().openSession()) { + return session.createQuery("from User", User.class).list(); + } + } +} diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java new file mode 100644 index 0000000000..9ab2dd4e74 --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/LineItem.java @@ -0,0 +1,45 @@ +package com.baeldung.jpa.removal; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import java.util.Objects; + +@Entity +public class LineItem { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name; + + @ManyToOne + private OrderRequest orderRequest; + + public LineItem(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + LineItem lineItem = (LineItem) o; + + return Objects.equals(id, lineItem.id); + } + + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } + + protected LineItem() { + } +} diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java new file mode 100644 index 0000000000..739c110d8c --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/OrderRequest.java @@ -0,0 +1,43 @@ +package com.baeldung.jpa.removal; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import java.util.List; + +@Entity +public class OrderRequest { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @OneToOne(cascade = { CascadeType.REMOVE, CascadeType.PERSIST }) + private ShipmentInfo shipmentInfo; + + @OneToMany(orphanRemoval = true, cascade = CascadeType.PERSIST, mappedBy = "orderRequest") + private List lineItems; + + public OrderRequest(ShipmentInfo shipmentInfo) { + this.shipmentInfo = shipmentInfo; + } + + public OrderRequest(List lineItems) { + this.lineItems = lineItems; + } + + public void removeLineItem(LineItem lineItem) { + lineItems.remove(lineItem); + } + + public void setLineItems(List lineItems) { + this.lineItems = lineItems; + } + + protected OrderRequest() { + } +} diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java new file mode 100644 index 0000000000..12274bcadf --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/removal/ShipmentInfo.java @@ -0,0 +1,23 @@ +package com.baeldung.jpa.removal; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class ShipmentInfo { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name; + + public ShipmentInfo(String name) { + this.name = name; + } + + protected ShipmentInfo() { + } +} diff --git a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml index 28a929f912..88378bd8db 100644 --- a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml @@ -1,25 +1,43 @@ - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.equality.EqualByJavaDefault - com.baeldung.jpa.equality.EqualById - com.baeldung.jpa.equality.EqualByBusinessKey - true - - - - - - - - - - - - + version="2.2"> + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.equality.EqualByJavaDefault + com.baeldung.jpa.equality.EqualById + com.baeldung.jpa.equality.EqualByBusinessKey + true + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.removal.ShipmentInfo + com.baeldung.jpa.removal.LineItem + com.baeldung.jpa.removal.OrderRequest + true + + + + + + + + + + + + diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/ignorable/fields/TransientFieldUnitTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/ignorable/fields/TransientFieldUnitTest.java new file mode 100644 index 0000000000..114a4cca4c --- /dev/null +++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/ignorable/fields/TransientFieldUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung.ignorable.fields; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.*; +import java.util.List; +import java.util.Random; + +import org.junit.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; + +public class TransientFieldUnitTest { + + private final UserDao userDao = new UserDao(); + + private final int randInt = new Random().nextInt(); + + private final User user = new User("user" + randInt + "@bar.com", "hunter2", "MacOSX"); + + @Test + public void givenFieldWithTransientAnnotation_whenSavingViaJPA_thenFieldIgnored() { + userDao.saveUser(user); + List allUsers = userDao.getUsers(); + User savedUser = allUsers.get(allUsers.indexOf(user)); + + assertNull(savedUser.getCurrentDevice()); + } + + @Test + public void givenFieldWithTransientAnnotation_whenSerializingObject_thenFieldSerialized() throws IOException, ClassNotFoundException { + + FileOutputStream fout = new FileOutputStream("test.obj"); + ObjectOutputStream out = new ObjectOutputStream(fout); + out.writeObject(user); + out.flush(); + out.close(); + + FileInputStream fin = new FileInputStream("test.obj"); + ObjectInputStream in = new ObjectInputStream(fin); + User savedUser = (User) in.readObject(); + in.close(); + + assertEquals(user.getCurrentDevice(), savedUser.getCurrentDevice()); + } + + @Test + public void givenFieldWithTransientAnnotation_whenSerializingToJSON_thenFieldSerialized() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + String json = objectMapper.writeValueAsString(user); + User savedUser = objectMapper.readValue(json, User.class); + + assertEquals(user.getCurrentDevice(), savedUser.getCurrentDevice()); + } + + @Test + public void givenJacksonHibernate5Module_whenSerializingTransientAnnotation_thenFieldIgnored() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new Hibernate5Module()); + String json = objectMapper.writeValueAsString(user); + User savedUser = objectMapper.readValue(json, User.class); + + assertNull(savedUser.getCurrentDevice()); + } + + @Test + public void givenPropagateTransientFieldFlag_whenSerializingTransientAnnotation_thenFieldSerialized() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true); + String json = objectMapper.writeValueAsString(user); + User savedUser = objectMapper.readValue(json, User.class); + + assertEquals(user.getCurrentDevice(), savedUser.getCurrentDevice()); + } +} diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java new file mode 100644 index 0000000000..8f99723ac6 --- /dev/null +++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/CascadeTypeRemoveIntegrationTest.java @@ -0,0 +1,73 @@ +package com.baeldung.jpa.removal; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.List; + +public class CascadeTypeRemoveIntegrationTest { + + private static EntityManagerFactory factory; + private static EntityManager entityManager; + + @BeforeClass + public static void setup() { + factory = Persistence.createEntityManagerFactory("jpa-h2-removal"); + entityManager = factory.createEntityManager(); + } + + @Test + public void whenOrderRequestIsDeleted_thenDeleteShipmentInfo() { + createOrderRequestWithShipmentInfo(); + + OrderRequest orderRequest = entityManager.find(OrderRequest.class, 1L); + + entityManager.getTransaction().begin(); + entityManager.remove(orderRequest); + entityManager.getTransaction().commit(); + + Assert.assertEquals(0, findAllOrderRequest().size()); + Assert.assertEquals(0, findAllShipmentInfo().size()); + } + + private void createOrderRequestWithShipmentInfo() { + ShipmentInfo shipmentInfo = new ShipmentInfo("name"); + OrderRequest orderRequest = new OrderRequest(shipmentInfo); + + entityManager.getTransaction().begin(); + entityManager.persist(orderRequest); + entityManager.getTransaction().commit(); + + Assert.assertEquals(1, findAllOrderRequest().size()); + Assert.assertEquals(1, findAllShipmentInfo().size()); + } + + private List findAllOrderRequest() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(OrderRequest.class); + Root root = cq.from(OrderRequest.class); + CriteriaQuery findAll = cq.select(root); + TypedQuery findAllQuery = entityManager.createQuery(findAll); + + return findAllQuery.getResultList(); + } + + private List findAllShipmentInfo() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(ShipmentInfo.class); + Root root = cq.from(ShipmentInfo.class); + CriteriaQuery findAll = cq.select(root); + TypedQuery findAllQuery = entityManager.createQuery(findAll); + + return findAllQuery.getResultList(); + } + +} diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java new file mode 100644 index 0000000000..615e8cf3a8 --- /dev/null +++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/removal/OrphanRemovalIntegrationTest.java @@ -0,0 +1,92 @@ +package com.baeldung.jpa.removal; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.PersistenceException; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.ArrayList; +import java.util.List; + +public class OrphanRemovalIntegrationTest { + + private static EntityManagerFactory factory; + private static EntityManager entityManager; + + @Before + public void setup() { + factory = Persistence.createEntityManagerFactory("jpa-h2-removal"); + entityManager = factory.createEntityManager(); + } + + @Test + public void whenLineItemIsRemovedFromOrderRequest_thenDeleteOrphanedLineItem() { + createOrderRequestWithLineItems(); + + OrderRequest orderRequest = entityManager.find(OrderRequest.class, 1L); + LineItem lineItem = entityManager.find(LineItem.class, 2L); + orderRequest.removeLineItem(lineItem); + + entityManager.getTransaction().begin(); + entityManager.merge(orderRequest); + entityManager.getTransaction().commit(); + + Assert.assertEquals(1, findAllOrderRequest().size()); + Assert.assertEquals(2, findAllLineItem().size()); + } + + @Test(expected = PersistenceException.class) + public void whenLineItemsIsReassigned_thenThrowAnException() { + createOrderRequestWithLineItems(); + + OrderRequest orderRequest = entityManager.find(OrderRequest.class, 1L); + orderRequest.setLineItems(new ArrayList<>()); + + entityManager.getTransaction().begin(); + entityManager.merge(orderRequest); + entityManager.getTransaction().commit(); + } + + private void createOrderRequestWithLineItems() { + List lineItems = new ArrayList<>(); + lineItems.add(new LineItem("line item 1")); + lineItems.add(new LineItem("line item 2")); + lineItems.add(new LineItem("line item 3")); + + OrderRequest orderRequest = new OrderRequest(lineItems); + + entityManager.getTransaction().begin(); + entityManager.persist(orderRequest); + entityManager.getTransaction().commit(); + + Assert.assertEquals(1, findAllOrderRequest().size()); + Assert.assertEquals(3, findAllLineItem().size()); + } + + private List findAllOrderRequest() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(OrderRequest.class); + Root root = cq.from(OrderRequest.class); + CriteriaQuery findAll = cq.select(root); + TypedQuery findAllQuery = entityManager.createQuery(findAll); + + return findAllQuery.getResultList(); + } + + private List findAllLineItem() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(LineItem.class); + Root root = cq.from(LineItem.class); + CriteriaQuery findAll = cq.select(root); + TypedQuery findAllQuery = entityManager.createQuery(findAll); + + return findAllQuery.getResultList(); + } +} diff --git a/pom.xml b/pom.xml index cba7e33b03..6c96d8d77e 100644 --- a/pom.xml +++ b/pom.xml @@ -397,6 +397,7 @@ ddd deeplearning4j + discord4j disruptor dozer drools @@ -909,6 +910,7 @@ ddd deeplearning4j + discord4j disruptor dozer drools diff --git a/spring-5-reactive/src/test/java/com/baeldung/reactive/Spring5ReactiveServerClientIntegrationTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/Spring5ReactiveServerClientIntegrationTest.java deleted file mode 100644 index b8dd9c9509..0000000000 --- a/spring-5-reactive/src/test/java/com/baeldung/reactive/Spring5ReactiveServerClientIntegrationTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.baeldung.reactive; - -import static org.springframework.web.reactive.function.server.RequestPredicates.GET; -import static org.springframework.web.reactive.function.server.RequestPredicates.POST; - -import java.time.Duration; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.springframework.http.server.reactive.HttpHandler; -import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter; -import org.springframework.web.reactive.function.server.RouterFunction; -import org.springframework.web.reactive.function.server.RouterFunctions; -import org.springframework.web.reactive.function.server.ServerResponse; - -import com.baeldung.web.reactive.Task; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.netty.DisposableServer; -import reactor.netty.http.server.HttpServer; - -public class Spring5ReactiveServerClientIntegrationTest { - private static DisposableServer disposableServer; - - @BeforeAll - public static void setUp() throws Exception { - HttpServer server = HttpServer.create() - .host("localhost") - .port(8080); - RouterFunction route = RouterFunctions.route(POST("/task/process"), request -> ServerResponse.ok() - .body(request.bodyToFlux(Task.class) - .map(ll -> new Task("TaskName", 1)), Task.class)) - .and(RouterFunctions.route(GET("/task"), request -> ServerResponse.ok() - .body(Mono.just("server is alive"), String.class))); - HttpHandler httpHandler = RouterFunctions.toHttpHandler(route); - ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - disposableServer = server.handle(adapter) - .bindNow(); - } - - @AfterAll - public static void shutDown() { - disposableServer.disposeNow(); - } - - // @Test - // public void givenCheckTask_whenServerHandle_thenServerResponseALiveString() throws Exception { - // WebClient client = WebClient.create("http://localhost:8080"); - // Mono result = client - // .get() - // .uri("/task") - // .exchange() - // .then(response -> response.bodyToMono(String.class)); - // - // assertThat(result.block()).isInstanceOf(String.class); - // } - - // @Test - // public void givenThreeTasks_whenServerHandleTheTasks_thenServerResponseATask() throws Exception { - // URI uri = URI.create("http://localhost:8080/task/process"); - // ExchangeFunction exchange = ExchangeFunctions.create(new ReactorClientHttpConnector()); - // ClientRequest request = ClientRequest - // .method(HttpMethod.POST, uri) - // .body(BodyInserters.fromPublisher(getLatLngs(), Task.class)) - // .build(); - // - // Flux taskResponse = exchange - // .exchange(request) - // .flatMap(response -> response.bodyToFlux(Task.class)); - // - // assertThat(taskResponse.blockFirst()).isInstanceOf(Task.class); - // } - - // @Test - // public void givenCheckTask_whenServerHandle_thenOragicServerResponseALiveString() throws Exception { - // URI uri = URI.create("http://localhost:8080/task"); - // ExchangeFunction exchange = ExchangeFunctions.create(new ReactorClientHttpConnector()); - // ClientRequest request = ClientRequest - // .method(HttpMethod.GET, uri) - // .body(BodyInserters.fromPublisher(getLatLngs(), Task.class)) - // .build(); - // - // Flux taskResponse = exchange - // .exchange(request) - // .flatMap(response -> response.bodyToFlux(String.class)); - // - // assertThat(taskResponse.blockFirst()).isInstanceOf(String.class); - // } - - private static Flux getLatLngs() { - return Flux.range(0, 3) - .zipWith(Flux.interval(Duration.ofSeconds(1))) - .map(x -> new Task("taskname", 1)) - .doOnNext(ll -> System.out.println("Produced: {}" + ll)); - } -}