DataWeave Delight: Reverse a string value
DataWeave 2.4 introduced the reverse
function in the Strings
module. With this function we reverse the string value that we pass in as argument. The result is the reversed string.
DataWeave 2.4 introduced the reverse
function in the Strings
module. With this function we reverse the string value that we pass in as argument. The result is the reversed string.
The Strings
module in DataWeave has some very useful functions to work with string values. For example to repeat a string value we can use the repeat
function. The first argument is the string value we want to repeat and the second argument the number of times the value must be repeated.
Testing classes that work with date calculations based on the current date and time (now) can be difficult. First of all we must make sure our class under test accepts a java.time.Clock
instance. This allows us to provide a specific Clock
instance in our tests where we can define for example a fixed value, so our tests don’t break when the actual date and time changes. But this can still not be enough for classes that will behave different based on the value returned for now. The Clock
instances in Java are immutable, so it is not possible to change the date or time for a Clock
instance.
In Spock 2.0 we can use the new MutableClock
class in our specifications to have a Clock
that can be used to go forward or backward in time on the same Clock
instance. We can create a MutableClock
and pass it to the class under test. We can test the class with the initial date and time of the Clock
object, then change the date and time for the clock and test the class again without having to create a new instance of the class under test. This is handy in situations like a queue implementation, where a message delivery date could be used to see if messages need to be delivered or not. By changing the date and time of the clock that is passed to the queue implementation we can write specifications that can check the functionality of the queue instance.
In Spock we can also get a hold on the arguments that are passed to method call of a mock and we can write assertions to check the parameters for certain conditions.
When we create a mock in Spock and invoke a method on the mock the arguments are matched using the equals() implementation of the argument type. If they are not equal Spock will tell us by showing a message that there are too few invocations of the method call. Let’s show this with an example. First we create some classes we want to test:
The Clojure namespace clojure.java.io
contains useful functions to work with files. One of those functions is make-parents
. We can pass a java.io.File
instance as arguments or use the same arguments that can be passed to the file
function that is also in this namespace. The function will create all parent directories for the file. The return result is true
if the directories are created (they didn’t exist before) and false
when the directories didn’t have to be created (already exist).
In the following example we see an example of usage of the make-parents
function:
When we convert our PlantUML diagrams we get a default look-and-feel for our diagrams that is mostly red and yellow based. We can alter the style and color of individual elements using the skinparam
command. But we can also apply so-called themes to our diagram that will alter the look-and-feel of our diagram with a simple theme reference.
We can define the name of the theme in our diagram markup using the !theme
directive. Or we can use the command-line option -theme
when we generate a diagram from our markup. We can even combine both methods where the end result is also a combination of both themes.
If we have an Optional
instance we can consume the value if it is present using the ifPresent
method. Since Java 9 the method ifPresentOrElse
has been added to the Optional
class. The first argument is of type Consumer
and is invoked when there is an optional value. The second argument is of type Runnable
and is executed when the the optional is empty. The method in the Consumer
and Runnable
implementations does not return a type but returns void
. Therefore we should use ifPresentOrElse
when we need a conditional side effect for an Optional
instance.
In the following example we have a method handleName
that will update a list if an optional value is present or increases a counter when the optional value is empty:
In the clojure.set
namespace we can find the function map-invert
. This function returns a new map where the values are keys with the appropriates keys of the original map assigned as value. If the original map has duplicate values than the latest key for the duplicate value will be the value of the new key.
In the following example code we see the result of using map-invert
:
If we want to get two types of information from a Stream
of objects we can consume the Stream
twice and collect the results. But that is not very efficient, especially when the stream has a lot of objects. Since Java 12 we can use the teeing
method of the java.util.stream.Collectors
class to get multiple results while consuming the stream of objects only once. The teeing
method takes two collectors as argument each returning a separate result for the stream items. As third argument we must pass a function that will merge the results of the two collectors into a new object.
In the following code we have two example use cases that use the teeing
method to get multiple results while consuming a Stream
of objects only one time:
Working with Java classes from Clojure code is easy. If we want to invoke methods or access fields on instances of Java classes we must first create an instance by invoking the constructor. In Clojure we can do that using the special form new
or using a dot (.
) notation. The new
special form has the class name of the Java class we want to create an instance of as argument followed by arguments for the Java class constructor. With the dot notation we place a .
after the class name followed by arguments for the class constructor to create a new instance.
In the following example we see several ways to create an instance of a Java class.
If we need to create a Java properties file in our build we could create a custom task and use the Properties
class to store a file with properties. Instead of writing our custom task we can use the task WriteProperties
that is already part of Gradle. Using this task Gradle will not add a timestamp in the comment to the properties file. Also the properties are sorted by name, so we know the properties are always in the same order in the output file. Finally, a fixed line separator is used, which is \n
by default, but can be set via the task property lineSeparator
.
To define the properties that need to be in the output file we can use the property
method for a single property, or we can use properties
method with a Map
argument to set multiple properties.
Java 15 introduced the multi-line string value referred to as a text block. With this introduction also the formatted
method was added to the String
class. The method can be invoked on a String
value directly and function exactly as the static String.format
method. The nice thing is that now we directly can use a method on the value instead of having to use a static method where the value is passed as argument.
In the following example we use the formatted
method for a normal String
value and a text block: