tag:blogger.com,1999:blog-197897582024-03-06T19:52:45.549+11:00Rob on ProgrammingRobert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comBlogger212125tag:blogger.com,1999:blog-19789758.post-2586421899442851712019-02-15T14:58:00.002+11:002019-02-15T18:16:48.903+11:00Using PubSubJS in React<p>Here I demonstrate how to use PubSubJS to allow a React component to listen for changes to some external object (external to the React application).</p>
<p>The problem being solved: I want an array of strings to exist globally such that any Javascript code can modify it (primarily to add to it), while at the same time providing a method for a visual component to listen to state changes on that array and update an on-screen list of those strings.</p>
<p>Main use case I had in mind: helping me to write React code via <a href="https://codepen.io">codepen.io</a> when on my iPad and have no access to Developer Tools, which means I can't see <code>console.log</code> messages.</p>
<p>Helpful resouce: <a href="https://anthonymineo.com/communication-between-independent-components-in-react-using-pubsubjs/">Communication Between Independent Components in React using PubSubJS</a></p>
<p>PubSubJS API lives at: <a href="https://www.npmjs.com/package/pubsub-js">https://www.npmjs.com/package/pubsub-js</a>.</p>
<p>See my live example of this at <a href="https://codepen.io/robertmarkbram/pen/JxEbwJ">codepen.io</a>.</p>
<p>The HTML is extremely basic, just providing a root object for React to hook into.</p>
<pre class="brush:Java" title="HTML for example, just providing a root for React to use">
<div id="root"></div>
</pre>
<p>The Javascript contains all the real work. I have put comments in-line to make it clear.</p>
<pre class="brush:Javascript" title="Javascript code that drives the example">
import React from 'react';
import ReactDOM from 'react-dom';
import PubSub from 'pubsub-js';
// In codepen.io, import via Settings and not via import statements here
/*
An object that provides controlled access to a
list of strings and notifies subscribers of any changes.
Notifications do not indicate what has changed; only that
something in the list has changed. Subscribers can get a copy
of the whole list as needed.
*/
class MessageList {
/* Start with an empty list. */
constructor() {
this.messages = new Array();
}
/*
Give back a *copy* of the messages so that external
code cannot modify the list themselves.
*/
getMessages() {
return this.messages.slice();
}
/*
Add new message, ignoring attempts to add anything other
than a string.
*/
push(message) {
if (typeof message !== "string") {
return;
}
this.messages.push(message);
PubSub.publish('MESSAGES UPDATED', 'added message');
}
/* Remove last message. */
pop() {
this.messages.pop();
PubSub.publish('MESSAGES UPDATED', 'removed most recent message');
}
/* Remove all messages. */
clear() {
this.messages.length = 0;
PubSub.publish('MESSAGES UPDATED', 'cleared all messages');
}
}
/*
Set up a single instance of a message list that can be used
globally by code wishing to add or remove messages.
*/
window.messages = new MessageList();
/*
This component is only concerned with displaying current
contents of the messages list, updating itself anytime some
change occurs in the list.
*/
class MessageDisplay extends React.Component {
/*
Starting state: no messages.
*/
constructor(props) {
super(props);
this.state = {
messages: [],
};
}
/*
When component is loaded, subscribe to changes in the
messages list.
*/
componentWillMount(){
// Subscribe this class to the 'MESSAGES UPDATED' subscription.
// When a publish event for 'MESSAGES UPDATED' has been fired, MessageDisplay.subscriber() will be triggered.
this.token = PubSub.subscribe('MESSAGES UPDATED', this.subscriber.bind(this));
}
/* Finalise subscription. */
componentDidMount(){
PubSub.publish('MESSAGES UPDATED', this.token);
}
/* Clean up: un-subscribe. */
componentWillUnmount(){
PubSub.unsubscribe(this.token);
}
/* This function is called any time a change to the message list occurs. */
subscriber(msg, data){
console.log("Subscriber has msg " + msg + " and data " + data);
// Update the UI with a new copy of all messages.
this.setState ({
messages : window.messages.getMessages(),
});
}
/* Update UI with a list all current messages. */
render() {
let messagesForDisplay = (this.state.messages ? this.state.messages : new Array());
if (messagesForDisplay.length === 0) {
messagesForDisplay.push("No messages");
}
return (
<div>
<p>Messages:</p>
<ul>
{messagesForDisplay.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
}
/*
Driving app in this case is just a shell to house the
message UI and provide some buttons to allow the user to
update the message list which in turn drives Pub-Sub activity.
*/
class App extends React.Component {
/* Add a message. */
onAddMessage = () => {
window.messages.push("A new message based on date: " + new Date());
}
/* Remove last message. */
onRemoveLastMessage = () => {
window.messages.pop();
}
/* Clear all messages. */
onClearMessages = () => {
window.messages.clear();
}
/* Display buttons and the messsage UI. */
render() {
return (
<div>
<button type="button" onClick={this.onAddMessage}>
Add a message
</button>
&nbsp;&nbsp;&nbsp;
<button type="button" onClick={this.onRemoveLastMessage}>
Remove last message
</button>
&nbsp;&nbsp;&nbsp;
<button type="button" onClick={this.onClearMessages}>
Clear messages
</button>
<MessageDisplay />
</div>
);
}
}
/* Start the app. */
ReactDOM.render(
<App />,
document.getElementById('root')
);
</pre>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-29515379701888077742019-01-16T22:41:00.000+11:002019-01-16T22:41:11.861+11:00Two ways to find files and grep through them in bash<p>I love <code>find</code> because it's a very versatile tool. In the past, I often used <code>find</code> to get files with multiple extensions and then search through them with <code>grep</code>. You can do the same with just <code>grep</code> however!</p>
<p>Here are my test files.</p>
<pre class="brush:java" title="Contents of test files">
$ for file in $(ls) ; do echo -e "----\nfile: $file has content:\n-"; cat $file; done
----
file: file_a.txt has content:
-
one two three four five six seven
eight nine ten eleven twelve thirteen
----
file: file_b.txt has content:
-
one two three four five six seven
eight nine ten eleven twelve thirteen
----
file: file_c.xml has content:
-
one two three four five six seven
eight nine ten eleven twelve thirteen
----
file: file_d.html has content:
-
one two three four five six seven
eight nine ten eleven twelve thirteen
----
file: file_e.php has content:
-
one two three four five six seven
eight nine ten eleven twelve thirteen
</pre>
<p>Here is how to use <code>find</code> and <code>grep</code> to search through multiple file types for a regular expression.</p>
<p>Look for the word <code>eleven</code> in all text, xml, html and php files using <code>find</code> and <code>grep</code>.</p>
<pre class="brush:java" title="Using find and piping the file names into grep">
$ find . -type f -regex '^.*\(txt\|xml\|html\|php\)$' -print0 | xargs -0 grep 'eleven'
./file_a.txt:eight nine ten eleven twelve thirteen
./file_b.txt:eight nine ten eleven twelve thirteen
./file_c.xml:eight nine ten eleven twelve thirteen
./file_d.html:eight nine ten eleven twelve thirteen
./file_e.php:eight nine ten eleven twelve thirteen
</pre>
<p>Now look for the word <code>eleven</code> in all text, xml, html and php files using just <code>grep</code>.</p>
<pre class="brush:java" title="Using grep to search though txt files">
$ grep -iER --include "*.txt" --include "*.xml" --include "*.html" --include "*.php" "eleven" .
./file_a.txt:eight nine ten eleven twelve thirteen
./file_b.txt:eight nine ten eleven twelve thirteen
./file_c.xml:eight nine ten eleven twelve thirteen
./file_d.html:eight nine ten eleven twelve thirteen
./file_e.php:eight nine ten eleven twelve thirteen
</pre>
<p>For grep: <code>-i</code> is case insensitive, <code>-E</code> is extended grep (you can use brackets without having to escape them), <code>-R</code> is recursive searching, so it will search through sub-folders.</p><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-50562104579385178132018-05-08T12:17:00.000+10:002018-05-08T12:35:16.645+10:00Five for loops in Java<style>
.forLoopTop {
font-size: smaller;
font-style: italic;
text-align: right;
}
</style>
<ol id="topForLoopPost">
<li><a href="#forLoopsListOfStrings">List of strings</a></li>
<li><a href="#forLoopsOldSkoolFor">Traditional for loop</a></li>
<li><a href="#forLoopsEnhancedJdk5">Enhanced for loop from Java 5</a></li>
<li><a href="#forLoopsForEachJdk8">forEach lambda from Java 8</a></li>
<li><a href="#forLoopsIterate1LambdaJdk8">Stream.iterate with one lambda from Java 8</a></li>
<li><a href="#forLoopsIterate2LambdaJdk9">Stream.iterate with two lambdas from Java 9</a></li>
<li><a href="#forLoopsFiveForLoops">All five for loops together</a></li>
</ol>
<p>The main conceptual difference between <code>for</code> and <code>while</code> loops is that a for loop uses some form of index or counting variable to track what row, record or iteration you are up to whereas a while loop does not.</p>
<p>Here are five ways to use "for loops" in Java.</p>
<p class="forLoopTop"><a href="#topForLoopPost">To top of post.</a></p>
<h2 id="forLoopsListOfStrings">List of strings</h2>
<p>I start out with a list of strings.</p>
<pre class="brush:java" title="List of strings to iterate over.">
final List<String> strings = Arrays.asList("one", "two", "three", "four", "five");
</pre>
<p class="forLoopTop"><a href="#topForLoopPost">To top of post.</a></p>
<h2 id="forLoopsOldSkoolFor">Traditional for loop</h2>
<p>The traditional for loop allows us to specify three things:</p>
<ol>
<li>The <code>seed</code> value: the initial value to give our index. The seed is 0 in this example.</li>
<li>The <code>hasNext</code> condition (a.k.a. exit condition): a boolean expression to answer the question <em>should we continue?</em> In our example, we continue as long as <code>index</code> is less than the size of the <code>strings</code> list.</li>
<li>The <code>next</code> value: an expression to generate the next index. In our example, we get <code>next</code> by adding 1 to index.</li>
</ol>
<pre class="brush:java" title="Traditional for loop.">
System.out.printf("Old school for loop.%n");
for (int index = 0; index < strings.size(); index++) {
System.out.printf("Next string is %s%n", strings.get(index));
}
</pre>
<p class="forLoopTop"><a href="#topForLoopPost">To top of post.</a></p>
<h2 id="forLoopsEnhancedJdk5">Enhanced for loop from Java 5</h2>
<p>In Java 5, we got the enhanced for loop, which feels more like a <code>while</code> loop because we don't have an index any more. The enhanced for loop specifically helps us in situations where you are iterating over all items in a collection. You don't need to specify <code>seed</code>, <code>hasNext</code> or <code>next</code>: they are all implied. Start with the first element, end with a last element and make sure we loop over each element in between. </p>
<pre class="brush:java" title="Enhanced for loop from Java 5.">
System.out.printf("%nEnhanced for loop from Java 5.%n");
for (final String string : strings) {
System.out.printf("Next string is %s%n", string);
}
</pre>
<p class="forLoopTop"><a href="#topForLoopPost">To top of post.</a></p>
<h2 id="forLoopsForEachJdk8">forEach lambda from Java 8</h2>
<p>Java 8 gave us lambdas and a new way to loop over elements. Again, this feels more like a while in some ways because we don't have an index.</p>
<p>Just like the enhanced for loop, it is perfect for situations where you have a collection and you want to do something with each element. Any collection in Java has <code>forEach</code> (through the <code>java.lang.Iterable</code> interface).</p>
<pre class="brush:java" title="The forEach lambda from Java 8.">
System.out.printf("%nThe forEach lambda from Java 8.%n");
strings.forEach(string -> System.out.printf("Next string is %s%n", string));
</pre>
<p>Java 8 introduced <code>java.util.stream.Stream</code> and gave us a whole new way to think about looping. Instead of thinking about how to formulate a while or for loop (by specifying seed and exit conditions), with streams we focus on <em>defining the set of values (a stream) that we want to operate on</em>. Stream also has <code>forEach</code>, so we start thinking more about "iterating over a stream of values".</p>
<p class="forLoopTop"><a href="#topForLoopPost">To top of post.</a></p>
<h2 id="forLoopsIterate1LambdaJdk8">Stream.iterate with one lambda from Java 8</h2>
<p><code>Stream.iterate</code> provides a way to use for loop ideas with a stream of values.</p>
<pre class="brush:java" title="Using Stream.iterate with one lambda from Java 8.">
System.out.printf("%nUsing Stream.iterate with one lambda from Java 8.%n");
Stream.iterate(0, index -> index + 1)
.limit(strings.size())
.forEach(index -> {
System.out.printf("Next string is %s%n", strings.get(index));
});
</pre>
<p>This version of <code>iterate()</code> has only two arguments, allowing us to specify:</p>
<ol>
<li>The <code>seed</code> value: the initial value to give our index. The seed is 0 in this example.</li>
<li>The <code>next</code> value: an expression to generate the next index. In our example, we get <code>next</code> by adding 1 to index.</li>
</ol>
<p>We still need a way to provide the exit condition though, so I have added a <code>limit()</code> call from the <code>Stream</code> API.</p>
<p class="forLoopTop"><a href="#topForLoopPost">To top of post.</a></p>
<h2 id="forLoopsIterate2LambdaJdk9">Stream.iterate with two lambdas from Java 9</h2>
<p><code>Stream.iterate</code> in Java 9 got overloaded to give a way to specify all three things we use in a traditional for loop.</p>
<pre class="brush:java" title="Using Stream.iterate with two lambdas from Java 9.">
System.out.printf("%nUsing Stream.iterate with two lambdas from Java 9.%n");
Stream.iterate(0, index -> index < strings.size(), index -> index + 1).forEach(index -> {
System.out.printf("Next string is %s%n", strings.get(index));
});
</pre>
<p>Now we can give:</p>
<ol>
<li>The <code>seed</code> value: the initial value to give our index. The seed is 0 in this example.</li>
<li>The <code>hasNext</code> condition (a.k.a. exit condition): a boolean expression to answer the question <em>should we continue?</em> In our example, we continue as long as <code>index</code> is less than the size of the <code>strings</code> list.</li>
<li>The <code>next</code> value: an expression to generate the next index. In our example, we get <code>next</code> by adding 1 to index.</li>
</ol>
<p class="forLoopTop"><a href="#topForLoopPost">To top of post.</a></p>
<h2 id="forLoopsFiveForLoops">All five for loops together</h2>
<p>In summary, the techniques all together are below.</p>
<pre class="brush:java" title="Five for loops in Java">
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public final class Scrapbook {
public static void main(final String[] args) {
final List<String> strings = Arrays.asList("one", "two", "three", "four", "five");
System.out.printf("Old school for loop.%n");
for (int index = 0; index < strings.size(); index++) {
System.out.printf("Next string is %s%n", strings.get(index));
}
System.out.printf("%nEnhanced for loop from Java 5.%n");
for (final String string : strings) {
System.out.printf("Next string is %s%n", string);
}
System.out.printf("%nThe forEach lambda from Java 8.%n");
strings.forEach(string -> System.out.printf("Next string is %s%n", string));
System.out.printf("%nUsing Stream.iterate with one lambda from Java 8.%n");
Stream.iterate(0, index -> index + 1).limit(strings.size()).forEach(index -> {
System.out.printf("Next string is %s%n", strings.get(index));
});
System.out.printf("%nUsing Stream.iterate with two lambdas from Java 9.%n");
Stream.iterate(0, index -> index < strings.size(), index -> index + 1).forEach(index -> {
System.out.printf("Next string is %s%n", strings.get(index));
});
}
}
</pre>
<p>Which gives the following output.</p>
<pre class="brush:plain" title="Output from running the five for loops.">
Old school for loop.
Next string is one
Next string is two
Next string is three
Next string is four
Next string is five
Enhanced for loop from Java 5.
Next string is one
Next string is two
Next string is three
Next string is four
Next string is five
The forEach lambda from Java 8.
Next string is one
Next string is two
Next string is three
Next string is four
Next string is five
Using Stream.iterate with one lambda from Java 8.
Next string is one
Next string is two
Next string is three
Next string is four
Next string is five
Using Stream.iterate with two lambdas from Java 9.
Next string is one
Next string is two
Next string is three
Next string is four
Next string is five
</pre>
<p class="forLoopTop"><a href="#topForLoopPost">To top of post.</a></p>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-11425858174691337512018-05-05T18:14:00.000+10:002018-05-07T09:59:11.998+10:00De-serialise JSON string to map with multiple value types<style>
.jacksonTop {
font-size: smaller;
font-style: italic;
text-align: right;
}
</style>
<ol id="topJacksonPost">
<li><a href="#mapStringLocalDateTime">Map of String to LocalDateTime</a></li>
<li><a href="#mapStringMultipleDateTypes">Map of String to multiple date types using a custom class</a></li>
<li><a href="#mapStringDeserialiser">Map of String to multiple date types using a custom de-serialiser</a></li>
<li><a href="#JacksonMavenDependencies">Maven dependencies</a></li>
</ol>
<p>I have a map that contains dates and strings. I convert it to a JSON string and later want to convert it back. In Java, the <a href="https://github.com/FasterXML/jackson">Jackson API</a> is perfect for this. In this post I explore three methods of doing this that cater for different levels of complexity involved in how many types of value are contained in the map.</p>
<p>I created this blog entry because I wanted to fully explore the options I found when trying to solve this problem in an app I am working on. The solution I ended up going ahead with came about from some great feedback in <a href="https://stackoverflow.com/questions/50171472/deserialising-string-to-map-with-multiple-types-using-jackson">this Stack Overflow post</a>, thanks to <a href="https://stackoverflow.com/users/7935614/aussie">@aussie</a>.</p>
<p class="jacksonTop"><a href="#topJacksonPost">To top of post.</a></p>
<h2 id="mapStringLocalDateTime">Map of String to LocalDateTime</h2>
<p>First, here is the map of <code>String</code> keys to
<code>LocalDateTime</code> object values.</p>
<pre class="brush:java" title="Create a map that contains string keys and Joda LocalDateTime">
// Create dates.
final LocalDateTime nowLocal = new LocalDateTime();
final LocalDateTime notNowLocal =
new LocalDateTime(2007, 3, 25, 2, 30, 0);
// Put them into a map.
final Map<String, LocalDateTime> dateMap = new HashMap<>();
dateMap.put("nowLocal", nowLocal);
dateMap.put("notNowLocal", notNowLocal);
</pre>
<p>Here is how I serialise it to a JSON string using Jackson.</p>
<pre class="brush:java" title="Serialise map to a JSON string">
// Create a mapper.
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.configure(com.fasterxml.jackson.databind
.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// Serialise the map as a JSON string.
final String dateMapJson = mapper.writeValueAsString(dateMap);
System.out.println(dateMapJson);
</pre>
<p>The result of this code is below.</p>
<pre class="brush:plain" title="program output">{"notNowLocal":"2007-03-25T02:30:00.000","nowLocal":"2018-05-05T15:57:25.108"}</pre>
<p>This is how I de-serialise the string <strong>back</strong> into a map.</p>
<pre class="brush:java" title="De-serialise the string back into a map">
/*
* Create a type definition of my map: something that will tell Jackson
* I want back a HashMap whose keys are String type objects and whose
* values are LocalDateTime objects.
*/
final TypeFactory typeFactory = mapper.getTypeFactory();
final MapType mapType = typeFactory.constructMapType(
HashMap.class, String.class, LocalDateTime.class);
// Use the mapper from above to convert the JSON string back to a map.
final Map<String, LocalDateTime> dateMapFromJson =
mapper.readValue(dateMapJson, mapType);
</pre>
<p>Here is a complete example of this code.</p>
<pre class="brush:java" title="Create a map with dates, serialise it to JSON and de-serialise it back to a map">
import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
import static java.lang.String.format;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.joda.time.LocalDateTime;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.datatype.joda.JodaModule;
/**
* Test converting a map of {@link LocalDateTime}s to a JSON string and back.
*/
public class JodaTimeMapTestOneDateType {
public static void main(final String[] args) throws Exception {
// Map with dates.
final LocalDateTime nowLocal = new LocalDateTime();
final LocalDateTime notNowLocal =
new LocalDateTime(2007, 3, 25, 2, 30, 0);
final Map<String, LocalDateTime> dateMap = new HashMap<>();
dateMap.put("nowLocal", nowLocal);
dateMap.put("notNowLocal", notNowLocal);
// Serialise map to string.
final ObjectMapper mapper = mapper();
final String dateMapJson = mapper.writeValueAsString(dateMap);
// De-serialise string to map.
final TypeFactory typeFactory = mapper.getTypeFactory();
final MapType mapType = typeFactory.constructMapType(HashMap.class,
String.class, LocalDateTime.class);
final Map<String, LocalDateTime> dateMapFromJson =
mapper.readValue(dateMapJson, mapType);
// Print off the maps, JSON string and proof that the maps are equal.
System.out.printf("Starting map.%s%n%n", mapToString(dateMap));
System.out.printf("Map serialised to a JSON string.%n %s%n%n",
dateMapJson);
System.out.printf("Map de-serialised from JSON.%s%n%n",
mapToString(dateMapFromJson));
System.out.printf("Maps are equal: %s%n",
dateMap.equals(dateMapFromJson));
}
/**
* @param map
* with strings and dates.
* @return string that tells me what the keys, value classes and values are.
*/
private static String mapToString(final Map<String, LocalDateTime> map) {
return format("%n %-13s %-30s %s", "key", "value class", "value") //
+ format("%n %-13s %-30s %s", "---", "-----------", "-----") //
+ map.entrySet().stream().map(entry -> {
final Object value = entry.getValue();
return format("%n %-13s %-30s %s", entry.getKey(),
value.getClass().getName(), value);
}).collect(Collectors.joining());
}
/**
* @return object that transform my maps to strings and back.
*/
private static ObjectMapper mapper() {
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.configure(WRITE_DATES_AS_TIMESTAMPS, false);
return mapper;
}
}
</pre>
<p>The result of running this code is below.</p>
<pre class="brush:plain" title="program output">
Starting map.
key value class value
--- ----------- -----
notNowLocal org.joda.time.LocalDateTime 2007-03-25T02:30:00.000
nowLocal org.joda.time.LocalDateTime 2018-05-05T16:16:23.572
Map serialised to a JSON string.
{"notNowLocal":"2007-03-25T02:30:00.000","nowLocal":"2018-05-05T16:16:23.572"}
Map de-serialised from JSON.
key value class value
--- ----------- -----
notNowLocal org.joda.time.LocalDateTime 2007-03-25T02:30:00.000
nowLocal org.joda.time.LocalDateTime 2018-05-05T16:16:23.572
Maps are equal: true
</pre>
<p class="jacksonTop"><a href="#topJacksonPost">To top of post.</a></p>
<h2 id="mapStringMultipleDateTypes">Map of String to multiple date types using a custom class</h2>
<p>What about if my map has multiple types, not just <code>LocalDateTime</code>?</p>
<pre class="brush:java" title="This map is String to LocalDateTime or DateTime serialised to a JSON string.">
// Different date objects.
final DateTime now = new DateTime().withZone(DateTimeZone.UTC);
final LocalDateTime nowLocal = new LocalDateTime();
final LocalDateTime notNowLocal =
new LocalDateTime(2007, 3, 25, 2, 30, 0);
// Make a map with the dates.
final Map<String, Object> dateMap = new HashMap<>();
dateMap.put("now", now);
dateMap.put("nowLocal", nowLocal);
dateMap.put("notNowLocal", notNowLocal);
// Create object mapper that knows how to write Jodatime dates.
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.configure(WRITE_DATES_AS_TIMESTAMPS, false);
// Serialise map to JSON string.
final String dateMapJson = mapper.writeValueAsString(dateMap);
System.out.println(dateMapJson);
</pre>
<p>The output of this code is below.</p>
<pre class="brush:plain" title="program output">{"now":"2018-05-05T06:35:21.330Z","notNowLocal":"2007-03-25T02:30:00.000","nowLocal":"2018-05-05T16:35:21.441"}</pre>
<p>The problem is how to tell Jackson about the combination of types to expect. In the previous section, I created a type definition to tell Jackson I want back a <code>HashMap</code> whose keys are <code>String</code> type objects and whose values are <code>LocalDateTime</code> objects.</p>
<pre class="brush:java" title="Create type definition of a map as HashMap with String keys and LocalDateTime values.">
final TypeFactory typeFactory = mapper.getTypeFactory();
final MapType mapType = typeFactory.constructMapType(
HashMap.class, String.class, LocalDateTime.class);
</pre>
<p>There is no other <code>constructMapType</code> method that lets me define multiple type definitions. However, look at the JSON string in another way.</p>
<pre class="brush:plain" title="program output">
{
"now" : "2018-05-05T06:35:21.330Z",
"notNowLocal" : "2007-03-25T02:30:00.000",
"nowLocal" : "2018-05-05T16:35:21.441"
}
</pre>
<p>Doesn't this JSON map look like it could fit a Java class with three date variables called <code>now</code>, <code>notNowLocal</code> and <code>nowLocal</code>?</p>
<pre class="brush:java" title="Class that holds dates whose variable names match the keys in my map.">
public class DateTimeHolder {
private DateTime now;
private LocalDateTime nowLocal;
private LocalDateTime notNowLocal;
public Map<String, Object> buildMap() {
final Map<String, Object> dateMap = new HashMap<>();
dateMap.put("now", now);
dateMap.put("nowLocal", nowLocal);
dateMap.put("notNowLocal", notNowLocal);
return dateMap;
}
// Getters and setters...
}
</pre>
<p>Now I have a class with variables whose names match the keys in my map, and whose variable types match the types of my map values. I can use this to de-serialise the JSON string, as below.</p>
<pre class="brush:java" title="Using custom class to de-serialise a JSON string.">
// Tell Jackson to read the string and convert it to a DateTimeHolder.
final DateTimeHolder holder =
mapper.readValue(dateMapJson, DateTimeHolder.class);
// Which I can now convert back into a map.
final Map<String, Object> dateMapFromJson = holder.buildMap();
</pre>
<p>This works fine. Here is the complete example.</p>
<pre class="brush:java" title="Create a map with different date types and use a custom class to de-serialise it JSON string">
import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
import static java.lang.String.format;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.joda.JodaModule;
/**
* Test converting a map of multiple date types to a JSON string and back.
*/
public class JodaTimeMapTestUsingCustomType {
public static void main(final String[] args) throws Exception {
// Map with dates.
final DateTime now = new DateTime().withZone(DateTimeZone.UTC);
final LocalDateTime nowLocal = new LocalDateTime();
final LocalDateTime notNowLocal =
new LocalDateTime(2007, 3, 25, 2, 30, 0);
final Map<String, Object> dateMap = new HashMap<>();
dateMap.put("now", now);
dateMap.put("nowLocal", nowLocal);
dateMap.put("notNowLocal", notNowLocal);
// Serialise map to string.
final ObjectMapper mapper = mapper();
final String dateMapJson = mapper.writeValueAsString(dateMap);
// De-serialise string to map.
final DateTimeHolder holder =
mapper.readValue(dateMapJson, DateTimeHolder.class);
final Map<String, Object> dateMapFromJson = holder.buildMap();
// Print off the maps, JSON string and proof that the maps are equal.
System.out.printf("Starting map.%s%n%n", mapToString(dateMap));
System.out.printf("Map serialised to a JSON string.%n %s%n%n",
dateMapJson);
System.out.printf("Map de-serialised from JSON.%s%n%n",
mapToString(dateMapFromJson));
System.out.printf("Maps are equal: %s%n",
dateMap.equals(dateMapFromJson));
}
/**
* @param map
* with strings and dates.
* @return string that tells me what the keys, value classes and values are.
*/
private static String mapToString(final Map<String, Object> map) {
return format("%n %-13s %-30s %s", "key", "value class", "value") //
+ format("%n %-13s %-30s %s", "---", "-----------", "-----") //
+ map.entrySet().stream().map(entry -> {
final Object value = entry.getValue();
return format("%n %-13s %-30s %s", entry.getKey(),
value.getClass().getName(), value);
}).collect(Collectors.joining());
}
/**
* @return object that transform my maps to strings and back.
*/
private static ObjectMapper mapper() {
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.configure(WRITE_DATES_AS_TIMESTAMPS, false);
return mapper;
}
}
</pre>
<p>This is the <code>DateHolder</code> class.</p>
<pre class="brush:java" title="The DateHolder class.">
import java.util.HashMap;
import java.util.Map;
import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;
/**
* This class defines dates whose variable names match the keys in my map.
*/
public class DateTimeHolder {
private DateTime now;
private LocalDateTime nowLocal;
private LocalDateTime notNowLocal;
public Map<String, Object> buildMap() {
final Map<String, Object> dateMap = new HashMap<>();
dateMap.put("now", now);
dateMap.put("nowLocal", nowLocal);
dateMap.put("notNowLocal", notNowLocal);
return dateMap;
}
public DateTime getNow() {
return now;
}
public void setNow(final DateTime now) {
this.now = now;
}
public LocalDateTime getNowLocal() {
return nowLocal;
}
public void setNowLocal(final LocalDateTime nowLocal) {
this.nowLocal = nowLocal;
}
public LocalDateTime getNotNowLocal() {
return notNowLocal;
}
public void setNotNowLocal(final LocalDateTime notNowLocal) {
this.notNowLocal = notNowLocal;
}
}
</pre>
<p>The output of running this code is below.</p>
<pre class="brush:plain" title="program output">
Starting map.
key value class value
--- ----------- -----
now org.joda.time.DateTime 2018-05-05T06:58:52.104Z
notNowLocal org.joda.time.LocalDateTime 2007-03-25T02:30:00.000
nowLocal org.joda.time.LocalDateTime 2018-05-05T16:58:52.260
Map serialised to a JSON string.
{"now":"2018-05-05T06:58:52.104Z","notNowLocal":"2007-03-25T02:30:00.000","nowLocal":"2018-05-05T16:58:52.260"}
Map de-serialised from JSON.
key value class value
--- ----------- -----
now org.joda.time.DateTime 2018-05-05T06:58:52.104Z
notNowLocal org.joda.time.LocalDateTime 2007-03-25T02:30:00.000
nowLocal org.joda.time.LocalDateTime 2018-05-05T16:58:52.260
Maps are equal: true
</pre>
<p>This is great, and works. However, if I am going to write a custom class for this, it is likely that I don't need a map at all. I should just use <code>DateHolder</code> everywhere.</p>
<p>The vast majority of times I use <code>Jackson</code> it is for just this case: I want to serialise a custom class to JSON and back again (not a map). This technique is preferable particularly when you have objects with more than a few fields of multiple types, and even more so when you are talking about compound objects - when your variables are other custom classes and so on.</p>
<p class="jacksonTop"><a href="#topJacksonPost">To top of post.</a></p>
<h2 id="mapStringDeserialiser">Map of String to multiple date types using a custom de-serialiser</h2>
<p>The whole reason I started looking into this was because I had a situation with the following characteristics.</p>
<ul>
<li>Lots of maps with different sets of keys.</li>
<li>The values are only strings or dates.</li>
<li>The keys used for dates are always the same, e.g. a key of <code>abc</code> will always map to a <code>DateTime</code>, whereas a key of <code>xyz</code> will always map to a <code>LocalDateTime</code>.</li>
<li>I didn't need the whole map in my application, just a few specific fields that were common across all the maps.</li>
</ul>
<p>All of this means is that if I wrote a custom class, the only use it would have would be for translation purposes and would not be used anywhere else. It felt like it would make more sense to see if I could provided a better way to tell Jackson how to translate my maps.</p>
<p>One way to do this is to provide a custom de-serialiser. Here is the class declaration and the single method I need to override.</p>
<pre class="brush:java" title="Outline of the de-serialiser class.">
public class JodaMapDeserialiser extends StdDeserializer<Object> {
@Override
public Object deserialize(final JsonParser p,
final DeserializationContext ctxt)
throws IOException, JsonProcessingException {
}
}
</pre>
<p>The first step is to create a way to translate my keys in such a way that I can tell what type of Jodatime a specific key would map to (otherwise I treat the value as a string).</p>
<pre class="brush:java" title="An enum I can use to indicate which Jodatime type a specific key value maps to">
/** Mapping between keys in the map to a type of Joda time. */
static enum DateType {
DATE_TIME("now"), LOCAL_DATE_TIME("notNowLocal", "nowLocal");
final List<String> keys;
DateType(final String... keys) {
this.keys = Arrays.asList(keys);
}
public static DateType forKeyString(final String keyString) {
return Stream.of(values()).filter(dateTypes -> dateTypes.keys.contains(keyString)) //
.findFirst().orElse(null);
}
}
</pre>
<p>Here is some code to briefly show how this <code>enum</code> works.</p>
<pre class="brush:java" title="Code to test the DateType enum.">
System.out.printf("%s: %s.%n", "now", DateType.forKeyString("now"));
System.out.printf("%s: %s.%n", "nowLocal", DateType.forKeyString("nowLocal"));
System.out.printf("%s: %s.%n", "notNowLocal", DateType.forKeyString("notNowLocal"));
System.out.printf("%s: %s.%n", "anythingElse", DateType.forKeyString("anythingElse"));
</pre>
<p>The output from the above code is below.</p>
<pre class="brush:plain" title="program output">
now: DATE_TIME.
nowLocal: LOCAL_DATE_TIME.
notNowLocal: LOCAL_DATE_TIME.
anythingElse: null.
</pre>
<p>Now assume I have a method that gets the <code>key</code> and <code>value</code> from every map entry. Here is how I can translate the value into a Jodatime date or leave the value as a string, all depending on the key.</p>
<pre class="brush:java" title="Code that translates value to a date or string depending on the key.">
// Each entry in the map has a key and value.
final String value; // Actual code has
final String key; // values for these two.
// Convert the value depending on what the key is.
switch (DateType.forKeyString(key)) {
case DATE_TIME:
return DateTime.parse(value);
case LOCAL_DATE_TIME:
return LocalDateTime.parse(value);
default:
return value;
}
</pre>
<p>Again, I create a map with dates in it.</p>
<pre class="brush:java" title="Create a map with different date types, serialise it to a JSON string.">
// Create dates.
final DateTime now = new DateTime().withZone(DateTimeZone.UTC);
final LocalDateTime nowLocal = new LocalDateTime();
final LocalDateTime notNowLocal =
new LocalDateTime(2007, 3, 25, 2, 30, 0);
// Put them into a map.
final Map<String, Object> dateMap = new HashMap<>();
dateMap.put("now", now);
dateMap.put("nowLocal", nowLocal);
dateMap.put("notNowLocal", notNowLocal);
</pre>
<p>This time, the mapper is more complicated because I have to register my custom de-serialiser module.</p>
<pre class="brush:java" title="Create object mapper and register custom de-serialiser.">
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.configure(WRITE_DATES_AS_TIMESTAMPS, false);
final SimpleModule dateDeserializerModule = new SimpleModule();
dateDeserializerModule.addDeserializer(Object.class,
new JodaMapDeserialiser());
mapper.registerModule(dateDeserializerModule);
</pre>
<p>The code to serialise and then de-serialise the map looks quite familiar. Note that I am still creating a type definition to tell Jackson I want back a <code>HashMap</code> with <code>String</code> keys and <code>Object</code> values.</p>
<pre class="brush:java" title="Serialise and de-serialise the map.">
// Serialise map to string.
final ObjectMapper mapper = mapper();
final String dateMapJson = mapper.writeValueAsString(dateMap);
// De-serialise string to map.
final TypeFactory typeFactory = mapper.getTypeFactory();
final MapType mapType = typeFactory.constructMapType(HashMap.class,
String.class, Object.class);
final Map<String, Object> dateMapFromJson =
mapper.readValue(dateMapJson, mapType);
</pre>
<p>Here is the complete example. First is the de-serialiser.</p>
<pre class="brush:java" title="Custom Jackson de-serialiser.">
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
/** De-serialise values from a map that contains Joda times and strings. */
public class JodaMapDeserialiser extends StdDeserializer<Object> {
/** Mapping between keys in the map to a type of Joda time. */
static enum DateType {
DATE_TIME("now"), LOCAL_DATE_TIME("notNowLocal", "nowLocal");
final List<String> keys;
DateType(final String... keys) {
this.keys = Arrays.asList(keys);
}
public static DateType forKeyString(final String keyString) {
return Stream.of(values())
.filter(dateTypes -> dateTypes.keys.contains(keyString)) //
.findFirst().orElse(null);
}
}
public JodaMapDeserialiser() {
super(Object.class);
}
@Override
public Object deserialize(final JsonParser p,
final DeserializationContext ctxt)
throws IOException, JsonProcessingException {
// Each entry in the map has a key and value.
final String value = p.readValueAs(String.class);
final String key = p.getCurrentName();
// Convert the value depending on what the key is.
switch (DateType.forKeyString(key)) {
case DATE_TIME:
return DateTime.parse(value);
case LOCAL_DATE_TIME:
return LocalDateTime.parse(value);
default:
return value;
}
}
/**
* Briefly test this enum.
*
* @param args
* not used.
*/
public static void main(final String[] args) {
System.out.printf("%s: %s.%n", "now", DateType.forKeyString("now"));
System.out.printf("%s: %s.%n", "nowLocal",
DateType.forKeyString("nowLocal"));
System.out.printf("%s: %s.%n", "notNowLocal",
DateType.forKeyString("notNowLocal"));
System.out.printf("%s: %s.%n", "anythingElse",
DateType.forKeyString("anythingElse"));
}
}
</pre>
<p>And the class that creates the map and does serialisation etc.</p>
<pre class="brush:java" title="Using custom de-serialiser to serialise and de-serialise a JSON string.">
import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
import static java.lang.String.format;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.datatype.joda.JodaModule;
/**
* Test converting a map of multiple date types to a JSON string and back.
*/
public class JodaTimeMapTestMultipleDateTypes {
public static void main(final String[] args) throws Exception {
// Map with dates.
final DateTime now = new DateTime().withZone(DateTimeZone.UTC);
final LocalDateTime nowLocal = new LocalDateTime();
final LocalDateTime notNowLocal =
new LocalDateTime(2007, 3, 25, 2, 30, 0);
final Map<String, Object> dateMap = new HashMap<>();
dateMap.put("now", now);
dateMap.put("nowLocal", nowLocal);
dateMap.put("notNowLocal", notNowLocal);
// Serialise map to string.
final ObjectMapper mapper = mapper();
final String dateMapJson = mapper.writeValueAsString(dateMap);
// De-serialise string to map.
final TypeFactory typeFactory = mapper.getTypeFactory();
final MapType mapType = typeFactory.constructMapType(HashMap.class,
String.class, Object.class);
final Map<String, Object> dateMapFromJson =
mapper.readValue(dateMapJson, mapType);
// Print off the maps, JSON string and proof that the maps are equal.
System.out.printf("Starting map.%s%n%n", mapToString(dateMap));
System.out.printf("Map serialised to a JSON string.%n %s%n%n",
dateMapJson);
System.out.printf("Map de-serialised from JSON.%s%n%n",
mapToString(dateMapFromJson));
System.out.printf("Maps are equal: %s%n",
dateMap.equals(dateMapFromJson));
}
/**
* @param map
* with strings and dates.
* @return string that tells me what the keys, value classes and values are.
*/
private static String mapToString(final Map<String, Object> map) {
return format("%n %-13s %-30s %s", "key", "value class", "value") //
+ format("%n %-13s %-30s %s", "---", "-----------", "-----") //
+ map.entrySet().stream().map(entry -> {
final Object value = entry.getValue();
return format("%n %-13s %-30s %s", entry.getKey(),
value.getClass().getName(), value);
}).collect(Collectors.joining());
}
/**
* @return object that transform my maps to strings and back.
*/
private static ObjectMapper mapper() {
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.configure(WRITE_DATES_AS_TIMESTAMPS, false);
final SimpleModule dateDeserializerModule = new SimpleModule();
dateDeserializerModule.addDeserializer(Object.class,
new JodaMapDeserialiser());
mapper.registerModule(dateDeserializerModule);
return mapper;
}
}
</pre>
<p>The output from running <code>JodaTimeMapTestMultipleDateTypes</code> is below.</p>
<pre class="brush:plain" title="program output">
Starting map.
key value class value
--- ----------- -----
now org.joda.time.DateTime 2018-05-05T08:01:39.033Z
notNowLocal org.joda.time.LocalDateTime 2007-03-25T02:30:00.000
nowLocal org.joda.time.LocalDateTime 2018-05-05T18:01:39.204
Map serialised to a JSON string.
{"now":"2018-05-05T08:01:39.033Z","notNowLocal":"2007-03-25T02:30:00.000","nowLocal":"2018-05-05T18:01:39.204"}
Map de-serialised from JSON.
key value class value
--- ----------- -----
now org.joda.time.DateTime 2018-05-05T08:01:39.033Z
notNowLocal org.joda.time.LocalDateTime 2007-03-25T02:30:00.000
nowLocal org.joda.time.LocalDateTime 2018-05-05T18:01:39.204
Maps are equal: true
</pre>
<p class="jacksonTop"><a href="#topJacksonPost">To top of post.</a></p>
<h2 id="JacksonMavenDependencies">Maven dependencies</h2>
<p>Finally, my maven dependencies (joda time is included in jackson-datatype-joda).</p>
<pre class="brush:plain" title="program output">
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>2.9.5</version>
</dependency>
</pre>
<p class="jacksonTop"><a href="#topJacksonPost">To top of post.</a></p>
<p>Updates to post.</p>
<ul>
<li>Monday, 7th of May 2018, 09:58:20 AM. Added a TOC.</li>
</ul>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-31436388748668677262018-04-16T00:45:00.015+10:002020-12-09T10:27:40.058+11:00Data driven tests in JUnit 5 with exception handling<style>
.example {
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 100%;
}
.example td, .example th {
border: 1px solid #ddd;
padding: 8px;
}
.example tr:nth-child(even){background-color: #f2f2f2;}
.example tr:hover {background-color: #ddd;}
.example th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: #4CAF50;
color: white;
}
</style>
<p>My previous post on data driven tests with TestNG (<a href="http://robertmarkbramprogrammer.blogspot.com.au/2018/04/debug-testng-data-driven-tests-when-you.html">Debug TestNG data driven tests when you only want to debug one row of data</a>) showed how handy <strong>parameterized tests</strong> are and how to get around some limitations of TestNG in Eclipse.</p>
<p>JUnit is in my opinion a better test engine, and JUnit 5 has some great new features and offers a far superior set of tooling and mechanisms for running data driven tests, some of which I shall show here.</p>
<h2>Data driven testing in JUnit</h2>
<p>In this example, I am testing the ability to use regular expressions in Java: specifically the ability to find the first <a href="https://docs.oracle.com/javase/tutorial/essential/regex/groups.html">capturing group</a>.</p>
<pre><code class='java'>// Method under test that applies a regex to a string, returning the first group
public String searchString(final String regex, final String stringToMatchAgainst) {
final Pattern pattern = Pattern.compile(regex);
final Matcher matcher = pattern.matcher(stringToMatchAgainst);
if (matcher.matches()) {
return matcher.group(1);
}
return null;
}
</code></pre>
<p>A bit about this method.</p>
<ol>
<li>
This method accepts two parameters:
<ol>
<li>The regular expression, named <code>regex</code>.</li>
<li>The string we will apply the regular expression to, in oder to find a match. It is called <code>stringToMatchAgainst</code>.</li>
</ol>
</li>
<li>The method returns a string, specifically the first capturing group.
<ul>
<li>Quick example of regex groups. Groups are bracketed portions of a regular expression that can be referred to later as <a href="https://www.regular-expressions.info/backref.html">backreferences</a>. If you were to apply the regular expression <code>"([a-z]+) ([0-9]+)"</code> against the string <code>"letters 334"</code>, the first group would be <code>"letters"</code> and the second group would be <code>"334"</code>.</li>
</ul>
</li>
</ol>
<p>This is the test data I am using.</p>
<table class="example">
<tr>
<th>Test label</th>
<th>Regular expression</th>
<th>String to apply regex to</th>
<th>Expected first group</th>
</tr>
<tr>
<td>Any string matches any string.</td>
<td>(.*)</td>
<td>xyz</td>
<td>xyz</td>
</tr>
<tr>
<td>Pick year digits out of a date.</td>
<td>[0-9]{2}/[0-9]{2}/([0-9]{4})</td>
<td>31/12/2032</td>
<td>2032</td>
</tr>
<tr>
<td>No digits found.</td>
<td>[0-9]+</td>
<td>not a digit</td>
<td>null</td>
</tr>
<tr>
<td>First two words.</td>
<td>(?<firstTwoWords>\\w+ \\w+) .*</td>
<td>abc xyz one two</td>
<td>abc xyz</td>
</tr>
<tr>
<td>Bad regex.</td>
<td>([0-9+)</td>
<td>123</td>
<td>
PatternSyntaxException: (?s)Unclosed character class.*<br /><br />
<small><em>(This test case will throw an exception because the regular expression is invalid.)</em></small>
</td>
</tr>
</table>
<p>As described earlier, the regular expressions here use <a href="https://docs.oracle.com/javase/tutorial/essential/regex/groups.html">capturing groups</a>. In the fourth data set, I have also used <a href="http://farenda.com/java/java-8-regex-match-group-named-capturing-groups/">named capturing groups</a> - a cool regex feature added to Java in JDK 8.</p>
<p>Data driven testing (a.k.a. parameterized tests) is about being able to call a unit test method multiple times, giving it the actual data used to run the tests. This is as opposed to unit tests where the data is hard-coded within the test. <a href="https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests">JUnit 5's parameterized tests</a> gives you a lot of flexibility around how to generate your test data.</p>
<ul>
<li><code>@ValueSource</code> - an array initialised within the annotation.</li>
<li><code>@EnumSource</code> - an enum</li>
<li><code>@MethodSource</code> - a factory method</li>
<li><code>@CsvFileSource</code> - a CSV file</li>
</ul>
<p>The <code>@MethodSource</code> is arguably the most flexible because you can do so many things within a method to generate the returned data, including generating the data from an array, an enum, a CSV file, even doing a database lookup or calling some other service to get the data. My example will use <code>@MethodSource</code> and will generate a <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/util/stream/Stream.html">stream</a> of JUnit 5 <a href="https://junit.org/junit5/docs/5.0.3/api/index.html?org/junit/jupiter/params/provider/Arguments.html">arguments</a>.</p>
<pre><code class='java'>// A method that returns a stream of JUnit Arguments
private static Stream<Arguments> dataForTestSearchString() {
return Stream.of(//
Arguments.of("Any string matches any string.", "(.*)", "xyz", "xyz") //
, Arguments.of("Pick year digits out of a date.", "[0-9]{2}/[0-9]{2}/([0-9]{4})", "31/12/2032", "2032") //
, Arguments.of("No digits found.", "[0-9]+", "not a digit", null) //
, Arguments.of("First two words.", "(?<firstTwoWords>\\w+ \\w+) .*", "abc xyz one two", "abc xyz") //
, Arguments.of("Bad regex.", "([0-9+)", "123", "PatternSyntaxException: (?s)Unclosed character class.*") //
);
}
</code></pre>
<p>Notes about this method:</p>
<ul>
<li>It has no annotations, but it returns a stream of JUnit specific objects - <code>org.junit.jupiter.params.provider.Arguments</code></li>
<li>Use the Java single line comment <code>//</code> by itself to ensure a line of code gets broken off when you use automatic formatting.</li>
<li>When creating a <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/util/List.html">Java list</a> (or array, or any collection really), putting the comma at the start of each line (after the first) makes it easy to copy and paste a line to form the next list element without having to worry about <em>removing the comma from the end of the last element</em>.</li>
</ul>
<p>Here is the <code>@Test</code> method that consumes this test data.</p>
<pre><code class='java'>// JUnit5 @Test method whose data comes from dataForTestSearchString
@ParameterizedTest(name = "#{index} - [{0}]")
@MethodSource("dataForTestSearchString")
public void testFilesFromDirectoriesAndPattern(final String label, final String regex,
final String stringToMatchAgainst, final String expected) {
final String actual = searchString(regex, stringToMatchAgainst);
assertEquals(expected, actual);
}
</code></pre>
<p>Notes about this method.</p>
<ul>
<li>The <a href="https://junit.org/junit5/docs/5.0.2/api/index.html?org/junit/jupiter/params/ParameterizedTest.html">@ParameterizedTest annotation</a> lets you specify the "name" of each test data, which affects how each call to your test method is labelled in Eclipse. I have used the pattern <code>#{index} - [{0}]</code>, which means each test case will be labelled with the index of that test data and whatever the first argument to the test method is (so the first argument becomes the test case label). See the screenshot below to see how wonderful this is.</li>
<li>
The <a href="https://junit.org/junit5/docs/5.0.2/api/index.html?org/junit/jupiter/params/provider/MethodSource.html">@MethodSource annotation</a> allows you to name the method (or give an array naming multiple methods) that will generate data to be consumed by this test.
<ul>
<li>In the background, JUnit will use reflection to call the method, which has a side effect in Eclipse: if nothing else calls that method, Eclipse will give you a warning that your data generating method is unused (because it cannot work out from this annotation that you are really using it).</li>
</ul>
</li>
</ul>
<p>This is what you see in Eclipse when running this class as a JUnit test.</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8xmX34GImAwW6Yq1Vhx9npil9BuZ3IaoG1xIJZKGPRREl6TyYgDAz7hocIiggqFl7aQ2V5cqquTKKX3ozyA9QZP4LY7ZbN2dWnpRm3XNJ13I4KANN9ntHERbqklcJqtgys1Pq/s1600/2018-04-16+00_00_51-CygwinJavaUtils_src_test_java_org_rmb_JunitDataDrivenTest.java+-+Spring+Tool+Sui.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="856" data-original-width="1021" height="536" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8xmX34GImAwW6Yq1Vhx9npil9BuZ3IaoG1xIJZKGPRREl6TyYgDAz7hocIiggqFl7aQ2V5cqquTKKX3ozyA9QZP4LY7ZbN2dWnpRm3XNJ13I4KANN9ntHERbqklcJqtgys1Pq/s640/2018-04-16+00_00_51-CygwinJavaUtils_src_test_java_org_rmb_JunitDataDrivenTest.java+-+Spring+Tool+Sui.png" width="640" /></a></div>
<p>One of the most important advantages of JUnit in Eclipse over TestNG is that you can run individual test cases by right-clicking on the one you want to re-run and select "Run" or "Debug" (<a href="http://robertmarkbramprogrammer.blogspot.com.au/2018/04/debug-testng-data-driven-tests-when-you.html">TestNG would re-run the whole lot</a>).</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIHE7-xvGFKzJdPxKl27QerBDIjG7LRx3iqh0G138n5BNiiCsGy6ZgpcHEV2WSJDcC5oD3fzMAkeSxpxWUMv9b6GRtG0fSTHHovlu1Oxn1VIwlzbZFJ1m_xxqXw7NpkPvN3Ol2/s1600/2018-04-15+23_25_47-Temp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="383" data-original-width="1024" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIHE7-xvGFKzJdPxKl27QerBDIjG7LRx3iqh0G138n5BNiiCsGy6ZgpcHEV2WSJDcC5oD3fzMAkeSxpxWUMv9b6GRtG0fSTHHovlu1Oxn1VIwlzbZFJ1m_xxqXw7NpkPvN3Ol2/s640/2018-04-15+23_25_47-Temp.png" width="640" /></a></div>
<p>Here is version 1 the full test case, incorporating the method being tested.</p>
<pre><code class='java'>// First version of the data driven test, including the method being tested
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
public class JunitDataDrivenTest {
/**
* @return test data. Each set of arguments should consist of
* <ol>
* <li>test label</li>
* <li>regex</li>
* <li>string we apply the regex to</li>
* <li>first group matched by the regex</li>
* </ol>
*/
@SuppressWarnings({ "unused" }) // Eclipse thinks this method is not used.
private static Stream<Arguments> dataForTestSearchString() {
return Stream.of(//
Arguments.of("Any string matches any string.", "(.*)", "xyz", "xyz") //
, Arguments.of("Pick year digits out of a date.", "[0-9]{2}/[0-9]{2}/([0-9]{4})", "31/12/2032", "2032") //
, Arguments.of("No digits found.", "[0-9]+", "not a digit", null) //
, Arguments.of("First two words.", "(?<firstTwoWords>\\w+ \\w+) .*", "abc xyz one two", "abc xyz") //
, Arguments.of("Bad regex.", "([0-9+)", "123", "PatternSyntaxException: (?s)Unclosed character class.*") //
);
}
/**
* @param label
* description of the current test. Data is used for reporting only.
* @param regex
* regular expression.
* @param stringToMatchAgainst
* string that we will apply the regex to
* @param expected
* first group matched by the regex. Will be null if no match is expected.
*/
@ParameterizedTest(name = "#{index} - [{0}]")
@MethodSource("dataForTestSearchString")
public void testFilesFromDirectoriesAndPattern(final String label, final String regex,
final String stringToMatchAgainst, final String expected) {
final String actual = searchString(regex, stringToMatchAgainst);
assertEquals(expected, actual);
}
/**
* A method being tested.
*
* @param regex
* regular expression.
* @param stringToMatchAgainst
* string that we will apply the regex to
* @return first group matched by the regex. Will be null if no match is expected.
*/
public String searchString(final String regex, final String stringToMatchAgainst) {
final Pattern pattern = Pattern.compile(regex);
final Matcher matcher = pattern.matcher(stringToMatchAgainst);
if (matcher.matches()) {
return matcher.group(1);
}
return null;
}
}
</code></pre>
<h2>Testing for exceptions</h2>
<p>Another new aspect of JUnit 5 is the set of <a href="https://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions">assertions that use lambdas from JDK 8</a>, particularly <a href="https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html#assertThrows-java.lang.Class-org.junit.jupiter.api.function.Executable-">the assertThrows method</a> which I will demonstrate next.</p>
<p>As mentioned above, the last test case throws an exception because of an invalid regular expression (<code>"([0-9+)"</code> doesn't close the square brackets: it should be <code>"([0-9]+)"</code>). A normal part of unit testing should be ensuring that code throws appropriate exceptions when something goes wrong. Here is the unit test adjusted so that if our parameterized data indicates that an exception is expected, we test for it. We test for the expected exception type and have a regular expression to test the exception's message.</p>
<pre><code class='java'>// JUnit test that checks if code throws an exception if our parameterized data indicates one is expected
@ParameterizedTest(name = "#{index} - [{0}]")
@MethodSource("dataForTestSearchString")
public void testFilesFromDirectoriesAndPattern(final String label, final String regex,
final String stringToMatchAgainst, final String expected) {
// Types of exceptions we test for.
final String patternSyntaxException = "PatternSyntaxException: ";
// PatternSyntaxException
if (expected != null && expected.startsWith(patternSyntaxException)) {
final PatternSyntaxException pse = assertThrows(PatternSyntaxException.class, () -> {
searchString(regex, stringToMatchAgainst);
});
final Pattern exceptionPattern = Pattern.compile(expected.substring(patternSyntaxException.length()));
final Matcher exceptionMatcher = exceptionPattern.matcher(pse.getMessage());
assertTrue(exceptionMatcher.matches());
} else {
// Normal operation.
final String actual = searchString(regex, stringToMatchAgainst);
assertEquals(expected, actual);
}
}
</code></pre>
<p>Notes about this method.</p>
<ul>
<li>We use one of the method parameters, a string named <code>expected</code> to tell the method what result we should expect under normal (successful) operation.</li>
<li>
I have extended the use of that string to also tell me what to expect in exceptional circumstances. In my code, I know what exceptions I am testing for and have decided that for test cases that should throw an exception, the <code>expected</code> string should start with the class name of the exception and the rest of the string will be a regular expression that should match the exception's message (<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Throwable.html#getMessage--">getMessage()</a>).
<ul>
<li>To do this I need some string processing: a test to see if the string starts with an exception class name and then a substring operation to pull out the regex.</li>
<li>I then need code to create the <code>Pattern</code>, the <code>Matcher</code> and then test if the regex matches the exception message.</li>
</ul>
</li>
</ul>
<p>The unit test now passes in all cases.</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6BRRBEDVGRy82u6TXLwi2JH6A0rJE7_0KP0fAejIKHCZ5HF_HrCMncn5agf7hnXQoOl64uWzMu-OW75Z-VLU32HZZ1azOAtIPLWCJwMeyBac9UH2RJgHMS8Rg_8rQCzDiRggz/s1600/2018-04-16+00_29_54-CygwinJavaUtils_src_test_java_org_rmb_JunitDataDrivenTest.java+-+Spring+Tool+Sui.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="856" data-original-width="1021" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6BRRBEDVGRy82u6TXLwi2JH6A0rJE7_0KP0fAejIKHCZ5HF_HrCMncn5agf7hnXQoOl64uWzMu-OW75Z-VLU32HZZ1azOAtIPLWCJwMeyBac9UH2RJgHMS8Rg_8rQCzDiRggz/s320/2018-04-16+00_29_54-CygwinJavaUtils_src_test_java_org_rmb_JunitDataDrivenTest.java+-+Spring+Tool+Sui.png" width="320" /></a></div>
<p>Here is the final version of the full test case, incorporating exception testing.</p>
<pre><code class='java'>// Final version of the data driven test including exception testing
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
public class JunitDataDrivenTest {
/**
* @return test data. Each set of arguments should consist of
* <ol>
* <li>test label</li>
* <li>regex</li>
* <li>string we apply the regex to</li>
* <li>first group matched by the regex</li>
* </ol>
*/
@SuppressWarnings({ "unused" }) // Eclipse thinks this method is not used.
private static Stream<Arguments> dataForTestSearchString() {
return Stream.of(//
Arguments.of("Any string matches any string.", "(.*)", "xyz", "xyz") //
, Arguments.of("Pick year digits out of a date.", "[0-9]{2}/[0-9]{2}/([0-9]{4})", "31/12/2032", "2032") //
, Arguments.of("No digits found.", "[0-9]+", "not a digit", null) //
, Arguments.of("First two words.", "(?<firstTwoWords>\\w+ \\w+) .*", "abc xyz one two", "abc xyz") //
, Arguments.of("Bad regex.", "([0-9+)", "123", "PatternSyntaxException: (?s)Unclosed character class.*") //
);
}
/**
* @param label
* description of the current test. Data is used for reporting only.
* @param regex
* regular expression.
* @param stringToMatchAgainst
* string that we will apply the regex to
* @param expected
* first group matched by the regex. Will be null if no match is expected.
*/
@ParameterizedTest(name = "#{index} - [{0}]")
@MethodSource("dataForTestSearchString")
public void testFilesFromDirectoriesAndPattern(final String label, final String regex,
final String stringToMatchAgainst, final String expected) {
// Types of exceptions we test for.
final String patternSyntaxException = "PatternSyntaxException: ";
// PatternSyntaxException
if (expected != null && expected.startsWith(patternSyntaxException)) {
final PatternSyntaxException pse = assertThrows(PatternSyntaxException.class, () -> {
searchString(regex, stringToMatchAgainst);
});
final Pattern exceptionPattern = Pattern.compile(expected.substring(patternSyntaxException.length()));
final Matcher exceptionMatcher = exceptionPattern.matcher(pse.getMessage());
assertTrue(exceptionMatcher.matches());
} else {
// Normal operation.
final String actual = searchString(regex, stringToMatchAgainst);
assertEquals(expected, actual);
}
}
/**
* A method being tested.
*
* @param regex
* regular expression.
* @param stringToMatchAgainst
* string that we will apply the regex to
* @return first group matched by the regex. Will be null if no match is expected.
*/
public String searchString(final String regex, final String stringToMatchAgainst) {
final Pattern pattern = Pattern.compile(regex);
final Matcher matcher = pattern.matcher(stringToMatchAgainst);
if (matcher.matches()) {
return matcher.group(1);
}
return null;
}
}
</code></pre>
<h2>Versions</h2>
<p>Software used in this post.</p>
<ul>
<li>JDK 1.8 (1.8.0_40)</li>
<li>Eclipse is <strong>Spring Tool Suite</strong> 3.9.2.RELEASE (build on Eclipse Oxygen.2 (4.7.2))</li>
<li><strong>Junit</strong> plugin is built in</li>
<li>JUnit dependencies in my <strong>pom.xml</strong>:
<pre><code class='xml'>
<!-- JUnit Maven dependencies -->
<!-- JUnit Jupiter is the API we write tests against. -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.1.0</version>
<scope>test</scope>
</dependency>
<!-- Parameterised tests is separate download because it is currently an experimental feature. -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.1.0</version>
<scope>test</scope>
</dependency>
<!-- The engined used by the IDE to run tests. JUnit is built in to Eclipse, but apparently my version of Eclipse can't run JUnit 5 tests. -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.1.0</version>
<scope>test</scope>
</dependency>
</code></pre>
</li>
</ul>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-43172928461438095822018-04-14T17:23:00.001+10:002018-04-15T17:35:07.217+10:00Debug TestNG data driven tests when you only want to debug one row of data<p><strong>Update</strong> Sunday, 15th of April 2018, 05:34:43 PM: added versioning information at the bottom of the post.</p>
<p><a href="http://testng.org/doc/index.html">TestNG</a> has a relatively straightforward mechanism for <a href="http://testng.org/doc/documentation-main.html#parameters">data driven tests</a> that lets you write a method (annotated with <a href="https://jitpack.io/com/github/cbeust/testng/master/javadoc/index.html?org/testng/annotations/DataProvider.html">@DataProvider</a>) that generates data that will be used to invoke a test method (annotated by <a href="https://jitpack.io/com/github/cbeust/testng/master/javadoc/index.html?org/testng/annotations/Test.html">@Test</a>). Here is an example where one of the tests will fail with a <code>NullPointerException</code>.</p>
<pre class="brush:java" title="TestNG data driven test.">
import static org.junit.Assert.assertTrue;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestString{
@DataProvider(name = "dataForTestStringLength")
public Object[][] dataForTestStringLength() {
return new Object[][] { //
new Object[] { "string" }, //
new Object[] { null }, //
new Object[] { "longer string" }, //
new Object[] { "an even longer string" }, //
};
}
@Test(dataProvider = "dataForTestStringLength")
public void testStringLength(final String stringToTest) {
assertTrue(stringToTest.length() > 3);
}
}
</pre>
<p>This is what the result looks like in Eclipse.</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNEC7zGpPw4mL5hpiOM2Er3tHm3ns5h31oEGCMw_4mJyMMLel-OW30EUTx78ifaE_mJnoc5aAS7jRMOvUeCtIcl8MdWRDmuPKDudBbjQj55RyCoq84agyDTrmQTWGKR0JQDShI/s1600/2018-04-14+17_15_30-CygwinJavaUtils_src_test_java_org_rmb_util_TestString.java+-+Spring+Tool+Suite.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="856" data-original-width="793" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNEC7zGpPw4mL5hpiOM2Er3tHm3ns5h31oEGCMw_4mJyMMLel-OW30EUTx78ifaE_mJnoc5aAS7jRMOvUeCtIcl8MdWRDmuPKDudBbjQj55RyCoq84agyDTrmQTWGKR0JQDShI/s640/2018-04-14+17_15_30-CygwinJavaUtils_src_test_java_org_rmb_util_TestString.java+-+Spring+Tool+Suite.png" width="592" /></a></div>
<p>This is fine and expected, but the problem starts when you want to run just that one failing test again, or to debug it.</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgntNdu340NJVTeavlJ0orhlcWJxkT2w03kgb4JFInbpDGIiPg878gGJy85rMtR7i9t4ZKVB2iYhuJaSZHcFKkttHHXoVx4QvaOm3cCcCMoC1yyfPB77z5en7Y_GKdmB0XdxVU/s1600/2018-04-14+17_15_41-Temp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="357" data-original-width="787" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgntNdu340NJVTeavlJ0orhlcWJxkT2w03kgb4JFInbpDGIiPg878gGJy85rMtR7i9t4ZKVB2iYhuJaSZHcFKkttHHXoVx4QvaOm3cCcCMoC1yyfPB77z5en7Y_GKdmB0XdxVU/s640/2018-04-14+17_15_41-Temp.png" width="640" /></a></div>
<p>Even though you right click on just the one data set, TestNG will re-run all of them (all four in this case). This makes it hard to debug tests, because if you set a debug point, you have to keep skipping until you get the actual test case you want. This becomes much more frustrating when you have a large data set. It might be easy to deal with just just four data sets, but not so easy when you have twenty or thirty or more. Plus, more complex tests won't have just one column of data to test, but four, five or more - it will be hard to even identify which test case failed when each of the combinations look similar.</p>
<p>Here is a technique I use to make it much easier to debug specific test cases.</p>
<pre class="brush:java" title="TestNG data driven test where it is easier to debug individual test cases">
import static org.junit.Assert.assertTrue;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestString {
@DataProvider(name = "dataForTestStringLength")
public Object[][] dataForTestStringLength() {
int count = 0;
final Object[][] data = new Object[][] { //
new Object[] { count++, "string" }, //
new Object[] { count++, null }, //
new Object[] { count++, "longer string" }, //
new Object[] { count++, "an even longer string" }, //
};
// Use this to test specific cases only.
final Object[][] debuggingData = new Object[][] { /* data[1] */ };
if (debuggingData.length > 0) {
return debuggingData;
}
return data;
}
@Test(dataProvider = "dataForTestStringLength")
public void testStringLength(final int index, final String stringToTest) {
assertTrue(stringToTest.length() > 3);
}
}
</pre>
<p>I have made two important changes here.</p>
<ol>
<li>I have modified the <code>@DataProvider</code> method so that it doesn't automatically return every test case.
Modify the <code>debuggingData</code> line to specify the index of the test case you want to test.</li>
<li>How do we know which test case to debug? That's the reason for the extra parameter added to the data returned from the <code>@DataProvider</code> method: an <code>int count</code> that gets incremented for each test case and received in the <code>@Test</code> as <code>final int index</code>.</li>
</ol>
<p>Now look what Eclipse shows when a test fails:</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsukmEmCC1__bMsJ8eEBBvhb1ZEKAjew1tq8ZHKTDgBWNxewNxGQ0Z7khL1FFbvBhw-Oo2L7Q-6iAWf_YaCa4qa40-CFsBXZJ0YmwPT8idfRCy27JlX6BA-NJJvyGiURRAzreG/s1600/2018-04-14+17_13_16-CygwinJavaUtils_src_test_java_org_rmb_util_TestString.java+-+Spring+Tool+Suite.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="856" data-original-width="793" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsukmEmCC1__bMsJ8eEBBvhb1ZEKAjew1tq8ZHKTDgBWNxewNxGQ0Z7khL1FFbvBhw-Oo2L7Q-6iAWf_YaCa4qa40-CFsBXZJ0YmwPT8idfRCy27JlX6BA-NJJvyGiURRAzreG/s640/2018-04-14+17_13_16-CygwinJavaUtils_src_test_java_org_rmb_util_TestString.java+-+Spring+Tool+Suite.png" width="592" /></a></div>
<p>The index of the failed test is now clearly visible, so it's easy for me to adjust the <code>@DataProvider</code> method to only return the data set I actually want to debug.</p>
<pre class="brush:java" title="The @DataProvider will now only return this single data set">
final Object[][] debuggingData = new Object[][] { data[1] };
</pre>
<p>Versions used in this post.</p>
<ul>
<li>Eclipse is <strong>Spring Tool Suite</strong> 3.9.2.RELEASE (build on Eclipse Oxygen.2 (4.7.2))</li>
<li><strong>TestNG</strong> 6.14 plugin</li>
<li>TestNG dependency in my <strong>pom.xml</strong>:
<pre class="brush:xml" title="TestNG Maven dependency">
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8</version>
<scope>test</scope>
</dependency>
</pre>
</li>
</ul>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-66722190914051572952017-09-11T11:21:00.000+10:002017-09-11T11:22:54.986+10:00Bash script to repeat a task until you tell it to stop<p>For example, when I am running some task that outputs to the database but takes time to finish, rather than running the SQL myself over and over, I will script it and run the script to repeat. Then I hit ENTER whenever I am ready to find out when it has finished. This becomes more effective when I script the whole task: start the asynchronous job that takes awhile, then repeat-run the monitoring script.</p>
<pre class="brush:bash" title="Repeat a task: repeat.sh">
#!/bin/bash
weContinue=true
while "${weContinue}" == true ; do
"$@"
echo "[$(date)] Press ENTER to continue; press any other key (then ENTER) to stop."
read response
if [ -n "${response}" ] ; then
weContinue=false
fi
done
</pre>
<p>Example running it.</p>
<pre>
Mon Sep 11 - 11:11 AM > repeat echo "Do something important"
Do something important
[Mon, Sep 11, 2017 11:19:54 AM] Press ENTER to continue; press any other key (then ENTER) to stop.
Do something important
[Mon, Sep 11, 2017 11:19:58 AM] Press ENTER to continue; press any other key (then ENTER) to stop.
Do something important
[Mon, Sep 11, 2017 11:20:01 AM] Press ENTER to continue; press any other key (then ENTER) to stop.
stop thanks
</pre>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-38035031301122238192017-07-30T17:56:00.000+10:002017-08-03T11:06:30.544+10:00Scripts and .screenrc to make GNU Screen splits easier<p><strong>Update</strong> Thursday, 3rd of August 2017, 11:04:30 AM: much better to use <code>bind</code> over <code>stuff</code> to run a script within the <code>.screenrc</code> file.</p>
<p>I enjoy <code>GNU screen</code> via Cygwin on Windows a lot, but some of the commands get a bit fiddly. Creating splits is like that: you create a split, then move to it, then assign a window to it.</p>
<p>My first set of shortcuts were to create scripts to do those jobs.</p>
<p>To make a vertical split:</p>
<script src="https://gist.github.com/robertmarkbram/996b36334abe31918915f0283a119ea7.js"></script>
<p>To make a horizontal script:</p>
<script src="https://gist.github.com/robertmarkbram/c16e720b5685f4db5eaa72721bfd6e01.js"></script>
<p>Lastly, key bindings that go in my <code>.screenrc</code> file to run those scripts.</p>
<pre class="brush:bash" title="Config for the .screenrc file">
# ------------------------------
# SPLIT HORIZONTALLY OR VERTICALLY.
# ------------------------------
# Uses split scripts.
# Control+a, V for vertical; control+a, H for horizontal.
# bind V stuff 'screenSplitVertical'\012''
# bind H stuff 'screenSplitHorizontal'\012''
bind V exec $HOME/bin/screenSplitVertical.sh
bind H exec $HOME/bin/screenSplitHorizontal.sh
</pre>
<p>Explanation for version that uses <em>exec</em>:</p>
<ol>
<li><code>bind V</code> says the rest of this line will be executed upon "<code>control+a, shift+v</code>"</li>
<li><code>exec</code> means run the rest of the line as a command.</li>
<li><code>$HOME/bin/screenSplitVertical.sh</code> is the full path to the command (script) I want to run.</li>
</ol>
<p>Explanation for version that uses <em>stuff</em>:</p>
<ol>
<li><code>bind V</code> says the rest of this line will be executed upon "<code>control+a, shift+v</code>"</li>
<li><code>stuff</code> will "write stuff to the command line" or "stuff text onto the command line".</li>
<li><code>'screenSplitVertical'\012''</code> will write out the command <strong>screenSplitVertical.sh</strong> and then <strong>'\012'</strong> which outputs a newline (<strong>ENTER</strong> key) to actually cause the script to run.</li>
</ol>
<p>In general, <code>exec</code> is more suitable than <code>stuff</code> in this situation because <code>stuff</code> will leave the command in my command history.</p>
<p>More screen magic? Check out <a href="https://gist.github.com/joaopizani/2718397">joaopizani's .screenrc config</a> for some great ideas about resizing splits and moving between them.</p><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-83968722346591115072015-11-08T16:55:00.000+11:002015-11-08T16:55:07.689+11:00Maven project with Spring, Log4j2 and properties<p>This a reference I use to quickly come up with a standalone app (no server) that uses Spring Boot, Log4j2 and a properties file.</p>
<p>The <code>pom.xml</code> file.</p>
<pre class="brush:xml" title="pom.xml">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.testproject</groupId>
<artifactId>TestProject</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>TestProject</name>
<url>http://maven.apache.org</url>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<jodatime.version>2.5</jodatime.version>
<junit.version>4.12</junit.version>
<log4j.version>2.4.1</log4j.version>
<spring.boot.version>1.2.5.RELEASE</spring.boot.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring.boot.version}</version>
</dependency>
</dependencies>
</project>
</pre>
<p>The configuration class that launches the app.</p>
<pre class="brush:java" title="The configuration class - TestApp.java">
package org.testproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* Configuration and runner for the test app.
*/
@Configuration
@ComponentScan(basePackages = { "org.testproject.*" })
@EnableAutoConfiguration
public final class TestApp {
/**
* Launch app.
*
* @param args
* not used
*/
public static void main(final String[] args) {
SpringApplication.run(Runner.class, args);
}
}
</pre>
<p>The runner - the class that does the actual work.</p>
<pre class="brush:java" title="The class that does the actual work - Runner.java">
package org.testproject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
/**
* Read in a message file from Touch Copy and transform the contents to be diary
* ready.
*
* @author RobertMarkBram
*/
@Component
@PropertySources(value = {@PropertySource("classpath:/application.properties")})
public final class Runner implements CommandLineRunner {
/** Logger for this class. */
static final Logger LOG = LogManager.getLogger(Runner.class
.getName());
/** Use to access properties. */
@Autowired
private Environment env;
/* (non-Javadoc)
* @see org.springframework.boot.CommandLineRunner#run(java.lang.String[])
*/
@Override
public void run(final String... args) throws Exception {
String testproperty = env.getProperty("testProperty");
LOG.info(testproperty);
}
}
</pre>
<p>The application property file.</p>
<pre class="brush:plain" title="Properties file - application.properties">
testProperty=Hello World
</pre>
<p>The log4j2 configuration - note that number 2 is there.. this not old log4j anymore.</p>
<pre class="brush:xml" title="log4j2 configuration - log4j2.xml">
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="CONSOLE" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<logger name="org.testproject" level="DEBUG" />
<Root level="ERROR">
<AppenderRef ref="CONSOLE"/>
</Root>
</Loggers>
</Configuration>
</pre>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-60654139586117904972015-09-15T21:58:00.001+10:002015-11-04T00:15:53.884+11:00Date time stamps in bash with ordinal indicator<p><strong>Update</strong> (Wednesday, 4th of November 2015, 12:15:35 AM): added link to more complicated script.</p>
<p>Date time stamps are easy in bash:</p>
<pre class="code">
> echo $(date +"%Y%m%d_%H%M%S")
20150915_214916
</pre>
<p>But I want more friendly date time stamps, like <code>Tuesday, 15th of September 2015, 09:54:42 PM</code>.</p>
<p>I found an algorithm that <a href="http://stackoverflow.com/users/13940/greg-mattes">Greg Mattes</a> wrote in this <a href="http://stackoverflow.com/a/4011232/257233">StackOverflow answer for Java</a>. Here it is in bash:</p>
<pre class="brush:bash" title="Output ordinal indicator for day of month, saved as dateOrdinal.sh">
#!/bin/bash
n=$(date +"%d")
if [ $n -ge 11 -a $n -le 13 ] ; then
echo "th"
else
case $(( $n%10 )) in
1)
echo st
;;
2)
echo nd
;;
3)
echo rd
;;
*)
echo th
;;
esac
fi
</pre>
<p>So now I can do:</p>
<pre>
> echo $(date +"%A, %d`dateOrdinal.sh` of %B %Y, %I:%M:%S %p")
Tuesday, 15th of September 2015, 09:57:53 PM
</pre>
<p>Here is a more complicated version of this script that will accept a date, a date format and output formatted date where you can use <code>%O</code> as a placeholder for the ordinal in the format: <a href="http://pastebin.com/xZ1afqqC">http://pastebin.com/xZ1afqqC</a>.</p><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-1171831221973262502015-06-18T23:36:00.001+10:002015-06-18T23:36:02.963+10:00JQuery UI tooltip with a close link for mobile
<p>Here is the JQuery code I use to to set up <a href="http://api.jqueryui.com/tooltip">JQuery UI tool tips</a> with a close link that only appears on mobile platforms. This is useful because on a desktop, the tool tip will close when you <code>mouseout</code> from the target element, but on a touch platform it sticks around.</p>
<pre class="brush:plain" title="JQuery to create tooltips on selected elements and add a close link on mobile.">
// Set up tool tips for images and anchors.
$( document ).tooltip({
items: "a[title], img[alt], .toolTip[title], :not(.noToolTip)",
track: true,
position: { my: "left+15 center", at: "right center" },
content: function() {
var element = $( this );
var closer = closerLink = '';
if (isMobile()) {
closer = ' <br><div onClick="$(this).parent().parent().remove();" style="color: blue; text-decoration: underline; text-align: right;">Close</div>';
closerLink = ' <br>Tap link again to open it.<br><div onClick="$(this).parent().parent().remove();" style="color: blue; text-decoration: underline; text-align: right;">Close</div>';
}
// noToolTip means NO TOOL TIP.
if ( element.is( ".noToolTip" ) ) {
return null;
}
// Anchor - use title.
if ( element.is( "a[title]" ) ) {
return element.attr( "title" ) + closerLink;
}
// Image - use alt.
if ( element.is( "img[alt]" ) ) {
return element.attr( "alt" ) + closer;
}
// Any element with toolTip class - use title.
if ( element.is( ".toolTip[title]" ) ) {
return element.attr( "title" ) + closer;
}
}
});
function isMobile() {
return (/iPhone|iPod|iPad|Android|BlackBerry/).test(navigator.userAgent);
}
</pre>
<p>I am targeting three types of things here:</p>
<ul>
<li>Anchor tags (<code>a</code>) with a <code>title</code> attribute.</li>
<li>Image tags (<code>img</code>) with a <code>title</code> attribute.</li>
<li>Any element with class <code>toolTip</code>.</li>
<li>And specifically <em>exclude</em> any element with class <code>noToolTip</code>.</li>
</ul>
<p>You can see this in action on my newly refreshed site: <a href="http://chihuahuarescuevictoria.org/">Chihuahua Rescue Victoria</a>.</p>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-89678997724456619522015-06-17T13:11:00.001+10:002015-06-17T13:11:31.646+10:00Run main class in test dir from maven with Java agent and Log4J configuration<p>It took a bit of help from <a href="http://stackoverflow.com/a/30839824/257233">Michal</a> (on this StackOverflow post: <a href="http://stackoverflow.com/questions/30839272/running-main-method-from-test-class-via-maven">Running main method from test class via maven</a>) before I got this right. But here it is:</p>
<pre class="brush:xml" title="Maven profile to run a main method of a test class">
<profile>
<id>run-importer</id>
<properties>
<loadTimeWeaverArg>-javaagent:"${settings.localRepository}/org/springframework/spring-agent/2.5.6/spring-agent-2.5.6.jar"</loadTimeWeaverArg>
<log4JConfigArg>-Dlog4j.configuration=file:${project.build.directory}/path/to/log4j.properties</log4JConfigArg>
<mainClassArg>com.myorg.MyClass</mainClassArg>
<arg1>foo</arg1>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>java</executable>
<classpathScope>test</classpathScope>
<arguments>
<argument>${log4JConfigArg}</argument>
<argument>${loadTimeWeaverArg}</argument>
<argument>-classpath</argument>
<classpath />
<argument>${mainClassArg}</argument>
<argument>${arg1}</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</pre>
<p>And I run it with the command line: <code>mvn -e exec:exec -Prun-importer</code></p>
<p>The advantages of this approach:</p>
<ul>
<li>The whole purpose of this profile is to run "special code" that should never be deployed but needs to make use of code in src and test src.</li>
<li>It leaves room in case this ever needs to be duplicated, so there is no "competition" regarding what gets run with <code>mvn -e exec:exec</code>.</li>
<li>I can specify java agent, log4j and lots of other config using variables that already exist in the pom.</li>
<li>I can override any of these arguments on the command line with <code>-Darg1="bar"</code></li>
</ul><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-31478235250297984232015-04-26T23:10:00.000+10:002015-04-27T15:12:30.773+10:00Generating getters setters toString hashCode and equals<p>Generating code is a good way to remove so much boilerplate in Java that you would otherwise write by hand. Getters and setters is a big one. Eclipse can generate those, but Eclipse generation clashes with Checkstule rules that I use. The <code>toString()</code>, <code>equals()</code> and <code>hashCode()</code> methods are important to get right too. Previously I set up Eclipse templates but I still had to fill in the details by hand. Most of the time it's better to start with a default implementation for each that uses every non-static field in the class.</p>
<p>This post demonstrates some code I have written to automate the generation of these things.</p>
<h2>Checkstyle vs Getters and Setters</h2>
<p>I use <a href="http://checkstyle.sourceforge.net/">Checkstyle</a> wherever I can. It encourages me to write code with a consistent style and, like <a href="http://findbugs.sourceforge.net/">FindBugs</a>, helps me to avoid common errors. Here are some Checkstyle rules that I use:</p>
<ol>
<li><a href="http://checkstyle.sourceforge.net/config_javadoc.html#JavadocMethod">Ensure that I have a jadvadoc comment on fields and methods</a>. This includes checking that I have a <code>@return</code> tag for non-void methods and a <code>@param</code> tag for each parameter. Javadoc comments let me impart important context that cannot always be achieved by <a href="http://en.wikipedia.org/wiki/Self-documenting">self documentating code</a>.</li>
<li><a href="http://checkstyle.sourceforge.net/config_misc.html#FinalParameters">Final parameters on methods</a>. Avoid accidentally re-assigning a parameter during method execution by making sure that all parameters are delcared as <code>final</code>. If I need a primitive (or wrapper or other immutable object like String) whose value will change, it is clearer to define a new local variable and assign it an initial value from the corresponding <code>final</code> parameter if needed.</li>
<li><a href="http://checkstyle.sourceforge.net/config_coding.html#HiddenField">Avoid hidden fields</a>. Don't have a parameter with the same name as an instance variable, because it is too easy to accidentally modify the wrong one. Using <code>this</code> on the instance variable will avoid these errors, but it is easy to forget.</li>
</ol>
<p>In my opinion, these are very good rules to live by when coding and as I write new methods, I find myself automatically implementing these rules: they have become <a href="http://www.tipitout.com/muscle-memory-by-dr-golf-geek/">muscle memory</a> for me.</p>
<p>However these rules have a cost when dealing with getters and setters. Let's say I create a new class, add ten fields, and in Eclipse select <code>Source > Generate getters and setters > select all > OK</code> and bam, I have ten corresponding accessor and mutator methods for my ten fields. Now I would have to edit <em>twenty methods</em> to correct the comments and edit <em>ten methods</em> to make parameters final and give them a different name. Here is an example of the getters and setters generated by Eclipse.</p>
<pre class="brush:java" title="Getters and setters generated by Eclipse.">private String name;
private int id;
/**
* @return the name
*/
public final String getName() {
return name;
}
/**
* @param name the name to set
*/
public final void setName(String name) {
this.name = name;
}
/**
* @return the id
*/
public final int getId() {
return id;
}
/**
* @param id the id to set
*/
public final void setId(int id) {
this.id = id;
}
</pre>
<p> Eclipse generation cannot, as yet, make parameters final or give them different names, and the comments are very basic and only use the parameter name to make them different. It is less likely that following the Checkstyle rules will create as much value on getters and setters as on other methods. Getters and setters are very simple methods, usually one-liners. Because they are so simple that they can be auto-generated, we don't generally modify them after creation - so there is less need to give them the protection of checkstyle rules like final parameters and avoiding hidden fields. Thus, the cost of editing so many methods is rarely worth the value it gives.</p>
<p>Having said all that, there a couple of reasons why I still want to follow these rules, even on getters and setters <em>if I can cut the cost significantly</em>.</p>
<ul>
<li>Comments are still valuable for fields/getters/setters that cannot be truly un-ambiguously named, which happens often enough no matter how much thought you can put into it. For the simple ones, simple comments are fine.</li>
<li>If my <em>Eclipse Problems or Markers view</em> is filled up with dozens of Checkstyle warnings from getters and setters, it is harder for me to spot the warnings I really should take care of. So I would prefer to keep my Problem/Markers view clean and automatically implement the Checkstyle rules if possible.</li>
</ul>
<h2>Generate Boilerplate</h2>
<p>So here is how I have attempted to fix this issue and make it as painless as possible to generate getters and setters and implement the Checkstyle rules I want. At the same time, I will generate decent default <code>toString()</code>, <code>equals()</code> and <code>hashCode()</code> methods to copy and paste too.</p>
<p>As a pre-requisite, I have checked out my utils project from <a href="https://github.com">GitHub</a> into Eclipse: <a href="https://github.com/robertmarkbram/RobUtils">https://github.com/robertmarkbram/RobUtils</a> so that I can use three classes in particular:</p>
<ul>
<li> <a href="https://github.com/robertmarkbram/RobUtils/blob/master/src/org/rmb/reflectionutils/OutputFieldList.java">OutputFieldList.java</a> which has some utility functions that use reflection to inspect a class and do things I sometimes find useful such as
<ul>
<li>output a list of fields or getters and setters that are present in a class.</li>
<li>output sample equals(), hashCode() and toString() impelementations using the <a href="http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/builder/package-summary.html">commons lang builders</a>.</li>
<li>outputs sample getters and setters from fields defined in a class.</li>
</ul>
</li>
<li><a href="https://github.com/robertmarkbram/RobUtils/blob/master/src/org/rmb/reflectionutils/javadoc/FieldComment.java">FieldComment.java</a> which is an annotation that stores a field's comment that <code>OutputFieldList</code> will read and output as javadoc comments for getter and setter fields. It's based on a solution <a href="http://stackoverflow.com/users/748766/abhi">Abhi</a> wrote about in this <a href="http://stackoverflow.com">StackOverflow</a> answer to the question: <a href="http://stackoverflow.com/a/21889648/257233">How to get a JavaDoc of a method at run time?</a></li>
<li><a href="https://github.com/robertmarkbram/RobUtils/blob/master/src/org/rmb/reflectionutils/javadoc/FieldCommentSampleClass.java">FieldCommentSampleClass.java</a> which is just a place I copy the field declarations into so that I can use the <code>FieldComments</code> annotation in the same project as the other things in RobUtils.</li>
</ul>
<p>I begin by writing out the fields in the actual class they belong to. I write out comments for each.</p>
<pre class="brush:java" title="Write out fields with comments.">
public class Foo {
/** User friendly label for display. */
private String name;
/** Unique ID within datastore. */
private int id;
}
</pre>
<p>I then copy these comments into <code>FieldCommentSampleClass.java</code>, which is just a scratch pad that has the advantage of being in the same project as the <code>@FieldComment</code> annotation. Within <code>FieldCommentSampleClass.java</code>, I do a couple of find and replace operations to change the javadoc comments to <code>@FieldComment</code> annotations.</p>
<ol>
<li>Replace <code>/** </code> with <code>@FieldComment(comment="</code>.</li>
<li>Replace <code>*/</code> with <code>")</code>.</li>
</ol>
<p>So that now have fields with the <code>@FieldComment</code> annotation:</p>
<pre class="brush:java" title="Fields with the @FieldComment annotation.">
public class FieldCommentSampleClass {
@FieldComment(comment="User friendly label for display. ")
private String name;
@FieldComment(comment="Unique ID within datastore. ")
private int id;
}
</pre>
<p>I then run the main method in <code>OutputFieldList.java</code> with these two calls. This will generate getters and setters, plus decent <code>toString()</code>, <code>hashCode()</code> and <code>equals()</code> methods for me.</p>
<pre class="brush:java" title="Main methods in OutputFieldList.java.">
public static void main(final String[] args) throws Exception {
generateGetAndSetMethods(FieldCommentSampleClass.class, //
OutputFields.NO_FIELDS, //
OutputGetters.OUTPUT_GETTERS, //
OutputSetters.OUTPUT_SETTERS);
outputToStringHashAndEquals(Foo.class);
}
</pre>
<p>I now have the following output that I copy and paste into my original class.</p>
<pre class="brush:java" title="Generated getters, setters, toString(), hashCode() and equals() that obey my checkstyle rules.">
/** @return user friendly label for display. */
public String getName() {
return name;
}
/** @return unique ID within datastore. */
public int getId() {
return id;
}
/** @param theName user friendly label for display. */
public void setName(final String theName) {
this.name = theName;
}
/** @param theId unique ID within datastore. */
public void setId(final int theId) {
this.id = theId;
}
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true; // test for reference equality
}
if (obj == null) {
return false; // test for null
}
if (obj instanceof FieldCommentSampleClass) {
final FieldCommentSampleClass other = (FieldCommentSampleClass) obj;
// @formatter:off
return new org.apache.commons.lang.builder.EqualsBuilder()
.append(name, other.name)
.append(id, other.id)
.isEquals();
// @formatter:on
} else {
return false;
}
}
@Override
public int hashCode() {
// @formatter:off
return new org.apache.commons.lang.builder.HashCodeBuilder()
.append(name)
.append(id)
.toHashCode();
// @formatter:on
}
@Override
public String toString() {
org.apache.commons.lang.builder.ToStringBuilder.setDefaultStyle(org.apache.commons.lang.builder.ToStringStyle.SHORT_PREFIX_STYLE);
// @formatter:off
return new org.apache.commons.lang.builder.ToStringBuilder(this)
.append("name", name)
.append("id", id)
.toString();
// @formatter:on
}
</pre>
<h2>Final notes</h2>
<p>A few notes to keep in mind.</p>
<ul>
<li><code>OutputFieldList</code> needs JDK 8 because it uses the <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/util/stream/Stream.html">Stream API</a> with lambdas.</li>
<li>The <code>toString()</code>, <code>equals()</code> and <code>hashCode()</code> methods generated use the fully qualified class names for the apache commons lang builders. I them use <code>Source > Add Import</code> (or <code>control+shift+m</code>) to replace the fully qualified class names with just the class names.</li>
<li>If the code I am generating boiler plate for relies on custom code (e.g. field types are not standard java types), I may have to modify my <code>RobUtils</code> project so that it can reference those types, which is easy: <code>Project > Properties > Java Build Path > Projects tab > Add</code> and select the projects I need to reference.</li>
<li>
I am pragmatic about following these Checkstyle rules.
<ul>
<li>When editing code written by someone else that has Checkstyle warnings, should I fix them? Perhaps. If there are just a few and I have time, sure. If there are many then only fix the ones in the actual lines of code I need to edit.</li>
<li>I don't force my own practices on other developers in a team. If the team has a policy already in place around the use of tools like Checkstyle or Findbugs, that takes precedence. Otherwise I practice what makes sense to me. If other developers are interested, explain how I use the tooling to help me write good code, but don't proselytise.</li>
<li>As I mentioned above, there is a cost to taking on processes like Checkstyle rules. If the cost is too high (i.e. there is little benefit to be gained), or the rules doesn't make sense to you, <em>don't do it</em>. Checkstyle warnings <a href="http://checkstyle.sourceforge.net/config.html">can be suppressed</a> for a class, method or code block and rules can be removed entirely from a project specific configuration if the rule is too burdensome.</li>
</ul>
</li>
</ul><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-3474285934742244952015-04-19T02:47:00.000+10:002015-05-12T09:48:02.975+10:00PHP iterating over Blogger posts from Atom Feed XML<p>Thanks to some decent PHP APIs, it is really easy to read XML from a URL and process the results.</p>
<p>Use case: I have written an <a href="http://www.chihuahuarescuevictoria.org/forms/adoption/Express-interest-in-adopting-from-Chihuahua-Rescue-Victoria.php">expression of interest form</a> that people can use to raise an application to adopt a rescued Chihuahua. Part of the form lists the dogs available - and this list comes from a Blogger feed. The <a href="http://chihuahuarescue.blogspot.com.au">blog</a> is used as a list of all the Chihuahuas that have been rescued (one dog per post) and the ones that are currently available all have a specific label: <a href="http://chihuahuarescue.blogspot.com.au/search/label/Available%20now">Available now</a>. The expression of interest form reads the Atom feed for this label and displays a list of the <em>available now</em> dogs on the form.</p>
<h2>Retrieve XML from URL and access child elements</h2>
<p>The function below reads an XML document from a URL (an Atom feed) and will return an array of the child elements that represent specific posts with a given label from the blog.</p>
<pre class="brush:php" title="PHP function to load Blogger posts with a specific label from an Atom Feed">
function retrieveAvailableNowPosts() {
// Set URL to XML we want to read - Available now.
$file="http://chihuahuarescue.blogspot.com.au/feeds/posts/default/-/Available%20now";
// Load specified XML file or report failure
$xml = simplexml_load_file($file);
if (!$xml) {
return false;
}
// Load blog entries
$posts = $xml -> entry;
if (sizeOf($posts) > 0) {
return $posts;
} else {
return null;
}
}
</pre>
<p>Notes about this function. </p>
<ul>
<li>
<code>$xml = simplexml_load_file($file);</code>
<ul>
<ul>
<li>
Loading the contents of a URL and then parsing the XML it contains is done with <a href="http://php.net/manual/en/function.simplexml-load-file.php">simplexml_load_file</a>. The return from this function is either an <a href="http://php.net/manual/en/class.simplexmlelement.php">SimpleXMLElement</a> object or a <code>boolean false</code> if there was an error reading XML from the file (URL in this case).
</li>
<li>The parameter to <code>simplexml_load_file</code> can be a file or URL.</li>
<li>Blogger <a href="https://support.google.com/blogger/answer/97933?hl=en">supports feeds either from RSS 2.0 or Atom 1.0</a>, and you can switch between them simply with a different URL.</li>
<li>The URL I am using (<code>http://chihuahuarescue.blogspot.com.au/feeds/posts/default/-/Available%20now</code>) is for an Atom feed. The label is the part after the last forward slash after it has been <a href="http://www.w3schools.com/tags/ref_urlencode.asp">URL encoded</a> i.e. <strong>Available now</strong> is the label, which becomes <code>Available%20now</code> after URL encoding. This was easy in my case because I only had to swap the space with <code>%20</code>. If you have more complicated labels (or perhaps need to URL encode dynamic labels), you can use the PHP function <a href="http://php.net/manual/en/function.urlencode.php">urlencode</a> to do this.</li>
</ul>
</ul>
</li>
<li>
<code>$posts = $xml -> entry;</code>
<ul>
<li><code>$xml</code> is the variable containing the XML read from <code>simplexml_load_file</code>.</li>
<li>The Atom feed XML returned from the URL has <code>feed</code> as the root element and it contains a variable number of <code>entry</code> elements, each of which is a blog post that was made against the target label. The skeleton is shown below.
<pre class="brush:xml" title="Skeleton the Atom fee XML showing that ENTRY elements are direct children of FEED">
<feed ...>
...
<entry>
...
</entry>
<entry>
...
</entry>
<entry>
...
</entry>
</feed></pre>
</li>
<li>We access the array of the <code>entry</code> elements on the feed using the "arrow" operator (<a href="http://php.net/manual/en/tokens.php">T_OBJECT_OPERATOR</a> for <a href="http://php.net/manual/en/language.oop5.php">objects</a>).</li>
<li><code>$posts</code> should therefore be an array which might be empty.</li>
</ul>
</li>
<li>
<code>if (sizeOf($posts) > 0)</code>
<ul>
<li>If the array has 1 or more elements, return it.</li>
<li>Otherwise, return null.</li>
</ul>
</li>
</ul>
<h2>Iterate through XML elements</h2>
<p>The function below accepts the XML elements read from the earlier function and iterates through them to output HTML.</p>
<pre class="brush:php" title="PHP function that outputs HTML list from Blogger posts loaded from an Atom Feed">
function createDogList($posts) {
$list = '<ul class="availableNowList">';
// Check if posts is undefined, null, false or empty.
if (!$posts || sizeOf($posts) == 0) {
$list .= '<li>Unfortunately there are no dogs available at this time.</li>';
} else {
// Go over each entry.
foreach($posts as $post) {
// Publish time
$dateTime = date("l jS F, Y", strtotime(strtok($post->published, 'T')));
// Link.
$link = $post->link[4]["href"];
// Title.
$title = $post->title;
// List the entry.
$list .=
'<li>
<a href="' . $link . '" target="_blank">'
. $title . '</a> <em><small>(published ' . $dateTime . ')</small></em>.
</li>';
}
}
$list .= '</ul>';
return $list;
}
</pre>
<p>Notes about this function.</p>
<ul>
<li>This function builds up an un-ordered list (<code>ul</code>) of blog posts, with each list item having
<ul>
<li>A link to the blog post - the link text being the blog entry title.</li>
<li>
The date on which the post was published. Example list:
<ul>
<li>
<a href="http://chihuahuarescue.blogspot.com/2015/03/rudi.html" >RUDI</a> <em><small>(published Sunday 29th March, 2015)</small></em>. </li>
<li>
<a href="http://chihuahuarescue.blogspot.com/2015/03/mimi.html" >MIMI</a> <em><small>(published Sunday 29th March, 2015)</small></em>. </li>
<li>
<a href="http://chihuahuarescue.blogspot.com/2015/03/baxter.html" >BAXTER</a> <em><small>(published Sunday 29th March, 2015)</small></em>. </li>
</ul>
</li>
</ul>
</li>
<li>If there are no posts against this label, output only one list item with an explanation that there are no matches at this time.</li>
<li>The parameter to this function is a list of blog posts against a certain label, retrieved by the previous function: <code>retrieveAvailableNowPosts()</code>.</li>
<li><code>if (!$posts || sizeOf($posts) == 0) { .. }</code>
<ul>
<li>This is more than just a null-check: <code>!$posts</code> will be <code>true</code> if the variable <code>$posts</code> is <em>null</em>, <em>not set</em> (undefined, has no value) or <em>false</em>.</li>
<li>
Here is a quick overview, showing that an <strong>IF</strong> is a good test for all three things.
<pre class="brush:php" title="PHP code to show how an IF can be used to test for variables that are null, false or not set.">
<?php
echo '<pre>';
$foo1; if($foo1) { ?>foo1 is set and not null/false.<?php } else { ?>foo1 is not set/null/false.<br><?php }
$foo2=null; if($foo2) { ?>foo2 is set and not null/false.<?php } else { ?>foo2 is not set/null/false.<br><?php }
$foo3=false; if($foo3) { ?>foo3 is set and not null/false.<?php } else { ?>foo3 is not set/null/false.<br><?php }
echo 'foo1 - ';
var_dump(isset($foo1));
echo 'foo2 - ';
var_dump(isset($foo2));
echo 'foo3 - ';
var_dump(isset($foo3));
echo '</pre>';
?>
</pre>
The output of the above is:
<pre>
foo1 is not set/null/false.
foo2 is not set/null/false.
foo3 is not set/null/false.
foo1 - bool(false)
foo2 - bool(false)
foo3 - bool(true)</pre>
</li>
<li>
This allows us to respond to two <a href="http://dcycleproject.org/blog/63/test-your-sad-path-first">sad cases</a> from <code>retrieveAvailableNowPosts()</code> at once.
<ul>
<li><code>retrieveAvailableNowPosts()</code> returns false if it couldn't read the Atom feed XML from the blog.</li>
<li><code>retrieveAvailableNowPosts()</code> returns null if the list of posts is empty.</li>
<li>The call to <a href="http://php.net/manual/en/function.sizeof.php">sizeof</a> (<code>sizeOf($posts) == 0</code>) is actually not needed, because <code>retrieveAvailableNowPosts()</code> returns null if the list of posts is empty, but I left it here in case I ever call this function from a different place and neglect to included the same rule.</li>
</ul>
</li>
</ul>
</li>
<li><code>$dateTime = date("l jS F, Y", strtotime(strtok($post->published, 'T')));</code>
<ul>
<li>
<code>$post->published</code>
<ul>
<li>The value of this looks like <code>2015-03-29T03:10:00.003-07:00</code>.</li>
<li>I only want the year, month and date only: I want to discard all the time information and just output the date. I will use a string tokenizer to do this in the next step.</li>
</ul>
</li>
<li>
<code>strtok($post->published, 'T')</code>
<ul>
<li>
I use a <a href="http://php.net/strtok">string tokenizer</a> with the letter "<code>T</code>" as the <a href="http://en.wikipedia.org/wiki/Delimiter">delimiter</a>. Note that the first call <code>strtok</code> will return the first token, and since I <em>only need the first token</em>, I don't store reference to the tokenizer. Here is how you would use the tokenizer in another situation to go over all tokens:
<pre class="brush:php" title="How to use PHP string tokenizer to go through all tokens">
$string = "String to split";
delimiter = " \n\t"; // Split string on spaces, newlines and tabs.
$token = strtok($string, $delimiter);
while ($token !== false) {
echo "Next token: $token <br />";
$token = strtok($delimiter);
}
</pre>
</li>
<li>The result of <code>strtok($post->published, 'T')</code> will be something like <code>2015-03-29</code> (note that it <strong>does not</strong> include the delimiter itself).</li>
</ul>
</li>
<li>
<code>date("l jS F, Y", strtotime(strtok($post->published, 'T')))</code>
<ul>
<li>I use the <a href="http://php.net/manual/en/function.date.php">date function</a> to parse the date (from text like <code>2015-03-29</code>) and output it in a different format (like <code>Sunday 29th March, 2015</code>).</li>
<li>See the PHP page for <a href="http://php.net/manual/en/function.date.php">date function</a> to find the full list of date format options, but here is what my format uses.
<ul>
<li><code>l</code> - A full textual representation of the day of the week: <em>Sunday through Saturday</em>.</li>
<li><code>j</code> - Day of the month without leading zeros: <em>1 to 31</em>.</li>
<li><code>S</code> - English ordinal suffix for the day of the month, 2 characters: <em>st, nd, rd or th</em>.</li>
<li><code>F</code> - A full textual representation of a month, such as January or March: <em>January through December</em>.</li>
<li><code>Y</code> - A full numeric representation of a year, 4 digits: <em>1999 or 2003</em>.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><code>$link = $post->link[4][href]</code>
<ul>
<li>In a given <code>entry</code> element, get the <code>href</code> attribute of the <strong>fifth</strong> <code>link</code> element (using a zero based index).</li>
<li>The fifth link element holds a direct URL to the post, such as: <code><link rel="alternate" type="text/html" href="http://chihuahuarescue.blogspot.com/2015/03/mimi.html" title="MIMI"/></code>.</li>
</ul>
</li>
<li>
Google's description of <a href="https://support.google.com/blogger/answer/47270#posts">what is in each post element</a> shows you what things you can access this way for each post:
<ul>
<li><code>posts</code>: A list of all posts for this page. Each post contains the following:
<ul>
<li> <code>dateHeader</code>: The date of this post, only present if this is the first post in the list that was posted on this day.</li>
<li> <code>id</code>: The numeric post ID.</li>
<li> <code>title</code>: The post's title.</li>
<li> <code>body</code>: The content of the post.</li>
<li> <code>author</code>: The display name of the post author.</li>
<li> <code>url</code>: The permalink of this post.</li>
<li> <code>timestamp</code>: The post's timestamp. Unlike dateHeader, this exists for every post.</li>
<li> <code>labels</code>: The list of the post's labels. Each label contains the following:
<ul>
<li> <code>name</code>: The label text.</li>
<li> <code>url</code>: The URL of the page that lists all posts in this blog with this label.</li>
<li> <code>isLast</code>: True or false. Whether this label is the last one in the list (useful for placing commas).</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>Error handling</h2>
<p>The primary error condition is from the call to <a href="http://php.net/manual/en/function.simplexml-load-file.php">simplexml_load_file</a>, which returns false if there was a failure reading XML from the URL. The secondary error condition occurs if we read the XML okay, but found it contained none of the elements we are interested in. On the <a href="http://www.chihuahuarescuevictoria.org/forms/adoption/Express-interest-in-adopting-from-Chihuahua-Rescue-Victoria.php">page that uses these functions</a>, both error conditions are treated as normal outputs from the <code>retrieveAvailableNowPosts</code> function and dealt with nicely, as you can see below. We output error messages if either error occurs, and display the "normal" content of the page otherwise.</p>
<pre class="brush:php" title="Overall error handling for no posts or error when retrieving XML">
$posts = retrieveAvailableNowPosts();
// If a boolean false is returned there was an error.
if ($posts === false) {
?>
<p style="text-align: center; color: red;">Unable to load list of Available Now dogs from Chihuahua Rescue Victoria!</p>
<?php
// And null means there is nothing present.
} else if ($posts === null) {
?>
<p style="text-align: center;">Unfortunately there are no dogs available at this time. Please try again later.</p>
<?php
// Otherwise, all good. Carry on.
} else {
?>
<?php
... normal page content goes here.
} // end else
?>
</pre>
<p>Just <a href="http://php.net/manual/en/function.die.php">die</a>!</p>
<p>We could have handled the error from <code>simplexml_load_file</code> in this way:</p>
<pre class="brush:php" title="Handling PHP error with die()">
$xml = simplexml_load_file($file) or die("<p>An error message.</p>");
</pre>
<p>This offers a <a href="http://www.phpfreaks.com/blog/or-die-must-die">very poor user experience</a>, especially on a web page because it will cause PHP to immediately exit and no further code on the page will be processed. This will most likely result in an ugly page with broken HTML.</p>
<h2>Resources that helped me.</h2>
<ul>
<li>
Blogger Help
<ul>
<li><a href="https://support.google.com/blogger/answer/53336?hl=en">Can I get site feeds for specific labels?</a></li>
<li><a href="https://support.google.com/blogger/answer/97933?hl=en">Blogger Feed URLs</a>.</li>
<li>How to get Blogger Feeds: <a href="https://support.google.com/blogger/answer/97933?hl=en">Blogger Feed URLs</a>. Blogger supports RSS 2.0 or Atom 1.0 feeds.</li>
</ul>
</li>
<li>
About the Atom Feed XML format
<ul>
<li><a href="http://atomenabled.org/developers/protocol/">Atom Publishing Protocol ? Introduction</a> - gives an overview of the elements you find in the XML that comes back from an Atom feed URL.</li>
<li>About the <a href="http://www.atomenabled.org/developers/syndication/#entry">Entry elements</a> (each of which is a blog post in this scenario).</li>
</ul>
</li>
</ul>
<p> </p>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-69378201568637452852015-04-18T23:44:00.002+10:002015-04-19T13:07:41.671+10:00UltraEdit macro to select HTML/XML tag
<p>In a previous post from 2010, <a href="http://robertmarkbramprogrammer.blogspot.com.au/2010/06/ultraedit-macro-to-select-htmlxml-tag.html">UltraEdit macro to select HTML/XML tag</a>, I detailed two <a href="www.ultraedit.com">UltraEdit</a> <em>macros</em> to select HTML/XML tags backwards and forwards. It had a couple of problems, such as not being able to distinguish between <code>PRE</code> and <code>P</code> when you start select <code>P</code> tags, so this version fixes that.</p>
<p>Here are the macros. The first is used to <em>select the previous tag</em>: I have it mapped to <code>control+shift+,</code>.</p>
<pre class="brush:plain" title="Select previous tag: mapped to control+shift+,">
InsertMode
ColumnModeOff
HexOff
UltraEditReOn
Clipboard 2
IfSel
Find RegExp Up Select "</++^c^{>^}^{[ ^p^r^n^t]+[~>]++>^}"
Else
Find Up "<"
Find RegExp "[A-Za-z]"
SelectWord
Copy
Find Up "<"
Key LEFT ARROW
Find RegExp Select "</++^c^{>^}^{[ ^p^r^n^t]+[~>]++>^}"
EndIf
Clipboard 0
</pre>
<p>The second is used to <em>select the next tag</em>: I have it mapped to <code>control+shift+.</code>.</p>
<pre class="brush:plain" title="Select next tag: mapped to control+shift+.">
InsertMode
ColumnModeOff
HexOff
UltraEditReOn
Clipboard 2
IfSel
Find RegExp Select "</++^c^{>^}^{[ ^p^r^n^t]+[~>]++>^}"
Else
Find "<"
Find RegExp "[A-Za-z]"
SelectWord
Copy
Find Up "<"
Key LEFT ARROW
Find RegExp Select "</++^c^{>^}^{[ ^p^r^n^t]+[~>]++>^}"
EndIf
Clipboard 0
</pre>
<p>A few notes about the macros.</p>
<ul>
<li>
Select previous tag.
<ol>
<li>Use it by leaving the cursor within an opening tag (<code><p></code>) or closing tag (<code></p></code> or unary tag (<code><br></code>) or within the text content of a tag. <strong>Do not select any text</strong>.</li>
<li>Press the shortcut (<code>control+shift+,</code>).</li>
<li>The macro will begin running <code>Else</code> part of the <code>IfSel</code> condition (because no text was selected).
<ol>
<li><code>Find "<"</code>
<ul>
<li>Looks for the first left angle bracket before the cursor.</li>
</ul>
</li>
<li><code>Find RegExp "[A-Za-z]"</code>
<ul>
<li>Find the next letter after the left angle bracket - which will be the start of the tag name.</li>
</ul>
</li>
<li><code>SelectWord</code>
<ul>
<li>Select the tag name.</li>
</ul>
</li>
<li><code>Copy</code>
<ul>
<li>Copy it - to the <em>second clipboard</em>, which was selected earlier in the macro by the command <code>Clipboard 2</code>.</li>
</ul>
</li>
<li><code>Find Up "<"</code>
<ul>
<li>Select the first left angle bracket before the cursor (again).</li>
</ul>
</li>
<li><code>Key LEFT ARROW</code>
<ul>
<li>Make sure cursor is to the left of that angle bracket so the next command (a <code>Find</code>) will have that character in scope.</li>
</ul>
</li>
<li><code>Find RegExp Select "</++^c^{>^}^{[ ^p^r^n^t]+[~>]++>^}"</code>
<ol>
<li>Select the entire open/close/unary tag.</li>
<li><code>Find</code> - because we had previously moved to the left of the opening left angle bracket of the tag, the search will take this tag into account.</li>
<li><code>RegExp</code> - use regular expressions. An earlier macro command (<code>UltraEditReOn</code>) specified that <em>UltraEdit regular expressions</em> are turned on (as opposed to Perl or Unix ones).</li>
<li><code>Select</code> - whatever we find with the next expression will be selected in UltraEdit.</li>
<li> A breakdown of the expression: <code></++^c^{>^}^{[ ^p^r^n^t]+[~>]++>^}</code>
<ol>
<li><code></++</code>
<ul>
<li>Find left angle bracket and zero or more forward slashes: matches <code><</code> or <code></</code>.</li>
</ul>
</li>
<li><code>^c</code>
<ul>
<li>Find text in <em>clipboard 2</em> (which we selected previously).</li>
</ul>
</li>
<li><code>^{>^}^{[ ^p^r^n^t]+[~>]++>^}</code>
<ul>
<li>
This is an <strong>OR</strong> expression. <code>^{A^}^{B^}</code> says find <strong>A</strong> or <strong>B</strong>. So this expression says to find either one of:
<ul>
<li><code>></code>
<ul>
<li>The right angle bracket that closes a tag. This covers the simple cases, e.g. <code><p></code>.</li>
</ul>
</li>
<li><code>[ ^p^r^n^t]+[~>]++></code>
<ul>
<li><code>[ ^p^r^n^t]+</code> one or zero of: space or newline (DOS, Mac or Unix) or tab.</li>
<li><code>[~>]++</code> zero or more of <em>any character other than</em> the right angle bracket.</li>
<li><code>></code> the right angle bracket.</li>
<li>This covers tags with attributes, e.g. <code><p style=""></code> which may or may not be spread across multiple lines.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li>Run the macro again with shortcut (<code>control+shift+,</code>).</li>
<li>The macro will run the <code>IfSel</code> condition because now there is text selected from the previous run.</li>
<li>It will run the exact same Find as was described above except for one difference.
<ol>
<li><code>Find RegExp Up Select "</++^c^{>^}^{[ ^p^r^n^t]+[~>]++>^}"</code></li>
<li>The <code>Up</code> part means that we will look for the next complete tag <em>to the left</em> of what we already have selected from the previous run.</li>
</ol>
</li>
</ol>
</li>
</ul>
<p>Here is a sample of HTML that I used to test this on.</p>
<pre class="brush:xml" title="Sample HTML to test these macros upon.">
<html>
<head>
<title>Some Title</title>
</head>
<body>
<div>
<div style="color: red;"
id="divWithId">Nested <span>div</span>.
<pre>
monospaced
</pre>
</div>
</div>
</body>
</html>
</pre>
<p>For the first run, I place the cursor as indicated below by <strong>|</strong> (either within the <code>DIV</code> open tag or within the <code>DIV</code> content.</p>
<pre class="codeSimple">
<html>
<head>
<title>Some Title</title>
</head>
<body>
<div>
<div style="color: red;"
id="divWit|hId">Nested| <span>div</span>.
<pre>
monospaced
</pre>
</div>
</div>
</body>
</html>
</pre>
<p>Run the <em>select previous tag</em> macro (I have it mapped to <code>control+shift+,</code>) and text will be selected as indicated below.</p>
<pre class="codeSimple">
<html>
<head>
<title>Some Title</title>
</head>
<body>
<div>
<span style="background-color:#19A96D; color: black;"><div style="color: red;"
id="divWithId"></span>Nested <span>div</span>.
<pre>
monospaced
</pre>
</div>
</div>
</body>
</html>
</pre>
<p>Now run the <em>select next tag</em> macro (I have it mapped to <code>control+shift+.</code>) and text will be selected as indicated below.</p>
<pre class="codeSimple">
<html>
<head>
<title>Some Title</title>
</head>
<body>
<div>
<span style="background-color:#19A96D; color: black;"><div style="color: red;"
id="divWithId">Nested <span>div</span>.
<pre>
monospaced
</pre>
</div></span>
</div>
</body>
</html>
</pre>
<p>Run the <em>select previous tag</em> macro again and text will be selected as indicated below.</p>
<pre class="codeSimple">
<html>
<head>
<title>Some Title</title>
</head>
<body>
<span style="background-color:#19A96D; color: black;"><div>
<div style="color: red;"
id="divWithId">Nested <span>div</span>.
<pre>
monospaced
</pre>
</div></span>
</div>
</body>
</html>
</pre>
<p>Run the <em>select next tag</em> macro again and text will be selected as indicated below.</p>
<pre class="codeSimple">
<html>
<head>
<title>Some Title</title>
</head>
<body>
<span style="background-color:#19A96D; color: black;"><div>
<div style="color: red;"
id="divWithId">Nested <span>div</span>.
<pre>
monospaced
</pre>
</div>
</div></span>
</body>
</html>
</pre>
<p>If you use either macro again at this point, nothing will happen because there are no more <code>DIV</code> elements in the document not already selected.</p>
<p>Importantly, these macros work correctly on similarly named tags such as <code>zip</code> <code>zipfileset</code> (which I have used in XML for Ant build files). If I am select <code>zip</code> tags, it skips nested <code>zipfileset</code> elements.</p>
<p>Two final notes.</p>
<ol>
<li>
Something this macro cannot do is to select an entire element that contains nested elements of the same tag. For example, consider the HTML below.
<pre class="brush:xml" title="Sample HTML with nested element of same tag.">
<div id="outer">
<div id="inner">
Inner DIV.
</div>
</div>
</pre>
Macros in UltraEdit cannot be used to select the entire outer <code>DIV</code> because you can't store state in a macro, which you would need to do in order to count nested elements to make sure you select the entire outer one. My workaround for this situation is to just make it easier to keep selecting next/previous <code>DIV</code> tag so that you can achieve the same effect with a bit of repetition.
</li>
<li>
UltraEdit <code>Find</code> commands in macros can use Perl regular expressions, which are very powerful too. One thing they can do much more easily is to treat <em>newline</em> characters as part of the wildcard. In a Perl regex, <code>(?s)</code> tells the regular expression to include newline characters when matching a <strong>.</strong> wildcard. You can also use backreferences in <code>Find</code> and <code>Replace</code> expressions. However, backreferences don't persist between macro calls. So, these two macros store the <code>tag name</code> in <strong>clipboard 2</strong> so that each time you call one of the macros afterwards, it "remembers" what tag you were searching for by looking at <strong>clipboard 2</strong>.
<ul></ul>
</li>
</ol>
<p>I wrote this up on the <a href="https://www.ultraedit.com/forums/">UltraEdit forum</a> here: <a href="https://www.ultraedit.com/forums/viewtopic.php?f=10&t=15547">macro to select HTML tag v2</a>.</p><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-70647059420244299902015-04-14T23:46:00.000+10:002015-04-16T22:43:52.059+10:00Add content to Blogger posts specific to a label<p>Mum uses her Blogger to post about <a href="http://chihuahuarescue.blogspot.com.au/">dogs she has rescued</a> and uses labels to mark which rescued Chihuahuas that are <a href="http://chihuahuarescue.blogspot.com.au/search/label/Available%20now">available to good homes</a>, or have been <a href="http://chihuahuarescue.blogspot.com.au/search/label/Happily%20Rehomed">happily re-homed</a> etc. I created an <a href="http://www.chihuahuarescuevictoria.org/forms/adoption/Express-interest-in-adopting-from-Chihuahua-Rescue-Victoria.php">expression of interest form</a> for people to apply for the dogs that are available, and I wanted a link to the form to appear below the blog entries labelled with "<code>Available now</code>" only. Here is how to do it.</p>
<p>You need to edit your Blogger XML template by going to the dashboard, selecting your blog, going to the Template section and clicking on the "Edit HTML" button. Take a backup of this content before you change it so that you can always go back! I haven't found a single comprehensive reference on the XML grammar and really only worked this out by experimentation and reading examples.</p>
<p>In the template, search for <code><data:post.body/></code>. If you use the <a href="https://support.google.com/blogger/answer/2685928?hl=en">template for your mobile version</a> as well, you will see two instances of that tag. I put my content under both instances because I wanted the same thing to appear on the desktop and mobile versions.</p>
<pre class="brush:xml" title="Excerpt of Blogger template showing content per blog post depending on label"><div class='post-body entry-content' expr:id='"post-body-" + data:post.id' itemprop='articleBody'>
<data:post.body/>
<!-- If the post has labels. -->
<b:if cond='data:post.labels'>
<!-- Go through all the labels attached to the post. -->
<b:loop values='data:post.labels' var='label'>
<!-- If current label is our target one. -->
<b:if cond='data:label.name == "Available now"'>
<!-- Display content I want to appear after the post. -->
<div style="text-align: center;">
<p><em>If you would like to adopt this dog, or any of our Chihuahua Rescue Victoria dogs, please fill out the <a href="http://www.chihuahuarescuevictoria.org/forms/adoption/Express-interest-in-adopting-from-Chihuahua-Rescue-Victoria.php">expression of interest form</a>.</em></p>
</div>
</b:if>
</b:loop>
</b:if>
<div style='clear: both;'/> <!-- clear for photos floats -->
</div>
</pre>
<p>Elements to note here.</p>
<ul>
<li><code><data:post.body/></code>
<ul>
<li>Indicates the body of each blog post.</li>
</ul>
</li>
<li><code><b:if cond='data:post.labels'></code>
<ul>
<li>Tests if the blog post has labels attached to it.</li>
</ul>
</li>
<li><code><b:loop values='data:post.labels' var='label'></code>
<ul>
<li>Loop through every label attached to this single post. The loop will place the current label in a variable named "label".</li>
</ul>
</li>
<li><code><b:if cond='data:label.name == "Available now"'></code>
<ul>
<li>Test if the current label's name is the label I am targeting.</li>
<li>I place my label-specific content within this tag.</li>
</ul>
</li>
</ul>
<p>So essentially what I am doing is looping through <code>post.labels</code> with each label in a variable called <code>label</code>, and for each one I examine <code>label.name</code>.</p>
<p>Look carefully at Google's description of <a href="https://support.google.com/blogger/answer/47270#posts">what is in each post element</a> to see what else you can access for each post:</p>
<ul>
<li><code>posts</code>: A list of all posts for this page. Each post contains the following:
<ul>
<li> <code>dateHeader</code>: The date of this post, only present if this is the first post in the list that was posted on this day.</li>
<li> <code>id</code>: The numeric post ID.</li>
<li> <code>title</code>: The post's title.</li>
<li> <code>body</code>: The content of the post.</li>
<li> <code>author</code>: The display name of the post author.</li>
<li> <code>url</code>: The permalink of this post.</li>
<li> <code>timestamp</code>: The post's timestamp. Unlike dateHeader, this exists for every post.</li>
<li> <code>labels</code>: The list of the post's labels. Each label contains the following:
<ul>
<li> <code>name</code>: The label text.</li>
<li> <code>url</code>: The URL of the page that lists all posts in this blog with this label.</li>
<li> <code>isLast</code>: True or false. Whether this label is the last one in the list (useful for placing commas).<br />
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>References I found useful.</p>
<ul>
<li><a href="https://support.google.com/blogger/answer/46995?hl=en">Widget Tags for Layouts</a> - has information on how to use control structures such as loop, if/else.</li>
<li><a href="http://postoneeighth.blogspot.com.au/2013/03/using-if-else-customize-elements-blogger-pages.html">Using if/else to customize elements in specific pages in Blogger</a> - a more detailed look at using if/else.</li>
<li><a href="http://monkeyraptor.johanpaul.net/2013/06/blogger-conditional-tag-bif-and-belse.html">Blogger Conditional Tag — b:if and b:else</a> - another good reference for if/else.</li>
<li><a href="https://support.google.com/blogger/answer/47270">Layouts Data Tags</a> - a description of various attributes to be found in some of the tags used in Blogger. Frustratingly short on examples.</li>
</ul>
<p> </p>
<p> </p>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-73237999239492140632015-04-12T17:15:00.001+10:002015-04-12T17:16:53.541+10:00Validation and error handling pointsI have been writing a form today to send off emails with a PHP back-end. All day I have been dealing with validation and trying to cover all the bases (so all your bases remain belonging to YOU).<br />
<br />
Things to keep in mind when validating data.<br />
<br />
<ol>
<li>Presence - if the field is mandatory, validate that it has a value.</li>
<ol>
<li>Always give some visual way of marking a field as mandatory.</li>
</ol>
<li>Size - check the size of the input i.e. that it is less than a certain number of characters.</li>
<ol>
<li>Do this for all values, whether they are coming from an input, text area, checkbox or radio button. One way a site can be attacked is for a malicious sender to ignore your HTML form and POST their own massive values.</li>
</ol>
<li>Escape and sanitise data before you use it to prevent <a href="https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet">cross site scripting</a> or <a href="https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet">SQL injection</a> attacks. Do this before you:</li>
<ol>
<li>Save to a DB.</li>
<li>Output back to HMTL.</li>
<li>Write to a file.</li>
<li>Send to an email.</li>
<li>Send it to another part of your back-end for further processing.</li>
</ol>
<li>Type - check that an input is an integer or double or boolean as required.</li>
<li>Format - check that input matches a required format, like a phone number or email etc.</li>
<ol>
<li>Can be helped by using <a href="http://en.wikipedia.org/wiki/Input_mask">input masks</a>, but you still need to validate that the data you received matches the mask on the server side.</li>
</ol>
<li>Value - check input against your own business logic. For example:</li>
<ol>
<li>Is a number within a given range.</li>
<li>Does the string match an element in a known list of choices.</li>
</ol>
<li>Related - apply any validation that requires examining multiple fields. For example, if country, state and postcode are given, make sure that they are a valid combination.</li>
<li>Server side first.</li>
<ol>
<li>Client side validation is often easier, but server side validation is more important because javascript can be disabled or ignored completely if a malicious sender simply POSTS their own requests.</li>
<li>Consider how to return errors in a such a way that they can be easily communicated back to the user on the interface.</li>
</ol>
<li>Client side second</li>
<ol>
<li>While server side is more important, client side validation makes for a faster and more responsive user experience because you can point out errors before the user ever hits SEND.</li>
<li>Consider things such as how to present errors to users and how mark things like dynamic business rules (where field A is only mandatory if field B is given a value).</li>
</ol>
</ol>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-59730331249532174362015-04-08T22:27:00.001+10:002015-04-08T22:27:58.845+10:00Lambdas are not instance methods<p>Here is a mistake I made. I had assumed that since a lambda becomes an instance of the <a href="https://www.facebook.com/freeflowpoet/posts/10153869335210656">functional interface</a> I thought that the lambda would be turned into an instance method.</p>
<pre class="brush:java" title="Cannot use this in a static content">
Runnable run = () -> System.out.println("This class: [" + this.getClass().getName() + "].");
</pre>
<p>No. I get the following compilation error: <code>Cannot use this in a static content</code>.</p>
<p>In response to the <a href="http://stackoverflow.com">StackOverflow</a> question <a href="http://stackoverflow.com/questions/21858482/what-is-a-java-8-lambda-expression-compiled-to">What is a Java 8 Lambda Expression Compiled to?</a> I found that <a href="http://stackoverflow.com/users/438154/sotirios-delimanolis">Sotirios Delimanolis</a> gives a <a href="http://stackoverflow.com/a/21858791/257233">very useful answer</a>, referring to part of the <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27.4">Java 8 Language Specification - 15.27.4. Run-Time Evaluation of Lambda Expressions</a>. He noted that the <em>JLS doesn't say anything about how the code should be compiled</em>, so it is up to the compiler creator to decide whether the lambda's body should be a static or instance method.</p><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-66444887290364142772015-04-06T14:21:00.003+10:002015-04-06T15:10:12.825+10:00Functional interfaces in JDK 8<style>
a[name]:hover, a.namedAnchor:hover {
text-decoration: inherit;
color: inherit;
background: inherit
}
</style>
<p>After my previous post on <a href="http://robertmarkbramprogrammer.blogspot.com.au/2015/04/introduction-to-lambdas-in-jdk-8.html">Lambdas</a>, I decided to have a closer look at what makes a <strong>functional interface</strong>.</p>
<h2>What is a functional interface?</h2>
<ol>
<li> A functional interface is an interface that has one abstract method. </li>
<ol>
<li>Functional interfaces used to be called Single Abstract Method (SAM) interfaces.</li>
</ol>
<li>A functional interface must be defined as an interface type, not an annotation type, enum, or class.</li>
<li>
A functional interface can optionally be annotated with the <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/FunctionalInterface.html">@FunctionalInterface</a> annotation.
<ol>
<li>This annotation is not necessary for Lambdas as the compiler will figure out if an interface is functional or not (by seeing if it has only one abstract method). The annotation is useful when you are writing a functional interface, because the compiler will generate an error if the interface you are writing does not meet the requirements of being a functional interface.</li>
</ol>
</li>
</ol>
<p>There are a number of conditions around what counts as the single abstract method in a functional interface.</p>
<ol>
<li>JDK 8 allows you to add concrete methods to interfaces by using the default keyword. These <a href="https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html">default methods</a> <em>do not count</em>.</li>
<li>JDK 8 allows you to add <a href="https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html#static">static methods to interfaces</a>. <em>These do not count</em>.</li>
<li>Interfaces can also re-declare (override) methods from <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Object.html">java.lang.Object</a> and while these methods are also abstract in an interface, <em>they don't count</em> either because any implementation of the interface will automatically inherit those methods from <code>Object</code>. A good example of this is <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Comparator.html">Comparator</a>, which re-declares the <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#equals-java.lang.Object-">equals method</a> so that it can put special notes about it in the javadocs (see: <a href="http://stackoverflow.com/questions/11013850/why-does-comparator-declare-equals">why does comparator declare equals?</a>).</li>
<li>An advanced case involves a functional interface that extends from multiple interfaces that include override-equivalent methods (methods that have the same signature after type erasure). See <a href="#override-equivalent">below</a>.</li>
</ol>
<h2>Functional interface as target type for a lambda</h2>
<p>Functional interfaces are much more powerful in JDK 8, where they are used as the target type for lambdas. Whenever you create a lambda in JDK 8:</p>
<ol>
<li>The compiler will figure out what functional interface fits the parameter list and return type for that lambda.</li>
<li>It will create the lambda as an instance of that functional interface (an object whose type is that of the interface).</li>
<li>The code within the lambda will be used as the concrete implementation of the sole abstract method.</li>
</ol>
<p>An example of a functional interface being assigned to a lamba is below. First we have a simple POJO representing a book.</p>
<pre class="brush:java" title="Book POJO">
public final class Book {
private final String title;
private final String author;
public Book(final String theAuthor, final String theTitle) {
title = theTitle;
author = theAuthor;
}
public String getAuthor() { return author; }
public String getTitle() { return title; }
@Override
public String toString() { return title + " by " + author; }
}
</pre>
<p>Then we have a class that will create a few <code>Book</code> instances and add them to a list. After that, the code uses two lambdas to sort and then print books. The last two lines invoke methods on <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/util/ArrayList.html">ArrayList</a> that accept functional interface type parameters. We use lambdas to provide them.</p>
<pre class="brush:java" title="Functional interfaces being assigned to a lamba">
public final class FunctionalInterfaceTest {
public static void main(String[] args) {
List<Book> books = new ArrayList<Book>();
books.add(new Book("Stephen King", "The Shining"));
books.add(new Book("Bram Stoker", "Dracula"));
books.add(new Book("Thomas Harris", "The Silence of the Lambs"));
books.add(new Book("Henry James", "The Turn of the Screw"));
books.add(new Book("David Wong", "John Dies at the End"));
books.add(new Book("Ryu Murakami", "Piercing"));
books.add(new Book("Peter Straub", "Ghost Story"));
// Sort books by title.
books.sort((book1, book2) -> book1.getTitle().compareTo(book2.getTitle()));
// Print books in their new order.
books.forEach((book) -> System.out.println(book));
}
}
</pre>
<p>The output of this code is:</p>
<pre>
Dracula by Bram Stoker
Ghost Story by Peter Straub
John Dies at the End by David Wong
Piercing by Ryu Murakami
The Shining by Stephen King
The Silence of the Lambs by Thomas Harris
The Turn of the Screw by Henry James
</pre>
<p>Here is line that sorts the books.</p>
<pre class="brush:java" title="Lambda for sorting">
// Sort books by title.
books.sort((book1, book2) -> book1.getTitle().compareTo(book2.getTitle()));
</pre>
<p>The argument to <a href="https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#sort-java.util.Comparator-">ArrayList's sort method</a> must be a <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Comparator.html">Comparator</a>, which is a functional interface. It's sole abstract method is <code>compare(T o1, T o2)</code> where <code>o1</code> and <code>o2</code> are not specified but must be the same type; also, the method returns an int. This is what the compiler expects us to provide as a parameter and the lambda we have written will fit that type.</p>
<p>Looking a bit closer into the lambda: <code>(book1, book2) -> book1.getTitle().compareTo(book2.getTitle())</code>.</p>
<ol>
<li>
<code>(book1, book2)</code>
<ol>
<li>The parameter list contains two arguments whose type we do not specify.</li>
<li>The compiler will infer them as being two <code>Book</code> objects because we are calling <code>sort</code> on a list of books (<code>List<Book></code>).</li>
</ol>
</li>
<li>
<code>book1.getTitle().compareTo(book2.getTitle())</code>
<ol>
<li>The code to execute in the lambda is an expression - a piece of code that will evaluate to a single value. The value in this case is an int because <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#compareTo-java.lang.String-">compareTo on String</a> returns an int.</li>
<li>This matches the sole abstract method in <code>Comparator</code>, which is <code>compareTo</code>. So the compiler will consider this lambda to be an instance of the functional interface <code>Comparator</code>.</li>
<li>Somewhere in the <code>sort</code> code, <code>compareTo</code> will be called on our lambda, which is now a <code>Comparator</code> object.</li>
</ol>
</li>
</ol>
<p>Here is line that prints the books.</p>
<pre class="brush:java" title="Lambda for printing">
// Print books in their new order.
books.forEach((book) -> System.out.println(book));
</pre>
<p>The argument to <a href="https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#forEach-java.util.function.Consumer-">ArrayList's forEach method</a> must be a <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/util/function/Consumer.html">Consumer</a>, which is a functional interface. It's sole abstract method is <code>accept(T t)</code> where <code>t</code> is some non-specific type and the method has a void return type. This is what the compiler expects us to provide as a parameter and the lambda we have written will fit that type.</p>
<p>Looking a bit closer into the lambda: <code>(book) -> System.out.println(book)</code>.</p>
<ol>
<li>
<code>(book)</code>
<ol>
<li>The parameter list contains one argument whose type we do not specify.</li>
<li>The compiler will infer that it is a <code>Book</code> object because we are calling <code>forEach</code> on a list of books (<code>List<Book></code>).</li>
</ol>
</li>
<li>
<code>System.out.println(book)</code>
<ol>
<li>The code to execute in the lambda is a single statement, with a void return type. Since we don't use the return keyword, compiler figures out that nothing is being returned and thus the lambda code has a void return type.</li>
<li>This matches the sole abstract method in <code>Consumer</code>, which is <code>accept</code>. So the compiler will consider this lambda to be an instance of the functional interface <code>Consumer</code>.</li>
<li>Somewhere in the <code>forEach</code> code, <code>accept</code> will be called on our lambda, which is now a <code>Consumer</code> object</li>
</ol>
</li>
</ol>
<h2><a class="namedAnchor" id="override-equivalent">Functional interfaces and override-equivalent methods</a></h2>
<p>With respect to functional interfaces and lambdas, this is a corner case. However, I am going into it in further detail here because it reveals much about the implications of type erasure that came with <a href="https://docs.oracle.com/javase/tutorial/java/generics/">Generics in JDK 5</a>. The question: what happens to a functional interface that extends from multiple interfaces that contain <em>override-equivalent methods</em> i.e. methods that have the same signature after type erasure?</p>
<p>First, a look at <em>type erasure</em>, which occurs when generic type information is removed when the compiler generates a class file from source Java. This is done so that code which uses generics will still be compatible with pre-JDK 5 code that doesn't use generics. Practically speaking, it means that you cannot have two methods like this in the same class:</p>
<pre class="brush:java" title="Two methods that will have the same signature after type erasure">
public void foo(List bar) { }
public void foo(List<String> bar) { }
</pre>
<p>This code will not compile because after type erasure, they would have exactly the same signature:</p>
<pre class="brush:java" title="How the two methods look like in the class file - after type erasure">
public void foo(List bar) { }
public void foo(List bar) { }
</pre>
<p>The above methods are <strong>override-equivalent</strong>: their signatures are the same after type erasure. <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.2">JLS (Java Language Specification), Chapter 8. Classes - 8.4.2. Method Signature</a> says that two methods are <em>override-equivalent</em> if they have the same signature (name and parameter list) <strong>or</strong> if they have the same signature <em>after type erasure</em>.</p>
<p>While you can't put two override-equivalent methods in a single class, you can <em>legally</em> end up inheriting from multiple interfaces that contain override-equivalent methods. The result will be a method that can legally override all the inherited abstract methods (after type erasure). The example below shows what happens when an interface<em> </em>extends other interfaces (<em>functional interfaces</em> in this case because they have only one abstract method each) whose sole methods are all <em>override-equivalent</em>: in fact, two of them are exactly the same before type erasure.</p>
<pre class="brush:java" title="Example showing a method that can legally override multiple override-equivalent methods">
interface Foo1 { void bar(List<String> arg); }
interface Foo2 { void bar(List<String> arg); }
interface Foo3 { void bar(List arg); }
@FunctionalInterface interface Foo extends Foo1, Foo2, Foo3 {}
public class OverrideEquivalent implements Foo {
// This compiles.
@Override public void bar(List arg) { }
// Does not compile if we use this one instead.
// @Override public void bar(List<String> arg) { }
}
</pre>
<p>The example above shows that a method without generics can legally override generic methods that will have the same signature after type erasure, or non-generic methods that are the same signature. If you use Foo as a functional interface, the method you end up overriding with will be the one that can override all the others i.e. it will have all the generic types erased.</p>
<p>References about type erasure:</p>
<ol>
<li><a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.6">JSL, Chapter 4. Types, Values, and Variables - 4.6. Type Erasure</a>.</li>
<li><a href="https://docs.oracle.com/javase/tutorial/java/generics/erasure.html">The Java Tutorials - Type Erasure</a>.</li>
<li>
This Stack Overflow post: <a href="http://stackoverflow.com/questions/339699/java-generics-type-erasure-when-and-what-happens">Java generics - type erasure - when and what happens</a>.
<ol>
<li>It features <a href="http://stackoverflow.com/a/339708/257233">this answer</a> by <a href="http://stackoverflow.com/users/732016/wchargin">WChargin</a> which explains how code that uses generics like this:
<pre class="brush:java" title="Code using generics">
List<String> list = new ArrayList<String>();
list.add("Hi");
</pre>
is compiled into the same code but with generic type information removed:
<pre class="brush:java" title="Code using generics after type erasure">
List list = new ArrayList();
list.add("Hi");
</pre>
It also points out that there is still metadata in the class file about generics, but it is not accessible to code that uses the class file: they are converted into compile-time checks and runtime casts.
</li>
</ol>
</li>
<li>
<a href="http://stackoverflow.com/a/4590006/257233">Another answer on the same question</a> shows a way to get around type erasure with anonymous classes, which is elaborated on further here:
<ol>
<li><a href="http://gafter.blogspot.com.au/2006/12/super-type-tokens.html">Super Type Tokens</a>.</li>
<li><a href="http://rgomes-info.blogspot.co.uk/2013/12/using-typetokens-to-retrieve-generic.html">Using TypeTokens to retrieve generic parameters</a>.</li>
</ol>
</li>
</ol>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-86884255901612088462015-04-04T21:03:00.000+11:002015-04-06T11:26:40.151+10:00Introduction to Lambdas in JDK 8<p>We write lambdas essentially as a block of code and a parameter list. The JVM will make an object out of those for us - an object whose <em>target type</em> that will be a <em>functional interface</em>. It's similar to creating an anonymous class, but removes a lot of the boiler plate: it's <a href="http://en.wikipedia.org/wiki/Syntactic_sugar">syntactic sugar</a> for creating instances of functional interfaces.</p>
<h2>Syntax of a Lambda</h2>
<p>Below is an example lambda being assigned to an instance of <code>Runnable</code>.</p>
<pre class="brush:java" title="Plain lambda">
Runnable run = () -> System.out.println("Lambra assigned to a Runnable.");
</pre>
<p>From left to right:</p>
<ol>
<li><code>Runnable run =</code>
<ul>
<li>The lambda is being assigned to an instance of <code>Runnable</code>. More on that later.</li>
</ul>
</li>
<li><code>()</code>
<ul>
<li>This is the lambda's parameter list (empty here).
Parentheses may or may not be required. Types may or may not be required. For example:
<ul>
<li><code>x</code>
<ul>
<li>Parentheses not needed because we have only parameter.</li>
<li>Parameter type not needed because it is inferred from the functional interface.</li>
</ul>
</li>
<li><code>(double x)</code>
<ul>
<li>Need the parentheses because we included the type.</li>
</ul>
</li>
<li><code>()</code>
<ul>
<li>Parentheses required because we have no parameters!</li>
</ul>
</li>
<li><code>(x, y)</code>
<ul>
<li>Parentheses required because we have more than one parameter.</li>
<li>Again, parameter types are inferred from the functional interface.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><code>-></code>
<ul>
<li>What follows this is the lambda code itself.</li>
</ul>
</li>
<li><code>{ ... }</code>
<ul>
<li>Actual code to be executed when the lambda is run. Could be any of these:</li>
<ul>
<li>An anonymous code block (zero or more statements enclosed in curly braces). For example:
<ul>
<li>Empty block: <code>{ }</code>
</li>
<li>Just one statement:
<pre class="brush:java" title="One statement in the block.">
Runnable run = () -> {
System.out.println("Hello World!");
};
</pre>
</li>
<li>Multiple statements:
<pre class="brush:java" title="Multiple statements in the block.">
Runnable run = () -> {
System.out.println("Hello World!");
System.out.println("Hello World!");
};
</pre>
</li>
</ul>
</li>
<li>A single statement (curly braces optional).
<pre class="brush:java" title="One statement in the block.">
Runnable run = () -> {
System.out.println("Hello World!");
};
</pre>
or
<pre class="brush:java" title="One statement with no curly braces.">
Runnable run = () -> System.out.println("Hello World!");
</pre>
</li>
<li>An expression (no curly braces).
<pre class="brush:java" title="An expression which cannot have curly braces.">
BinaryCalculator division = (v1, v2) -> v1 / v2;
</pre>
</li>
</ul>
</ul>
</li>
</ol>
<h2>Target type is a functional interface</h2>
<p>Lambdas are objects in Java, but we do not have to explicitly define their type (like we do with an anonymous class). Instead, Java will try to match a lambda to a <em>target type</em>. The target type of a lambda is a <em>functional interface</em>. A functional interface is an interface that has only one abstract method defined within it (JDK 8 now allows interfaces to contain static and <a href="https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html">default methods</a>, but these don't count here). Optionally, a functional interface may be marked with the <code>@FunctionalInterface</code> annotation. For example: <a href="http://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Runnable.html">Runnable</a> or <a href="http://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/Callable.html">Callable</a> in JDK 8 are both annotated with <code>@FunctionalInterface</code>.</p>
<p>Lambdas can be passed directly to constructors or methods and the compiler will automagically work out which functional interface to use as a compatible type for the lambda. The compiler will take the parameter list of the lambda and the return type of the lambda code and look for a <em>functional interface</em> whose single method matches it. Consider this example:
</p>
<pre class="brush:java" title="A lambda assigned to a Runnable instance.">
Runnable run = () -> System.out.println("Hello World!");
</pre>
<p>The parameter list of the lambda is empty - <code>()</code>. The return type of the code block is null - <code>System.out.println("Hello World!")</code>. Plus, we are assigning this lambda to an instance of a <code>Runnable</code>, whose sole method (<a href="http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html#run--">run</a>) accepts no paramaters and has a void return type, so this works.</p>
<p>The interface does not have to marked with the <code>@FunctionalInterface</code> annotation though. This also works. </p>
<pre class="brush:java" title="A lambda assigned to a Comparable instance.">
System.out.println("bbb compared to aaa: "
+ compareStrings((value) -> "bbb".compareTo(value), "aaa"));
// ..
static int compareStrings(final Comparable<String> comparator, final String value1) {
return comparator.compareTo(value1);
}
</pre>
<p>The lambda <code>(value) -> "bbb".compareTo(value), "aaa")</code> is the first parameter to the <code>compareStrings</code> method, whose type is a <a href="http://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Comparable.html">Comparable</a>. The only method to that interface is <a href="http://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html#compareTo-T-">compareTo</a> - which accepts some type <code>T</code> and returns an <code>int</code>. This matches the lambda - which accepts an object of any type (<code>T</code> is unspecified, so it just has to be <em>some type</em>) and it returns an <code>int</code>. Therefore, the lambda can be assigned to a <code>Comparable</code> instance <strong>and</strong> the <code>Comparable</code> interface is not marked with the <code>@FunctionalInterface</code> annotation.</p>
<h2>Using lambdas</h2>
<p>Here is an example of using lambdas, which I have adapted from this brilliant JavaWorld article: <a href="http://www.javaworld.com/article/2895887/java-language/the-essential-java-language-features-tour-part-6.html">The essential Java language features tour, Part 6 - Getting started with lambdas and functional interfaces</a>.</p>
<pre class="brush:java" title="Test of lambda expressions">
public final class LambdaTest {
public static void main(final String[] args) {
final BinaryCalculator addition = (double v1, double v2) -> {
return v1 + v2;
};
final BinaryCalculator division = (v1, v2) -> v1 / v2;
final UnaryCalculator negation = v -> -v;
final UnaryCalculator square = (double v) -> v * v;
final double value1 = 18;
final double value2 = 36.5;
System.out.printf("%2.1f + %2.1f = %10.3f%n", value1, value2,
calculate(addition, value1, value2));
System.out.printf("%2.1f / %2.1f = %10.3f%n", value1, value2,
calculate(division, value1, value2));
System.out.printf("%2.1f / %2.1f = %10.3f%n", value1, value2,
calculate(negation, value1));
System.out.printf("%2.1f / %2.1f = %10.3f%n", value1, value2,
calculate(square, value1));
}
static double calculate(final BinaryCalculator calculator,
final double value1, final double value2) {
return calculator.calculate(value1, value2);
}
static double calculate(final UnaryCalculator calculator,
final double value) {
return calculator.calculate(value);
}
@FunctionalInterface
interface BinaryCalculator {
double calculate(double value1, double value2);
}
@FunctionalInterface
interface UnaryCalculator {
double calculate(double value);
}
}</pre>
<p>A little bit of discussion on these follows.</p>
<pre class="brush:java" title="Needs parenthesis around parameters, body expression turned into a statement">
final BinaryCalculator addition = (double v1, double v2) -> {
return v1 + v2;
};
</pre>
<p>The example above needs parenthesis around the parameters because there are more than one. Parameter types are specified. The body of the lambda could be just an expression, but has been turned into a statement with the <code>return</code> keyword and a semi-colon.</p>
<pre class="brush:java" title="Test of lambda expressions">
final BinaryCalculator division = (v1, v2) -> v1 / v2;
</pre>
<p>The example above needs parenthesis around the parameters because there are more than one. Parameter types are left out, because they can be inferred. The lambda is being assigned to an instance of <code>BinaryCalculator</code>: a functional interface whose sole method accepts two parameters of type <code>double</code>, so the JVM can <em>infer the parameter types</em> for the lambda. The body of the lambda here is just an expression (so no curly braces and no semi-colon).</p>
<p><strong>Note</strong>: an expression is something that evaluates to a single value. A statement forms a complete unit of execution that ends with a semi-colon. A block is a group of zero or more statements between balanced braces and can be used anywhere a single statement is allowed.</p>
<pre class="brush:java" title="Test of lambda expressions">
final UnaryCalculator negation = v -> -v;
</pre>
<p>The example above doesn't need parenthesis around the parameters because there is only one. The lambda is being assigned to an instance of <code>UnaryCalculator</code>: a functional interface whose sole method accepts one parameter of type <code>double</code>, so the JVM can <em>infer the parameter type</em> for the lambda. The body of the lambda here is just an expression (so no curly braces and no semi-colon).</p>
<pre class="brush:java" title="Test of lambda expressions">
final UnaryCalculator square = (double v) -> v * v;
</pre>
<p>The above example shows the same things as the one above it except for one thing: even with just one parameter, you can still define the type and surround it with parenthesis.</p>
<h2>Type inference is powerful</h2>
<p>This deserves a little further explanation. Type inference is syntactic sugar that means we can write shorter code, leaving out a lot of boilerplate code because the compiler will figure out <strong>types</strong> without us having to explicitly declare them: that's interface type and parameter types. In the example above, I directly assign lambdas to instance variables i.e. the type of the lambda is explicitly declared. Note that the parameter types are still being inferred.</p>
<pre class="brush:java" title="Example of a lambda being assigned to a variable">
final BinaryCalculator division = (v1, v2) -> v1 / v2;
</pre>
<p>Now let's look at an example where the lambda is sent directly as an argument, without being declared as a variable first.</p>
<pre class="brush:java" title="Example of a lambda being sent directly as a parameter">
System.out.printf("%2.1f + %2.1f = %10.3f%n", value1, value2,
calculate((v1, v2) -> v1 / v2, value1, value2));
</pre>
<p>Nothing in the code explicitly says what type the lambda or parameters are and they do not match any local or instance variables. Here we are forcing the compiler to first work out what the <em>target type</em> of the lambda is, and then it has to figure out what parameter types are.</p>
<ol>
<li>What is the target type? The compiler has to find a functional interface whose sole abstract method matches the parameter list and return type of the lambda, but the compiler won't know the parameter types straight away.
<ol>
<li>The biggest clue that the compiler can take is by <em>looking at what we are sending the lambda to</em>. We are calling a method called <code>calculate</code> with three parameters. That matches the version of <code>calculate</code> whose first parameter is a <code>BinaryCalculator</code>.</li>
<li>Another clue is that the lambda accepts two parameters.</li>
<li>Maybe the compiler even looks at the body and sees a divide operation that can only return double. (Not sure about this though.)</li>
<li>Then the compiler should look through all the functional interfaces it knows about until it finds one that matches all these conditions:
<ol>
<li>The functional interface type is assignable to the parameter of the method that the lambda is being sent to.</li>
<li>The functional interface's sole abstract method has a parameter list that matches what it knows about the parameters being sent to the lambda.</li>
<li>The functional interface's sole abstract method has a return type that matches what is being returned by the lambda code.</li>
</ol>
</li>
</ol>
</li>
<li>So it picks <code>BinaryCalculator</code> as the functional interface - it has only one abstract method.</li>
<li><code>BinaryCalculator</code>'s sole abstract method is <code>calculate(double value1, double value2)</code>, which accepts two double parameters, so it knows what types to give the parameters too.</li>
</ol>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-52053723259767287022015-03-31T23:31:00.000+11:002015-03-31T23:31:05.645+11:00Remove hover from named anchors in HTML5
<style type="text/css">
#anchorPost a:hover {text-decoration: underline; color: red; background: yellow}
#anchorPost a.namedAnchor {text-decoration: inherit; color: inherit; background: inherit}
</style>
<div id="anchorPost">
<h3><a name="top_of_post">Top of this post - a named anchor with an unintended <code>:hover</code> effect.</a></h3>
<p>I want <code>:hover</code> on links (anchors with a <code>href</code> attribute), but not on named links (anchors with a <code>name</code> attribute).</p>
<p>I use <code>:hover</code> to make links change color when the mouse hovers over them, for example, hover your mouse over this link: <a href="http://www.w3schools.com/cssref/sel_hover.asp">link to :hover on w3Schools</a>. However, I also have named anchors on my site (e.g. <code><a name="top_of_post">Top of this post - etc ...</a></code>) so that I can link to parts of the page (e.g. <a href="#top_of_post">click this link to go to the top of this post i.e. to my named anchor</a>). Hover your mouse over the anchor above (at the top of this post - the text that says "Top of this post - etc ...") and you will see that it gets <code>:hover</code> as well, because it is an anchor tag.</p>
<p>Both of these use the anchor tag, but only one of them is an actual link. I want <code>:hover</code> on the links (<code><a href="http:/www..."></code>) but not on the anchors (<code><a name="top_of_post"></code>).</p>
<p>The page <a href="http://www.timrivera.com/tests/hover.html">A:hover and named anchors</a> has a fix for this. Create a CSS rule that will reverse <code>:hover</code> for anchor tags with a name attribute:</p>
<pre>
a:hover {text-decoration: underline; color: red; background: yellow}
a[name]:hover {text-decoration: inherit; color: inherit; background: inherit}
</pre>
<p>This works nicely, except that in HTML 5, the <a href="http://www.w3.org/TR/html5/obsolete.html">name attribute on anchor elements is marked as obsolete</a>. It is recommended that you use the <code>ID</code> attribute instead of <code>NAME</code>. I could change that CSS rule to use <code>a[id]:hover</code> instead of <code>a[name]:hover</code>, but that presents a new problem. I will use <strong>ID</strong> in anchor tags for many reasons, not just to create named anchors. I certainly <strong>do not</strong> want to remove <code>:hover</code> effects from all anchor tags that I might give an <strong>ID</strong> to.</p>
<p>So, the fix I now use for HTML 5 is to create a class for named anchors. It isn't as nice because I have to modify my code, but at least I can easily do a global find all <code><a name="</code> and replace with <code><a class="namedAnchor" id="</code>.</p>
<pre>
a:hover {text-decoration: underline; color: red; background: yellow}
a.namedAnchor {text-decoration: inherit; color: inherit; background: inherit}
</pre>
<p>And now I have named anchors with no <code>:hover</code>.</p>
<h3><a class="namedAnchor" name="bottom_of_post">Bottom of this post - a named anchor with <strong>no</strong> <code>:hover</code> effect.</a></h3>
</div>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-35994376011579204912015-03-02T23:17:00.000+11:002015-04-26T13:42:13.621+10:00Using historical data to determine how long local maven builds take<p>As part of an exercise in putting together a business case for <a href="http://zeroturnaround.com/software/jrebel/">JRebel</a> licences, a colleague asked me how long do my builds take on average. Well, because I have been using my own wrapper around maven (<a href="http://robertmarkbramprogrammer.blogspot.com.au/2015/01/do-you-use-mvn-on-bash-prompt.html">bash shell</a> or <a href="http://robertmarkbramprogrammer.blogspot.com.au/2015/01/do-you-use-mvn-on-dos-prompt.html">Windows batch</a>) to store the build logs, I was able to say exactly how long each particular build command had taken on average.</p>
<p>The longest builds, for example:</p>
<table border=1>
<tr style="background-color: grey; color:white;">
<td>Average Time in Seconds</td>
<td>Number of Runs</td>
<td>Command</td>
</tr>
<tr>
<td>682.09</td>
<td>23</td>
<td>mvn -T1C -Plocal clean compile deploy</td>
</tr>
<tr>
<td>518.68</td>
<td>31</td>
<td>mvn -T1C -Plocal -DdisableDojoProdBuild -DdisableGWTBuild -DdisableJspCompile clean deploy</td>
</tr>
</table>
<p>I generate my results from this Maven utility class I wrote: <a href="https://github.com/robertmarkbram/RobUtils/blob/master/src/org/rmb/maven/MavenBuildTimes.java">MavenBuildTimes.java</a>, available within the same <a href="https://github.com/robertmarkbram/RobUtils">git repo</a> that the maven wrappers are within. All you need to do is adjust the path to the log directory and you can run it across your own build logs too!</p><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-53728749408534028692015-02-13T15:45:00.001+11:002015-02-13T15:45:38.543+11:00I've seen things you people wouldn't believeI've... seen things you people wouldn't believe...<br />
De-compiled code in a torn off Eclipse editor on my second monitor.<br />
I watched core dumps so large my 32-bit editor literally couldn't open them.<br />
All those... moments... will be lost in time, like [small cough] my Wetern Digital 3TB... hard... disk. Which... died...<br />
<br />
<div style="text-align: right;">
<span style="font-size: xx-small;"><a href="http://en.wikipedia.org/wiki/Tears_in_rain_monologue">Loved it.</a></span></div>
<div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-17592434165757433172015-01-08T17:21:00.002+11:002015-04-26T13:38:12.137+10:00Do you use mvn on a bash prompt?<p><strong>Update</strong> Sunday 26 April 2015, 01:36:51 PM: renamed my github repos where these files are stored.</p>
<p>Here is my bash version of the DOS script I wrote about in <a href="http://robertmarkbramprogrammer.blogspot.com.au/2015/01/do-you-use-mvn-on-dos-prompt.html">Do you use mvn on a DOS prompt?</a>.</p>
<p>Do you use mvn on a bash prompt? Sick of having to scroll through a tiny bash prompt looking for an error amongst thousands of lines of output? Sick of not being able to search through the log? Want to save logs for future reference?</p>
<p>Well, look no further! I have written raven.sh, a wrapper around mvn that does one thing: saves the output to a file (which still gets displayed on the console) and opens the file in your favourite text editor.</p>
<p>The script itself includes instructions for setting up dependencies (not much set up) and how to use the script.</p>
<p>You can also see this script in GitHub: <a href="https://github.com/robertmarkbram/RobUtils/blob/master/tools/maven/raven.sh">https://github.com/robertmarkbram/RobUtils/blob/master/tools/maven/raven.sh</a> which is where I shall keep it updated. <a href="http://pastebin.com/VZAdTu48">Pastebin too</a>.</p>
<pre class="brush:bash" title="Save to raven.sh">
#!/bin/bash
# ------------------------------------------------------------------------------
# -- What is Raven?
# A Bash wrapper around mvn to save output to file and open it in an editor
# By Robert Mark Bram
# https://github.com/robertmarkbram/RobUtils
# http://robertmarkbramprogrammer.blogspot.com.au/2015/01/do-you-use-mvn-on-bash-prompt.html
# ------------------------------------------------------------------------------
# Set-up Dependencies first.
# - This script
# - Save this script as raven.sh in some folder you like to use for utilities etc.
# - Add the path (folder/directory name) where this script lives to your PATH (*see note 1*).
# - Otherwise you will have to use the absolute path to this script: e.g. "/C/myApps/Batch/raven" instead of just "raven".
# - Maven
# - Download it from: http://maven.apache.org/
# - Set M2_HOME variable (*see note 1*) or LOCAL_M2_HOME in this script.
# - Java
# - Download and install it from: http://www.oracle.com/technetwork/java/javase/downloads/index.html
# - Set JAVA_HOME variable (*see note 1*) or LOCAL_JAVA_HOME in this script.
# - tee (to send output to file and console)
# - Should already be part of Cygwin/nix install.
# - Your favourite text editor.
# - This script defaults to notepad. If you like it, do nothing.
# - If you want to use something else, set EDITOR in this script
# - Because we are *nix, you can set it to vim or less as well.
# - Temp dir
# - This script defaults to ${TEMP}/maven.
# - If you want to use something else, set TMPDIR in this script
#
# How to use this script.
# - Instead of using "mvn", just use "raven", e.g.
# raven clean deploy
# /C/myApps/Batch/raven clean deploy
#
# Note 1 - changing PATH or other environment variables on Win7 and above: two options.
# - OPTION 1: Start button > Search for "Environment Variables for your account" > modify PATH (or other variable) in top section, "user variables for USERNAME"
# - No re-boot required, just restart the DOS prompt.
# - PATH is set only for your user. Other logged users will not see it.
# - OPTION 2: Start button > Search for "Edit the System Environment Variables" > Environment Variables > modify PATH (or other variable) in bottom section, "System Variables"
# - Re-boot required.
# - PATH is set for all logged in users.
# ------------------------------------------------------------------------------
# -- Journal of Changes
# ------------------------------------------------------------------------------
# Thursday 08 January 2015, 04:57:36 PM
# - Adapted so that shell version works the same way as batch version.
# - Modified the way this script looks for maven and java such that it always uses local versions first.
# ------------------------------------------------------------------------------
# -- Variables for this script.
# Edit these variables - dependencies of this script.
# ------------------------------------------------------------------------------
# Could be vim or less too.
# EDITOR=/C/Program\ Files\ \(x86\)/IDM\ Computer\ Solutions/UltraEdit/Uedit32.exe
EDITOR=notepad
LOCAL_JAVA_HOME=/C/Program\ Files/Java/jdk1.7.0_67
LOCAL_M2_HOME=/C/apps/apache-maven-3.2.3
TMPDIR=${TEMP}/maven
MAVEN_OPTS="-Xms512m -Xmx1024m -XX:MaxPermSize=256m"
# ############################################################################
# DO NOT EDIT BELOW HERE
# ############################################################################
# ------------------------------------------------------------------------------
# -- Common functions for this script.
# ------------------------------------------------------------------------------
# === FUNCTION ===============================================================
# DESCRIPTION: Output message if verbose is on
# PARAMETERS: 1 - message to be printed
# 2 - options
# - "off" - don't use -e in echo
# RETURNS: -
# ==============================================================================
function message() {
if [ "$#" -eq 2 -a "$2" == "off" ] ; then
echo "$1" 2>&1 | tee -a "${outputFile}"
else
echo -e "$1" 2>&1 | tee -a "${outputFile}"
fi
}
# === FUNCTION ===============================================================
# DESCRIPTION: Check that all dependencies exist.
# PARAMETERS: -
# RETURNS: -
# ==============================================================================
function checkDependencies() {
# Temp dir for logs.
if [ ! -e "$TMPDIR" ] ; then
mkdir "$TMPDIR"
fi
# Check for tee.
type tee >/dev/null 2>&1 || {
echo -e "\n**************"
echo Please update your *nix to install the \"tee\" command.
echo -e "**************\n"
}
# Check editor.
if [ "${EDITOR}" != "notepad" -a "${EDITOR}" != "notepad.exe" -a "${EDITOR}" != "less" -a "${EDITOR}" != "vim" ] ; then
if [ ! -e "${EDITOR}" ] ; then
message "\n**************"
message "Please update EDITOR [${EDITOR}]"
message "variable to point to an editor you wish to use. Using notepad."
message "**************\n"
set EDITOR=notepad
fi
fi
# Check Maven.
# First check if local version is defined and exists.
# Allows user to specify a different maven than what exists in M2_HOME or PATH.
if [ -e "${LOCAL_M2_HOME}/bin/mvn" ] ; then
# All good, use local.
M2_HOME="${LOCAL_M2_HOME}"
PATH="${M2_HOME}/bin;${PATH}"
# Next check if M2_HOME set.
elif [ -e "${M2_HOME}/bin/mvn" ] ; then
PATH="${M2_HOME}/bin;${PATH}"
# LOCAL_M2_HOME and M2_HOME don't work.
# OK, no mvn then.
else
# OK, no mvn then.
message "\n**************"
message "-- Please download Maven from http://maven.apache.org/ and make"
message "-- the mvn command available via one of the following methods"
message "-- (this script detects maven in this order):"
message "-- 1. Set LOCAL_M2_HOME in this script."
message "-- 2. Set M2_HOME environment variable (system or user level)."
message "-- --"
message "-- We must be able to set M2_HOME from one of these."
message "**************\n"
reportResults
exit 3
fi
# Check Java.
# First check if local version is defined and exists.
# Allows user to specify a different maven than what exists in JAVA_HOME or PATH.
if [ -e "${LOCAL_JAVA_HOME}/bin/java" ] ; then
# All good, use local.
JAVA_HOME="${LOCAL_JAVA_HOME}"
PATH="${JAVA_HOME}/bin;${PATH}"
# Next check if JAVA_HOME set.
elif [ -e "${JAVA_HOME}/bin/java" ] ; then
PATH="${JAVA_HOME}/bin;${PATH}"
# LOCAL_JAVA_HOME and JAVA_HOME don't work.
# One of these MUST be set because maven requires JAVA_HOME to be set.
else
message "\n**************"
message "-- Please download and install Java from"
message "-- http://www.oracle.com/technetwork/java/javase/downloads/index.html"
message "-- and make the java command available via one of the following methods"
message "-- (this script detects java in this order):"
message "-- 1. Set LOCAL_JAVA_HOME in this script."
message "-- 2. Set JAVA_HOME environment variable (system or user level)."
message "-- --"
message "-- We must be able to set JAVA_HOME from one of these or maven will fail."
message "**************\n"
reportResults
exit 3
fi
}
# === FUNCTION ===============================================================
# DESCRIPTION: Open log in editor.
# PARAMETERS: -
# RETURNS: -
# ==============================================================================
function reportResults() {
case "${EDITOR}" in
less )
message "Output sent to $outputFile"
less -I "${outputFile}" ;;
vim )
message "\nOutput sent to $outputFile"
vim "${outputFile}" ;;
* )
# Some windows app.
outputFileWin=`cygpath -w -a "${outputFile}"`
message "\n"
message "Output sent to ${outputFileWin}" off
unix2dos "${outputFile}"
"${EDITOR}" "${outputFileWin}" &;;
esac
}
# === FUNCTION ===============================================================
# DESCRIPTION: Output environment details to aid debugging.
# PARAMETERS: -
# RETURNS: -
# ==============================================================================
function showEnvironmentDetails() {
message "\n-----------"
message "Current Directory [`pwd`]"
message "This script [`pwd -P`/$0]"
message "M2_HOME [$M2_HOME]"
message "JAVA_HOME [$JAVA_HOME]"
message "EDITOR [$EDITOR]"
message "MTEE [`type tee`]"
message "TMPDIR [$TMPDIR]"
message "PATH [$PATH]"
message "-----------\n"
}
# ------------------------------------------------------------------------------
# -- Script Logic
# ------------------------------------------------------------------------------
# No args means just open default notes file.
# Create timestamp.
timestamp=$(date +"%Y%m%d_%H%M%S")
outputFile=$TMPDIR/maven_$timestamp.txt
checkDependencies
showEnvironmentDetails
message "Caw caw said the Raven!\n"
message "==========================================================================="
message "Command:"
message "mvn $@"
message "===========================================================================\n"
mvn "$@" 2>&1 | tee -a "${outputFile}"
reportResults
</pre><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.comtag:blogger.com,1999:blog-19789758.post-39649694351185976152015-01-07T14:42:00.001+11:002015-04-26T13:40:14.153+10:00Do you use mvn on a DOS prompt?<p><strong>Update</strong> Thursday 08 January 2015, 05:17:54 PM - Modified the way this script looks for maven and java such that it always uses local versions first.</p>
<p>Do you use mvn on a DOS prompt? Sick of having to scroll through a tiny DOS prompt looking for an error amongst thousands of lines of output? Sick of not being able to search through the log? Want to save logs for future reference?</p>
<p>Well, look no further! I have written raven.bat, a wrapper around mvn that does one thing: saves the output to a file (which still gets displayed on the console) and opens the file in your favourite text editor.</p>
<p>The script itself includes instructions for setting up dependencies (not much set up) and how to use the script.</p>
<p>You can also see this script in GitHub: <a href="https://github.com/robertmarkbram/RobUtils/blob/master/tools/maven/raven.bat">https://github.com/robertmarkbram/RobUtils/blob/master/tools/maven/raven.bat</a> which is where I shall keep it updated. <a href="http://pastebin.com/Ykzsb9aH">Pastebin</a> too.</p>
<pre class="brush:batch" title="Save to raven.bat">
@echo off
SETLOCAL
:: ------------------------------------------------------------------------------
:: -- What is Raven?
:: A DOS Batch wrapper around mvn to save output to file and open it in an editor
:: By Robert Mark Bram
:: https://github.com/robertmarkbram/RobUtils
:: http://robertmarkbramprogrammer.blogspot.com.au/2015/01/do-you-use-mvn-on-dos-prompt.html
:: ------------------------------------------------------------------------------
:: Set-up Dependencies first.
:: - This script
:: - Save this script as raven.bat in some folder you like to use for utilities etc.
:: - Add the path (folder/directory name) where this script lives to your PATH (*see note 1*).
:: - Otherwise you will have to use the absolute path to this script: e.g. "C:\myApps\Batch\raven" instead of just "raven".
:: - Maven
:: - Download it from: http://maven.apache.org/
:: - Set M2_HOME variable (*see note 1*) or LOCAL_M2_HOME in this script.
:: - Java
:: - Download and install it from: http://www.oracle.com/technetwork/java/javase/downloads/index.html
:: - Set JAVA_HOME variable (*see note 1*) or LOCAL_JAVA_HOME in this script.
:: - mtee.exe (to send output to file and console)
:: - Download mtee.exe from http://www.commandline.co.uk/mtee/
:: - Add the path (folder/directory name) where mtee.exe lives to your PATH (*see note 1*) or set MTEE variable in this script.
:: - Your favourite text editor.
:: - This script defaults to notepad. If you like it, do nothing.
:: - If you want to use something else, set EDITOR in this script
:: - Temp dir
:: - This script defaults to %TEMP%\maven.
:: - If you want to use something else, set TMPDIR in this script
:: How to use this script.
:: - Instead of using "mvn", just use "raven", e.g.
:: raven clean deploy
:: C:\myApps\Batch\raven clean deploy
:: Note 1 - changing PATH or other environment variables on Win7 and above: two options.
:: - OPTION 1: Start button > Search for "Environment Variables for your account" > modify PATH (or other variable) in top section, "user variables for USERNAME"
:: - No re-boot required, just restart the DOS prompt.
:: - PATH is set only for your user. Other logged users will not see it.
:: - OPTION 2: Start button > Search for "Edit the System Environment Variables" > Environment Variables > modify PATH (or other variable) in bottom section, "System Variables"
:: - Re-boot required.
:: - PATH is set for all logged in users.
:: History
:: Wednesday 07 January 2015, 07:07:33 PM
:: - Updated to check java, maven, mtee temp dir and editor variables.
:: Thursday 08 January 2015, 04:57:36 PM
:: - Modified the way this script looks for maven and java such that it always uses local versions first.
:: ############################################################################
:: Edit these variables - dependencies of this script.
:: ############################################################################
:: set EDITOR=C:\Program Files (x86)\IDM Computer Solutions\UltraEdit\Uedit32.exe
set EDITOR=notepad
set LOCAL_JAVA_HOME=C:\Program Files\Java\jdk1.7.0_67
set LOCAL_M2_HOME=C:\apps\apache-maven-3.2.3
set MTEE=C:\apps\mtee.exe
set TMPDIR=%TEMP%\maven
set MAVEN_OPTS=-Xms512m -Xmx1024m -XX:MaxPermSize=256m
:: ############################################################################
:: DO NOT EDIT BELOW HERE
:: ############################################################################
:: Create timestamp.
SET hh=%time:~0,2%
if "%time:~0,1%"==" " SET hh=0%hh:~1,1%
SET YYYYMMDD_HHMMSS=%date:~10,4%%date:~7,2%%date:~4,2%_%hh%%time:~3,2%%time:~6,2%
set LOG_FILE=%TMPDIR%\maven_%YYYYMMDD_HHMMSS%.txt
:: Check temp dir.
if not exist %TMPDIR% mkdir %TMPDIR%
:: Check mtee.exe
:: Check in path first.
set MTEE_FOUND=
for %%e in (%PATHEXT%) do (
for %%X in (mtee%%e) do (
if not defined MTEE_FOUND (
set MTEE_FOUND=%%~$PATH:X
)
)
)
if "%MTEE_FOUND%" == "" (
:: Not in path. Check script variable.
if not exist %MTEE% (
echo.
echo **************
echo Please download mtee.exe from http://www.commandline.co.uk/mtee/
echo and update MTEE variable in this script.
echo **************
echo.
goto :exit
)
) else (
set MTEE=%MTEE_FOUND%
)
:: Check editor.
if "%EDITOR%" == "notepad.exe" goto :editor_check_end
if "%EDITOR%" == "notepad" goto :editor_check_end
if not exist "%EDITOR%" (
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo ************** 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo Please update EDITOR ["%EDITOR%"] 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo variable to point to an editor you wish to use. Using notepad. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo ************** 2<&1 | "%MTEE%" /+ %LOG_FILE%
set EDITOR=notepad
)
:editor_check_end
:: Check Maven.
:: First check if local version is defined and exists.
:: Allows user to specify a different maven than what exists in M2_HOME or PATH.
if exist "%LOCAL_M2_HOME%\bin\mvn.bat" (
set M2_HOME=%LOCAL_M2_HOME%
set "PATH=%M2_HOME%\bin;%PATH%"
) else if exist "%M2_HOME%\bin\mvn" (
:: Next check if M2_HOME set. It is.
set "PATH=%M2_HOME%\bin;%PATH%"
) else (
:: LOCAL_M2_HOME and M2_HOME don't work.
:: OK, no mvn then.
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo ************** 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- Please download Maven from http://maven.apache.org/ and make 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- the mvn command available via one of the following methods 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- ^(this script detects maven in this order^): 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- 1. Set LOCAL_M2_HOME in this script. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- 2. Set M2_HOME environment variable ^(system or user level^). 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- -- 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- We must be able to set M2_HOME from one of these. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo ************** 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
goto :report_results
)
:: Check Java.
:: First check if local version is defined and exists.
:: Allows user to specify a different java than what exists in JAVA_HOME.
if exist "%LOCAL_JAVA_HOME%\bin\java.exe" (
set JAVA_HOME=%LOCAL_JAVA_HOME%
set "PATH=%JAVA_HOME%\bin;%PATH%"
) else if exist "%JAVA_HOME%\bin\java.exe" (
:: Next check if JAVA_HOME set. It is.
set "PATH=%JAVA_HOME%\bin;%PATH%"
) else (
:: LOCAL_JAVA_HOME and JAVA_HOME don't work.
:: One of these MUST be set because maven requires JAVA_HOME to be set.
:: OK, no java then.
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo ************** 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- Please download and install Java from 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- http://www.oracle.com/technetwork/java/javase/downloads/index.html 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- and make the java command available via one of the following methods 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- ^(this script detects java in this order^): 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- 1. Set LOCAL_JAVA_HOME in this script. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- 2. Set JAVA_HOME environment variable ^(system or user level^). 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- -- 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo -- We must be able to set JAVA_HOME from one of these or maven will fail. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo ************** 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
goto :report_results
)
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo ----------- 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo Current Directory [%cd%] 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo This script [%0] 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo M2_HOME [%M2_HOME%] 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo JAVA_HOME [%JAVA_HOME%] 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo EDITOR [%EDITOR%] 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo MTEE [%MTEE%] 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo TMPDIR [%TMPDIR%] 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo PATH [%PATH%] 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo ----------- 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo Caw caw said the Raven! 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo =========================================================================== 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo Command: 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo mvn %* 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo =========================================================================== 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
mvn %* 2<&1 | "%MTEE%" /+ %LOG_FILE%
:report_results
echo. 2<&1 | "%MTEE%" /+ %LOG_FILE%
echo Output sent to %LOG_FILE% 2<&1 | "%MTEE%" /+ %LOG_FILE%
start "" "%EDITOR%" %LOG_FILE%
:exit
echo.
echo Done.
</pre><div class="blogger-post-footer">Thank you for reading. :)</div>Robert Mark Bramhttp://www.blogger.com/profile/06992070434006567093noreply@blogger.com