├── JavaKatas.png ├── JavaKatasFavIcon.png ├── java-datetime ├── JavaTimeAPI.pdf ├── assets │ └── images │ │ └── DukeTime.png ├── src │ ├── main │ │ └── java │ │ │ └── none │ │ │ └── cvg │ │ │ └── datetime │ │ │ ├── LenientAssert.java │ │ │ └── DateTimeKataDisplayNames.java │ ├── test │ │ └── java │ │ │ └── none │ │ │ └── cvg │ │ │ └── datetime │ │ │ ├── TestKata5DateTimePartials.java │ │ │ └── TestKata1InstantAndDateInterop.java │ └── solutions │ │ └── java │ │ └── none │ │ └── cvg │ │ └── datetime │ │ ├── TestSolution5DateTimePartials.java │ │ └── TestSolution1InstantAndDateInterop.java ├── pom.xml └── README.adoc ├── java-handles ├── docs │ ├── davinci.png │ ├── MethodType.png │ ├── MethodHandle.png │ ├── MethodHandles.Lookup.png │ ├── index.md │ ├── _config.yml │ ├── page20.md │ ├── page12.md │ ├── page18.md │ ├── page07.md │ ├── page15.md │ ├── page03.md │ ├── page04.md │ ├── page00.md │ ├── page02.md │ ├── page14.md │ ├── page08.md │ ├── page19.md │ ├── page13.md │ ├── page16.md │ ├── page06.md │ ├── page10.md │ ├── page17.md │ ├── page11.md │ ├── page05.md │ ├── page01.md │ ├── page09.md │ └── _layouts │ │ └── default.html ├── assets │ └── images │ │ ├── davinci.png │ │ ├── MethodType.png │ │ ├── MethodHandle.png │ │ └── MethodHandles.Lookup.png ├── src │ ├── main │ │ └── java │ │ │ └── none │ │ │ └── cvg │ │ │ └── handles │ │ │ ├── ErrorMessages.java │ │ │ ├── DemoClass.java │ │ │ └── HandlesKataDisplayNames.java │ ├── test │ │ └── java │ │ │ └── none │ │ │ └── cvg │ │ │ ├── methods │ │ │ ├── TestKataPublicMethodInvocation.java │ │ │ ├── TestKataPublicStaticMethodInvocation.java │ │ │ ├── TestKataPrivateMethodInvocation.java │ │ │ └── TestKataProtectedMethodInvocation.java │ │ │ └── constructors │ │ │ └── TestKataParameteredConstructorInvocation.java │ └── solutions │ │ └── java │ │ └── none │ │ └── cvg │ │ ├── methods │ │ ├── TestSolutionPublicMethodInvocation.java │ │ ├── TestSolutionPublicStaticMethodInvocation.java │ │ ├── TestSolutionPrivateMethodInvocation.java │ │ └── TestSolutionProtectedMethodInvocation.java │ │ └── constructors │ │ └── TestSolutionParameteredConstructorInvocation.java ├── _layouts │ └── default.html └── pom.xml ├── java-futures ├── assets │ ├── images │ │ ├── Background.png │ │ └── DukeCompletableFuture.png │ └── docs │ │ ├── Exceptions.adoc │ │ ├── Future.adoc │ │ ├── CompletionStage.adoc │ │ └── CompletableFuture.adoc ├── pom.xml ├── README.adoc └── src │ └── test │ └── java │ └── none │ └── cvg │ └── futures │ └── TestKata1SimpleCompletableFutureOperations.java ├── java-lambdas ├── assets │ └── images │ │ └── DukeLambda.png ├── src │ ├── main │ │ └── java │ │ │ └── none │ │ │ └── cvg │ │ │ └── lambdas │ │ │ ├── Calculator.java │ │ │ ├── IntegerPairFactory.java │ │ │ ├── IntegerPair.java │ │ │ ├── Person.java │ │ │ └── LambdasKataDisplayNames.java │ ├── solutions │ │ └── java │ │ │ └── none │ │ │ └── cvg │ │ │ └── lambdas │ │ │ ├── TestSolution2LambdasDeeperDive.java │ │ │ └── TestSolution1LambdaBasics.java │ └── test │ │ └── java │ │ └── none │ │ └── cvg │ │ └── lambdas │ │ └── TestKata2LambdasDeeperDive.java ├── pom.xml └── README.adoc ├── java-optional ├── assets │ └── images │ │ └── DukeOptional.png ├── pom.xml ├── README.adoc └── src │ ├── test │ └── java │ │ └── none │ │ └── cvg │ │ └── optional │ │ ├── TestKata1OptionalCreationAndFetchingValues.java │ │ └── TestKata3StreamsAndOptionals.java │ └── solutions │ └── java │ └── none │ └── cvg │ └── optional │ └── TestSolution1OptionalCreationAndFetchingValues.java ├── .gitignore ├── .github └── workflows │ ├── ci.yml │ ├── QualityOutreach.yml │ └── QualityOutreachOpenJDK.yml ├── LICENSE ├── CodeKataMission.adoc ├── pom.xml ├── README.adoc └── CONTRIBUTING.adoc /JavaKatas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/JavaKatas.png -------------------------------------------------------------------------------- /JavaKatasFavIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/JavaKatasFavIcon.png -------------------------------------------------------------------------------- /java-datetime/JavaTimeAPI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-datetime/JavaTimeAPI.pdf -------------------------------------------------------------------------------- /java-handles/docs/davinci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-handles/docs/davinci.png -------------------------------------------------------------------------------- /java-handles/docs/MethodType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-handles/docs/MethodType.png -------------------------------------------------------------------------------- /java-handles/docs/MethodHandle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-handles/docs/MethodHandle.png -------------------------------------------------------------------------------- /java-datetime/assets/images/DukeTime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-datetime/assets/images/DukeTime.png -------------------------------------------------------------------------------- /java-handles/assets/images/davinci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-handles/assets/images/davinci.png -------------------------------------------------------------------------------- /java-futures/assets/images/Background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-futures/assets/images/Background.png -------------------------------------------------------------------------------- /java-handles/assets/images/MethodType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-handles/assets/images/MethodType.png -------------------------------------------------------------------------------- /java-handles/docs/MethodHandles.Lookup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-handles/docs/MethodHandles.Lookup.png -------------------------------------------------------------------------------- /java-lambdas/assets/images/DukeLambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-lambdas/assets/images/DukeLambda.png -------------------------------------------------------------------------------- /java-handles/assets/images/MethodHandle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-handles/assets/images/MethodHandle.png -------------------------------------------------------------------------------- /java-optional/assets/images/DukeOptional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-optional/assets/images/DukeOptional.png -------------------------------------------------------------------------------- /java-futures/assets/images/DukeCompletableFuture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-futures/assets/images/DukeCompletableFuture.png -------------------------------------------------------------------------------- /java-handles/assets/images/MethodHandles.Lookup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/java-katas/main/java-handles/assets/images/MethodHandles.Lookup.png -------------------------------------------------------------------------------- /java-lambdas/src/main/java/none/cvg/lambdas/Calculator.java: -------------------------------------------------------------------------------- 1 | package none.cvg.lambdas; 2 | 3 | public interface Calculator { 4 | int calculate(int x, int y); 5 | } 6 | -------------------------------------------------------------------------------- /java-lambdas/src/main/java/none/cvg/lambdas/IntegerPairFactory.java: -------------------------------------------------------------------------------- 1 | package none.cvg.lambdas; 2 | 3 | @FunctionalInterface 4 | public interface IntegerPairFactory { 5 | IntegerPair get(); 6 | } 7 | -------------------------------------------------------------------------------- /java-handles/docs/index.md: -------------------------------------------------------------------------------- 1 | Hello. 2 | 3 | 4 |             5 |             6 |             7 |             8 |             9 | [Next >>](page00.md) -------------------------------------------------------------------------------- /java-handles/docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: Java Handles 2 | description: A Code Kata 3 | plugins: 4 | - jekyll-relative-links 5 | relative_links: 6 | enabled: true 7 | collections: true 8 | include: 9 | - CONTRIBUTING.md 10 | - README.md 11 | - LICENSE.md 12 | - COPYING.md 13 | - CODE_OF_CONDUCT.md 14 | - CONTRIBUTING.md 15 | - ISSUE_TEMPLATE.md 16 | - PULL_REQUEST_TEMPLATE.md 17 | theme: jekyll-theme-midnight 18 | -------------------------------------------------------------------------------- /java-handles/docs/page20.md: -------------------------------------------------------------------------------- 1 | # THANK 2 | 3 | # YOU 4 | 5 | [<< Prev](page19.md) 6 |             7 |             8 |             9 |             10 |             11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | pom.xml.tag 3 | pom.xml.releaseBackup 4 | pom.xml.versionsBackup 5 | pom.xml.next 6 | release.properties 7 | dependency-reduced-pom.xml 8 | buildNumber.properties 9 | .mvn/timing.properties 10 | 11 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 12 | !/.mvn/wrapper/maven-wrapper.jar 13 | **/.idea/ 14 | **/*.iml 15 | 16 | # Ignore eclipse settings 17 | .classpath 18 | .project 19 | .settings 20 | 21 | -------------------------------------------------------------------------------- /java-futures/assets/docs/Exceptions.adoc: -------------------------------------------------------------------------------- 1 | 2 | .Exception Handling in Completable Futures 3 | |=== 4 | |Type|`whenComplete()`|`handle()`|`exceptionally()` 5 | 6 | |Can use success result |Yes |Yes |*_No_* 7 | |Called if previous stage successful |Yes |Yes |*_No_* 8 | |Can use exception result |Yes |Yes |Yes 9 | |Called if previous stage has exception |Yes |Yes |Yes 10 | |Failure recovery |*_No_* |Yes |Yes 11 | |Return a different result |*_No_* |Yes |*_No_* 12 | |=== -------------------------------------------------------------------------------- /java-handles/docs/page12.md: -------------------------------------------------------------------------------- 1 | # Live 2 | # 3 | # Coding 4 | 5 | [<< Prev](page11.md) 6 |             7 |             8 |             9 |             10 |             11 | [Next >>](page13.md) -------------------------------------------------------------------------------- /java-handles/docs/page18.md: -------------------------------------------------------------------------------- 1 | # Live 2 | # 3 | # Coding 4 | 5 | [<< Prev](page17.md) 6 |             7 |             8 |             9 |             10 |             11 | [Next >>](page19.md) -------------------------------------------------------------------------------- /java-handles/docs/page07.md: -------------------------------------------------------------------------------- 1 | # What 2 | # Changed ? 3 | 4 | 5 | [<< Prev](page06.md) 6 |             7 |             8 |             9 |             10 |             11 | [Next >>](page08.md) 12 | 13 | -------------------------------------------------------------------------------- /java-handles/docs/page15.md: -------------------------------------------------------------------------------- 1 | # What 2 | # Changed ? 3 | 4 | 5 | [<< Prev](page14.md) 6 |             7 |             8 |             9 |             10 |             11 | [Next >>](page16.md) 12 | 13 | -------------------------------------------------------------------------------- /java-handles/docs/page03.md: -------------------------------------------------------------------------------- 1 | # FUTURE ORIENTED CHANGES 2 | 3 | # IN JAVA 4 | 5 | ## (A STEP BACK IN TIME) 6 | 7 | 8 | 9 | 10 | [<< Prev](page02.md) 11 |             12 |             13 |             14 |             15 |             16 | [Next >>](page04.md) 17 | 18 | -------------------------------------------------------------------------------- /java-handles/src/main/java/none/cvg/handles/ErrorMessages.java: -------------------------------------------------------------------------------- 1 | package none.cvg.handles; 2 | 3 | public enum ErrorMessages { 4 | 5 | REFLECTION_FAILURE("Reflection Test Failed. Exception message: "), 6 | UNSAFE_FAILURE("Unsafe Test Failed. Exception message: "), 7 | TEST_FAILURE("Test Failure - Fix all TODOs. Exception message: "); 8 | 9 | private String value; 10 | 11 | ErrorMessages(String value) { 12 | this.value = value; 13 | } 14 | 15 | public String getValue() { 16 | return value; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /java-handles/docs/page04.md: -------------------------------------------------------------------------------- 1 | DaVinci Machine Project 2 | 3 | 4 | [<< Prev](page03.md) 5 |             6 |             7 |             8 |             9 |             10 | [Next >>](page05.md) 11 | 12 | -------------------------------------------------------------------------------- /java-handles/docs/page00.md: -------------------------------------------------------------------------------- 1 | # Alternates to 2 | # Java Reflection 3 | # and 4 | # Unsafe usage 5 | 6 | ## Chandra Guntur 7 | 8 | 9 | 10 | 11 | 12 | ##### Twitter: @CGuntur 13 | 14 | 15 | 16 |             17 |             18 |             19 |             20 |             21 | [Next >>](page01.md) -------------------------------------------------------------------------------- /java-handles/docs/page02.md: -------------------------------------------------------------------------------- 1 | # Agenda 2 | 3 | ## EXPLANATION and CODE SAMPLES FOR: 4 | 5 | ### Java Reflection 6 | * Usage until now 7 | * New alternates - A Code Kata 8 | 9 | ### `sun.misc.Unsafe` 10 | * Usage until now 11 | * New alternates - A Code Kata 12 | 13 | [<< Prev](page01.md) 14 |             15 |             16 |             17 |             18 |             19 | [Next >>](page03.md) 20 | 21 | -------------------------------------------------------------------------------- /java-handles/docs/page14.md: -------------------------------------------------------------------------------- 1 | # Usage of Unsafe 2 | 3 | `sun.misc.Unsafe` has quite a few usages: 4 | 5 | * Low level memory information 6 | * Object & field manipulation 7 | * Classes and static field manipulation 8 | * Array manipulations 9 | * Low-level primitive for synchronization 10 | * Direct memory access 11 | * Avoiding initialization/constructor calls 12 | * Faster serialization/deserialization 13 | 14 | [<< Prev](page13.md) 15 |             16 |             17 |             18 |             19 |             20 | [Next >>](page15.md) -------------------------------------------------------------------------------- /java-handles/docs/page08.md: -------------------------------------------------------------------------------- 1 | * JSR-292 led to lightweight references to methods 2 | * The references are called Method Handles 3 | * A call via a handle is as fast as a statically linked Java call 4 | * A bit more verbose than reflection code 5 | * APIs to investigate : 6 | * **`java.lang.invoke.MethodHandles.Lookup`** 7 | * **`java.lang.invoke.MethodHandle`** 8 | * **`java.lang.invoke.MethodType`** 9 | 10 | 11 | [<< Prev](page07.md) 12 |             13 |             14 |             15 |             16 |             17 | [Next >>](page09.md) 18 | 19 | -------------------------------------------------------------------------------- /java-handles/docs/page19.md: -------------------------------------------------------------------------------- 1 | # Unsafe -to - VarHandle Recap 2 | 3 | * Get a MethodHandles.Lookup via : 4 | * **`lookup().in(`** requestedLookupClass **`)`** 5 | * **`privateLookupIn(`** targetClass, lookup **`)`** 6 | * Find a VarHandle : 7 | * For fields : 8 | * **`findVarHandle(`** receiverClass, attributeName, attributeType **`)`**
 9 | * For array elements : 10 | * **`arrayElementVarHandle(`** arrayClass **`)`** 11 | 12 | 13 | [<< Prev](page18.md) 14 |             15 |             16 |             17 |             18 |             19 | [Next >>](page20.md) -------------------------------------------------------------------------------- /java-handles/docs/page13.md: -------------------------------------------------------------------------------- 1 | # Reflection - To - MethodHandles Recap 2 | 3 | * MethodHandles.Lookup the methods on the class. 4 | * Acquire a MethodHandle to invoke: 5 | * by **Method type** approach :: 6 | * Describe the method to create a MethodType 7 | * `find*()` method to extract a MethodHandle 8 | * by **Method signature** approach :: 9 | * Get a Method instance by name and arity 10 | * `unreflect()` the Method instance to extract a MethodHandle. 11 | 12 | [<< Prev](page12.md) 13 |             14 |             15 |             16 |             17 |             18 | [Next >>](page14.md) -------------------------------------------------------------------------------- /java-handles/docs/page16.md: -------------------------------------------------------------------------------- 1 | # Unsafe Replacement: VarHandle (Java 9) 2 | 3 | * JSR-292 led to lightweight references to attributes 4 | * The references are called VarHandles 5 | * Standard replacements for features in : 6 | * **`java.util.concurrent.atomic.*`** 7 | * **`sun.misc.Unsafe`** 8 | * The VarHandle API provides : 9 | * **Field and array index element access** 10 | * **Memory fences** for fine-grained control of memory ordering 11 | * A strong **reachability-fence** operation for an object 12 | 13 | [<< Prev](page15.md) 14 |             15 |             16 |             17 |             18 |             19 | [Next >>](page17.md) -------------------------------------------------------------------------------- /java-handles/docs/page06.md: -------------------------------------------------------------------------------- 1 | ## Reflection introduced in Java 1.1 circa 1997 2 | * Used to examine/alter behavior and structure 3 | * Bypasses accessibility and instantiation rules 4 | * Reflection drawbacks * : 5 | * **performance overhead** - dynamic resolution, no optimization 6 | * **security restrictions** - runtime permission, SecurityManager override 7 | * **exposure of internals** - breaks abstractions and encapsulation 8 | 9 | * Read more at: https://docs.oracle.com/javase/tutorial/reflect/ 10 | 11 | [<< Prev](page05.md) 12 |             13 |             14 |             15 |             16 |             17 | [Next >>](page07.md) 18 | 19 | -------------------------------------------------------------------------------- /java-futures/assets/docs/Future.adoc: -------------------------------------------------------------------------------- 1 | = Future 2 | :toc: 3 | 4 | == What is a Future 5 | 6 | Introduced in Java 5 (2004). 7 | 8 | A link:https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/concurrent/Future.html[`java.util.concurrent.Future`] is a placeholder for a result of a computation task that hasn't finished yet. 9 | 10 | Once the task completes, the Future holds the result. 11 | 12 | == Operations on a Future 13 | 14 | The following operations can be performed on a Future: 15 | 16 | .Future operations 17 | [width="99%", options="header"] 18 | |=== 19 | |Method name |Description 20 | 21 | |`*cancel*` |Attempts to cancel execution of this task. 22 | |`*get*`|Waits if necessary for the computation to complete, and then retrieves its result, with or without a timeout parameter. 23 | |`*isCancelled*`|Check if the Future has been canceled, prior to normal completion. 24 | |`*isDone*`|Check if the Future completed normally. 25 | |=== -------------------------------------------------------------------------------- /java-handles/docs/page10.md: -------------------------------------------------------------------------------- 1 | # MethodHandle - "The Executor" 2 | 3 | MethodHandles are just Handles that can be acted on 4 | 5 | 6 | * Direct executable reference to an underlying method 7 | * Not distinguished by name of method or class 8 | * Special invoker methods : 9 | * **`invoke()`** 10 | * **`invokeExact()`** 11 | * Immutable and stateless 12 | 13 | 14 | https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/MethodHandle.html 15 | 16 | 17 | [<< Prev](page09.md) 18 |             19 |             20 |             21 |             22 |             23 | [Next >>](page11.md) 24 | -------------------------------------------------------------------------------- /java-handles/docs/page17.md: -------------------------------------------------------------------------------- 1 | # Unsafe Replacement: VarHandles - Purpose 2 | 3 | * **Safety** - JVM cannot be placed in a corrupt memory state : 4 | * Content data types must match or be ‘castable’ to field type 5 | * Array indexes must exist in order to be accessed/written to 6 | * **Integrity** - Field access rules cannot be violated : 7 | * Same rules as for **`getfield`** and **`putfield`** byte codes 8 | * A final field cannot be updated 9 | * **Performance** - Must be similar to **`Unsafe`** operations 10 | * **Usability** - Friendlier, consistent API compared to **`Unsafe`** 11 | 12 | [<< Prev](page16.md) 13 |             14 |             15 |             16 |             17 |             18 | [Next >>](page18.md) -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | ci: 10 | name: "JDK ${{ matrix.java }} on ${{ matrix.os }}" 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | os: [ ubuntu-latest ] # [ ubuntu-latest, macos-latest, windows-latest ] 15 | java: [ 16 ] # [ 17-ea, 16, 15 ] 16 | runs-on: ${{ matrix.os }} 17 | steps: 18 | - name: 'Check out repository' 19 | uses: actions/checkout@v2 20 | - name: 'Download JDK' 21 | id: download-jdk 22 | uses: sormuras/download-jdk@v1 23 | with: 24 | feature: ${{ matrix.java }} 25 | - name: 'Set up JDK, Project ${{ matrix.project }}' 26 | uses: actions/setup-java@v1 27 | with: 28 | java-version: ${{ steps.download-jdk.outputs.version }} 29 | jdkFile: "${{ steps.download-jdk.outputs.file }}" 30 | - name: 'Print Java version' 31 | run: java -version 32 | - name: 'Build with Maven' 33 | run: mvn --batch-mode --no-transfer-progress verify 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Chandra Guntur 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /java-handles/docs/page11.md: -------------------------------------------------------------------------------- 1 | # MethodType - "The Discriminator" 2 | 3 | MethodType acts as a discriminator in indentifying the exact method by its signature and arity. 4 | 5 | 6 | * Represents return type and input parameters of a method : 7 | * First parameter of a method type is return type 8 | * Other parameters are input parameter types 9 | * Immutable 10 | * Primitives, arrays and void (return) values are types : 11 | * **`int.class`** 12 | * **`double.class`** 13 | * **`void.class`** 14 | * **`int[].class`** 15 | * **`...`** 16 | 17 | https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/MethodType.html 18 | 19 | [<< Prev](page10.md) 20 |             21 |             22 |             23 |             24 |             25 | [Next >>](page12.md) 26 | -------------------------------------------------------------------------------- /java-handles/docs/page05.md: -------------------------------------------------------------------------------- 1 | # Future-Oriented changes in Java - Circa 2006 2 | 3 | * JSR-292 * - Multi-Language Virtual Machine proposed in 2006 4 | * Code-named **Da Vinci Machine Project** 5 | * Formulated to ease implementation of dynamic languages (JRuby **) 6 | * Core features introduced in Java 7: 7 | * *addition of an invokedynamic instruction at the JVM level* 8 | * gave us **lambdas** and **method references** in Java 9 | * **ability to change classes & methods at runtime, dynamically** 10 | * ***session focuses on this second core feature*** 11 | 12 | * https://www.jcp.org/en/jsr/detail?id=292 13 | 14 | ** Read more at: https://groups.google.com/forum/#!topic/jvm-languages/28Oko4KGiQQ 15 | 16 | [<< Prev](page04.md) 17 |             18 |             19 |             20 |             21 |             22 | [Next >>](page06.md) 23 | 24 | -------------------------------------------------------------------------------- /java-handles/docs/page01.md: -------------------------------------------------------------------------------- 1 | 2 | # CHANDRA GUNTUR - #Saganist 3 | 4 | Picture of Chandra Guntur 5 | 6 | ## Active in Java Community 7 | * **JUG Leader**: Organizer, Presenter at NYJavaSIG and NYJavaSIG Hands-On Workshops 8 | 9 | * **Speaker**: Oracle Code One, Devnexus, QCon New York, Oracle Code New York and at several Java User Groups 10 | 11 | * **Advocacy**: Active on *blogging* and *tweeting* on all things Java 12 | 13 | ## Work Portfolio 14 | 15 | * Director, Resilient Systems Engineering 16 | * Java, Eclipse Collections, Spring Boot/Cloud & Microprofile Advocate & Evangelist 17 | * Typical-day tools: Java, Groovy, Spring Boot, Vert.x, Drools, Spock 18 | 19 | #### Twitter: @CGuntur 20 | 21 | 22 | [<< Prev](page00.md) 23 |             24 |             25 |             26 |             27 |             28 | [Next >>](page02.md) 29 | 30 | -------------------------------------------------------------------------------- /CodeKataMission.adoc: -------------------------------------------------------------------------------- 1 | == What is a Code-Kata 2 | 3 | A code-kata is a coding exercise that builds muscle memory by a practice of programming to arrive 4 | at a known solution. 5 | 6 | === How does one go about with this code kata? 7 | 8 | The essence of the exercise (presentation material and code kata) is to demonstrate the 9 | usage patterns for the java API or functionality. 10 | 11 | This set of code katas rely on fixing broken tests. The tests may have multiple solutions, the 12 | intent is to learn and experiment. 13 | 14 | The project contains several JUnit tests that fail. 15 | 16 | ==== Simple steps to use this kata 17 | 18 | . Run the test class(es). 19 | . One or more tests will fail with the test failure message. 20 | . Fix the failing tests by using `HINT` and `TODO` comments. 21 | . Repeat above steps until all tests pass. 22 | . Check the solutions to see if there are other ways to solve. 23 | (Remember, the solution may be less performant/optimal than yours) 24 | . Rinse and repeat (delete and checkout again, then back to Step 1) to build muscle memory. 25 | 26 | === Mission 27 | > ***Your mission**, should you choose to accept it, will be to fix the JUnit tests. This 28 | message will self-destruct in* **NaN** *minutes* 29 | 30 | -------------------------------------------------------------------------------- /java-handles/docs/page09.md: -------------------------------------------------------------------------------- 1 | # MethodHandles.Lookup - "The Searcher" 2 | 3 | MethodHandles.Lookup is a serach facility to 'find...' methods. 4 | 5 | * Enclosed in a MethodHandles factory class 6 | * _MethodHandles is itself a sledgehammer of various Java operations_ 7 | * _Iteration, While, Do While Loops_ 8 | * _Try Finally, Throw Exception, Consume Exception_ 9 | * ... 10 | * Performs access checks and security manager interactions 11 | * If allowed creates a method handle reference 12 | * Has several lookup methods such as : 13 | * **`findGetter`** 14 | * **`findStaticSetter`** 15 | * **`findVirtual`** 16 | * **`findConstructor`** 17 | * **`...`** 18 | 19 | https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html 20 | 21 | [<< Prev](page08.md) 22 |             23 |             24 |             25 |             26 |             27 | [Next >>](page10.md) 28 | 29 | -------------------------------------------------------------------------------- /java-handles/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% seo %} 8 | 10 | 13 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 |
