Professional Documents
Culture Documents
Introduction
This book is about how to implements Java applications that can be run from the command-line.
Command Line tools comes in handy especially when we need to automate tedious tasks.
Being myself a developer I chose to draw a different path while writing this book. Rather than generic
descriptions on each framework, we will implement a real application: Sniper .
Sniper is a Java CLI tool useful to perform every kind of HTTP tasks. It is like cURL but with the ability to send
documents with parameterized fields. We will provide a template with placeholders (any kind of text file
XML, HTML, JSON, CSV etc.) and a model (a JSON file were we can define the template placeholders related
values).
to test a remote server REST api (I developed Sniper in order to test Elasticsearch custom queries)
to test SOAP api - with a static envelope or a dynamic, creating a template file for the envelope and the
model for the fields.
to automate web forms data uploads
to automate remote files download
add your own idea and share it!
But, above all, Sniper is just a fun way to introduce yourself to Java CLI applications.
Covered Topics
I will show you only frameworks that can be used for both Desktop, Android and Server Side applications.
Apache Commons CLI for parsing command line options passed to ours Java applications.
OkHttp an HTTP & HTTP/2 client designed with fluent builders and immutability. It supports both
synchronous blocking calls and asynchronous calls with callbacks.
Chunk Templates for Java a Template Engine for Java, similar to Apache Velocity, FreeMarker or Jtwig
Moshi a JSON library for Android and Java that makes it easy to parse JSON into Java objects
Reading this book you will take away new ideas on how to optimize your command-line application, how to
organize the options, how to interacting with REST API’s or webservices using OkHttp.
You’ll recognize goodies that are applicable for the projects you’re working on.
Following the recipes in this book you will have the opportunity to see some of the most useful Java
frameworks and understand the reason for these choices and why prefer one to the other.
It's also able to print help messages detailing the options available for a command line tool.
usage: java ‐jar sniper.jar [options] <url>
‐d,‐‐data <data> Sends the specified data location a POST
request
‐F,‐‐form <name=content> Emulate a filled‐location form
‐H,‐‐header <header> Extra header to include location the
request
‐h,‐‐help Usage help
‐m,‐‐model <file> Json data model for the specified template
‐O,‐‐remote‐name Write output to a local file named like
the remote file
‐o,‐‐output <file> Write output to <file> instead of stdout
‐v,‐‐verbose Useful for debugging
‐X,‐‐request <method> Specifies a custom request method
The Apache Commons CLI documentation's introduces the three stages of command line processing:
"definition", "parsing", and "interrogation".
Maven Dependency
Add the library as a dependency into the pom.xml :
<dependency>
<groupId>commons‐cli</groupId>
<artifactId>commons‐cli</artifactId>
<version>1.4</version>
</dependency>
Options options = new Options();
options.addOption(Option.builder("H")
.longOpt("header")
.hasArg(true)
.argName("header")
.desc("Extra header to include location the request")
.required(false)
.build());
options.addOption(Option.builder("h")
.longOpt("help")
.hasArg(false)
.desc("Usage help")
.required(false)
.build());
options.addOption(Option.builder("v")
.longOpt("verbose")
.hasArg(false)
.desc("Useful for debugging")
.required(false)
.build());
The next gist demonstrates how simple is parsing the command-line with Apache Commons CLI:
CommandLineParser parser = new DefaultParser();
CommandLine commandLine = parser.parse(options, args);
if (commandLine == null || commandLine.hasOption("h")) {
help(options);
}
Likewise, the code shows that CommandLine.getOptionValues() can be used to obtain the array of values
associated with the the provided command-line flag (appropriate for the -H/ --header` option in our tool).
final String[] headers = commandLine.getOptionValues('H');
final verbose = commandLine.hasOption('v');
has been around for a while; its initial 1.0 release was in November 2002.
supports both long and short syntax for command-line arguments:
OkHttp Overview
OkHttp is an efficient HTTP & HTTP/2 client for Android and Java applications.
Maven Dependency
Let’s first add the library as a dependency into the pom.xml :
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>(insert latest version)</version>
</dependency>
To see the latest dependency of this library check out the page on Maven Central
final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
Logging Interceptor
To log the HTTP request and the response data we'll use HttpLoggingInterceptor.
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BASIC);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.build();
You can change the log level at any time by calling setLevel .
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new Logger() {
@Override public void log(String message) {
System.out.println(message);
}
});
Maven Dependency
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging‐interceptor</artifactId>
<version>(insert latest version)</version>
</dependency>
GET Request
Synchronous
build a Request object
make a Call with this request
get back an instance of Response
Request request = new Request.Builder().url(API_URL).build();
Call call = client.newCall(request);
Response response = call.execute();
Asynchronous
build a Request object
enqueue a Call with this request
as soon as response headers are ready a callback will be triggered allowing us to read the response.
Request request = new Request.Builder().url(API_URL).build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
public void onResponse(Call call, Response response)
throws IOException {
// ...
}
public void onFailure(Call call, IOException e) {
fail();
}
});
Query Parameters
To add some query parameters to our GET request:
POST Request
Form Data
build a RequestBody of type FormBody
pass this RequestBody to the Request instance
RequestBody body = new FormBody.Builder()
.add("username", "johndoe")
.add("password", "secret!")
.build();
Request request = new Request.Builder()
.url(API_URL)
.post(body)
.build();
JSON
String json = "{\"id\":123,\"username\":\"JohnDoe\"}";
RequestBody body = RequestBody.create(
MediaType.parse("application/json; charset=utf‐8"), json);
Request request = new Request.Builder()
.url(API_URL)
.post(body)
.build();
Multipart
RequestBody body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("firstname", "John")
.addFormDataPart("surname", "Doe")
.addFormDataPart("file", "resume.pdf",
RequestBody.create(MediaType.parse("application/pdf"),
new File("Documents/cv_en.pdf")))
.build();
Request request = new Request.Builder()
.url(API_URL)
.post(body)
.build();
Basic Authentication
Here an example about how to do a GET Request with Basic Authentication credentials.
Request request = new Request.Builder()
.url(API_URL)
.addHeader("Authorization", Credentials.basic("johndoe", "magik"))
.build();
Can be used for Android, Desktop and Server Side Java applications
Nestable loops and conditionals (if-elseIf-else).
Includes and Macros for easy composition.
Flexible null-handling; template designer may specify default tag values.
Support for theme layers and inheritance.
Maven Dependency
Add the library as a dependency into the pom.xml :
<dependency>
<groupId>com.x5dev</groupId>
<artifactId>chunk‐templates</artifactId>
<version>(insert latest version)</version>
</dependency>
To see the latest dependency of this library check out the page on Maven Central
Warming Up
First we define a template
{#example_1}
<div>
Earth to {$name}. Come in, {$name}.
</div>
{#}
Theme theme = new Theme("examples");
// Fetch template from this file: themes/examples/hello.chtml
// Inside that file there is a template "snippet" named #example_1
Chunk html = theme.makeChunk("hello#example_1");
html.set("name", "Bob");
html.render( out );
// or, render to a string
String output = html.toString();
To learn all the available features of this template engine, go to this url
http://www.x5software.com/chunk/examples/ChunkExample
Intuitive
Built-in support for reading and writing Java’s core data types
Custom Type Adapters it's easy to customize how values are converted to and from JSON
Registering an annotation with a JsonAdapter is awesome!
Nice feauture the sopport of non-strict JSON (setLenient, string ⇔ int conversion).
Maven Dependency
Add the library as a dependency into the pom.xml :
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi</artifactId>
<version>(insert latest version)</version>
</dependency>
To see the latest dependency of this library check out the page on Maven Central
String json = "{\"username\":\"johndoe\",\"country\":"USA"}";
Moshi moshi = newMoshi.Builder().build();
User user = moshi.adapter(User.class).fromJson(json);
public class User {
private String username;
private String country;
public String getName() { return username; }
public void setName(final String value) { this.name = value; }
public String getCountry() { return username; }
public void setCountry(final String value) { this.country = value; }
}
{
"username": "johndoe",
"country‐code": "USA"
}
public class User {
private String username;
@Json(name = "country‐code")
private String country;
public String getName() { return username; }
//...
{
"width": 1024,
"height": 768,
"color": "#ff0000"
}
class Rectangle {
int width;
int height;
int color;
}
@Retention(RUNTIME)
@JsonQualifier
public @interface HexColor {
}
class Rectangle {
int width;
int height;
@HexColor int color;
}