28 | {{ content }} 29 | 30 |
31 | Project maintained by 32 | {{ site.github.owner_name }} 33 | 34 | Twitter: — 35 | @CGuntur 36 | 37 |
38 |
39 | 40 |
41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /java-handles/docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% seo %} 8 | 10 | 13 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 |
28 | {{ content }} 29 | 30 |
31 | Project maintained by 32 | {{ site.github.owner_name }} 33 | 34 | Twitter: — 35 | @CGuntur 36 | 37 |
38 |
39 | 40 |
41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /java-lambdas/src/main/java/none/cvg/lambdas/IntegerPair.java: -------------------------------------------------------------------------------- 1 | package none.cvg.lambdas; 2 | 3 | public class IntegerPair { 4 | 5 | public static String getDesctiption() { 6 | return "Integer Pair Holder"; 7 | } 8 | 9 | int first; 10 | int second; 11 | 12 | public IntegerPair() { 13 | this(1, 6); 14 | } 15 | 16 | public IntegerPair(int first, int second) { 17 | this.first = first; 18 | this.second = second; 19 | } 20 | 21 | public int getFirst() { 22 | return first; 23 | } 24 | 25 | public void setFirst(int first) { 26 | this.first = first; 27 | } 28 | 29 | public int getSecond() { 30 | return second; 31 | } 32 | 33 | public void setSecond(int second) { 34 | this.second = second; 35 | } 36 | 37 | @Override 38 | public boolean equals(Object o) { 39 | if (this == o) return true; 40 | if (o == null || getClass() != o.getClass()) return false; 41 | 42 | IntegerPair that = (IntegerPair) o; 43 | 44 | if (first != that.first) return false; 45 | return second == that.second; 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | int result = first; 51 | result = 31 * result + second; 52 | return result; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "IntegerPair{" + 58 | "first=" + first + 59 | ", second=" + second + 60 | '}'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /java-lambdas/src/main/java/none/cvg/lambdas/Person.java: -------------------------------------------------------------------------------- 1 | package none.cvg.lambdas; 2 | 3 | public class Person { 4 | 5 | public static final Person ALICE = new Person("Alice", "Smith"); 6 | public static final Person BOB = new Person("Bob", "Jones"); 7 | public static final Person CATHY = new Person("Cathy", "Williams"); 8 | public static final Person DHRUV = new Person("Dhruv", "Patel"); 9 | public static final Person EMILY = new Person("Emily", "Cruz"); 10 | 11 | String firstName = ""; 12 | String lastName = ""; 13 | 14 | public Person(String firstName, String lastName) { 15 | this.firstName = firstName; 16 | this.lastName = lastName; 17 | } 18 | 19 | public String getFirstName() { 20 | return firstName; 21 | } 22 | 23 | public void setFirstName(String firstName) { 24 | this.firstName = firstName; 25 | } 26 | 27 | public String getLastName() { 28 | return lastName; 29 | } 30 | 31 | public void setLastName(String lastName) { 32 | this.lastName = lastName; 33 | } 34 | 35 | @Override 36 | public boolean equals(Object o) { 37 | if (this == o) return true; 38 | if (o == null || getClass() != o.getClass()) return false; 39 | 40 | Person person = (Person) o; 41 | 42 | if (!firstName.equals(person.firstName)) return false; 43 | return lastName.equals(person.lastName); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | int result = firstName.hashCode(); 49 | result = 31 * result + lastName.hashCode(); 50 | return result; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return firstName + " " + lastName; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /.github/workflows/QualityOutreach.yml: -------------------------------------------------------------------------------- 1 | name: Quality_Outreach 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | 7 | build: 8 | name: 'Java ${{ matrix.java }} on ${{ matrix.os }}' 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | os: [ ubuntu-latest ] 13 | java: [ 17-ea, 16, 15, 14 ] 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - name: 'Check out repository' 17 | uses: actions/checkout@v2 18 | - name: 'Set up JDK ${{ matrix.java }}' 19 | uses: actions/setup-java@v1 20 | with: 21 | java-version: ${{ matrix.java }} 22 | - name: 'Print Java version' 23 | run: java -version 24 | - name: 'Build with Maven' 25 | run: mvn --batch-mode --no-transfer-progress verify 26 | 27 | projects: 28 | name: 'Project ${{ matrix.project }} on ${{ matrix.os }}' 29 | needs: [ build ] 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | os: [ ubuntu-latest ] # , macos-latest, windows-latest ] 34 | project: [ Loom, Panama, Valhalla ] 35 | exclude: 36 | - { os: macos-latest, project: Valhalla } # missing 'libjli.dylib' 37 | runs-on: ${{ matrix.os }} 38 | steps: 39 | - name: 'Check out repository' 40 | uses: actions/checkout@v2 41 | - name: 'Download JDK' 42 | id: download-jdk 43 | uses: sormuras/download-jdk@v1 44 | with: 45 | feature: ${{ matrix.project }} 46 | - name: 'Set up JDK, Project ${{ matrix.project }}' 47 | uses: actions/setup-java@v1 48 | with: 49 | java-version: ${{ steps.download-jdk.outputs.version }} 50 | jdkFile: "${{ steps.download-jdk.outputs.file }}" 51 | - name: 'Print Java version' 52 | run: java -version 53 | - name: 'Build with Maven' 54 | run: mvn --batch-mode --no-transfer-progress verify 55 | -------------------------------------------------------------------------------- /java-lambdas/src/main/java/none/cvg/lambdas/LambdasKataDisplayNames.java: -------------------------------------------------------------------------------- 1 | package none.cvg.lambdas; 2 | 3 | import org.junit.jupiter.api.DisplayNameGenerator; 4 | 5 | import java.lang.reflect.Method; 6 | 7 | import static java.lang.Character.isDigit; 8 | import static java.lang.Character.isLetterOrDigit; 9 | import static java.lang.Character.isUpperCase; 10 | 11 | public class LambdasKataDisplayNames extends DisplayNameGenerator.Standard { 12 | @Override 13 | public String generateDisplayNameForClass(Class aClass) { 14 | String className = aClass.getSimpleName(); 15 | if (className.startsWith("TestKata")) { 16 | return camelToText(className.substring(9)); 17 | } 18 | if (className.startsWith("TestSolution")) { 19 | return camelToText(className.substring(13)); 20 | } 21 | return super.generateDisplayNameForClass(aClass); 22 | } 23 | 24 | @Override 25 | public String generateDisplayNameForMethod(Class aClass, Method method) { 26 | String methodName = method.getName(); 27 | return camelToText(methodName); 28 | } 29 | 30 | 31 | private static String camelToText(String text) { 32 | StringBuilder builder = new StringBuilder(); 33 | char lastChar = ' '; 34 | for (char c : text.toCharArray()) { 35 | char nc = c; 36 | 37 | if (isUpperCase(nc) && !isUpperCase(lastChar)) { 38 | if (lastChar != ' ' && isLetterOrDigit(lastChar)) { 39 | builder.append(" "); 40 | } 41 | nc = Character.toLowerCase(c); 42 | } else if (isDigit(lastChar) && !isDigit(c)) { 43 | if (lastChar != ' ') { 44 | builder.append(" "); 45 | } 46 | nc = Character.toLowerCase(c); 47 | } 48 | 49 | if (lastChar != ' ' || c != ' ') { 50 | builder.append(nc); 51 | } 52 | lastChar = c; 53 | } 54 | return builder.toString(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /java-datetime/src/main/java/none/cvg/datetime/LenientAssert.java: -------------------------------------------------------------------------------- 1 | package none.cvg.datetime; 2 | 3 | import static org.junit.jupiter.api.Assertions.fail; 4 | 5 | public class LenientAssert { 6 | 7 | public static final String NOT_EQUAL = "The two values are not equal within the tolerance"; 8 | 9 | public static void assertAlmostEquals(long first, String second, long tolerance) { 10 | 11 | assertAlmostEquals(first, second, tolerance, NOT_EQUAL); 12 | } 13 | 14 | public static void assertAlmostEquals(long first, long second, long tolerance) { 15 | 16 | assertAlmostEquals(first, second, tolerance, NOT_EQUAL); 17 | } 18 | 19 | public static void assertAlmostEquals(long first, long second, long tolerance, String message) { 20 | 21 | if (!(Math.abs(first - second) <= tolerance)) { 22 | fail(format(message, first, second)); 23 | } 24 | } 25 | 26 | public static void assertAlmostEquals(long first, String second, long tolerance, String message) { 27 | 28 | fail(format(message, first, second)); 29 | } 30 | 31 | private static String format(String message, Object expected, Object actual) { 32 | 33 | String formatted = ""; 34 | if (message != null && !message.equals("")) { 35 | formatted = message + " "; 36 | } 37 | String expectedString = String.valueOf(expected); 38 | String actualString = String.valueOf(actual); 39 | if (expectedString.equals(actualString)) { 40 | return formatted + "expected: " 41 | + formatClassAndValue(expected, expectedString) 42 | + " but was: " + formatClassAndValue(actual, actualString); 43 | } else { 44 | return formatted + "expected:<" + expectedString + "> but was:<" 45 | + actualString + ">"; 46 | } 47 | } 48 | 49 | private static String formatClassAndValue(Object value, String valueString) { 50 | 51 | String className = value == null ? "null" : value.getClass().getName(); 52 | return className + "<" + valueString + ">"; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /.github/workflows/QualityOutreachOpenJDK.yml: -------------------------------------------------------------------------------- 1 | name: QualityOutreachOpenJDK 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | 7 | build: 8 | name: 'Java ${{ matrix.java }} on ${{ matrix.os }}' 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | os: [ ubuntu-latest ] 13 | java: [ 17, 16, 15, 14 ] 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - name: 'Check out repository' 17 | uses: actions/checkout@v2 18 | - name: 'Download JDK' 19 | id: download-jdk 20 | uses: sormuras/download-jdk@v1 21 | with: 22 | feature: ${{ matrix.java }} 23 | - name: 'Set up JDK, Version ${{ matrix.java }}' 24 | uses: actions/setup-java@v1 25 | with: 26 | java-version: ${{ steps.download-jdk.outputs.version }} 27 | jdkFile: "${{ steps.download-jdk.outputs.file }}" 28 | - name: 'Print Java version' 29 | run: java -version 30 | - name: 'Build with Maven' 31 | run: mvn --batch-mode --no-transfer-progress verify 32 | 33 | projects: 34 | name: 'Project ${{ matrix.project }} on ${{ matrix.os }}' 35 | needs: [ build ] 36 | strategy: 37 | fail-fast: false 38 | matrix: 39 | os: [ ubuntu-latest ] # , macos-latest, windows-latest ] 40 | project: [ Loom, Panama, Valhalla ] 41 | exclude: 42 | - { os: macos-latest, project: Valhalla } # missing 'libjli.dylib' 43 | runs-on: ${{ matrix.os }} 44 | steps: 45 | - name: 'Check out repository' 46 | uses: actions/checkout@v2 47 | - name: 'Download JDK' 48 | id: download-jdk 49 | uses: sormuras/download-jdk@v1 50 | with: 51 | feature: ${{ matrix.project }} 52 | - name: 'Set up JDK, Project ${{ matrix.project }}' 53 | uses: actions/setup-java@v1 54 | with: 55 | java-version: ${{ steps.download-jdk.outputs.version }} 56 | jdkFile: "${{ steps.download-jdk.outputs.file }}" 57 | - name: 'Print Java version' 58 | run: java -version 59 | - name: 'Build with Maven' 60 | run: mvn --batch-mode --no-transfer-progress verify 61 | -------------------------------------------------------------------------------- /java-lambdas/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | 9 | none.cvg.katas 10 | java-katas 11 | 1.0.1 12 | 13 | 14 | java-lambdas 15 | Code Kata : Java Lambdas 16 | http://cguntur.me 17 | 18 | 19 | 20 | 21 | org.junit.jupiter 22 | junit-jupiter 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.apache.maven.plugins 33 | maven-surefire-plugin 34 | 35 | 36 | 37 | org.codehaus.mojo 38 | build-helper-maven-plugin 39 | 40 | 41 | add-test-source 42 | generate-test-sources 43 | 44 | add-test-source 45 | 46 | 47 | 48 | src/solutions/java 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-compiler-plugin 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /java-datetime/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | 9 | none.cvg.katas 10 | java-katas 11 | 1.0.1 12 | 13 | 14 | java-datetime 15 | Code Kata : Java DateTime API 16 | http://cguntur.me 17 | 18 | 19 | 20 | 21 | org.junit.jupiter 22 | junit-jupiter 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.apache.maven.plugins 33 | maven-compiler-plugin 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-surefire-plugin 39 | 40 | 41 | 42 | org.codehaus.mojo 43 | build-helper-maven-plugin 44 | 45 | 46 | add-test-source 47 | generate-test-sources 48 | 49 | add-test-source 50 | 51 | 52 | 53 | src/solutions/java 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /java-optional/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | 9 | none.cvg.katas 10 | java-katas 11 | 1.0.1 12 | 13 | 14 | java-optional 15 | Code Kata : Java Optionals API 16 | http://cguntur.me 17 | 18 | 19 | 20 | 21 | org.junit.jupiter 22 | junit-jupiter 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.apache.maven.plugins 33 | maven-compiler-plugin 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-surefire-plugin 39 | 40 | 41 | 42 | org.codehaus.mojo 43 | build-helper-maven-plugin 44 | 45 | 46 | add-test-source 47 | generate-test-sources 48 | 49 | add-test-source 50 | 51 | 52 | 53 | src/solutions/java 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /java-futures/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | 9 | none.cvg.katas 10 | java-katas 11 | 1.0.1 12 | 13 | 14 | java-futures 15 | Code Kata : Java CompletableFuture API 16 | http://cguntur.me 17 | 18 | 19 | 20 | 21 | org.junit.jupiter 22 | junit-jupiter 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.apache.maven.plugins 33 | maven-compiler-plugin 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-surefire-plugin 39 | 40 | 41 | 42 | org.codehaus.mojo 43 | build-helper-maven-plugin 44 | 45 | 46 | add-test-source 47 | generate-test-sources 48 | 49 | add-test-source 50 | 51 | 52 | 53 | src/solutions/java 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /java-datetime/src/main/java/none/cvg/datetime/DateTimeKataDisplayNames.java: -------------------------------------------------------------------------------- 1 | package none.cvg.datetime; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.junit.jupiter.api.DisplayNameGenerator; 6 | 7 | import static java.lang.Character.isDigit; 8 | import static java.lang.Character.isLetterOrDigit; 9 | import static java.lang.Character.isUpperCase; 10 | 11 | public class DateTimeKataDisplayNames extends DisplayNameGenerator.Standard { 12 | 13 | @Override 14 | public String generateDisplayNameForClass(Class aClass) { 15 | 16 | String className = aClass.getSimpleName(); 17 | if (className.startsWith("Test")) { 18 | return camelToText(className.substring(5)); 19 | } 20 | if (className.startsWith("STest")) { 21 | return camelToText(className.substring(6)); 22 | } 23 | return className; 24 | } 25 | 26 | @Override 27 | public String generateDisplayNameForNestedClass(Class aClass) { 28 | 29 | return super.generateDisplayNameForNestedClass(aClass); 30 | } 31 | 32 | @Override 33 | public String generateDisplayNameForMethod(Class aClass, Method method) { 34 | 35 | String methodName = method.getName(); 36 | return camelToText(methodName); 37 | } 38 | 39 | 40 | private static String camelToText(String text) { 41 | 42 | StringBuilder builder = new StringBuilder(); 43 | char lastChar = ' '; 44 | for (char c : text.toCharArray()) { 45 | char nc = c; 46 | 47 | if (isUpperCase(nc) && !isUpperCase(lastChar)) { 48 | if (lastChar != ' ' && isLetterOrDigit(lastChar)) { 49 | builder.append(" "); 50 | } 51 | nc = Character.toLowerCase(c); 52 | } else if (isDigit(lastChar) && !isDigit(c)) { 53 | if (lastChar != ' ') { 54 | builder.append(" "); 55 | } 56 | nc = Character.toLowerCase(c); 57 | } 58 | 59 | if (lastChar != ' ' || c != ' ') { 60 | builder.append(nc); 61 | } 62 | lastChar = c; 63 | } 64 | return builder.toString(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /java-handles/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | 9 | none.cvg.katas 10 | java-katas 11 | 1.0.1 12 | 13 | 14 | java-handles 15 | Code Kata : Java Handles API 16 | Code Kata : Java Reflection (since Java 7) and sun.misc.Unsafe (since Java 9) alternates 17 | http://cguntur.me 18 | 19 | 20 | 21 | 22 | org.junit.jupiter 23 | junit-jupiter 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-compiler-plugin 35 | 36 | 37 | 38 | org.apache.maven.plugins 39 | maven-surefire-plugin 40 | 41 | 42 | 43 | org.codehaus.mojo 44 | build-helper-maven-plugin 45 | 46 | 47 | add-test-source 48 | generate-test-sources 49 | 50 | add-test-source 51 | 52 | 53 | 54 | src/solutions/java 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /java-handles/src/main/java/none/cvg/handles/DemoClass.java: -------------------------------------------------------------------------------- 1 | package none.cvg.handles; 2 | 3 | public class DemoClass { 4 | 5 | private String name; 6 | 7 | public DemoClass() { 8 | this.name = "No param DemoClass constructor"; 9 | } 10 | 11 | public DemoClass(String name) { 12 | this.name = name; 13 | } 14 | 15 | /** 16 | * Public static method with a parameter 17 | * 18 | * @param input - String that will be embedded in the returned content 19 | * @return - A String as a successful execution of the method. 20 | */ 21 | public static String publicStaticMethod(String input) { 22 | return "DemoClass.class - Public static method " + input; 23 | } 24 | 25 | public String printStuff(String input) { 26 | return "[" + this.name + "] - " + input; 27 | } 28 | 29 | /** 30 | * Public method with a parameter 31 | * 32 | * @param input - String that will be embedded in the returned content 33 | * @return - A String as a successful execution of the method. 34 | */ 35 | public String publicMethod(String input) { 36 | return "[" + this.getClass().getSimpleName() + "] - Public method - " + input; 37 | } 38 | 39 | /** 40 | * Private method with a parameter 41 | * 42 | * @param input - String that will be embedded in the returned content 43 | * @return - A String as a successful execution of the method. 44 | */ 45 | private String privateMethod(String input) { 46 | return "[" + this.getClass().getSimpleName() + "] - Private method " + input; 47 | } 48 | 49 | /** 50 | * Protected method with a parameter 51 | * 52 | * @param input - String that will be embedded in the returned content 53 | * @return - A String as a successful execution of the method. 54 | */ 55 | protected String protectedMethod(String input) { 56 | return "[" + this.getClass().getSimpleName() + "] - Protected method " + input; 57 | } 58 | 59 | /** 60 | * Default (package-protected) method with a parameter 61 | * 62 | * @param input - String that will be embedded in the returned content 63 | * @return - A String as a successful execution of the method. 64 | */ 65 | String packageProtectedMethod(String input) { 66 | return "[" + this.getClass().getSimpleName() + "] - Package protected method " + input; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /java-handles/src/main/java/none/cvg/handles/HandlesKataDisplayNames.java: -------------------------------------------------------------------------------- 1 | package none.cvg.handles; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.junit.jupiter.api.DisplayNameGenerator; 6 | 7 | import static java.lang.Character.isDigit; 8 | import static java.lang.Character.isLetterOrDigit; 9 | import static java.lang.Character.isUpperCase; 10 | 11 | public class HandlesKataDisplayNames extends DisplayNameGenerator.Standard { 12 | @Override 13 | public String generateDisplayNameForClass(Class aClass) { 14 | return super.generateDisplayNameForClass(aClass); 15 | } 16 | 17 | @Override 18 | public String generateDisplayNameForNestedClass(Class aClass) { 19 | return super.generateDisplayNameForNestedClass(aClass); 20 | } 21 | 22 | @Override 23 | public String generateDisplayNameForMethod(Class aClass, Method method) { 24 | String methodName = method.getName(); 25 | if (methodName.startsWith("reflection")) { 26 | return "using Reflection"; 27 | } 28 | if (methodName.startsWith("unsafe")) { 29 | return "using Unsafe"; 30 | } 31 | if (methodName.startsWith("methodHandle")) { 32 | return "using Method Handles"; 33 | } 34 | if (methodName.startsWith("compareAndSet")) { 35 | return camelToText(methodName.substring(13)); 36 | } 37 | if (methodName.startsWith("get")) { 38 | return camelToText(methodName.substring(3)); 39 | } 40 | return camelToText(methodName); 41 | } 42 | 43 | 44 | private static String camelToText(String text) { 45 | StringBuilder builder = new StringBuilder(); 46 | char lastChar = ' '; 47 | for (char c : text.toCharArray()) { 48 | char nc = c; 49 | 50 | if (isUpperCase(nc) && !isUpperCase(lastChar)) { 51 | if (lastChar != ' ' && isLetterOrDigit(lastChar)) { 52 | builder.append(" "); 53 | } 54 | nc = Character.toLowerCase(c); 55 | } else if (isDigit(lastChar) && !isDigit(c)) { 56 | if (lastChar != ' ') { 57 | builder.append(" "); 58 | } 59 | nc = Character.toLowerCase(c); 60 | } 61 | 62 | if (lastChar != ' ' || c != ' ') { 63 | builder.append(nc); 64 | } 65 | lastChar = c; 66 | } 67 | return builder.toString(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /java-futures/assets/docs/CompletionStage.adoc: -------------------------------------------------------------------------------- 1 | = CompletionStage 2 | :toc: 3 | 4 | == What is CompletionStage 5 | 6 | Introduced in Java 8 (2014). 7 | 8 | A link:https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/concurrent/CompletionStage.html[`java.util.concurrent.CompletionState`] interface represents an asynchronous or synchronous computation task. 9 | 10 | This task performs an action or computes a value when another CompletionStage completes. 11 | 12 | There are a few classifications that are identifiable via patterns in the method's name. 13 | 14 | == Classifications 15 | 16 | === Core methods 17 | 18 | Types of computation determined by method name pattern 19 | 20 | .Core Methods 21 | [width="99%", options="header"] 22 | |=== 23 | |Pattern in method name |Description 24 | 25 | |`*apply/Apply*`|https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/function/Function.html[Function] computation on result or value of the CompletionStage 26 | |`*accept/Accept*`|https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/function/Consumer.html[Consumer] computation on result or value of the CompletionStage 27 | |`*run/Run*`|https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Runnable.html[Runnable] computation 28 | |=== 29 | 30 | === Action methods 31 | 32 | Actions performed determined by method name pattern 33 | 34 | .Action methods 35 | [width="99%", options="header"] 36 | |=== 37 | |Pattern in method name |Description 38 | 39 | |`*Compose*`|Similar to apply, returns a new CompletionStage after the completion of the current one, thus allowing pipelines 40 | |`*Combine*`|Combine results of two completion stages into a BiFunction and returns a new CompletionStage 41 | |`*exceptionally*`|handle any exception via a Function that returns a CompletedStage, successful completion is returned as the value of CompletionStage 42 | |`*whenComplete*`|handle either successful result or exception passed as a BiConsumer and returns a new CompletionStage 43 | |`*handle*`|handle either successful result or exception passed as a BiFunction and returns a new CompletionStage 44 | |=== 45 | 46 | === Synchronicity 47 | 48 | Synchronicity of the stage is either Sync or Async 49 | 50 | .Synchronicity 51 | [width="99%", options="header"] 52 | |=== 53 | |Pattern in method name |Description 54 | 55 | |**|synchronous 56 | |`*Async*`|asynchronous 57 | |=== 58 | 59 | === Post Execution 60 | 61 | Actions to perform post-execution 62 | 63 | .Post Execution 64 | [width="99%", options="header"] 65 | |=== 66 | |Pattern in method name |Description 67 | 68 | |`*then*`|a single stage 69 | |`*Both*`|both of two stages 70 | |`*Either*`|either of two stages 71 | |=== 72 | 73 | 74 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | none.cvg.katas 9 | java-katas 10 | 1.0.1 11 | pom 12 | 13 | Aggregator POM for Java Katas 14 | http://cguntur.me 15 | 16 | 17 | 18 | java-datetime 19 | java-handles 20 | java-optional 21 | java-lambdas 22 | java-futures 23 | 24 | 25 | 26 | 27 | UTF-8 28 | 29 | 14 30 | 14 31 | 32 | 5.5.0 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | org.junit.jupiter 41 | junit-jupiter 42 | ${junit5.version} 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-compiler-plugin 58 | 3.8.1 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-surefire-plugin 64 | 2.22.2 65 | 66 | PASSING 67 | TODO 68 | 69 | 70 | 71 | 72 | org.codehaus.mojo 73 | build-helper-maven-plugin 74 | 3.0.0 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = java-katas 2 | 3 | image::https://github.com/c-guntur/java-katas/actions/workflows/ci.yml/badge.svg[link="https://github.com/c-guntur/java-katas/actions/workflows/ci.yml"] 4 | image:https://img.shields.io/badge/License-MIT-lightsalmon.svg[link="LICENSE"] 5 | image:https://img.shields.io/badge/CodeKata-Java-blue.svg[link="https://github.com/topics/codekata"] 6 | 7 | 8 | image:JavaKatas.png[Java Katas] 9 | 10 | One repo to rule them all. Java code katas - using JUnit5 11 | 12 | The java-katas is a code repository for learning various Java features. 13 | 14 | == What is a kata (a code kata) ? 15 | 16 | From http://wikipedia: Kata originally were teaching and training methods by which successful combat techniques were preserved and passed on. Practicing kata allowed a company of persons to engage in a struggle, using a systematic approaches, rather by practicing in a repetitive manner the learner develops the ability to execute those techniques and movements in a natural, reflex-like manner. Systematic practice does not mean permanently rigid. The goal is to internalize the movements and techniques of a kata; so they can be executed and adapted under different circumstances, without thought or hesitation. A novice’s actions will look uneven and difficult, while a master’s appear simple and smooth. 17 | 18 | === What is a code kata? 19 | 20 | From http://codekata.com: Code Kata is an attempt to bring the element of practice to software development. A kata is an exercise in karate where you repeat a form many, many times, making little improvements in each. The intent behind code kata is similar. Each is a short exercise (perhaps 30 minutes to an hour long). Some involve programming, and can be coded in many ways. Some are open-ended, and involve thinking about the issues behind programming. These are unlikely to have a single correct answer. 21 | 22 | Code katas were first introduced by Dave Thomas and are a great tool to practice programming something new. 23 | 24 | == So, what is in this repo? 25 | 26 | This Git repo is a collection of several code katas about features, utilities and APIs in Java language. 27 | 28 | The general structure of each project is a maven quickstart project with a pom.xml, a src directory that contains at least two directories. Code Katas are available under the src/test/java while solutions are under src/solutions/java under each module. The code katas typically contain failing tests with TODO markers that need to be fixed in order to fix the test, 29 | 30 | **Remember, the src/solutions may not be the perfect way to solve the kata, maybe a solution you come up with is better**. Feel free to submit a pull request if you think you have a better solution than the one you find. 31 | 32 | === Current katas 33 | 34 | `java-handles`:: Understand Java Reflection and `sun.misc.Unsafe`, then, learn the alternates for those in Method Handles API and VarHandles API in more recent version of Java. 35 | 36 | `java-datetime`:: Learn the Java Time API (introduced in Java 8), that replaces the java.util.Date and java.util.Calendar with a more humane and extensible API. 37 | 38 | `java-optional`:: Learn the Java Optional API, as a replacement for null-checks and unexpected ``NullPointerException``s that crop up causing developer unhappiness and/or application instability issues. 39 | 40 | `java-lambdas`:: Learn Java Lambdas, a feature that allows for closure-like syntax, and the ability to replace anonymous classes with functional blocks. 41 | 42 | `java-futures`:: Learn Java CompletableFuture API, an API that allows for synchronous as well as asynchronous tasks with pipelines and task chaining/combinations with many ways to handle exceptions, with and without recovery paths. 43 | 44 | More katas will be added, feel free to contribute if you have ideas. 45 | -------------------------------------------------------------------------------- /java-lambdas/README.adoc: -------------------------------------------------------------------------------- 1 | = Java Lambdas - A Code kata 2 | :toc: 3 | :toclevels: 4 4 | 5 | image:assets/images/DukeLambda.png[Java Duke Lambda Logo] 6 | 7 | Java lambdas are anonymous functions that make code much moe concise and simpler. 8 | 9 | == What is a Code-Kata 10 | 11 | A code-kata is a coding exercise that builds muscle memory by a practice of programming to arrive 12 | at a known solution. 13 | 14 | === How does one go about with this code kata? 15 | 16 | The essence of the exercise (presentation material and code kata) is to demonstrate the 17 | usage patterns for the java API or functionality. 18 | 19 | This set of code katas rely on fixing broken tests. The tests may have multiple solutions, the 20 | intent is to learn and experiment. 21 | 22 | The project contains several JUnit tests that fail. 23 | 24 | ==== Simple steps to use this kata 25 | 26 | . Run the test class(es). 27 | . One or more tests will fail with the test failure message. 28 | . Fix the failing tests by using `HINT` and `TODO` comments. 29 | . Repeat above steps until all tests pass. 30 | . Check the solutions to see if there are other ways to solve. 31 | (Remember, the solution may be less performant/optimal than yours) 32 | . Rinse and repeat (delete and checkout again, then back to Step 1) to build muscle memory. 33 | 34 | === Mission 35 | > Your mission, should you choose to accept it, will be to fix the JUnit tests. This 36 | message will self-destruct in `**NaN**` minutes. 37 | 38 | == Requirements 39 | How to prepare for coding along 40 | 41 | This kata is developed as a Java maven project.Ensure that you have: 42 | 43 | . Apache Maven 3.6.x or above. _Tested with Apache Maven 3.6.3_. 44 | Link: https://maven.apache.org/download.cgi 45 | 46 | . JDK 11 or above. _Tested with OpenJDK 11_ 47 | Link: http://jdk.java.net/11/ 48 | 49 | . Your favorite Java IDE. _IntelliJ IDEA Ultimate was used to develop this kata_. 50 | 51 | == Project Structure 52 | 53 | The structure of the project: 54 | 55 | [source] 56 | ---- 57 | |____pom.xml 58 | |____README.md 59 | | 60 | |____src 61 | | | 62 | | |____test <------------------- Kata Tests 63 | | | |____java 64 | | | |____none 65 | | | |____cvg 66 | | | |____lambdas 67 | | | 68 | | |____main <------------------- Shared ErrorMessages & DemoClass 69 | | | |____java 70 | | | |____none 71 | | | |____cvg 72 | | | |____lambdas 73 | | | 74 | | |____solutions <------------------- Solutions 75 | | | |____java 76 | | | |____none 77 | | | |____cvg 78 | | | |____lambdas 79 | ---- 80 | 81 | == Tests Included 82 | 83 | === Java Lambda 84 | 85 | The JUnit tests listed below are setup to teach/learn the Java Lambda features. 86 | 87 | link:src/test/java/none/cvg/lambdas/TestKata1LambdaBasics.java[TestKata1LambdaBasics.java]:: show the basic features of lambdas in Java. 88 | 89 | link:src/test/java/none/cvg/lambdas/TestKata2LambdasDeeperDive.java[TestKata2LambdasDeeperDive.java]:: explore deeper into Java Lambda usages. 90 | 91 | 92 | == Solutions 93 | 94 | .Solutions for each test: 95 | 96 | |=== 97 | | Kata Test | Solution 98 | 99 | |link:src/test/java/none/cvg/lambdas/TestKata1LambdaBasics.java[TestKata1LambdaBasics.java] 100 | |link:src/solutions/java/none/cvg/lambdas/TestSolution1LambdaBasics.java[TestSolution1LambdaBasics.java] 101 | 102 | |link:src/test/java/none/cvg/lambdas/TestKata2LambdasDeeperDive.java[TestKata2LambdasDeeperDive.java] 103 | |link:src/solutions/java/none/cvg/lambdas/TestSolution2LambdasDeeperDive.java[TestSolution2LambdasDeeperDive.java] 104 | |=== 105 | 106 | == Take Away 107 | 108 | The key take-away from this kata is a solid understanding of the Java Lambdas. 109 | -------------------------------------------------------------------------------- /java-futures/assets/docs/CompletableFuture.adoc: -------------------------------------------------------------------------------- 1 | = CompletableFuture 2 | :toc: 3 | 4 | == What is a CompletableFuture 5 | 6 | Introduced in Java 8 (2014). 7 | 8 | A link:https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/concurrent/CompletableFuture.html[`java.util.concurrent.CompletableFuture`] is a complete implementation of *both* `Future` and `CompletionStage`. 9 | 10 | CompletableFuture provides static methods as means to execute the tasks. 11 | 12 | CompletableFuture allows for chaining and combining outcomes from multiple other CompletableFutures. 13 | 14 | == Classifications 15 | 16 | .Operations return type 17 | [width="99%", options="header"] 18 | |=== 19 | |Pattern in method name |Description 20 | 21 | |`*run/Run*`|Perform a task without a return value, using a https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Runnable.html[Runnable]. 22 | |`*supply/Supply*`|Perform a task that returns a value, using a https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/function/Supplier.html[Supplier]. 23 | |=== 24 | 25 | === Synchronicity 26 | 27 | Synchronicity is either Sync or Async 28 | 29 | .Synchronicity 30 | [width="99%", options="header"] 31 | |=== 32 | |Pattern in method name |Description 33 | 34 | |**| *_synchronous_*, performed by the thread running the CompletableFuture. 35 | |`*Async*`| *_asynchronous_*, performed by default by the ForkJoinPool.commonPool unless an executor is provided. 36 | |=== 37 | 38 | === Results 39 | 40 | There are two methods to retrieve the results. 41 | 42 | Both *_wait for the CompletableFuture to complete_*, then return the result if successful. 43 | 44 | Unsuccessful outcomes are due to cancellation, exceptional outcomes and interruptions. 45 | 46 | .Results 47 | [width="99%", options="header"] 48 | |=== 49 | |Method name |Description 50 | 51 | |`*get*`|Return the result. Throws *_checked exceptions_* when unsuccessful. 52 | |`*join*`|Return the result. Throws *_unchecked runtime exceptions_* when unsuccessful. 53 | |=== 54 | 55 | === Multiple CompletableFutures 56 | 57 | .Chaining and Combining 58 | [width="99%", options="header"] 59 | |=== 60 | |Pattern in method name |Description 61 | 62 | 2+| Chaining 63 | |`*thenCompose**`| Chain two CompletableFuture, the second executed *_after_* the first using the result of the first as a value in a Function, *_returning a CompletableFuture_*. 64 | |`*thenCombine**`| Chain two CompletableFuture, *_when both are completed_* using the result of both as values in a BiFunction, *_returning a CompletableFuture_*. 65 | 2+| Combining All 66 | |`*thenAcceptBoth**`| Chain two CompletableFuture, *_when both are completed_* using the result of both as values in a BiConsumer, *_returning a value_*. 67 | |`*runAfterBoth**`| Chain two CompletableFuture, *_when both are completed_* run a Runnable, *_returning a CompletableFuture_*. 68 | |`*allOf*`| Await the completion of *_all of_* a list of CompletableFuture instances, *_returning a CompletableFuture_*. 69 | 2+| Combining Either 70 | |`*applyToEither**`| Accept the completion of the current or other CompletableFuture using the value in a Function, *_returning a CompletableFuture_*. 71 | |`*acceptEither**`| Accept the completion of the current or other CompletableFuture using the value in a Consumer, *_returning a CompletableFuture_*. 72 | |`*runAfterEither**`| Accept the completion of the current or other CompletableFuture, then run a Runnable, *_returning a CompletableFuture_*. 73 | |`*anyOf*`| Await the completion of *_any one of_* a list of CompletableFuture instances, *_returning a CompletableFuture_*. 74 | |=== 75 | 76 | == Understanding Pipelines in CompletableFuture 77 | 78 | CompletionFuture has Stages. 79 | 80 | Each Stage may produce an output or signal when completed successfully. 81 | Any stage can fail, leading to an exception. The exception can be handled. 82 | A handling of an exception may cause the pipeline to be repaired or may be fatal enough to fail. 83 | 84 | [source] 85 | ---- 86 | /----S--o--S--o--S--------------S--o--S--o----SUCCESS 87 | / \ / 88 | CompletableFuture | | 89 | \ \ / 90 | \-------------------E--h--E--h--E--h----------FAILURE 91 | ---- -------------------------------------------------------------------------------- /java-handles/src/test/java/none/cvg/methods/TestKataPublicMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.methods; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.invoke.MethodType; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | import none.cvg.handles.DemoClass; 10 | import none.cvg.handles.HandlesKataDisplayNames; 11 | import org.junit.jupiter.api.DisplayName; 12 | import org.junit.jupiter.api.DisplayNameGeneration; 13 | import org.junit.jupiter.api.MethodOrderer; 14 | import org.junit.jupiter.api.Order; 15 | import org.junit.jupiter.api.Tag; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.TestMethodOrder; 18 | 19 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 20 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.junit.jupiter.api.Assertions.fail; 23 | 24 | /* 25 | * TODO: 26 | * This test aims at using MethodHandles to invoke a public method on a class. 27 | * Each solved test shows how this can be achieved with the traditional reflection calls. 28 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 29 | * the exercise to achieve the same goal with MethodHandles. 30 | */ 31 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 32 | @DisplayName("Invoke DemoClass.publicMethod(String)") 33 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 34 | public class TestKataPublicMethodInvocation { 35 | 36 | @Test 37 | @Tag("PASSING") 38 | @Order(1) 39 | public void reflectionPublicMethod() { 40 | 41 | String expectedOutput = "[DemoClass] - Public method - via reflection"; 42 | 43 | try { 44 | 45 | // Find the method on the class via a getMethod. 46 | Method publicMethod = 47 | DemoClass.class.getMethod("publicMethod", 48 | String.class); 49 | 50 | DemoClass demoClass = new DemoClass(); 51 | 52 | assertEquals(expectedOutput, 53 | publicMethod.invoke(demoClass, "via reflection"), 54 | "Reflection invocation failed"); 55 | 56 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 57 | 58 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 59 | } 60 | } 61 | 62 | @Test 63 | @Tag("TODO") 64 | @Order(2) 65 | public void methodHandlePublicMethod() { 66 | 67 | String expectedOutput = "[DemoClass] - Public method - via Method Handles"; 68 | 69 | /* 70 | * TODO: 71 | * Get a public lookup from java.lang.invoke.MethodHandles 72 | * Public parts of a class are looked up via "public lookups" 73 | * Check API: java.lang.invoke.MethodHandles.publicLookup() 74 | */ 75 | MethodHandles.Lookup publicMethodHandlesLookup = null; 76 | 77 | /* 78 | * TODO: 79 | * Replace the "null"s with valid values to extract a method signature for publicMethod. 80 | * Create a methodType instance that matches the signature of what we wish to invoke 81 | * HINT: The publicMethod() returns a String and accepts a String parameter 82 | * Check API: java.lang.invoke.MethodType.methodType(?, ?) 83 | */ 84 | MethodType methodType = null; // HINT: MethodType.methodType(?, ?); 85 | 86 | try { 87 | 88 | /* 89 | * TODO: 90 | * Replace the "null"s with appropriate values to get a handle to publicMethod. 91 | * "Find" a method of the class via the Lookup instance, 92 | * based on the methodType described above and the method name. 93 | * Public methods can be searched via the findVirtual() method. 94 | * Check API: java.lang.invoke.MethodHandles.Lookup.findVirtual(?, ?, ?) 95 | */ 96 | MethodHandle publicMethodHandle = 97 | publicMethodHandlesLookup.findVirtual(null, 98 | null, null); // Class, Method name, MethodType 99 | 100 | DemoClass demoClass = new DemoClass(); 101 | 102 | assertEquals(expectedOutput, 103 | publicMethodHandle.invoke(demoClass, 104 | "via Method Handles"), 105 | "Method handles invocation failed"); 106 | 107 | } catch (NoSuchMethodException | IllegalAccessException e) { 108 | 109 | fail("Failed to execute a public method invocation via Method Handles: " 110 | + e.getMessage()); 111 | } catch (Throwable t) { 112 | 113 | // invoke throws a Throwable (hence catching Throwable separately). 114 | fail(TEST_FAILURE.getValue() + t.getMessage()); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /java-handles/src/solutions/java/none/cvg/methods/TestSolutionPublicMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.methods; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.invoke.MethodType; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | import none.cvg.handles.DemoClass; 10 | import none.cvg.handles.HandlesKataDisplayNames; 11 | import org.junit.jupiter.api.DisplayName; 12 | import org.junit.jupiter.api.DisplayNameGeneration; 13 | import org.junit.jupiter.api.MethodOrderer; 14 | import org.junit.jupiter.api.Order; 15 | import org.junit.jupiter.api.Tag; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.TestMethodOrder; 18 | 19 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 20 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.junit.jupiter.api.Assertions.fail; 23 | 24 | /* 25 | * DONE: 26 | * This test aims at using MethodHandles to invoke a public method on a class. 27 | * Each solved test shows how this can be achieved with the traditional reflection calls. 28 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 29 | * the exercise to achieve the same goal with MethodHandles. 30 | */ 31 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 32 | @DisplayName("Invoke DemoClass.publicMethod(String)") 33 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 34 | public class TestSolutionPublicMethodInvocation { 35 | 36 | @Test 37 | @Tag("PASSING") 38 | @Order(1) 39 | public void reflectionPublicMethod() { 40 | 41 | String expectedOutput = "[DemoClass] - Public method - via reflection"; 42 | 43 | try { 44 | 45 | // Find the method on the class via a getMethod. 46 | Method publicMethod = 47 | DemoClass.class.getMethod("publicMethod", 48 | String.class); 49 | 50 | DemoClass demoClass = new DemoClass(); 51 | 52 | assertEquals(expectedOutput, 53 | publicMethod.invoke(demoClass, "via reflection"), 54 | "Reflection invocation failed"); 55 | 56 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 57 | 58 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 59 | } 60 | } 61 | 62 | @Test 63 | @Tag("PASSING") 64 | @Order(2) 65 | public void methodHandlePublicMethod() { 66 | 67 | String expectedOutput = "[DemoClass] - Public method - via Method Handles"; 68 | 69 | /* 70 | * DONE: 71 | * Get a public lookup from java.lang.invoke.MethodHandles 72 | * Public parts of a class are looked up via "public lookups" 73 | * Check API: java.lang.invoke.MethodHandles.publicLookup() 74 | */ 75 | MethodHandles.Lookup publicMethodHandlesLookup = MethodHandles.publicLookup(); 76 | 77 | /* 78 | * DONE: 79 | * Replace the "null"s with valid values to extract a method signature for publicMethod. 80 | * Create a methodType instance that matches the signature of what we wish to invoke 81 | * HINT: The publicMethod() returns a String and accepts a String parameter 82 | * Check API: java.lang.invoke.MethodType.methodType(?, ?) 83 | */ 84 | MethodType methodType = MethodType.methodType(String.class, String.class); 85 | 86 | try { 87 | 88 | /* 89 | * DONE: 90 | * Replace the "null"s with appropriate values to get a handle to publicMethod. 91 | * "Find" a method of the class via the Lookup instance, 92 | * based on the methodType described above and the method name. 93 | * Public methods can be searched via the findVirtual() method. 94 | * Check API: java.lang.invoke.MethodHandles.Lookup.findVirtual(?, ?, ?) 95 | */ 96 | MethodHandle publicMethodHandle = 97 | publicMethodHandlesLookup.findVirtual(DemoClass.class, 98 | "publicMethod", methodType); // Class, Method name, MethodType 99 | 100 | DemoClass demoClass = new DemoClass(); 101 | 102 | assertEquals(expectedOutput, 103 | publicMethodHandle.invoke(demoClass, 104 | "via Method Handles"), 105 | "Method handles invocation failed"); 106 | 107 | } catch (NoSuchMethodException | IllegalAccessException e) { 108 | 109 | fail("Failed to execute a public method invocation via Method Handles: " 110 | + e.getMessage()); 111 | } catch (Throwable t) { 112 | 113 | // invoke throws a Throwable (hence catching Throwable separately). 114 | fail(TEST_FAILURE.getValue() + t.getMessage()); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /java-datetime/src/test/java/none/cvg/datetime/TestKata5DateTimePartials.java: -------------------------------------------------------------------------------- 1 | package none.cvg.datetime; 2 | 3 | import java.time.Clock; 4 | import java.time.DayOfWeek; 5 | import java.time.Instant; 6 | import java.time.LocalDateTime; 7 | import java.time.Month; 8 | import java.time.MonthDay; 9 | import java.time.Year; 10 | import java.time.YearMonth; 11 | import java.time.ZoneId; 12 | 13 | import org.junit.jupiter.api.BeforeEach; 14 | import org.junit.jupiter.api.DisplayName; 15 | import org.junit.jupiter.api.DisplayNameGeneration; 16 | import org.junit.jupiter.api.MethodOrderer; 17 | import org.junit.jupiter.api.Order; 18 | import org.junit.jupiter.api.Tag; 19 | import org.junit.jupiter.api.Test; 20 | import org.junit.jupiter.api.TestMethodOrder; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | /** 25 | * DateTime partials: Month, MonthDay, Year, YearMonth and DayOfWeek tests. 26 | *

27 | * Note: We create a Clock instance in setup() used for some of the tests. 28 | * 29 | * @see Clock 30 | * @see Month 31 | * @see MonthDay 32 | * @see Year 33 | * @see YearMonth 34 | * @see DayOfWeek 35 | */ 36 | @DisplayNameGeneration(DateTimeKataDisplayNames.class) 37 | @DisplayName("Date and Time partials such as credit card expiration") 38 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 39 | public class TestKata5DateTimePartials { 40 | 41 | private Clock terminatorOriginalJudgementDay = null; 42 | 43 | @BeforeEach 44 | public void setup() { 45 | 46 | Instant instant = Instant.parse("1997-08-29T06:14:30Z"); 47 | // We make an assumption for GMT -4 as the timezone for users of this test. 48 | terminatorOriginalJudgementDay = Clock.fixed(instant, ZoneId.of("GMT-4")); 49 | } 50 | 51 | @Test 52 | @Tag("TODO") 53 | @Order(1) 54 | public void verifyMonth() { 55 | 56 | LocalDateTime tOJDateTime = LocalDateTime.now(terminatorOriginalJudgementDay); 57 | 58 | // TODO: Replace the "Month.JANUARY" below get a Month instance. 59 | // Check: java.time.LocalDateTime.getMonth() 60 | Month tOJMonth = Month.JANUARY; 61 | 62 | assertEquals(Month.AUGUST, 63 | tOJMonth, 64 | "The Month enumeration should match August."); 65 | } 66 | 67 | @Test 68 | @Tag("TODO") 69 | @Order(2) 70 | public void verifyMonthDay() { 71 | 72 | // Real world: Birthday or anniversary 73 | 74 | // TODO: Replace the MonthDay.now() below get a MonthDay anniversary for the Judgement Day. 75 | // Check: java.time.MonthDay.now(java.time.Clock) 76 | MonthDay anniversaryofJudgementDay = MonthDay.now(); 77 | 78 | assertEquals(Month.AUGUST, 79 | anniversaryofJudgementDay.getMonth(), 80 | "The month enumeration should match August."); 81 | 82 | assertEquals(8, 83 | anniversaryofJudgementDay.getMonthValue(), 84 | "The month value should match 8."); 85 | 86 | assertEquals(29, 87 | anniversaryofJudgementDay.getDayOfMonth(), 88 | "The date value should match 29."); 89 | } 90 | 91 | @Test 92 | @Tag("TODO") 93 | @Order(3) 94 | public void verifyYear() { 95 | 96 | // Real world: Age or Year of occurrence. 97 | 98 | // TODO: Replace the Year.now() below get a Year for the Judgement Day. 99 | // Check: java.time.Year.now(java.time.Clock) 100 | Year yearOfJudgementDay = Year.now(); 101 | 102 | assertEquals(1997, 103 | yearOfJudgementDay.getValue(), 104 | "The year value should match 1997."); 105 | } 106 | 107 | @Test 108 | @Tag("TODO") 109 | @Order(4) 110 | public void verifyYearMonth() { 111 | 112 | // Real world: CreditCard or Medicine expiration. 113 | 114 | // TODO: Replace the YearMonth.now() below get a YearMonth for the Judgement Day. 115 | // Check: java.time.YearMonth.now(java.time.Clock) 116 | YearMonth yearMonthOfJudgementDay = YearMonth.now(); 117 | 118 | assertEquals(Month.AUGUST, 119 | yearMonthOfJudgementDay.getMonth(), 120 | "The month enumeration should match August."); 121 | 122 | assertEquals(8, 123 | yearMonthOfJudgementDay.getMonthValue(), 124 | "The month value should match 8."); 125 | 126 | assertEquals(1997, 127 | yearMonthOfJudgementDay.getYear(), 128 | "The year value should match 1997."); 129 | } 130 | 131 | @Test 132 | @Tag("TODO") 133 | @Order(5) 134 | public void verifyDayOfWeek() { 135 | 136 | LocalDateTime tOJDateTime = LocalDateTime.now(terminatorOriginalJudgementDay); 137 | 138 | // TODO: Replace the null below to get the Day Of Week from the tOJDateTime. 139 | // Check: java.time.LocalDateTime.getDayOfWeek() 140 | DayOfWeek dayOfWeek = null; 141 | 142 | assertEquals(DayOfWeek.FRIDAY, 143 | dayOfWeek, 144 | "The day of the week enumeration should match Friday."); 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /java-handles/src/test/java/none/cvg/methods/TestKataPublicStaticMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.methods; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.invoke.MethodType; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | import none.cvg.handles.DemoClass; 10 | import none.cvg.handles.HandlesKataDisplayNames; 11 | import org.junit.jupiter.api.DisplayName; 12 | import org.junit.jupiter.api.DisplayNameGeneration; 13 | import org.junit.jupiter.api.MethodOrderer; 14 | import org.junit.jupiter.api.Order; 15 | import org.junit.jupiter.api.Tag; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.TestMethodOrder; 18 | 19 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 20 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.junit.jupiter.api.Assertions.fail; 23 | 24 | /* 25 | * TODO: 26 | * This test aims at using MethodHandles to invoke a public static method on a class. 27 | * Each solved test shows how this can be achieved with the traditional reflection calls. 28 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 29 | * the exercise to achieve the same goal with MethodHandles. 30 | */ 31 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 32 | @DisplayName("Invoke DemoClass.publicStaticMethod(String)") 33 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 34 | public class TestKataPublicStaticMethodInvocation { 35 | 36 | @Test 37 | @Tag("PASSING") 38 | @Order(1) 39 | public void reflectionPublicStaticMethod() { 40 | 41 | String expectedOutput = "DemoClass.class - Public static method via reflection"; 42 | 43 | try { 44 | 45 | // Find the method on the class via a getMethod. 46 | Method publicStaticMethod = 47 | DemoClass.class.getMethod("publicStaticMethod", 48 | String.class); 49 | 50 | assertEquals(expectedOutput, 51 | publicStaticMethod.invoke(DemoClass.class, "via reflection"), 52 | "Reflection invocation failed"); 53 | 54 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 55 | 56 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 57 | } 58 | } 59 | 60 | @Test 61 | @Tag("TODO") 62 | @Order(2) 63 | public void methodHandlePublicStaticMethod() { 64 | 65 | String expectedOutput = "DemoClass.class - Public static method via Method Handles"; 66 | 67 | /* 68 | * TODO: 69 | * Get a public lookup from java.lang.invoke.MethodHandles 70 | * Public parts of a class are looked up via "public lookups" 71 | * Check API: java.lang.invoke.MethodHandles.publicLookup() 72 | */ 73 | MethodHandles.Lookup publicStaticMethodHandlesLookup = null; 74 | 75 | /* 76 | * TODO: 77 | * Replace the "null"s with valid values to get a signature for a publicStaticMethod. 78 | * Create a methodType instance that matches the signature of what we wish to invoke 79 | * The publicMethod() returns a String and accepts a String parameter 80 | * Check API: java.lang.invoke.MethodType.methodType(?, ?) 81 | */ 82 | MethodType methodType = null; // HINT: MethodType.methodType(null, null); 83 | 84 | try { 85 | 86 | /* 87 | * TODO: 88 | * Replace the "null"s with valid values to get a handle to publicStaticMethod. 89 | * "Find" a method of the class via the Lookup instance, 90 | * based on the methodType described above and the method name. 91 | * Public static methods can be searched via the findStatic() method. 92 | * Check API: java.lang.invoke.MethodHandles.Lookup.findStatic(?, ?, ?) 93 | */ 94 | MethodHandle publicStaticMethodHandle = 95 | publicStaticMethodHandlesLookup.findStatic(null, 96 | null, null); // Class, Method name, Method type 97 | 98 | /* 99 | * ATTENTION: The invoke() method does not take an instance of demoClass as its 100 | * first parameter for static method invocation. 101 | */ 102 | assertEquals(expectedOutput, 103 | publicStaticMethodHandle.invoke( 104 | "via Method Handles"), 105 | "Method handles invocation failed"); 106 | 107 | } catch (NoSuchMethodException | IllegalAccessException e) { 108 | 109 | fail("Failed to execute a public static method invocation via Method Handles: " 110 | + e.getMessage()); 111 | } catch (Throwable t) { 112 | 113 | // invoke throws a Throwable (hence catching Throwable separately). 114 | fail(TEST_FAILURE.getValue() + t.getMessage()); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /java-handles/src/solutions/java/none/cvg/methods/TestSolutionPublicStaticMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.methods; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.invoke.MethodType; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | import none.cvg.handles.DemoClass; 10 | import none.cvg.handles.HandlesKataDisplayNames; 11 | import org.junit.jupiter.api.DisplayName; 12 | import org.junit.jupiter.api.DisplayNameGeneration; 13 | import org.junit.jupiter.api.MethodOrderer; 14 | import org.junit.jupiter.api.Order; 15 | import org.junit.jupiter.api.Tag; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.TestMethodOrder; 18 | 19 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 20 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.junit.jupiter.api.Assertions.fail; 23 | 24 | /* 25 | * DONE: 26 | * This test aims at using MethodHandles to invoke a public static method on a class. 27 | * Each solved test shows how this can be achieved with the traditional reflection calls. 28 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 29 | * the exercise to achieve the same goal with MethodHandles. 30 | */ 31 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 32 | @DisplayName("Invoke DemoClass.publicStaticMethod(String)") 33 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 34 | public class TestSolutionPublicStaticMethodInvocation { 35 | 36 | @Test 37 | @Tag("PASSING") 38 | @Order(1) 39 | public void reflectionPublicStaticMethod() { 40 | 41 | String expectedOutput = "DemoClass.class - Public static method via reflection"; 42 | 43 | try { 44 | 45 | // Find the method on the class via a getMethod. 46 | Method publicStaticMethod = 47 | DemoClass.class.getMethod("publicStaticMethod", 48 | String.class); 49 | 50 | assertEquals(expectedOutput, 51 | publicStaticMethod.invoke(DemoClass.class, "via reflection"), 52 | "Reflection invocation failed"); 53 | 54 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 55 | 56 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 57 | } 58 | } 59 | 60 | @Test 61 | @Tag("PASSING") 62 | @Order(2) 63 | public void methodHandlePublicStaticMethod() { 64 | 65 | String expectedOutput = "DemoClass.class - Public static method via Method Handles"; 66 | 67 | /* 68 | * DONE: 69 | * Get a public lookup from java.lang.invoke.MethodHandles 70 | * Public parts of a class are looked up via "public lookups" 71 | * Check API: java.lang.invoke.MethodHandles.publicLookup() 72 | */ 73 | MethodHandles.Lookup publicStaticMethodHandlesLookup = MethodHandles.publicLookup(); 74 | 75 | /* 76 | * DONE 77 | * Replace the "null"s with valid values to get a signature for a publicStaticMethod. 78 | * Create a methodType instance that matches the signature of what we wish to invoke 79 | * The publicMethod() returns a String and accepts a String parameter 80 | * Check API: java.lang.invoke.MethodType.methodType(?, ?) 81 | */ 82 | MethodType methodType = MethodType.methodType(String.class, String.class); 83 | 84 | try { 85 | 86 | /* 87 | * DONE 88 | * Replace the "null"s with valid values to get a handle to publicStaticMethod. 89 | * "Find" a method of the class via the Lookup instance, 90 | * based on the methodType described above and the method name. 91 | * Public static methods can be searched via the findStatic() method. 92 | * Check API: java.lang.invoke.MethodHandles.Lookup.findStatic(?, ?, ?) 93 | */ 94 | MethodHandle publicStaticMethodHandle = 95 | publicStaticMethodHandlesLookup.findStatic(DemoClass.class, 96 | "publicStaticMethod", methodType); // Class, Method name, Method type 97 | 98 | /* 99 | * ATTENTION: The invoke() method does not take an instance of demoClass as its 100 | * first parameter for static method invocation. 101 | */ 102 | assertEquals(expectedOutput, 103 | publicStaticMethodHandle.invoke( 104 | "via Method Handles"), 105 | "Method handles invocation failed"); 106 | 107 | } catch (NoSuchMethodException | IllegalAccessException e) { 108 | 109 | fail("Failed to execute a public static method invocation via Method Handles: " 110 | + e.getMessage()); 111 | } catch (Throwable t) { 112 | 113 | // invoke throws a Throwable (hence catching Throwable separately). 114 | fail(TEST_FAILURE.getValue() + t.getMessage()); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /java-datetime/src/solutions/java/none/cvg/datetime/TestSolution5DateTimePartials.java: -------------------------------------------------------------------------------- 1 | package none.cvg.datetime; 2 | 3 | import java.time.Clock; 4 | import java.time.DayOfWeek; 5 | import java.time.Instant; 6 | import java.time.LocalDateTime; 7 | import java.time.Month; 8 | import java.time.MonthDay; 9 | import java.time.Year; 10 | import java.time.YearMonth; 11 | import java.time.ZoneId; 12 | 13 | import org.junit.jupiter.api.BeforeEach; 14 | import org.junit.jupiter.api.DisplayName; 15 | import org.junit.jupiter.api.DisplayNameGeneration; 16 | import org.junit.jupiter.api.MethodOrderer; 17 | import org.junit.jupiter.api.Order; 18 | import org.junit.jupiter.api.Tag; 19 | import org.junit.jupiter.api.Test; 20 | import org.junit.jupiter.api.TestMethodOrder; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | /** 25 | * DateTime partials: Month, MonthDay, Year, YearMonth and DayOfWeek tests. 26 | *

27 | * Note: We create a Clock instance in setup() used for some of the tests. 28 | * 29 | * @see Clock 30 | * @see Month 31 | * @see MonthDay 32 | * @see Year 33 | * @see YearMonth 34 | * @see DayOfWeek 35 | */ 36 | @DisplayNameGeneration(DateTimeKataDisplayNames.class) 37 | @DisplayName("Date and Time partials such as credit card expiration") 38 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 39 | public class TestSolution5DateTimePartials { 40 | 41 | private Clock terminatorOriginalJudgementDay = null; 42 | 43 | @BeforeEach 44 | public void setup() { 45 | 46 | Instant instant = Instant.parse("1997-08-29T06:14:30Z"); 47 | // We make an assumption for GMT -4 as the timezone for users of this test. 48 | terminatorOriginalJudgementDay = Clock.fixed(instant, ZoneId.of("GMT-4")); 49 | } 50 | 51 | @Test 52 | @Tag("PASSING") 53 | @Order(1) 54 | public void verifyMonth() { 55 | 56 | LocalDateTime tOJDateTime = LocalDateTime.now(terminatorOriginalJudgementDay); 57 | 58 | // DONE: Replace the "null" below get a Month instance. 59 | // Check: java.time.LocalDateTime.getMonth() 60 | Month tOJMonth = tOJDateTime.getMonth(); 61 | 62 | assertEquals(Month.AUGUST, 63 | tOJMonth, 64 | "The Month enumeration should match August."); 65 | } 66 | 67 | @Test 68 | @Tag("PASSING") 69 | @Order(2) 70 | public void verifyMonthDay() { 71 | 72 | // Real world: Birthday or anniversary 73 | 74 | // DONE: Replace the MonthDay.now() below get a MonthDay anniversary for the Judgement Day. 75 | // Check: java.time.MonthDay.now(java.time.Clock) 76 | MonthDay anniversaryofJudgementDay = MonthDay.now(terminatorOriginalJudgementDay); 77 | 78 | assertEquals(Month.AUGUST, 79 | anniversaryofJudgementDay.getMonth(), 80 | "The month enumeration should match August."); 81 | 82 | assertEquals(8, 83 | anniversaryofJudgementDay.getMonthValue(), 84 | "The month value should match 8."); 85 | 86 | assertEquals(29, 87 | anniversaryofJudgementDay.getDayOfMonth(), 88 | "The date value should match 29."); 89 | } 90 | 91 | @Test 92 | @Tag("PASSING") 93 | @Order(3) 94 | public void verifyYear() { 95 | 96 | // Real world: Age or Year of occurrence. 97 | 98 | // DONE: Replace the Year.now() below get a Year for the Judgement Day. 99 | // Check: java.time.Year.now(java.time.Clock) 100 | Year yearOfJudgementDay = Year.now(terminatorOriginalJudgementDay); 101 | 102 | assertEquals(1997, 103 | yearOfJudgementDay.getValue(), 104 | "The year value should match 1997."); 105 | } 106 | 107 | @Test 108 | @Tag("PASSING") 109 | @Order(4) 110 | public void verifyYearMonth() { 111 | 112 | // Real world: CreditCard or Medicine expiration. 113 | 114 | // DONE: Replace the YearMonth.now() below get a YearMonth for the Judgement Day. 115 | // Check: java.time.YearMonth.now(java.time.Clock) 116 | YearMonth yearMonthOfJudgementDay = YearMonth.now(terminatorOriginalJudgementDay); 117 | 118 | assertEquals(Month.AUGUST, 119 | yearMonthOfJudgementDay.getMonth(), 120 | "The month enumeration should match August."); 121 | 122 | assertEquals(8, 123 | yearMonthOfJudgementDay.getMonthValue(), 124 | "The month value should match 8."); 125 | 126 | assertEquals(1997, 127 | yearMonthOfJudgementDay.getYear(), 128 | "The year value should match 1997."); 129 | } 130 | 131 | @Test 132 | @Tag("PASSING") 133 | @Order(5) 134 | public void verifyDayOfWeek() { 135 | 136 | LocalDateTime tOJDateTime = LocalDateTime.now(terminatorOriginalJudgementDay); 137 | 138 | // DONE: Replace the null below to get the Day Of Week from the tOJDateTime. 139 | // Check: java.time.LocalDateTime.getDayOfWeek() 140 | DayOfWeek dayOfWeek = tOJDateTime.getDayOfWeek(); 141 | 142 | assertEquals(DayOfWeek.FRIDAY, 143 | dayOfWeek, 144 | "The day of the week enumeration should match Friday."); 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /java-optional/README.adoc: -------------------------------------------------------------------------------- 1 | = java-optional 2 | :toc: 3 | :toclevels: 4 4 | 5 | image:assets/images/DukeOptional.png[Java Duke Optional Logo, 233, 420] 6 | 7 | Quite often, we have to test if a field or variable is `null` or has a value. 8 | Conditional checks in traditional java relied on an if condition. 9 | Failure to check and assumption of existence of a value can lead to the 10 | ever-so-popular `NullPointerException`. 11 | 12 | Sir Charles Anthony Richard Hoare (Tony Hoare), creator of the *null reference* 13 | rued the creation of null in 2009: 14 | 15 | >I call it my billion-dollar mistake. It was the invention of the null reference in 1965. 16 | At that time, I was designing the first comprehensive type system for references in an 17 | object-oriented language (ALGOL W). My goal was to ensure that all use of references 18 | should be absolutely safe, with checking performed automatically by the compiler. 19 | But, I couldn't resist the temptation to put in a null reference, simply because it was 20 | so easy to implement. This has led to innumerable errors, vulnerabilities, and 21 | system crashes, which have probably caused a billion dollars of pain and damage in 22 | the last forty years. 23 | 24 | Optional was added in Java 8 as a possible solution to errant null issues. An Optional wrapper 25 | over a field or variable ensures there is a check - or - a deliberate attempt to get a value from 26 | the wrapper. The kata will help us better understand the features of `java.util.Optional` 27 | 28 | == What is a Code-Kata 29 | 30 | A code-kata is a coding exercise that builds muscle memory by a practice of programming to arrive 31 | at a known solution. 32 | 33 | === How does one go about with this code kata? 34 | 35 | The essence of the exercise (presentation material and code kata) is to demonstrate the 36 | usage patterns for the java API or functionality. 37 | 38 | This set of code katas rely on fixing broken tests. The tests may have multiple solutions, the 39 | intent is to learn and experiment. 40 | 41 | The project contains several JUnit tests that fail. 42 | 43 | ==== Simple steps to use this kata 44 | 45 | . Run the test class(es). 46 | . One or more tests will fail with the test failure message. 47 | . Fix the failing tests by using `HINT` and `TODO` comments. 48 | . Repeat above steps until all tests pass. 49 | . Check the solutions to see if there are other ways to solve. 50 | (Remember, the solution may be less performant/optimal than yours) 51 | . Rinse and repeat (delete and checkout again, then back to Step 1) to build muscle memory. 52 | 53 | === Mission 54 | > Your mission, should you choose to accept it, will be to fix the JUnit tests. This 55 | message will self-destruct in `**NaN**` minutes. 56 | 57 | == Requirements 58 | How to prepare for coding along 59 | 60 | This kata is developed as a Java maven project.Ensure that you have: 61 | 62 | . Apache Maven 3.6.x or above. _Tested with Apache Maven 3.6.0_. 63 | Link: https://maven.apache.org/download.cgi 64 | 65 | . JDK 11 or above. _Tested with OpenJDK 11_ 66 | Link: http://jdk.java.net/11/ 67 | 68 | . Your favorite Java IDE. _IntelliJ IDEA Ultimate was used to develop this kata_. 69 | 70 | == Project Structure 71 | 72 | The structure of the project: 73 | 74 | [source] 75 | ---- 76 | |____pom.xml 77 | |____README.md 78 | | 79 | |____src 80 | | | 81 | | |____test <------------------- Kata Tests 82 | | | |____java 83 | | | |____none 84 | | | |____cvg 85 | | | |____optional 86 | | | 87 | | |____solutions <------------------- Solutions 88 | | | |____java 89 | | | |____none 90 | | | |____cvg 91 | | | |____optional 92 | ---- 93 | 94 | == Tests Included 95 | 96 | === Java Optional API 97 | The JUnit tests listed below are set to utilize the Java Optional API features. 98 | 99 | link:src/test/java/none/cvg/optional/TestKata1OptionalCreationAndFetchingValues.java[TestKata1OptionalCreationAndFetchingValues.java]:: show creation of and fetching value from an Optional. 100 | 101 | link:src/test/java/none/cvg/optional/TestKata2OptionalConditionalFetching.java[TestKata2OptionalConditionalFetching.java]:: show conditional checks and alternate actions when fetching values from an Optional. 102 | 103 | link:src/test/java/none/cvg/optional/TestKata3StreamsAndOptionals.java[TestKata3StreamsAndOptionals.java]:: show the usage of Optional in Java Stream API. 104 | 105 | == Solutions 106 | 107 | .Solutions for each test 108 | |=== 109 | | Kata Test | Solution 110 | 111 | |link:src/test/java/none/cvg/optional/TestKata1OptionalCreationAndFetchingValues.java[TestKata1OptionalCreationAndFetchingValues.java] 112 | |link:src/solutions/java/none/cvg/optional/TestSolution1OptionalCreationAndFetchingValues.java[TestSolution1OptionalCreationAndFetchingValues.java] 113 | 114 | |link:src/test/java/none/cvg/optional/TestKata2OptionalConditionalFetching.java[TestKata2OptionalConditionalFetching.java] 115 | |link:src/solutions/java/none/cvg/optional/TestSolution2OptionalConditionalFetching.java[TestSolution2OptionalConditionalFetching.java] 116 | 117 | |link:src/test/java/none/cvg/optional/TestKata3StreamsAndOptionals.java[TestKata3StreamsAndOptionals.java] 118 | |link:src/solutions/java/none/cvg/optional/TestSolution3StreamsAndOptionals.java[TestSolution3StreamsAndOptionals.java] 119 | |=== 120 | 121 | == Take Away 122 | 123 | The key take-away from this kata is a solid understanding of the Java Optional API. 124 | -------------------------------------------------------------------------------- /java-datetime/src/test/java/none/cvg/datetime/TestKata1InstantAndDateInterop.java: -------------------------------------------------------------------------------- 1 | package none.cvg.datetime; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.time.Instant; 5 | import java.util.Date; 6 | import java.util.TimeZone; 7 | 8 | import org.junit.jupiter.api.BeforeEach; 9 | import org.junit.jupiter.api.DisplayName; 10 | import org.junit.jupiter.api.DisplayNameGeneration; 11 | import org.junit.jupiter.api.MethodOrderer; 12 | import org.junit.jupiter.api.Order; 13 | import org.junit.jupiter.api.Tag; 14 | import org.junit.jupiter.api.Test; 15 | import org.junit.jupiter.api.TestMethodOrder; 16 | 17 | import static none.cvg.datetime.LenientAssert.assertAlmostEquals; 18 | import static org.junit.jupiter.api.Assertions.assertEquals; 19 | import static org.junit.jupiter.api.Assertions.assertTrue; 20 | 21 | /** 22 | * The tests in this class aim to show interoperability between 23 | * `java.util.Date` and the newer `java.time.Instant`. 24 | * 25 | * @see Instant 26 | * @see Date 27 | * @see LenientAssert 28 | */ 29 | @DisplayNameGeneration(DateTimeKataDisplayNames.class) 30 | @DisplayName("Instant And Date Interoperability") 31 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 32 | public class TestKata1InstantAndDateInterop { 33 | 34 | private Date classicDate; 35 | 36 | private SimpleDateFormat classicDateFormatter = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss.SSS'Z'"); 37 | 38 | @BeforeEach 39 | public void setup() { 40 | classicDate = new Date(); 41 | } 42 | 43 | @Test 44 | @Tag("TODO") 45 | @Order(1) 46 | public void verifyInstantAndDateHaveSameEpochMilliseconds() { 47 | 48 | // TODO: Replace the Instant.now() with an instant from classicDate. 49 | // Use a Date API that converts Date instances into Instant instances. 50 | // Check: java.util.Date.toInstant() 51 | Instant instant = Instant.now(); 52 | 53 | // TODO: Replace the "null" below to get milliseconds from epoch from the Instant 54 | // Use an Instant API which converts it into milliseconds 55 | // Check: java.time.Instant.toEpochMilli() 56 | assertEquals(Long.valueOf(classicDate.getTime()), 57 | null, 58 | "Date and Instant milliseconds should be equal"); 59 | } 60 | 61 | @Test 62 | @Tag("TODO") 63 | @Order(2) 64 | public void verifyInstantAndDateHaveAlmostSameEpochSeconds() { 65 | 66 | Instant instant = classicDate.toInstant(); 67 | 68 | // NOTE: There is no simpler API method to get epoch seconds. 69 | long classicDateInSeconds = classicDate.getTime() / 1000; 70 | 71 | // TODO: Replace the "null" below to get seconds from epoch from the Instant 72 | // Assert that the seconds from epoch from both Date and Instant are equal. 73 | // Check: java.time.Instant.getEpochSecond() 74 | // NOTE: We use a custom assertion here since the millis to second arithmetic may cause 75 | // rounding issues. We add a tolerance of 1 second. 76 | assertAlmostEquals(classicDateInSeconds, 77 | null, 78 | 1L, 79 | "Date and Instant seconds should almost match"); 80 | } 81 | 82 | @Test 83 | @Tag("TODO") 84 | @Order(3) 85 | public void verifyInstantHasNanoseconds() { 86 | 87 | Instant instant = Instant.now(); 88 | 89 | // TODO: Replace the string "-2" below to get nanos from the Instant 90 | // Assert that instant has nano seconds. 91 | // Check: java.time.Instant.getNano() 92 | assertTrue(Integer.valueOf("-2") > -1, 93 | "Instant should have nanoseconds"); 94 | } 95 | 96 | @Test 97 | @Tag("TODO") 98 | @Order(4) 99 | public void verifyInstantDefaultFormatting() { 100 | 101 | classicDateFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); 102 | 103 | Instant instant = classicDate.toInstant(); 104 | 105 | // TODO: Replace the "null" below to retrieve an instant as a string 106 | // Assert that instant default toString matches the ISO8601 full date format. 107 | assertEquals(classicDateFormatter.format(classicDate), 108 | null, 109 | "Instant toString() should match ISO8601 format"); 110 | } 111 | 112 | @Test 113 | @Tag("TODO") 114 | @Order(5) 115 | public void verifyInstantDateInteroperability() { 116 | 117 | // ***************************************************** 118 | // Converting Date to an Instant. 119 | // ***************************************************** 120 | Instant instant = classicDate.toInstant(); 121 | assertEquals(classicDate.getTime(), instant.toEpochMilli()); 122 | 123 | 124 | // ***************************************************** 125 | // Converting an Instant to a Date. 126 | // ***************************************************** 127 | // TODO: Replace the "null" below to convert an Instant into a Date 128 | // Check: java.util.Date.from() 129 | Date anotherDate = null; 130 | assertEquals(classicDate, anotherDate); 131 | 132 | // ***************************************************** 133 | // Think about why all conversions and inter-ops are 134 | // built into Date and not the newer java.time API. 135 | // ***************************************************** 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /java-datetime/README.adoc: -------------------------------------------------------------------------------- 1 | = Java Time API - A Code kata 2 | :toc: 3 | :toclevels: 4 4 | 5 | image:assets/images/DukeTime.png[Java Duke Date Time Logo, 233, 420] 6 | 7 | Most, if not all Java developers need to rely on Java date and time libraries. 8 | 9 | == What is a Code-Kata 10 | 11 | A code-kata is a coding exercise that builds muscle memory by a practice of programming to arrive 12 | at a known solution. 13 | 14 | === How does one go about with this code kata? 15 | 16 | The essence of the exercise (presentation material and code kata) is to demonstrate the 17 | usage patterns for the java API or functionality. 18 | 19 | This set of code katas rely on fixing broken tests. The tests may have multiple solutions, the 20 | intent is to learn and experiment. 21 | 22 | The project contains several JUnit tests that fail. 23 | 24 | ==== Simple steps to use this kata 25 | 26 | . Run the test class(es). 27 | . One or more tests will fail with the test failure message. 28 | . Fix the failing tests by using `HINT` and `TODO` comments. 29 | . Repeat above steps until all tests pass. 30 | . Check the solutions to see if there are other ways to solve. 31 | (Remember, the solution may be less performant/optimal than yours) 32 | . Rinse and repeat (delete and checkout again, then back to Step 1) to build muscle memory. 33 | 34 | === Mission 35 | > Your mission, should you choose to accept it, will be to fix the JUnit tests. This 36 | message will self-destruct in `**NaN**` minutes. 37 | 38 | == Requirements 39 | How to prepare for coding along 40 | 41 | This kata is developed as a Java maven project.Ensure that you have: 42 | 43 | . Apache Maven 3.6.x or above. _Tested with Apache Maven 3.6.3_. 44 | Link: https://maven.apache.org/download.cgi 45 | 46 | . JDK 11 or above. _Tested with OpenJDK 11_ 47 | Link: http://jdk.java.net/11/ 48 | 49 | . Your favorite Java IDE. _IntelliJ IDEA Ultimate was used to develop this kata_. 50 | 51 | == Project Structure 52 | 53 | The structure of the project: 54 | 55 | [source] 56 | ---- 57 | |____pom.xml 58 | |____README.md 59 | | 60 | |____src 61 | | | 62 | | |____test <------------------- Kata Tests 63 | | | |____java 64 | | | |____none 65 | | | |____cvg 66 | | | |____datetime 67 | | | 68 | | |____main <------------------- Shared ErrorMessages & DemoClass 69 | | | |____java 70 | | | |____none 71 | | | |____cvg 72 | | | |____datetime 73 | | | 74 | | |____solutions <------------------- Solutions 75 | | | |____java 76 | | | |____none 77 | | | |____cvg 78 | | | |____datetime 79 | ---- 80 | 81 | 82 | == Tests Included 83 | 84 | === Java Date Time API 85 | 86 | The JUnit tests listed below are setup to utilize the Java Time API features. 87 | 88 | link:src/test/java/none/cvg/datetime/TestKata1InstantAndDateInterop.java[TestKata1InstantAndDateInterop.java]:: show interoperability between `java.util.Date`, and the newer `java.time.Instant`. 89 | 90 | link:src/test/java/none/cvg/datetime/TestKata2Clocks.java[TestKata2Clocks.java]:: show the usage of `java.time.Clock`. 91 | 92 | link:src/test/java/none/cvg/datetime/TestKata3LocalAndZonedDateTimes.java[TestKata3LocalAndZonedDateTimes.java]:: show the usage of `java.time.LocalDate`, `java.time.LocalTime`, `java.time.LocalDateTime` and `java.time.ZonedDateTime`. 93 | 94 | link:src/test/java/none/cvg/datetime/TestKata4PeriodsAndDurations.java[TestKata4PeriodsAndDurations.java]:: show the usage of DateTime ranges: Period, Duration tests. 95 | 96 | link:src/test/java/none/cvg/datetime/TestKata5DateTimePartials.java[TestKata5DateTimePartials.java]:: show the usage of DateTime partials: Month, MonthDay, Year, YearMonth and DayOfWeek tests. 97 | 98 | link:src/test/java/none/cvg/datetime/TestKata6StreamsInDateTime.java[TestKata6StreamsInDateTime.java]:: show the usage of DateTime in Java `stream()` lazy iterations. 99 | 100 | == Solutions 101 | 102 | .Solutions for each test: 103 | |=== 104 | | Kata Test | Solution 105 | 106 | |link:src/test/java/none/cvg/datetime/TestKata1InstantAndDateInterop.java[TestKata1InstantAndDateInterop.java] 107 | |link:src/solutions/java/none/cvg/datetime/TestSolution1InstantAndDateInterop.java[TestSolution1InstantAndDateInterop.java] 108 | 109 | |link:src/test/java/none/cvg/datetime/TestKata2Clocks.java[TestKata2Clocks.java] 110 | |link:src/solutions/java/none/cvg/datetime/TestSolution2Clocks.java[TestSolution2Clocks.java] 111 | 112 | |link:src/test/java/none/cvg/datetime/TestKata3LocalAndZonedDateTimes.java[TestKata3LocalAndZonedDateTimes.java] 113 | |link:src/solutions/java/none/cvg/datetime/TestSolution3LocalAndZonedDateTimes.java[TestSolution3LocalAndZonedDateTimes.java] 114 | 115 | |link:src/test/java/none/cvg/datetime/TestKata4PeriodsAndDurations.java[TestKata4PeriodsAndDurations.java] 116 | |link:src/solutions/java/none/cvg/datetime/TestSolution4PeriodsAndDurations.java[TestSolution4PeriodsAndDurations.java] 117 | 118 | |link:src/test/java/none/cvg/datetime/TestKata5DateTimePartials.java[TestKata5DateTimePartials.java] 119 | |link:src/solutions/java/none/cvg/datetime/TestSolution5DateTimePartials.java[TestSolution5DateTimePartials.java] 120 | 121 | |link:src/test/java/none/cvg/datetime/TestKata6StreamsInDateTime.java[TestKata6StreamsInDateTime.java] 122 | |link:src/solutions/java/none/cvg/datetime/TestSolution6StreamsInDateTime.java[TestSolution6StreamsInDateTime.java] 123 | |=== 124 | 125 | == Take Away 126 | 127 | The key take-away from this kata is a solid understanding of the Java Time API. 128 | -------------------------------------------------------------------------------- /java-datetime/src/solutions/java/none/cvg/datetime/TestSolution1InstantAndDateInterop.java: -------------------------------------------------------------------------------- 1 | package none.cvg.datetime; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.time.Instant; 5 | import java.util.Date; 6 | import java.util.TimeZone; 7 | 8 | import org.junit.jupiter.api.BeforeEach; 9 | import org.junit.jupiter.api.DisplayName; 10 | import org.junit.jupiter.api.DisplayNameGeneration; 11 | import org.junit.jupiter.api.MethodOrderer; 12 | import org.junit.jupiter.api.Order; 13 | import org.junit.jupiter.api.Tag; 14 | import org.junit.jupiter.api.Test; 15 | import org.junit.jupiter.api.TestMethodOrder; 16 | 17 | import static none.cvg.datetime.LenientAssert.assertAlmostEquals; 18 | import static org.junit.jupiter.api.Assertions.assertEquals; 19 | import static org.junit.jupiter.api.Assertions.assertTrue; 20 | 21 | /** 22 | * The tests in this class aim to show interoperability between 23 | * `java.util.Date` and the newer `java.time.Instant`. 24 | * 25 | * @see Instant 26 | * @see Date 27 | * @see LenientAssert 28 | */ 29 | @DisplayNameGeneration(DateTimeKataDisplayNames.class) 30 | @DisplayName("Instant And Date Interoperability") 31 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 32 | public class TestSolution1InstantAndDateInterop { 33 | 34 | private Date classicDate; 35 | 36 | private SimpleDateFormat classicDateFormatter = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss.SSS'Z'"); 37 | 38 | @BeforeEach 39 | public void setup() { 40 | classicDate = new Date(); 41 | } 42 | 43 | @Test 44 | @Tag("PASSING") 45 | @Order(1) 46 | public void verifyInstantAndDateHaveSameEpochMilliseconds() { 47 | 48 | // DONE: Replace the Instant.now() with an instant from classicDate. 49 | // Use a Date API that converts Date instances into Instant instances. 50 | // Check: java.util.Date.toInstant() 51 | Instant instant = classicDate.toInstant(); 52 | 53 | // DONE: Replace the "null" below to get milliseconds from epoch from the Instant 54 | // Use an Instant API which converts it into milliseconds 55 | // Check: java.time.Instant.toEpochMilli() 56 | assertEquals(Long.valueOf(classicDate.getTime()), 57 | instant.toEpochMilli(), 58 | "Date and Instant milliseconds should be equal"); 59 | } 60 | 61 | @Test 62 | @Tag("PASSING") 63 | @Order(2) 64 | public void verifyInstantAndDateHaveAlmostSameEpochSeconds() { 65 | 66 | Instant instant = classicDate.toInstant(); 67 | 68 | // NOTE: There is no simpler API method to get epoch seconds. 69 | long classicDateInSeconds = classicDate.getTime() / 1000; 70 | 71 | // DONE: Replace the "null" below to get seconds from epoch from the Instant 72 | // Assert that the seconds from epoch from both Date and Instant are equal. 73 | // Check: java.time.Instant.getEpochSecond() 74 | // NOTE: We use a custom assertion here since the millis to second arithmetic may cause 75 | // rounding issues. We add a tolerance of 1 second. 76 | assertAlmostEquals(classicDateInSeconds, 77 | instant.getEpochSecond(), 78 | 1L, 79 | "Date and Instant seconds should almost match"); 80 | } 81 | 82 | @Test 83 | @Tag("PASSING") 84 | @Order(3) 85 | public void verifyInstantHasNanoseconds() { 86 | 87 | Instant instant = Instant.now(); 88 | 89 | // DONE: Replace the "null" below to get nanos from the Instant 90 | // Assert that instant has nano seconds. 91 | // Check: java.time.Instant.getNano() 92 | assertTrue(Integer.valueOf(instant.getNano()) > -1, 93 | "Instant should have nanoseconds"); 94 | } 95 | 96 | @Test 97 | @Tag("PASSING") 98 | @Order(4) 99 | public void verifyInstantDefaultFormatting() { 100 | 101 | classicDateFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); 102 | 103 | Instant instant = classicDate.toInstant(); 104 | 105 | // DONE: Replace the "null" below to retrieve an instant as a string 106 | // Assert that instant default toString matches the ISO8601 full date format. 107 | assertEquals(classicDateFormatter.format(classicDate), 108 | instant.toString(), 109 | "Instant toString() should match ISO8601 format"); 110 | } 111 | 112 | @Test 113 | @Tag("PASSING") 114 | @Order(5) 115 | public void verifyInstantDateInteroperability() { 116 | 117 | // ***************************************************** 118 | // Converting Date to an Instant. 119 | // ***************************************************** 120 | Instant instant = classicDate.toInstant(); 121 | assertEquals(classicDate.getTime(), instant.toEpochMilli()); 122 | 123 | 124 | // ***************************************************** 125 | // Converting an Instant to a Date. 126 | // ***************************************************** 127 | // DONE: Replace the "null" below to convert an Instant into a Date 128 | // Check: java.util.Date.from() 129 | Date anotherDate = Date.from(instant); 130 | assertEquals(classicDate, anotherDate); 131 | 132 | // ***************************************************** 133 | // Think about why all conversions and inter-ops are 134 | // built into Date and not the newer java.time API. 135 | // ***************************************************** 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /CONTRIBUTING.adoc: -------------------------------------------------------------------------------- 1 | = Contributing 2 | 3 | Thank you for your interest in contributing to this set of Code Katas ! 4 | 5 | == Contribution Guide 6 | 7 | === Build policy 8 | 9 | The Code Katas in this repository are arranged as independent maven projects that can be orchestrated or built together using the aggregator and **parent pom** pom.xml at the root of the project. The parent pom (located at the root of the project) defines a few properties used throughout (such as the *JUnit version*, and the *Java compiler's source and target* version). In addition, some common build plugins are configured under the `pluginManagement` section of the parent pom. 10 | 11 | ==== REQUIREMENT 12 | The individual Kata projects should remain independent build targets and should not depend on any other module or kata for a successful build. 13 | 14 | === Kata structure 15 | 16 | Irrespective of the contribution style (a full module or enhancement/bug fix to existing module), here are some requirements: 17 | 18 | ==== General Project Structure 19 | 20 | The project layout in the every Code Kata is similar.Here is a tree structure to explain: 21 | 22 | [source] 23 | ---- 24 | |____pom.xml <------------------- Project pom, using the java-katas/pom.xml as parent 25 | |____README.md <------------------- Well documented README, with links to tests & solutions 26 | | 27 | |____src 28 | | | 29 | | |____test <------------------- Kata Tests 30 | | | |____java 31 | | | |____none 32 | | | |____cvg 33 | | | |____ <------------------- Name the package that corresponds to the kata. 34 | | | |____ <------------------- Optional multiple packages if the kata covers more sections 35 | | | 36 | | |____main <------------------- Shared content (re-used in both tests and solutions) 37 | | | |____java 38 | | | |____none 39 | | | |____cvg 40 | | | 41 | | |____solutions <------------------- Solutions 42 | | | |____java 43 | | | |____none 44 | | | |____cvg 45 | | | |____ <------------------- Name the package that corresponds to the kata. 46 | | | |____ <------------------- Optional multiple packages if the kata covers more sections 47 | 48 | ---- 49 | ==== REQUIREMENT 50 | The Code Kata project structure should comply with the setup of a `test` folder with failing tests, and a `solution` folder with solved working tests. 51 | 52 | When contributing to this repository, please first discuss the change you wish to make via issue, 53 | email, or any other method with the owners of this repository before making a change. 54 | 55 | == Code of Conduct 56 | 57 | In the interest of fostering an open and welcoming environment, we as 58 | contributors and maintainers pledge to making participation in our project, and 59 | our community a harassment-free experience for everyone, regardless of age, body 60 | size, disability, ethnicity, gender identity and expression, level of experience, 61 | nationality, personal appearance, race, religion, or sexual identity and 62 | orientation. 63 | 64 | === Our Standards 65 | 66 | Examples of behavior that contributes to creating a positive environment 67 | include: 68 | 69 | * Using welcoming and inclusive language 70 | * Being respectful of differing viewpoints and experiences 71 | * Gracefully accepting constructive criticism 72 | * Focusing on what is best for the community 73 | * Showing empathy towards other community members 74 | 75 | Examples of unacceptable behavior by participants include: 76 | 77 | * The use of sexualized language or imagery and unwelcome sexual attention or 78 | advances 79 | * Trolling, insulting/derogatory comments, and personal or political attacks 80 | * Public or private harassment 81 | * Publishing others' private information, such as a physical or electronic 82 | address, without explicit permission 83 | * Other conduct which could reasonably be considered inappropriate in a 84 | professional setting 85 | 86 | === Our Responsibilities 87 | 88 | Project maintainers are responsible for clarifying the standards of acceptable 89 | behavior and are expected to take appropriate and fair corrective action in 90 | response to any instances of unacceptable behavior. 91 | 92 | Project maintainers have the right and responsibility to remove, edit, or 93 | reject comments, commits, code, wiki edits, issues, and other contributions 94 | that are not aligned to this Code of Conduct, or to ban temporarily or 95 | permanently any contributor for other behaviors that they deem inappropriate, 96 | threatening, offensive, or harmful. 97 | 98 | === Scope 99 | 100 | This Code of Conduct applies both within project spaces and in public spaces 101 | when an individual is representing the project or its community.Examples of 102 | representing a project or community include using an official project e-mail 103 | address, posting via an official social media account, or acting as an appointed 104 | representative at an online or offline event.Representation of a project may be 105 | further defined and clarified by project maintainers. 106 | 107 | === Enforcement 108 | 109 | Project maintainers who do not follow or enforce the Code of Conduct in good 110 | faith may face temporary or permanent repercussions as determined by other 111 | members of the project's leadership. 112 | 113 | === Attribution 114 | 115 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 116 | available at [http://contributor-covenant.org/version/1/4][version] 117 | 118 | [homepage]: http://contributor-covenant.org 119 | [version]: http://contributor-covenant.org/version/1/4/ 120 | -------------------------------------------------------------------------------- /java-lambdas/src/solutions/java/none/cvg/lambdas/TestSolution2LambdasDeeperDive.java: -------------------------------------------------------------------------------- 1 | package none.cvg.lambdas; 2 | 3 | import org.junit.jupiter.api.DisplayName; 4 | import org.junit.jupiter.api.DisplayNameGeneration; 5 | import org.junit.jupiter.api.MethodOrderer; 6 | import org.junit.jupiter.api.Order; 7 | import org.junit.jupiter.api.Tag; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestMethodOrder; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.Comparator; 15 | import java.util.List; 16 | import java.util.function.BiFunction; 17 | import java.util.function.Function; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertEquals; 20 | import static org.junit.jupiter.api.Assertions.assertTrue; 21 | 22 | @DisplayNameGeneration(LambdasKataDisplayNames.class) 23 | @DisplayName("Lambdas - A deeper dive") 24 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 25 | public class TestSolution2LambdasDeeperDive { 26 | 27 | @Test 28 | @Tag("PASSING") 29 | @Order(1) 30 | @DisplayName("use a BiFunction") 31 | public void useBiFunction() { 32 | 33 | final int integer1 = 3; 34 | final int integer2 = 4; 35 | 36 | // DONE: 37 | // Replace the MyBiFuncton class with a BiFunction named add. 38 | // Replace the max with a sum() function. 39 | // ------------------- 40 | // Hint: BiFunction adder = (x, y) -> //do something 41 | // Check API: java.util.function.BiFunction 42 | // Check API: java.util.function.BiFunction.apply 43 | BiFunction adder = (x, y) -> Integer.sum(x, y); 44 | // ------------------- 45 | 46 | assertEquals(7, adder.apply(integer1, integer2), 47 | "The function should produce a result of 7"); 48 | } 49 | 50 | @Test 51 | @Tag("PASSING") 52 | @Order(2) 53 | public void partialFunctions() { 54 | // Partial application describes the conversion of a multi-argument function 55 | // into one that accepts fewer arguments, with values for the elided arguments 56 | // supplied in advance. It partially applies some arguments to a function, 57 | // returning a function with a signature that consists of the remaining arguments. 58 | BiFunction add = (x, y) -> x + y; 59 | 60 | // TODO: 61 | // Replace the below Function to create a partial function from the above BiFunction 62 | // Create an addOne, which passes in a 1 and a int n to the add function and 63 | // returns a partial application of 1, n. 64 | // HINT: use the add.apply(?, ?) 65 | Function addOne = n -> add.apply(1, n); 66 | 67 | // TODO: 68 | // Replace the 6 with a call to addOne 69 | // HINT: use the addOne.apply() to return a value of 7 70 | assertEquals(7, addOne.apply(6), 71 | "The function should return 7"); 72 | } 73 | 74 | /** 75 | * @see Calculator - An interface with a single calculate() abstract method. 76 | */ 77 | @Test 78 | @Tag("PASSING") 79 | @Order(3) 80 | public void customSingleAbstractFunctions() { 81 | // DONE: 82 | // Replace the below Function to a lambda 83 | // Replace the zero with a valid function call 84 | Calculator addition = (x, y) -> x + y; 85 | 86 | // DONE: 87 | // Replace the below Function to a lambda 88 | // Replace the zero with a valid function call 89 | Calculator subtraction = (x, y) -> x - y; 90 | 91 | // DONE: 92 | // Replace the below Function to a lambda 93 | // Replace the zero with a valid function call 94 | Calculator multiplication = (x, y) -> x * y; 95 | 96 | assertTrue(7 == addition.calculate(6, 1), 97 | "The addition should return a value of 7"); 98 | 99 | assertTrue(7 == subtraction.calculate(10, 3), 100 | "The subtraction should return a value of 7"); 101 | 102 | assertTrue(49 == multiplication.calculate(7, 7), 103 | "The multiplication should return a value of 49"); 104 | } 105 | 106 | @Test 107 | @Tag("PASSING") 108 | @Order(4) 109 | public void sortNames() { 110 | List persons = 111 | Arrays.asList(Person.ALICE, Person.BOB, Person.CATHY, Person.DHRUV, Person.EMILY); 112 | List expectedList = 113 | Arrays.asList(Person.EMILY, Person.BOB, Person.DHRUV, Person.ALICE, Person.CATHY); 114 | 115 | // TODO: 116 | // Replace the anonymous class with a lambda. 117 | // Replace the postions of o2 and o1 to pass the test as well 118 | 119 | // ----------------- Solution 1 ----------------- 120 | Comparator nameSorter = (Comparator) (o1, o2) -> o1.getLastName().compareTo(o2.getLastName()); 121 | List actualList = new ArrayList<>(); 122 | actualList.addAll(persons); 123 | Collections.sort(actualList, nameSorter); 124 | // ----------------------------------------------- 125 | 126 | // ----------------- Solution 2 ----------------- 127 | // Comparator nameSorter = Comparator.comparing(Person::getLastName); 128 | // List actualList = persons.stream().sorted(nameSorter).collect(Collectors.toList()); 129 | // ----------------------------------------------- 130 | 131 | assertEquals(expectedList, actualList, "The sorted lists should match"); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /java-lambdas/src/test/java/none/cvg/lambdas/TestKata2LambdasDeeperDive.java: -------------------------------------------------------------------------------- 1 | package none.cvg.lambdas; 2 | 3 | import org.junit.jupiter.api.DisplayName; 4 | import org.junit.jupiter.api.DisplayNameGeneration; 5 | import org.junit.jupiter.api.MethodOrderer; 6 | import org.junit.jupiter.api.Order; 7 | import org.junit.jupiter.api.Tag; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestMethodOrder; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.Comparator; 15 | import java.util.List; 16 | import java.util.function.BiFunction; 17 | import java.util.function.Function; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertEquals; 20 | import static org.junit.jupiter.api.Assertions.assertTrue; 21 | 22 | @DisplayNameGeneration(LambdasKataDisplayNames.class) 23 | @DisplayName("Lambdas - A deeper dive") 24 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 25 | public class TestKata2LambdasDeeperDive { 26 | 27 | @Test 28 | @Tag("TODO") 29 | @Order(1) 30 | @DisplayName("use a BiFunction") 31 | public void useBiFunction() { 32 | 33 | final int integer1 = 3; 34 | final int integer2 = 4; 35 | 36 | // TODO: 37 | // Replace the MyBiFuncton class with a BiFunction named add. 38 | // Replace the max with a sum() function. 39 | // ------------------- 40 | // Hint: BiFunction adder = (x, y) -> //do something 41 | // Check API: java.util.function.BiFunction 42 | // Check API: java.util.function.BiFunction.apply 43 | class MyBiFunction { 44 | int apply(int x, int y) { 45 | return Integer.max(x, y); 46 | } 47 | } 48 | MyBiFunction adder = new MyBiFunction(); 49 | // ------------------- 50 | 51 | assertEquals(7, adder.apply(integer1, integer2), 52 | "The function should produce a result of 7"); 53 | } 54 | 55 | @Test 56 | @Tag("TODO") 57 | @Order(2) 58 | public void partialFunctions() { 59 | // Partial application describes the conversion of a multi-argument function 60 | // into one that accepts fewer arguments, with values for the elided arguments 61 | // supplied in advance. It partially applies some arguments to a function, 62 | // returning a function with a signature that consists of the remaining arguments. 63 | BiFunction add = (x, y) -> x + y; 64 | 65 | // TODO: 66 | // Replace the below Function to create a partial function from the above BiFunction 67 | // Create an addOne, which passes in a 1 and a int n to the add function and 68 | // returns a partial application of 1, n. 69 | // HINT: use the add.apply(?, ?) 70 | Function addOne = n -> 0; 71 | 72 | // TODO: 73 | // Replace the 6 with a call to addOne 74 | // HINT: use the addOne.apply() to return a value of 7 75 | assertEquals(7, addOne.apply(6), 76 | "The function should return 7"); 77 | } 78 | 79 | /** 80 | * @see Calculator - An interface with a single calculate() abstract method. 81 | */ 82 | @Test 83 | @Tag("TODO") 84 | @Order(3) 85 | public void customSingleAbstractFunctions() { 86 | // TODO: 87 | // Replace the below Function to a lambda 88 | // Replace the zero with a valid function call 89 | Calculator addition = new Calculator() { 90 | @Override 91 | public int calculate(int x, int y) { 92 | return 0; 93 | } 94 | }; 95 | 96 | // TODO: 97 | // Replace the below Function to a lambda 98 | // Replace the zero with a valid function call 99 | Calculator subtraction = new Calculator() { 100 | @Override 101 | public int calculate(int x, int y) { 102 | return 0; 103 | } 104 | }; 105 | 106 | // TODO: 107 | // Replace the below Function to a lambda 108 | // Replace the zero with a valid function call 109 | Calculator multiplication = new Calculator() { 110 | @Override 111 | public int calculate(int x, int y) { 112 | return 0; 113 | } 114 | }; 115 | 116 | assertTrue(7 == addition.calculate(6, 1), 117 | "The addition should return a value of 7"); 118 | 119 | assertTrue(7 == subtraction.calculate(10, 3), 120 | "The subtraction should return a value of 7"); 121 | 122 | assertTrue(49 == multiplication.calculate(7, 7), 123 | "The multiplication should return a value of 49"); 124 | } 125 | 126 | @Test 127 | @Tag("TODO") 128 | @Order(4) 129 | public void sortNames() { 130 | List persons = 131 | Arrays.asList(Person.ALICE, Person.BOB, Person.CATHY, Person.DHRUV, Person.EMILY); 132 | List expectedList = 133 | Arrays.asList(Person.EMILY, Person.BOB, Person.DHRUV, Person.ALICE, Person.CATHY); 134 | 135 | // TODO: 136 | // Replace the anonymous class with a lambda. 137 | // Replace the postions of o2 and o1 to pass the test as well 138 | Comparator nameSorter = new Comparator<>() { 139 | @Override 140 | public int compare(Person o1, Person o2) { 141 | return o2.getLastName().compareTo(o1.getLastName()); 142 | } 143 | }; 144 | List actualList = new ArrayList<>(); 145 | actualList.addAll(persons); 146 | Collections.sort(actualList, nameSorter); 147 | 148 | assertEquals(expectedList, actualList, "The sorted lists should match"); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /java-optional/src/test/java/none/cvg/optional/TestKata1OptionalCreationAndFetchingValues.java: -------------------------------------------------------------------------------- 1 | package none.cvg.optional; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.DisplayName; 5 | import org.junit.jupiter.api.MethodOrderer; 6 | import org.junit.jupiter.api.Order; 7 | import org.junit.jupiter.api.Tag; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestMethodOrder; 10 | 11 | import java.util.NoSuchElementException; 12 | import java.util.Optional; 13 | 14 | import static org.junit.jupiter.api.Assertions.assertEquals; 15 | import static org.junit.jupiter.api.Assertions.assertFalse; 16 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 17 | import static org.junit.jupiter.api.Assertions.assertThrows; 18 | import static org.junit.jupiter.api.Assertions.assertTrue; 19 | 20 | /* 21 | * TODO: 22 | * This test aims at understanding the basic features of Optional 23 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 24 | * the exercise. 25 | * 26 | * empty(), of(?), ofNullable(?), isPresent(), get() 27 | */ 28 | @DisplayName("java.util.Optional Creation And Getting value") 29 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 30 | public class TestKata1OptionalCreationAndFetchingValues { 31 | 32 | @BeforeEach 33 | public void setUp() { 34 | } 35 | 36 | @Test 37 | @DisplayName("create an empty Optional") 38 | @Tag("TODO") 39 | @Order(1) 40 | public void emptyOptional() { 41 | 42 | /* 43 | * TODO: 44 | * Replace the "null" to create an empty Optional. 45 | * Check API: java.util.Optional.empty() 46 | */ 47 | Optional optionalEmptyString = null; 48 | 49 | assertTrue(optionalEmptyString instanceof Optional, 50 | "The optionalEmptyString should be an instance of Optional"); 51 | 52 | assertTrue(optionalEmptyString.isEmpty(), 53 | "The optionalEmptyString should be empty"); 54 | } 55 | 56 | @Test 57 | @DisplayName("create an Optional from a variable") 58 | @Tag("TODO") 59 | @Order(2) 60 | public void createOptionalFromValue() { 61 | 62 | Integer anInteger = 10; 63 | 64 | /* 65 | * TODO: 66 | * Replace the "null" to create an Optional for anInteger. 67 | * Check API: java.util.Optional.of(?) 68 | */ 69 | Optional optionalForInteger = null; 70 | 71 | assertTrue(optionalForInteger instanceof Optional, 72 | "The optionalEmptyString should be an instance of Optional"); 73 | 74 | assertFalse(optionalForInteger.isEmpty(), 75 | "The optionalForInteger should not be empty"); 76 | } 77 | 78 | @Test 79 | @DisplayName("create a nullable Optional from a variable") 80 | @Tag("TODO") 81 | @Order(3) 82 | public void createNullableOptionalFromValue() { 83 | 84 | Integer anInteger = null; 85 | 86 | /* 87 | * TODO: 88 | * Replace the "null" to create a nullable Optional for anInteger. 89 | * Check API: java.util.Optional.ofNullable(?) 90 | */ 91 | Optional optionalNullableInteger = Optional.of(10); 92 | 93 | assertTrue(optionalNullableInteger instanceof Optional, 94 | "The optionalNullableInteger should be an instance of Optional"); 95 | 96 | assertTrue(optionalNullableInteger.isEmpty(), 97 | "The optionalNullableInteger should be empty"); 98 | } 99 | 100 | @Test 101 | @DisplayName("check a non-null Optional has a value") 102 | @Tag("TODO") 103 | @Order(4) 104 | public void checkOptionalForNonNullValueIsPresent() { 105 | 106 | Integer anInteger = 10; 107 | 108 | Optional optionalInteger = Optional.ofNullable(anInteger); 109 | 110 | /* 111 | * TODO: 112 | * Replace the "false" to check that the Optional has a non-null value. 113 | * Check API: java.util.Optional.isPresent() 114 | */ 115 | assertTrue(false, 116 | "The optionalNullableInteger should be present"); 117 | 118 | 119 | anInteger = null; 120 | 121 | optionalInteger = Optional.ofNullable(anInteger); 122 | 123 | /* 124 | * TODO: 125 | * Replace the "true" to check that the Optional has a non-null value. 126 | * Check API: java.util.Optional.isPresent() 127 | */ 128 | assertFalse(true, 129 | "The optionalNullableInteger should not be present"); 130 | 131 | } 132 | 133 | @Test 134 | @DisplayName("fetch from a non-null and from a null holding Optional") 135 | @Tag("TODO") 136 | @Order(5) 137 | public void getValueFromOptionalForNonNullValue() { 138 | 139 | Integer anInteger = 10; 140 | 141 | Optional optionalInteger = Optional.ofNullable(anInteger); 142 | 143 | /* 144 | * TODO: 145 | * Replace the "11" to check that the Optional has a non-null value. 146 | * Check API: java.util.Optional.get() 147 | */ 148 | assertEquals(10, 149 | 11, 150 | "The optionalNullableInteger should be present"); 151 | 152 | 153 | anInteger = null; 154 | 155 | Optional anotherOptionalInteger = Optional.ofNullable(anInteger); 156 | 157 | /* 158 | * TODO: 159 | * Replace the "10" to get the Optional has a null value. 160 | * Verify that the call throws a NoSuchElementException 161 | * Check API: java.util.Optional.get() 162 | */ 163 | assertThrows(NoSuchElementException.class, () -> { 164 | 165 | assertNotEquals(10, 166 | 10, 167 | "This call should throw a NoSuchElementException"); 168 | }); 169 | 170 | } 171 | 172 | } 173 | -------------------------------------------------------------------------------- /java-handles/src/test/java/none/cvg/constructors/TestKataParameteredConstructorInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.constructors; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.invoke.MethodType; 6 | import java.lang.reflect.Constructor; 7 | import java.lang.reflect.InvocationTargetException; 8 | 9 | import none.cvg.handles.DemoClass; 10 | import none.cvg.handles.HandlesKataDisplayNames; 11 | import org.junit.jupiter.api.DisplayName; 12 | import org.junit.jupiter.api.DisplayNameGeneration; 13 | import org.junit.jupiter.api.MethodOrderer; 14 | import org.junit.jupiter.api.Order; 15 | import org.junit.jupiter.api.Tag; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.TestMethodOrder; 18 | 19 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 20 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.junit.jupiter.api.Assertions.fail; 23 | 24 | /* 25 | * TODO: 26 | * This test aims at using MethodHandles to invoke a constructor with a parameter on a class in 27 | * order to create a new instance. 28 | * Each solved test shows how this can be achieved with the traditional reflection calls. 29 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 30 | * the exercise to achieve the same goal with MethodHandles. 31 | */ 32 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 33 | @DisplayName("Invoke DemoClass(String)") 34 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 35 | public class TestKataParameteredConstructorInvocation { 36 | 37 | @Test 38 | @Tag("PASSING") 39 | @Order(1) 40 | public void reflectionParamConstructor() { 41 | 42 | String expectedOutput = "[Constructor Demo]" + 43 | " - Constructor via reflection"; 44 | 45 | try { 46 | 47 | Class demoClassClass = 48 | (Class) Class.forName("none.cvg.handles.DemoClass"); 49 | 50 | Constructor demoClassConstructor = 51 | demoClassClass.getConstructor(String.class); 52 | 53 | DemoClass demoClass = 54 | demoClassConstructor.newInstance("Constructor Demo"); 55 | 56 | assertEquals(expectedOutput, 57 | demoClass.printStuff("Constructor via reflection"), 58 | "Reflection invocation failed"); 59 | 60 | } catch (ClassNotFoundException | NoSuchMethodException | 61 | InstantiationException | IllegalAccessException | InvocationTargetException e) { 62 | 63 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 64 | } 65 | } 66 | 67 | 68 | @Test 69 | @Tag("TODO") 70 | @Order(2) 71 | public void methodHandleParamConstructor() { 72 | 73 | String expectedOutput = "[Constructor Demo] - Constructor via Method Handles"; 74 | 75 | /* 76 | * TODO: 77 | * The API provides a few lookup mechanisms. For a public constructor, on a 78 | * public class, we can use the lookup with minimal checks and trust. 79 | * Public members of public classes are looked up via "public lookups" 80 | * Check API: java.lang.invoke.MethodHandles.publicLookup() 81 | */ 82 | MethodHandles.Lookup publicMethodHandlesLookup = null; 83 | 84 | /* 85 | * TODO: 86 | * Create a methodType instance that matches the constructor that takes a string param 87 | * Constructors should have a void return type 88 | * This constructor has a string parameter 89 | * Search for method that: has a return type of void (Constructor) 90 | * and accepts a String parameter. 91 | * Check API: java.lang.invoke.MethodType.methodType(?, ?) 92 | */ 93 | MethodType methodType = null; // HINT: MethodType.methodType(?, ?); 94 | 95 | try { 96 | 97 | /* 98 | * TODO: 99 | * Replace the "nulls" to find a constructor handle for DemoClass using methodType 100 | * "Find" a constructor of the class via the Lookup instance, 101 | * based on the methodType described above 102 | * Check API: java.lang.invoke.MethodHandles.Lookup.findConstructor(?, ?) 103 | */ 104 | MethodHandle demoClassConstructor = 105 | publicMethodHandlesLookup.findConstructor(null, null); 106 | // Hint: Class and MethodType 107 | 108 | /* 109 | * TODO: 110 | * Invoke the constructor and pass in "Constructor Demo" as the parameter. 111 | * Create an instance of the DemoClass by invoking the method handle 112 | * The MethodHandle has two methods invoke() and invokeExact() 113 | * The invoke() is good for conversion/substitution of param types 114 | * The invokeExact() is great if there is no ambiguity 115 | * Check API: java.lang.invoke.MethodHandle.invokeExact(?) 116 | */ 117 | DemoClass demoClass = 118 | null; //HINT: invokeExact( 119 | //constructor argument(s)); Requires casting. 120 | 121 | assertEquals(expectedOutput, 122 | demoClass.printStuff( 123 | "Constructor via Method Handles"), 124 | "Method handles invocation failed"); 125 | 126 | } catch (NoSuchMethodException | IllegalAccessException e) { 127 | 128 | fail("Failed to execute a constructor invocation via Method Handles: " 129 | + e.getMessage()); 130 | } catch (Throwable t) { 131 | 132 | // invokeExact() throws a Throwable (hence catching Throwable separately). 133 | fail(TEST_FAILURE.getValue() + t.getMessage()); 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /java-optional/src/test/java/none/cvg/optional/TestKata3StreamsAndOptionals.java: -------------------------------------------------------------------------------- 1 | package none.cvg.optional; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.DisplayName; 5 | import org.junit.jupiter.api.MethodOrderer; 6 | import org.junit.jupiter.api.Order; 7 | import org.junit.jupiter.api.Tag; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestMethodOrder; 10 | 11 | import java.util.HashMap; 12 | import java.util.HashSet; 13 | import java.util.Map; 14 | import java.util.Optional; 15 | import java.util.Set; 16 | import java.util.TreeSet; 17 | 18 | import static org.junit.jupiter.api.Assertions.assertEquals; 19 | 20 | /* 21 | * TODO: 22 | * These tests show how Optionals can be used in stream APIs 23 | * The first test demonstrates a simple usage of Optional using isPresent() and get() 24 | * while the second test shows the newer API flatMap() that returns Optionals if they exist 25 | * and discards empty values. 26 | * 27 | * stream(), isPresent(), get() 28 | */ 29 | @DisplayName("Optional - using Optionals in collections with Stream API") 30 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 31 | public class TestKata3StreamsAndOptionals { 32 | 33 | private Set expectedSetOfNameValuePairs; 34 | private Set namesSet = new HashSet<>(); 35 | private Map nameNameValuePairMap = new HashMap<>(); 36 | 37 | private static class NameValuePair implements Comparable { 38 | private String name; 39 | 40 | private String value; 41 | 42 | public NameValuePair() { 43 | } 44 | 45 | public NameValuePair(String name, String value) { 46 | this.name = name; 47 | this.value = value; 48 | } 49 | 50 | public NameValuePair name(final String name) { 51 | this.name = name; 52 | return this; 53 | } 54 | 55 | public NameValuePair value(final String value) { 56 | this.value = value; 57 | return this; 58 | } 59 | 60 | public String getName() { 61 | return name; 62 | } 63 | 64 | public void setName(String name) { 65 | this.name = name; 66 | } 67 | 68 | public String getValue() { 69 | return value; 70 | } 71 | 72 | public void setValue(String value) { 73 | this.value = value; 74 | } 75 | 76 | @Override 77 | public int compareTo(Object o) { 78 | NameValuePair that = (NameValuePair) o; 79 | return this.getName().compareTo(that.getName()); 80 | } 81 | 82 | } 83 | 84 | @BeforeEach 85 | public void setUp() { 86 | expectedSetOfNameValuePairs = new TreeSet<>(); 87 | expectedSetOfNameValuePairs.add(new NameValuePair("ABC", "01_02_03")); 88 | expectedSetOfNameValuePairs.add(new NameValuePair("DEF", "04_05_06")); 89 | expectedSetOfNameValuePairs.add(new NameValuePair("XYZ", "24_25_26")); 90 | 91 | namesSet = new HashSet<>(); 92 | namesSet.add("ABC"); 93 | namesSet.add("DEF"); 94 | namesSet.add("XYZ"); 95 | namesSet.add("ZZZ"); 96 | 97 | nameNameValuePairMap.put("ABC", new NameValuePair("ABC", "01_02_03")); 98 | nameNameValuePairMap.put("DEF", new NameValuePair("DEF", "04_05_06")); 99 | nameNameValuePairMap.put("XYZ", new NameValuePair("XYZ", "24_25_26")); 100 | } 101 | 102 | public Optional findOptionalNameValuePair(String name) { 103 | return Optional.ofNullable(nameNameValuePairMap.get(name)); 104 | } 105 | 106 | @Test 107 | @DisplayName("Java 8 Streaming with Optional") 108 | @Tag("TODO") 109 | @Order(1) 110 | public void java8Example() { 111 | 112 | /* 113 | * TODO: 114 | * Replace the code below to use stream() API: 115 | * 1. stream() the namesSet 116 | * 2. map() to get an Optional using this::findOptionalNameValuePair(?) 117 | * 3. filter() to include non empty Optionals, use Optional::isPresent as predicate 118 | * 4. map() to get the actual NameValuePair object, use Optional::get 119 | * 5. collect() to a Set, use Collectors.toSet() 120 | */ 121 | Set actualNameValuePairs = new TreeSet<>(); 122 | for (String name : namesSet) { 123 | NameValuePair nameValuePair = nameNameValuePairMap.get(name); 124 | if (nameValuePair != null) { 125 | actualNameValuePairs.add(nameValuePair); 126 | } 127 | } 128 | 129 | assertEquals( 130 | expectedSetOfNameValuePairs, 131 | actualNameValuePairs, 132 | "The two collections should be the same"); 133 | } 134 | 135 | @Test 136 | @DisplayName("Java 9 and above Streaming with Optional") 137 | @Tag("TODO") 138 | @Order(2) 139 | public void java9Example() { 140 | /* 141 | * TODO: 142 | * Replace the code below to use stream() API: 143 | * 1. stream() the namesSet 144 | * 2. map() to get an Optional using this::findOptionalNameValuePair(?) 145 | * 3. flatMap() to include non empty Optionals, use Optional::stream flattener 146 | * 4. collect() to a Set, use Collectors.toSet() 147 | */ 148 | Set actualNameValuePairs = new TreeSet<>(); 149 | for (String name : namesSet) { 150 | NameValuePair nameValuePair = nameNameValuePairMap.get(name); 151 | if (nameValuePair != null) { 152 | actualNameValuePairs.add(nameValuePair); 153 | } 154 | } 155 | 156 | assertEquals( 157 | expectedSetOfNameValuePairs, 158 | actualNameValuePairs, 159 | "The two collections should be the same"); 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /java-handles/src/solutions/java/none/cvg/constructors/TestSolutionParameteredConstructorInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.constructors; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.invoke.MethodType; 6 | import java.lang.reflect.Constructor; 7 | import java.lang.reflect.InvocationTargetException; 8 | 9 | import none.cvg.handles.DemoClass; 10 | import none.cvg.handles.HandlesKataDisplayNames; 11 | import org.junit.jupiter.api.DisplayName; 12 | import org.junit.jupiter.api.DisplayNameGeneration; 13 | import org.junit.jupiter.api.MethodOrderer; 14 | import org.junit.jupiter.api.Order; 15 | import org.junit.jupiter.api.Tag; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.TestMethodOrder; 18 | 19 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 20 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.junit.jupiter.api.Assertions.fail; 23 | 24 | /* 25 | * DONE: 26 | * This test aims at using MethodHandles to invoke a constructor with a parameter on a class in 27 | * order to create a new instance. 28 | * Each solved test shows how this can be achieved with the traditional reflection calls. 29 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 30 | * the exercise to achieve the same goal with MethodHandles. 31 | */ 32 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 33 | @DisplayName("Invoke DemoClass(String)") 34 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 35 | public class TestSolutionParameteredConstructorInvocation { 36 | 37 | @Test 38 | @Tag("PASSING") 39 | @Order(1) 40 | public void reflectionParamConstructor() { 41 | 42 | String expectedOutput = "[Constructor Demo]" + 43 | " - Constructor via reflection"; 44 | 45 | try { 46 | 47 | Class demoClassClass = 48 | (Class) Class.forName("none.cvg.handles.DemoClass"); 49 | 50 | Constructor demoClassConstructor = 51 | demoClassClass.getConstructor(String.class); 52 | 53 | DemoClass demoClass = 54 | demoClassConstructor.newInstance("Constructor Demo"); 55 | 56 | assertEquals(expectedOutput, 57 | demoClass.printStuff("Constructor via reflection"), 58 | "Reflection invocation failed"); 59 | 60 | } catch (ClassNotFoundException | NoSuchMethodException | 61 | InstantiationException | IllegalAccessException | InvocationTargetException e) { 62 | 63 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 64 | } 65 | } 66 | 67 | 68 | @Test 69 | @Tag("PASSING") 70 | @Order(2) 71 | public void methodHandleParamConstructor() { 72 | 73 | String expectedOutput = "[Constructor Demo] - Constructor via Method Handles"; 74 | 75 | /* 76 | * DONE: 77 | * The API provides a few lookup mechanisms. For a public constructor, on a 78 | * public class, we can use the lookup with minimal checks and trust. 79 | * Public members of public classes are looked up via "public lookups" 80 | * Check API: java.lang.invoke.MethodHandles.publicLookup() 81 | */ 82 | MethodHandles.Lookup publicMethodHandlesLookup = MethodHandles.publicLookup(); 83 | 84 | /* 85 | * DONE: 86 | * Create a methodType instance that matches the constructor that takes a string param 87 | * Constructors should have a void return type 88 | * This constructor has a string parameter 89 | * Search for method that: has a return type of void (Constructor) 90 | * and accepts a String parameter. 91 | * Check API: java.lang.invoke.MethodType.methodType(?, ?) 92 | */ 93 | MethodType methodType = MethodType.methodType(void.class, String.class); 94 | 95 | try { 96 | 97 | /* 98 | * DONE: 99 | * Replace the "nulls" to find a constructor handle for DemoClass using methodType 100 | * "Find" a constructor of the class via the Lookup instance, 101 | * based on the methodType described above 102 | * Check API: java.lang.invoke.MethodHandles.Lookup.findConstructor(?, ?) 103 | */ 104 | MethodHandle demoClassConstructor = 105 | publicMethodHandlesLookup.findConstructor(DemoClass.class, methodType); 106 | // Hint: Class and MethodType 107 | 108 | /* 109 | * DONE: 110 | * Invoke the constructor and pass in "Constructor Demo" as the parameter. 111 | * Create an instance of the DemoClass by invoking the method handle 112 | * The MethodHandle has two methods invoke() and invokeExact() 113 | * The invoke() is good for conversion/substitution of param types 114 | * The invokeExact() is great if there is no ambiguity 115 | * Check API: java.lang.invoke.MethodHandle.invokeExact(?) 116 | */ 117 | DemoClass demoClass = 118 | (DemoClass) demoClassConstructor.invokeExact( 119 | "Constructor Demo"); 120 | 121 | assertEquals(expectedOutput, 122 | demoClass.printStuff( 123 | "Constructor via Method Handles"), 124 | "Method handles invocation failed"); 125 | 126 | } catch (NoSuchMethodException | IllegalAccessException e) { 127 | 128 | fail("Failed to execute a constructor invocation via Method Handles: " 129 | + e.getMessage()); 130 | } catch (Throwable t) { 131 | 132 | // invokeExact() throws a Throwable (hence catching Throwable separately). 133 | fail(TEST_FAILURE.getValue() + t.getMessage()); 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /java-futures/README.adoc: -------------------------------------------------------------------------------- 1 | = java-futures 2 | :toc: 3 | :toclevels: 4 4 | 5 | image:assets/images/DukeCompletableFuture.png[Duke with Back to the Future Car, 480, 321] 6 | 7 | `java.util.concurrent.CompletableFuture` is a versatile utility in Java (since Java 8).It provides a means of task execution, both synchronous and asynchronous. 8 | 9 | A CompletableFuture implements `java.util.concurrent.Future` (available since Java 5) and `java.util.concurrent.CompletionStage` (available since Java 8) and adds additional methods for operating on tasks. 10 | 11 | Some additional documentation about the three in this kata: 12 | 13 | * link:assets/docs/Future.adoc[Future] 14 | * link:assets/docs/CompletionStage.adoc[CompletionStage] 15 | * link:assets/docs/CompletableFuture.adoc[CompletableFuture] 16 | 17 | A special lookup for exception handling: 18 | 19 | * link:assets/docs/Exceptions.adoc[Exception Handling in CompletableFuture] 20 | 21 | == What is a Code-Kata 22 | 23 | A code-kata is a coding exercise that builds muscle memory by a practice of programming to arrive 24 | at a known solution. 25 | 26 | === How does one go about with this code kata? 27 | 28 | The essence of the exercise (presentation material and code kata) is to demonstrate the 29 | usage patterns for the java API or functionality. 30 | 31 | This set of code katas rely on fixing broken tests. The tests may have multiple solutions, the 32 | intent is to learn and experiment. 33 | 34 | The project contains several JUnit tests that fail. 35 | 36 | ==== Simple steps to use this kata 37 | 38 | . Run the test class(es). 39 | . One or more tests will fail with the test failure message. 40 | . Fix the failing tests by using `HINT` and `TODO` comments. 41 | . Repeat above steps until all tests pass. 42 | . Check the solutions to see if there are other ways to solve. 43 | (Remember, the solution may be less performant/optimal than yours) 44 | . Rinse and repeat (delete and checkout again, then back to Step 1) to build muscle memory. 45 | 46 | === Mission 47 | > Your mission, should you choose to accept it, will be to fix the JUnit tests. This 48 | message will self-destruct in `**NaN**` minutes. 49 | 50 | == Requirements 51 | How to prepare for coding along 52 | 53 | This kata is developed as a Java maven project. Ensure that you have: 54 | 55 | . Apache Maven 3.6.x or above. _Tested with Apache Maven 3.6.3_. 56 | Link: https://maven.apache.org/download.cgi 57 | 58 | . JDK 11 or above. _Tested with OpenJDK 16_ 59 | Link: http://jdk.java.net/11/ 60 | 61 | . Your favorite Java IDE. _IntelliJ IDEA Ultimate was used to develop this kata_. 62 | 63 | == Project Structure 64 | 65 | The structure of the project: 66 | 67 | [source] 68 | ---- 69 | |____pom.xml 70 | |____README.adoc <------------------- This file 71 | |____assets 72 | | |____docs <------------------- Documentation 73 | | |____images 74 | |____src 75 | | |____test <------------------- Kata Tests 76 | | | |____java 77 | | | |____none 78 | | | |____cvg 79 | | | |____futures 80 | | |____solutions <------------------- Solutions 81 | | | |____java 82 | | | |____none 83 | | | |____cvg 84 | | | |____futures 85 | ---- 86 | 87 | == Tests Included 88 | 89 | === Java CompletableFuture 90 | 91 | The JUnit tests listed below are set up to utilize the Java CompletableFuture API features. 92 | 93 | 94 | link:src/test/java/none/cvg/futures/TestKata1SimpleCompletableFutureOperations.java[TestKata1SimpleCompletableFutureOperations.java]:: covers the basic features of creating CompletableFuture instances and fetching results. 95 | 96 | link:src/test/java/none/cvg/futures/TestKata2HandleExceptionsInCompletableFuture.java[TestKata2HandleExceptionsInCompletableFuture.java]:: covers how CompletableFuture exceptions are handled. + 97 | Also check: link:assets/docs/Exceptions.adoc[Tabulated Exception Handling in CompletableFuture] 98 | 99 | link:src/test/java/none/cvg/futures/TestKata3CompletableFutureExecutions.java[TestKata3CompletableFutureExecutions.java]:: covers some common executions in CompletableFuture. 100 | 101 | link:src/test/java/none/cvg/futures/TestKata4CompletableFutureChaining.java[TestKata4CompletableFutureChaining.java]:: covers CompletableFuture chaining. 102 | 103 | link:src/test/java/none/cvg/futures/TestKata5CompletableFutureCombinations.java[TestKata5CompletableFutureCombinations.java]:: Tcovers a few common combinations in CompletableFuture. 104 | 105 | 106 | == Solutions 107 | 108 | .Solutions for each test 109 | |=== 110 | | Kata Test | Solution 111 | 112 | |link:src/test/java/none/cvg/futures/TestKata1SimpleCompletableFutureOperations.java[TestKata1SimpleCompletableFutureOperations.java] 113 | |link:src/solutions/java/none/cvg/futures/TestSolution1SimpleCompletableFutureOperations.java[TestSolution1SimpleCompletableFutureOperations.java] 114 | 115 | |link:src/test/java/none/cvg/futures/TestKata2HandleExceptionsInCompletableFuture.java[TestKata2HandleExceptionsInCompletableFuture.java] 116 | |link:src/solutions/java/none/cvg/futures/TestSolution2HandleExceptionsInCompletableFuture.java[TestSolution2HandleExceptionsInCompletableFuture.java]. 117 | 118 | |link:src/test/java/none/cvg/futures/TestKata3CompletableFutureExecutions.java[TestKata3CompletableFutureExecutions.java] 119 | |link:src/solutions/java/none/cvg/futures/TestSolution3CompletableFutureExecutions.java[TestSolution3CompletableFutureExecutions.java] 120 | 121 | |link:src/test/java/none/cvg/futures/TestKata4CompletableFutureChaining.java[TestKata4CompletableFutureChaining.java] 122 | |link:src/solutions/java/none/cvg/futures/TestSolution4CompletableFutureChaining.java[TestSolution4CompletableFutureChaining.java] 123 | 124 | |link:src/test/java/none/cvg/futures/TestKata5CompletableFutureCombinations.java[TestKata5CompletableFutureCombinations.java] 125 | |link:src/solutions/java/none/cvg/futures/TestSolution5CompletableFutureCombinations.java[TestSolution5CompletableFutureCombinations.java] 126 | 127 | |=== 128 | 129 | 130 | == Take Away 131 | 132 | The key take-away from this kata is a solid understanding of the Java CompletableFuture API. 133 | -------------------------------------------------------------------------------- /java-futures/src/test/java/none/cvg/futures/TestKata1SimpleCompletableFutureOperations.java: -------------------------------------------------------------------------------- 1 | package none.cvg.futures; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.DisplayName; 5 | import org.junit.jupiter.api.MethodOrderer; 6 | import org.junit.jupiter.api.Order; 7 | import org.junit.jupiter.api.Tag; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestMethodOrder; 10 | 11 | import java.util.concurrent.CompletableFuture; 12 | 13 | import static org.junit.jupiter.api.Assertions.assertEquals; 14 | import static org.junit.jupiter.api.Assertions.assertNotNull; 15 | import static org.junit.jupiter.api.Assertions.assertTrue; 16 | import static org.junit.jupiter.api.Assertions.fail; 17 | 18 | /* 19 | * This test covers the basic features of creating CompletableFuture instances and fetching 20 | * results. 21 | */ 22 | @DisplayName("Simple CompletableFuture operations to: ") 23 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 24 | public class TestKata1SimpleCompletableFutureOperations { 25 | 26 | private static final String REPLACE_THIS = ""; 27 | 28 | @BeforeEach 29 | public void setUp() { 30 | } 31 | 32 | @DisplayName("create a completed CompletableFuture") 33 | @Test 34 | @Tag("TODO") 35 | @Order(1) 36 | public void createCompletedCompletableFuture() { 37 | 38 | String successMessage = "This is a completed future"; 39 | 40 | // completedFuture() returns a new CompletableFuture that is already completed with the 41 | // given value. 42 | // TODO: 43 | // Create a completedFuture. Replace the null with a completedFuture. 44 | // HINT: 45 | // • Use the static CompletableFuture.completedFuture() method with 46 | // the successMessage. 47 | CompletableFuture completedFuture = 48 | null; 49 | 50 | assertNotNull(completedFuture, 51 | "The completedFuture should be null"); 52 | 53 | assertTrue(completedFuture instanceof CompletableFuture, 54 | "The completedFuture should be an instance of CompletableFuture"); 55 | } 56 | 57 | @DisplayName("create a failed CompletableFuture") 58 | @Test 59 | @Tag("TODO") 60 | @Order(2) 61 | public void failedCompletableFuture() { 62 | 63 | String exceptionMessage = "This CompletableFuture has failed"; 64 | 65 | // failedFuture() returns a new CompletableFuture that is already completed 66 | // exceptionally with the given exception. 67 | // TODO: 68 | // Create a failedFuture. Replace the null with a failedFuture. 69 | // HINT: 70 | // • Use the static CompletableFuture.failedFuture() method with 71 | // a new RuntimeException(exceptionMessage). 72 | CompletableFuture failedFuture = 73 | null; 74 | 75 | assertNotNull(failedFuture, 76 | "The completedFuture should be null"); 77 | 78 | assertTrue(failedFuture instanceof CompletableFuture, 79 | "The completedFuture should be an instance of CompletableFuture"); 80 | } 81 | 82 | @DisplayName("check if a future is completed") 83 | @Test 84 | @Tag("TODO") 85 | @Order(3) 86 | public void checkCompletableFuture() { 87 | 88 | String successMessage = "This is a completed future"; 89 | 90 | CompletableFuture completedFuture = CompletableFuture 91 | .completedFuture(successMessage); 92 | 93 | // TODO: 94 | // Check if the completedFuture is done. Replace the 'false' with a check. 95 | // HINT: 96 | // • Use the instance method isDone() on CompletableFuture. 97 | assertTrue(false, 98 | "The completedFuture should be done"); 99 | } 100 | 101 | @DisplayName("get the value of a CompletableFuture using get()") 102 | @Test 103 | @Tag("TODO") 104 | @Order(4) 105 | public void valueOfCompletableFutureUsingGet() { 106 | 107 | String successMessage = "This is a completed future"; 108 | 109 | CompletableFuture completedFuture = CompletableFuture 110 | .completedFuture(successMessage); 111 | 112 | try { 113 | // TODO: 114 | // Get the value of the completedFuture. Replace the REPLACE_THIS_STRING with a 115 | // valid call. 116 | // HINT: 117 | // • Use the instance method get() on CompletableFuture. 118 | // • The get() method throws checked exceptions, which need to be caught and handled. 119 | assertEquals(successMessage, 120 | REPLACE_THIS, 121 | "The completedFuture value should return the content of successMessage"); 122 | // TODO: 123 | // Replace the catch-block with right Exceptions thrown by the get(). 124 | } catch (Exception e) { 125 | fail("Failed to get the value of the CompletedFuture"); 126 | } 127 | } 128 | 129 | @DisplayName("get the value of a CompletableFuture using join()") 130 | @Test 131 | @Tag("TODO") 132 | @Order(5) 133 | public void valueOfCompletableFutureUsingJoin() { 134 | 135 | String successMessage = "This is a completed future"; 136 | 137 | CompletableFuture completedFuture = CompletableFuture 138 | .completedFuture(successMessage); 139 | 140 | // TODO: 141 | // Get the value of the completedFuture. Replace the REPLACE_THIS_STRING with a 142 | // valid call. 143 | // HINT: 144 | // • Use the instance method join() on CompletableFuture. 145 | // • The join() method throws unchecked exceptions, which need not be caught. 146 | // The join method throws the following RuntimeExceptions: 147 | // • java.util.concurrent.CancellationException 148 | // • java.util.concurrent.CompletionException 149 | assertEquals(successMessage, 150 | REPLACE_THIS, 151 | "The completedFuture value should return the content of successMessage"); 152 | } 153 | } -------------------------------------------------------------------------------- /java-optional/src/solutions/java/none/cvg/optional/TestSolution1OptionalCreationAndFetchingValues.java: -------------------------------------------------------------------------------- 1 | package none.cvg.optional; 2 | 3 | import java.util.NoSuchElementException; 4 | import java.util.Optional; 5 | 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.DisplayName; 8 | import org.junit.jupiter.api.DisplayNameGeneration; 9 | import org.junit.jupiter.api.MethodOrderer; 10 | import org.junit.jupiter.api.Order; 11 | import org.junit.jupiter.api.Tag; 12 | import org.junit.jupiter.api.Test; 13 | import org.junit.jupiter.api.TestMethodOrder; 14 | 15 | import static org.junit.jupiter.api.Assertions.assertEquals; 16 | import static org.junit.jupiter.api.Assertions.assertFalse; 17 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 18 | import static org.junit.jupiter.api.Assertions.assertThrows; 19 | import static org.junit.jupiter.api.Assertions.assertTrue; 20 | 21 | /* 22 | * DONE: 23 | * This test aims at understanding the basic features of Optional 24 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 25 | * the exercise. 26 | * 27 | * empty(), of(?), ofNullable(?), isPresent(), get() 28 | */ 29 | @DisplayName("java.util.Optional Creation And Getting value") 30 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 31 | public class TestSolution1OptionalCreationAndFetchingValues { 32 | 33 | @BeforeEach 34 | public void setUp() { 35 | } 36 | 37 | @Test 38 | @DisplayName("create an empty Optional") 39 | @Tag("PASSING") 40 | @Order(1) 41 | public void emptyOptional() { 42 | 43 | /* 44 | * DONE: 45 | * Replace the "null" to create an empty Optional. 46 | * Check API: java.util.Optional.empty() 47 | */ 48 | Optional optionalEmptyString = Optional.empty(); 49 | 50 | assertTrue(optionalEmptyString instanceof Optional, 51 | "The optionalEmptyString should be an instance of Optional"); 52 | 53 | assertTrue(optionalEmptyString.isEmpty(), 54 | "The optionalEmptyString should be empty"); 55 | } 56 | 57 | @Test 58 | @DisplayName("create an Optional from a variable") 59 | @Tag("PASSING") 60 | @Order(2) 61 | public void createOptionalFromValue() { 62 | 63 | Integer anInteger = 10; 64 | 65 | /* 66 | * DONE: 67 | * Replace the "null" to create an Optional for anInteger. 68 | * Check API: java.util.Optional.of(?) 69 | */ 70 | Optional optionalForInteger = Optional.of(anInteger); 71 | 72 | assertTrue(optionalForInteger instanceof Optional, 73 | "The optionalEmptyString should be an instance of Optional"); 74 | 75 | assertFalse(optionalForInteger.isEmpty(), 76 | "The optionalForInteger should not be empty"); 77 | } 78 | 79 | @Test 80 | @DisplayName("create a nullable Optional from a variable") 81 | @Tag("PASSING") 82 | @Order(3) 83 | public void createNullableOptionalFromValue() { 84 | 85 | Integer anInteger = null; 86 | 87 | /* 88 | * DONE: 89 | * Replace the "null" to create a nullable Optional for anInteger. 90 | * Check API: java.util.Optional.ofNullable(?) 91 | */ 92 | Optional optionalNullableInteger = Optional.ofNullable(anInteger); 93 | 94 | assertTrue(optionalNullableInteger instanceof Optional, 95 | "The optionalNullableInteger should be an instance of Optional"); 96 | 97 | assertTrue(optionalNullableInteger.isEmpty(), 98 | "The optionalNullableInteger should be empty"); 99 | } 100 | 101 | @Test 102 | @DisplayName("check a non-null Optional has a value") 103 | @Tag("PASSING") 104 | @Order(4) 105 | public void checkOptionalForNonNullValueIsPresent() { 106 | 107 | Integer anInteger = 10; 108 | 109 | Optional optionalInteger = Optional.ofNullable(anInteger); 110 | 111 | /* 112 | * DONE: 113 | * Replace the "false" to check that the Optional has a non-null value. 114 | * Check API: java.util.Optional.isPresent() 115 | */ 116 | assertTrue(optionalInteger.isPresent(), 117 | "The optionalNullableInteger should be present"); 118 | 119 | 120 | anInteger = null; 121 | 122 | optionalInteger = Optional.ofNullable(anInteger); 123 | 124 | /* 125 | * DONE: 126 | * Replace the "false" to check that the Optional has a non-null value. 127 | * Check API: java.util.Optional.isPresent() 128 | */ 129 | assertFalse(optionalInteger.isPresent(), 130 | "The optionalNullableInteger should not be present"); 131 | 132 | } 133 | 134 | @Test 135 | @DisplayName("fetch from a non-null and from a null holding Optional") 136 | @Tag("PASSING") 137 | @Order(5) 138 | public void getValueFromOptionalForNonNullValue() { 139 | 140 | Integer anInteger = 10; 141 | 142 | Optional optionalInteger = Optional.ofNullable(anInteger); 143 | 144 | /* 145 | * DONE: 146 | * Replace the "null" to check that the Optional has a non-null value. 147 | * Check API: java.util.Optional.get() 148 | */ 149 | assertEquals(10, 150 | optionalInteger.get(), 151 | "The optionalNullableInteger should be present"); 152 | 153 | 154 | anInteger = null; 155 | 156 | Optional anotherOptionalInteger = Optional.ofNullable(anInteger); 157 | 158 | /* 159 | * DONE: 160 | * Replace the "null" to get the Optional has a null value. 161 | * Verify that the call throws a NoSuchElementException 162 | * Check API: java.util.Optional.get() 163 | */ 164 | assertThrows(NoSuchElementException.class, () -> { 165 | 166 | assertNotEquals(10, 167 | anotherOptionalInteger.get(), 168 | "This call should throw a NoSuchElementException"); 169 | }); 170 | 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /java-lambdas/src/solutions/java/none/cvg/lambdas/TestSolution1LambdaBasics.java: -------------------------------------------------------------------------------- 1 | package none.cvg.lambdas; 2 | 3 | import org.junit.jupiter.api.DisplayName; 4 | import org.junit.jupiter.api.DisplayNameGeneration; 5 | import org.junit.jupiter.api.MethodOrderer; 6 | import org.junit.jupiter.api.Order; 7 | import org.junit.jupiter.api.Tag; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestMethodOrder; 10 | 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | import java.util.function.Function; 13 | 14 | import static org.junit.jupiter.api.Assertions.assertEquals; 15 | 16 | /** 17 | * The tests in this class aim to show how functions can be invoked as lambdas 18 | * and method references 19 | * 20 | * @see Function 21 | */ 22 | @DisplayNameGeneration(LambdasKataDisplayNames.class) 23 | @DisplayName("Lambdas and Method Reference Basics") 24 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 25 | public class TestSolution1LambdaBasics { 26 | 27 | /** 28 | * @see IntegerPairFactory 29 | * @see IntegerPair 30 | */ 31 | @Test 32 | @Tag("PASSING") 33 | @Order(1) 34 | public void newObjectUsingLambdas() { 35 | IntegerPair classic = new IntegerPair(); 36 | 37 | // DONE: 38 | // Replace the anonymous class with a lambda. 39 | // Hint: () -> new object() 40 | IntegerPairFactory integerPairFactory = () -> new IntegerPair(); 41 | 42 | assertEquals(classic, integerPairFactory.get(), 43 | "Both objects should be equal"); 44 | } 45 | 46 | /** 47 | * @see IntegerPairFactory 48 | * @see IntegerPair 49 | */ 50 | @Test 51 | @Tag("PASSING") 52 | @Order(2) 53 | public void newObjectUsingMethodReferences() { 54 | IntegerPair classic = new IntegerPair(); 55 | 56 | // TODO: 57 | // Replace the anonymous class with a method reference. 58 | // Hint: () -> Object::new 59 | IntegerPairFactory integerPairFactory = IntegerPair::new; 60 | 61 | assertEquals(classic, integerPairFactory.get(), 62 | "Both objects should be equal"); 63 | } 64 | 65 | /** 66 | * @see IntegerPair 67 | * @see Function 68 | */ 69 | @Test 70 | @Tag("PASSING") 71 | @Order(3) 72 | public void methodCallAsLambda() { 73 | IntegerPair integerPair = new IntegerPair(); 74 | 75 | // DONE: 76 | // Replace the below anonymous class with a lambda call 77 | // Most IDEs allow for an automatic conversion 78 | // Hint: object -> object.method() 79 | Function getSecond = integerPair1 -> integerPair1.getSecond(); 80 | 81 | // DONE: 82 | // Fix the assertion to return the correct expectation (6) 83 | // Check API: java.util.function.Function.apply(?) 84 | assertEquals(6, getSecond.apply(integerPair), 85 | "The key should have a value of \'defaultKey\'"); 86 | } 87 | 88 | /** 89 | * @see IntegerPair 90 | * @see Function 91 | */ 92 | @Test 93 | @Tag("PASSING") 94 | @Order(4) 95 | public void methodCallAsMethodReference() { 96 | IntegerPair integerPair = new IntegerPair(); 97 | 98 | // DONE: 99 | // Replace the below anonymous class with a method reference 100 | // Most IDEs allow for an automatic conversion (no parenthesis for method) 101 | // Hint: object -> Object::method 102 | Function getSecond = IntegerPair::getSecond; 103 | 104 | // DONE: 105 | // Fix the assertion to return the correct expectation (6) 106 | // Check API: java.util.function.Function.apply(?) 107 | assertEquals(6, getSecond.apply(integerPair), 108 | "The key should have a value of \'defaultKey\'"); 109 | } 110 | 111 | @Test 112 | @Tag("PASSING") 113 | @Order(5) 114 | public void convertAnonymousClassToLambda() { 115 | 116 | final AtomicInteger counter = new AtomicInteger(); 117 | 118 | // DONE: 119 | // Replace the anonymous class with a lambda. Hint: () -> 120 | // The addAndGet() needs to be updated to add 1 instead of 0. 121 | Runnable runnable = () -> counter.addAndGet(1); 122 | 123 | runnable.run(); 124 | 125 | assertEquals(1, counter.get() ); 126 | } 127 | 128 | @Test 129 | @Tag("PASSING") 130 | @Order(6) 131 | public void customFunctionWithLambda() { 132 | 133 | int integer = 10; 134 | 135 | String s = Integer.toBinaryString(integer); 136 | 137 | // DONE: 138 | // Create a Function that maps any integer into a String using a lambda syntax 139 | // Do not create a new method. Replace the empty String below to invoke a toBinaryString 140 | // Check API: java.util.function.Function 141 | // Check API: java.util.function.Function.apply(?) 142 | Function toBinaryStringFunction = i -> Integer.toBinaryString(i); 143 | 144 | assertEquals("1010", 145 | toBinaryStringFunction.apply(10), 146 | ""); 147 | 148 | assertEquals("11110", 149 | toBinaryStringFunction.apply(30), 150 | ""); 151 | 152 | } 153 | 154 | @Test 155 | @Tag("PASSING") 156 | @Order(7) 157 | public void customFunctionWithMethodReference() { 158 | 159 | // DONE: 160 | // Create a Function that maps any integer into a String using a method reference 161 | // Do not create a new method. Replace the lambda below to invoke a toBinaryString 162 | // as a method reference 163 | // Check API: java.util.function.Function 164 | // Check API: java.util.function.Function.apply(?) 165 | // Check API: java.lang.Integer.toBinaryString(?) 166 | Function toBinaryStringFunction = Integer::toBinaryString; 167 | 168 | assertEquals("1010", 169 | toBinaryStringFunction.apply(10), 170 | ""); 171 | 172 | assertEquals("11110", 173 | toBinaryStringFunction.apply(30), 174 | ""); 175 | 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /java-handles/src/test/java/none/cvg/methods/TestKataPrivateMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.methods; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.lang.reflect.Method; 7 | 8 | import none.cvg.handles.DemoClass; 9 | import none.cvg.handles.HandlesKataDisplayNames; 10 | import org.junit.jupiter.api.DisplayName; 11 | import org.junit.jupiter.api.DisplayNameGeneration; 12 | import org.junit.jupiter.api.MethodOrderer; 13 | import org.junit.jupiter.api.Order; 14 | import org.junit.jupiter.api.Tag; 15 | import org.junit.jupiter.api.Test; 16 | import org.junit.jupiter.api.TestMethodOrder; 17 | 18 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 19 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | import static org.junit.jupiter.api.Assertions.fail; 22 | 23 | /* 24 | * TODO: 25 | * This test aims at using MethodHandles to invoke a private method on a class. 26 | * Each solved test shows how this can be achieved with the traditional reflection calls. 27 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 28 | * the exercise to achieve the same goal with MethodHandles. 29 | */ 30 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 31 | @DisplayName("Invoke DemoClass.privateMethod(String)") 32 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 33 | public class TestKataPrivateMethodInvocation { 34 | 35 | @Test 36 | @Tag("PASSING") 37 | @Order(1) 38 | public void reflectionPrivateMethod() { 39 | 40 | String expectedOutput = "[DemoClass] - Private method via reflection"; 41 | 42 | try { 43 | 44 | // Cannot call getMethod(), use getDeclaredMethod() to get private and protected methods 45 | Method privateMethod = 46 | DemoClass.class.getDeclaredMethod("privateMethod", 47 | String.class); 48 | 49 | /* 50 | * Method has to be made accessible. 51 | * Not setting this will cause IllegalAccessException 52 | * Setting accessible to true causes the JVM to skip access control checks 53 | * 54 | * This is needed to access non-public content 55 | */ 56 | privateMethod.setAccessible(true); 57 | 58 | DemoClass demoClass = new DemoClass(); 59 | 60 | assertEquals(expectedOutput, 61 | privateMethod.invoke(demoClass, "via reflection"), 62 | "Reflection invocation failed"); 63 | 64 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 65 | 66 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 67 | } 68 | } 69 | 70 | @Test 71 | @Tag("TODO") 72 | @Order(2) 73 | public void methodHandlePrivateMethod() { 74 | 75 | String expectedOutput = "[DemoClass] - Private method via Method Handles"; 76 | 77 | /* 78 | * TODO: 79 | * Get a non-public lookup from java.lang.invoke.MethodHandles 80 | * Non-public methods are looked up via "lookup" 81 | * Find the differences between lookup() and publicLookup() on MethodHandles. 82 | * Check API: java.lang.invoke.MethodHandles.lookup() 83 | */ 84 | MethodHandles.Lookup privateMethodHandlesLookup = null; 85 | 86 | try { 87 | 88 | /* 89 | * TODO: 90 | * Replace the "null"s with valid values to produce a privateMethod instance. 91 | * Create a method instance that matches the name "privateMethod()" 92 | * See java.lang.class for a getDeclaredMethod() 93 | * Look for the declared method on the DemoClass.class 94 | * The privateMethod() needs a String input parameter. 95 | * Same call as is used in vanilla reflection. 96 | * Check API: java.lang.Class.getDeclaredMethod(?, ?) 97 | */ 98 | Method privateMethod = 99 | DemoClass.class.getDeclaredMethod(null, 100 | null); // Method name, Class ... = Parameter types 101 | 102 | /* 103 | * Method has to be made accessible. 104 | * Not setting this will cause IllegalAccessException 105 | * Setting accessible to true causes the JVM to skip access control checks 106 | * 107 | * This is needed to access non-public content 108 | */ 109 | privateMethod.setAccessible(true); 110 | 111 | /* 112 | * TODO: 113 | * Replace the "null" with a valid value to get an unreflected private method handle. 114 | * Unreflect to create a method handle from a method instance 115 | * Generate a MethodHandle from the method instance created earlier. 116 | * See unreflect method in the innerclass Lookup of MethodHandles. 117 | * java.lang.invoke.MethodHandles.Lookup.unreflect() 118 | * We can unreflect the method since we bypassed the access control checks above. 119 | * Check API: java.lang.invoke.MethodHandles.Lookup.unreflect(?) 120 | */ 121 | MethodHandle privateMethodHandle = 122 | privateMethodHandlesLookup.unreflect(null); 123 | 124 | DemoClass demoClass = new DemoClass(); 125 | 126 | assertEquals(expectedOutput, 127 | privateMethodHandle.invoke(demoClass, 128 | "via Method Handles"), 129 | "Method handles invocation failed"); 130 | 131 | } catch (NoSuchMethodException | IllegalAccessException e) { 132 | 133 | fail("Failed to execute a private method invocation via Method Handles: " 134 | + e.getMessage()); 135 | } catch (Throwable t) { 136 | 137 | // invoke throws a Throwable (hence catching Throwable separately). 138 | fail(TEST_FAILURE.getValue() + t.getMessage()); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /java-handles/src/test/java/none/cvg/methods/TestKataProtectedMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.methods; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.lang.reflect.Method; 7 | 8 | import none.cvg.handles.DemoClass; 9 | import none.cvg.handles.HandlesKataDisplayNames; 10 | import org.junit.jupiter.api.DisplayName; 11 | import org.junit.jupiter.api.DisplayNameGeneration; 12 | import org.junit.jupiter.api.MethodOrderer; 13 | import org.junit.jupiter.api.Order; 14 | import org.junit.jupiter.api.Tag; 15 | import org.junit.jupiter.api.Test; 16 | import org.junit.jupiter.api.TestMethodOrder; 17 | 18 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 19 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | import static org.junit.jupiter.api.Assertions.fail; 22 | 23 | /* 24 | * TODO: 25 | * This test aims at using MethodHandles to invoke a protected method on a class. 26 | * Each solved test shows how this can be achieved with the traditional reflection calls. 27 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 28 | * the exercise to achieve the same goal with MethodHandles. 29 | */ 30 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 31 | @DisplayName("Invoke DemoClass.protectedMethod(String)") 32 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 33 | public class TestKataProtectedMethodInvocation { 34 | 35 | @Test 36 | @Tag("PASSING") 37 | @Order(1) 38 | public void reflectionProtectedMethod() { 39 | 40 | String expectedOutput = "[DemoClass] - Protected method via reflection"; 41 | 42 | try { 43 | 44 | // Cannot call getMethod(), use getDeclaredMethod() to get private and protected methods 45 | Method protectedMethod = 46 | DemoClass.class.getDeclaredMethod("protectedMethod", 47 | String.class); 48 | 49 | /* 50 | * Method has to be made accessible. 51 | * Not setting this will cause IllegalAccessException 52 | * Setting accessible to true causes the JVM to skip access control checks 53 | * 54 | * This is needed to access non-public content 55 | */ 56 | protectedMethod.setAccessible(true); 57 | 58 | DemoClass demoClass = new DemoClass(); 59 | 60 | assertEquals(expectedOutput, 61 | protectedMethod.invoke(demoClass, "via reflection"), 62 | "Reflection invocation failed"); 63 | 64 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 65 | 66 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 67 | } 68 | } 69 | 70 | @Test 71 | @Order(2) 72 | @Tag("TODO") 73 | public void methodHandleProtectedMethod() { 74 | 75 | String expectedOutput = "[DemoClass] - Protected method via Method Handles"; 76 | 77 | /* 78 | * TODO: 79 | * Get a non-public lookup from java.lang.invoke.MethodHandles 80 | * Non-public methods are looked up via "lookup" 81 | * Find the differences between lookup() and publicLookup() on MethodHandles. 82 | * Check API: java.lang.invoke.MethodHandles.lookup() 83 | */ 84 | MethodHandles.Lookup protectedMethodHandlesLookup = null; 85 | 86 | try { 87 | 88 | /* 89 | * TODO: 90 | * Replace the "null"s valid values to create a protectedMethod instance. 91 | * Create a method instance that matches the name "protectedMethod()" 92 | * See java.lang.class for a getDeclaredMethod() 93 | * Look for the declared method on the DemoClass.class 94 | * The protectedMethod() accepts a String input parameter. 95 | * Same call as is used in vanilla reflection. 96 | * Check API: java.lang.Class.getDeclaredMethod(?, ?) 97 | */ 98 | Method protectedMethod = 99 | DemoClass.class.getDeclaredMethod(null, 100 | null); // Method name, Class ... = Parameter types 101 | 102 | /* 103 | * Method has to be made accessible. 104 | * Not setting this will cause IllegalAccessException 105 | * Setting accessible to true causes the JVM to skip access control checks 106 | * 107 | * This is needed to access non-public content 108 | */ 109 | protectedMethod.setAccessible(true); 110 | 111 | /* 112 | * TODO: 113 | * Replace the null with the method instance to produce a protectedMethod handle. 114 | * Unreflect to create a method handle from a method instance 115 | * Generate a MethodHandle from the method instance created earlier. 116 | * See unreflect method in the innerclass Lookup of MethodHandles. 117 | * java.lang.invoke.MethodHandles.Lookup.unreflect() 118 | * We can unreflect the method since we bypassed the access control checks above. 119 | * Check API: java.lang.invoke.MethodHandles.Lookup.unreflect(?) 120 | */ 121 | MethodHandle protectedMethodHandle = 122 | protectedMethodHandlesLookup.unreflect(null); 123 | 124 | DemoClass demoClass = new DemoClass(); 125 | 126 | assertEquals(expectedOutput, 127 | protectedMethodHandle.invoke(demoClass, 128 | "via Method Handles"), 129 | "Method handles invocation failed"); 130 | 131 | } catch (NoSuchMethodException | IllegalAccessException e) { 132 | 133 | fail("Failed to execute a protected method invocation via Method Handles: " 134 | + e.getMessage()); 135 | } catch (Throwable t) { 136 | 137 | // invoke throws a Throwable (hence catching Throwable separately). 138 | fail(TEST_FAILURE.getValue() + t.getMessage()); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /java-handles/src/solutions/java/none/cvg/methods/TestSolutionPrivateMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.methods; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.lang.reflect.Method; 7 | 8 | import none.cvg.handles.DemoClass; 9 | import none.cvg.handles.HandlesKataDisplayNames; 10 | import org.junit.jupiter.api.DisplayName; 11 | import org.junit.jupiter.api.DisplayNameGeneration; 12 | import org.junit.jupiter.api.MethodOrderer; 13 | import org.junit.jupiter.api.Order; 14 | import org.junit.jupiter.api.Tag; 15 | import org.junit.jupiter.api.Test; 16 | import org.junit.jupiter.api.TestMethodOrder; 17 | 18 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 19 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | import static org.junit.jupiter.api.Assertions.fail; 22 | 23 | /* 24 | * DONE: 25 | * This test aims at using MethodHandles to invoke a private method on a class. 26 | * Each solved test shows how this can be achieved with the traditional reflection calls. 27 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 28 | * the exercise to achieve the same goal with MethodHandles. 29 | */ 30 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 31 | @DisplayName("Invoke DemoClass.privateMethod(String)") 32 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 33 | public class TestSolutionPrivateMethodInvocation { 34 | 35 | @Test 36 | @Tag("PASSING") 37 | @Order(1) 38 | public void reflectionPrivateMethod() { 39 | 40 | String expectedOutput = "[DemoClass] - Private method via reflection"; 41 | 42 | try { 43 | 44 | // Cannot call getMethod(), use getDeclaredMethod() to get private and protected methods 45 | Method privateMethod = 46 | DemoClass.class.getDeclaredMethod("privateMethod", 47 | String.class); 48 | 49 | /* 50 | * Method has to be made accessible. 51 | * Not setting this will cause IllegalAccessException 52 | * Setting accessible to true causes the JVM to skip access control checks 53 | * 54 | * This is needed to access non-public content 55 | */ 56 | privateMethod.setAccessible(true); 57 | 58 | DemoClass demoClass = new DemoClass(); 59 | 60 | assertEquals(expectedOutput, 61 | privateMethod.invoke(demoClass, "via reflection"), 62 | "Reflection invocation failed"); 63 | 64 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 65 | 66 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 67 | } 68 | } 69 | 70 | @Test 71 | @Tag("PASSING") 72 | @Order(2) 73 | public void methodHandlePrivateMethod() { 74 | 75 | String expectedOutput = "[DemoClass] - Private method via Method Handles"; 76 | 77 | /* 78 | * DONE: 79 | * Get a non-public lookup from java.lang.invoke.MethodHandles 80 | * Non-public methods are looked up via "lookup" 81 | * Find the differences between lookup() and publicLookup() on MethodHandles. 82 | * Check API: java.lang.invoke.MethodHandles.lookup() 83 | */ 84 | MethodHandles.Lookup privateMethodHandlesLookup = MethodHandles.lookup(); 85 | 86 | try { 87 | 88 | /* 89 | * DONE: 90 | * Replace the "null"s with valid values to produce a privateMethod instance. 91 | * Create a method instance that matches the name "privateMethod()" 92 | * See java.lang.class for a getDeclaredMethod() 93 | * Look for the declared method on the DemoClass.class 94 | * The privateMethod() needs a String input parameter. 95 | * Same call as is used in vanilla reflection. 96 | * Check API: java.lang.Class.getDeclaredMethod(?, ?) 97 | */ 98 | Method privateMethod = 99 | DemoClass.class.getDeclaredMethod("privateMethod", 100 | String.class); // Method name, Class ... = Parameter types 101 | 102 | /* 103 | * Method has to be made accessible. 104 | * Not setting this will cause IllegalAccessException 105 | * Setting accessible to true causes the JVM to skip access control checks 106 | * 107 | * This is needed to access non-public content 108 | */ 109 | privateMethod.setAccessible(true); 110 | 111 | /* 112 | * DONE: 113 | * Replace the "null" with a valid value to get an unreflected private method handle. 114 | * Unreflect to create a method handle from a method instance 115 | * Generate a MethodHandle from the method instance created earlier. 116 | * See unreflect method in the innerclass Lookup of MethodHandles. 117 | * java.lang.invoke.MethodHandles.Lookup.unreflect() 118 | * We can unreflect the method since we bypassed the access control checks above. 119 | * Check API: java.lang.invoke.MethodHandles.Lookup.unreflect(?) 120 | */ 121 | MethodHandle privateMethodHandle = 122 | privateMethodHandlesLookup.unreflect(privateMethod); 123 | 124 | DemoClass demoClass = new DemoClass(); 125 | 126 | assertEquals(expectedOutput, 127 | privateMethodHandle.invoke(demoClass, 128 | "via Method Handles"), 129 | "Method handles invocation failed"); 130 | 131 | } catch (NoSuchMethodException | IllegalAccessException e) { 132 | 133 | fail("Failed to execute a private method invocation via Method Handles: " 134 | + e.getMessage()); 135 | } catch (Throwable t) { 136 | 137 | // invoke throws a Throwable (hence catching Throwable separately). 138 | fail(TEST_FAILURE.getValue() + t.getMessage()); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /java-handles/src/solutions/java/none/cvg/methods/TestSolutionProtectedMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package none.cvg.methods; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.lang.reflect.Method; 7 | 8 | import none.cvg.handles.DemoClass; 9 | import none.cvg.handles.HandlesKataDisplayNames; 10 | import org.junit.jupiter.api.DisplayName; 11 | import org.junit.jupiter.api.DisplayNameGeneration; 12 | import org.junit.jupiter.api.MethodOrderer; 13 | import org.junit.jupiter.api.Order; 14 | import org.junit.jupiter.api.Tag; 15 | import org.junit.jupiter.api.Test; 16 | import org.junit.jupiter.api.TestMethodOrder; 17 | 18 | import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE; 19 | import static none.cvg.handles.ErrorMessages.TEST_FAILURE; 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | import static org.junit.jupiter.api.Assertions.fail; 22 | 23 | /* 24 | * DONE: 25 | * This test aims at using MethodHandles to invoke a protected method on a class. 26 | * Each solved test shows how this can be achieved with the traditional reflection calls. 27 | * Each unsolved test provides a few hints that will allow the kata-taker to manually solve 28 | * the exercise to achieve the same goal with MethodHandles. 29 | */ 30 | @DisplayNameGeneration(HandlesKataDisplayNames.class) 31 | @DisplayName("Invoke DemoClass.protectedMethod(String)") 32 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 33 | public class TestSolutionProtectedMethodInvocation { 34 | 35 | @Test 36 | @Tag("PASSING") 37 | @Order(1) 38 | public void reflectionProtectedMethod() { 39 | 40 | String expectedOutput = "[DemoClass] - Protected method via reflection"; 41 | 42 | try { 43 | 44 | // Cannot call getMethod(), use getDeclaredMethod() to get private and protected methods 45 | Method protectedMethod = 46 | DemoClass.class.getDeclaredMethod("protectedMethod", 47 | String.class); 48 | 49 | /* 50 | * Method has to be made accessible. 51 | * Not setting this will cause IllegalAccessException 52 | * Setting accessible to true causes the JVM to skip access control checks 53 | * 54 | * This is needed to access non-public content 55 | */ 56 | protectedMethod.setAccessible(true); 57 | 58 | DemoClass demoClass = new DemoClass(); 59 | 60 | assertEquals(expectedOutput, 61 | protectedMethod.invoke(demoClass, "via reflection"), 62 | "Reflection invocation failed"); 63 | 64 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 65 | 66 | fail(REFLECTION_FAILURE.getValue() + e.getMessage()); 67 | } 68 | } 69 | 70 | @Test 71 | @Order(2) 72 | @Tag("PASSING") 73 | public void methodHandleProtectedMethod() { 74 | 75 | String expectedOutput = "[DemoClass] - Protected method via Method Handles"; 76 | 77 | /* 78 | * DONE: 79 | * Get a non-public lookup from java.lang.invoke.MethodHandles 80 | * Non-public methods are looked up via "lookup" 81 | * Find the differences between lookup() and publicLookup() on MethodHandles. 82 | * Check API: java.lang.invoke.MethodHandles.lookup() 83 | */ 84 | MethodHandles.Lookup protectedMethodHandlesLookup = MethodHandles.lookup(); 85 | 86 | try { 87 | 88 | /* 89 | * DONE: 90 | * Replace the "null"s valid values to create a protectedMethod instance. 91 | * Create a method instance that matches the name "protectedMethod()" 92 | * See java.lang.class for a getDeclaredMethod() 93 | * Look for the declared method on the DemoClass.class 94 | * The protectedMethod() accepts a String input parameter. 95 | * Same call as is used in vanilla reflection. 96 | * Check API: java.lang.Class.getDeclaredMethod(?, ?) 97 | */ 98 | Method protectedMethod = 99 | DemoClass.class.getDeclaredMethod("protectedMethod", 100 | String.class); // Method name, Class ... = Parameter types 101 | 102 | /* 103 | * Method has to be made accessible. 104 | * Not setting this will cause IllegalAccessException 105 | * Setting accessible to true causes the JVM to skip access control checks 106 | * 107 | * This is needed to access non-public content 108 | */ 109 | protectedMethod.setAccessible(true); 110 | 111 | /* 112 | * DONE: 113 | * Replace the null with the method instance to produce a protectedMethod handle. 114 | * Unreflect to create a method handle from a method instance 115 | * Generate a MethodHandle from the method instance created earlier. 116 | * See unreflect method in the innerclass Lookup of MethodHandles. 117 | * java.lang.invoke.MethodHandles.Lookup.unreflect() 118 | * We can unreflect the method since we bypassed the access control checks above. 119 | * Check API: java.lang.invoke.MethodHandles.Lookup.unreflect(?) 120 | */ 121 | MethodHandle protectedMethodHandle = 122 | protectedMethodHandlesLookup.unreflect(protectedMethod); 123 | 124 | DemoClass demoClass = new DemoClass(); 125 | 126 | assertEquals(expectedOutput, 127 | protectedMethodHandle.invoke(demoClass, 128 | "via Method Handles"), 129 | "Method handles invocation failed"); 130 | 131 | } catch (NoSuchMethodException | IllegalAccessException e) { 132 | 133 | fail("Failed to execute a protected method invocation via Method Handles: " 134 | + e.getMessage()); 135 | } catch (Throwable t) { 136 | 137 | // invoke throws a Throwable (hence catching Throwable separately). 138 | fail(TEST_FAILURE.getValue() + t.getMessage()); 139 | } 140 | } 141 | } --------------------------------------------------------------------------------