In my programming career, I have used a wide variety of frontend frameworks. From JQuery and Angularjs (not Angular!). To Vue and React.
A common theme with these was a SPA (Single Page Application) architecture. The server would respond with JSON, the frontend would parse it, do some javascript-y things, and ultimately render as html on the page.
But this isn’t cool anymore! There has been a trend towards moving rendering to the server, demonstrated by technologies like Next.js and React Server Components.
But did you know that a server can just respond with plain old HTML, without needing to refresh the whole page and not needing a complicated frontend framework to achieve this?
Enter: htmx.
htmx is a very basic frontend library, that operates based on special hx-*
attributes on HTML elements.
An example of this is the following (ripped straight off htmx’s homepage):
<button hx-post="/clicked" hx-swap="outerHTML">
Click Me
</button>
This can be described as: “When this button is clicked, make a POST request to /clicked and replace the button with the HTML response”.
Basically, all of htmx revolves around:
This is a simple, but powerful paradigm.
It simplifies frontend devlopment, making it easy to learn and maintain, without the need for complex frontend build tools.
In the blog post, I will describe a Java web app stack using:
to enable fast and simple web app development. I will explain what each part of the stack does, and how we can put it all together to build a simple counter app in a single Java file!
If you are using Maven, here’s the list of dependencies that you can chuck in your pom.xml
file.
Don’t worry, this blog post will explain what each of them does!
<!-- Place the below in the <dependencies> section of your pom.xml -->
<dependency>
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>5.5.0</version>
</dependency>
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>htmx.org</artifactId>
<version>1.9.2</version>
</dependency>
<!-- Defining a logger as Javalin will complain if there is no SL4J logger -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
<version>2.0.5</version>
</dependency>
A way to generate HTML in Java is to use a templating engine like Thymeleaf. However, this means the template files are outside Java, and as the blog title suggests, we want everything in Java!
A nice alternative to a templating engine is j2html.
j2html is a Java library that allows us to build HTML in a fluent and typesafe manner. If you know HTML, you know j2html!
import static j2html.TagCreator.*;
public class Main
public static void main(String[] args) {
// Fluently build a HTML structure.
var content = html(
body(
h1("Hello World!")
)
);
// Let's render that HTML!
System.out.println(content.render());
}
}
Output:
<html><body><h1>Hello world</h1></body></html>
Now, let’s serve that html through a sever. We can do that using Javalin.
According to https://javalin.io/, Javalin is a simple web framework for Java and Kotlin. I agree!
I feel like it is very similar to the Express framework for Node.js. For instance, the following Express code:
// Using Express as an example.
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen()
Is the same as the following Javalin code:
import io.javalin.Javalin;
public class Main {
public static void main(String[] args) {
var app = Javalin.create()
.get("/", ctx -> ctx.result("Hello World"))
.start();
}
}
Now let’s combine j2html and Javalin.
We can use Javalin’s Context#html
to allow the server to respond with HTML.
import io.javalin.Javalin;
import static j2html.TagCreator.*;
public static void main(String[] args) {
// Create a new Javalin instance.
// By default it will run on port 8080, but can be changed.
var javalin = Javalin.create();
// Handle a GET request to the path "/".
javalin.get("/", ctx -> {
// Build the HTML, and render it.
var content = html(
body(
h1("Hello world")
)
);
// We prefix with the doctype to ensure the browser does not use quirks mode.
// https://developer.mozilla.org/en-US/docs/Web/HTML/Quirks_Mode_and_Standards_Mode
var rendered = "<!DOCTYPE html>\n" + content.render();
// Return the html in the response.
ctx.html(rendered);
});
javalin.start();
}
If we run this, we will see some output in the console.
INFO [main] (JavalinLogger.kt:16) - Listening on http://localhost:8080/
INFO [main] (JavalinLogger.kt:16) - You are running Javalin 5.5.0 (released May 1, 2023).
INFO [main] (JavalinLogger.kt:16) - Javalin started in 273ms \o/
Once you see the “Javalin” started command, we can put in the url http://localhost:8080
into a
browser. This should show something like this:
Isn’t it beautiful?
Lastly, lets add some interactivity with htmx!
To add htmx to our project, we can add it as a WebJar. A WebJar is basically just a way to manage Javascript dependencies using standard Java build tools, like Maven or Gradle.
<!-- Was in the dependencies at the top of this blog post, but putting
here in case you forgot! -->
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>htmx.org</artifactId>
<version>1.9.2</version>
</dependency>
To use this, we need to:
<head>
element of our HTML.public static void main(String[] args) {
var javalin = Javalin.create(config -> {
// Enable WebJar support.
config.staticFiles.enableWebJars();
});
javalin.get("/", ctx -> {
var content = html(
head(
// The WebJars path follows the format:
// /webjars/<artifactId>/<version>/<path-to-file>
// We can find the <path-to-file> via npmjs.com 'Code' view.
// For instance: https://www.npmjs.com/package/htmx.org?activeTab=code
script().withSrc("/webjars/htmx.org/1.9.2/dist/htmx.min.js")
),
body(
h1("Hello world")
)
);
var rendered = "<!DOCTYPE html>\n" + content.render();
ctx.html(rendered);
});
javalin.start();
}
Now, let’s start actually using htmx! For this example, we’ll create a simple counter app. It will show a number, that can be incremented by pressing a button.
Firstly, let’s create a method that produces the HTML for the count. This will make a bit more sense later on.
// Create a H2 tag with an id.
private H2Tag createCounterElement(int count) {
return h2("count: " + count)
.withId("counter");
}
Next, we need a way to store the count on the server.
The easiest way is to use an AtomicInteger
.
We can use this count and the createCounter
method we created before in the handler we have:
public static void main() {
var count = new AtomicInteger();
javalin.get("/", ctx -> {
var content = html(
head(
script().withSrc("/webjars/htmx.org/1.9.2/dist/htmx.min.js")
), (
body(
h1("Hello world"),
createCounterElement(count.get())
)
)
);
var rendered = "<!DOCTYPE html>\n" + content.render();
ctx.html(rendered);
});
}
We then need a way for the server to increment this counter. We can do this by defining a new handler on our server.
Let’s make it accept POST
requests on the path /increment
.
It will increment the count on the server and return only the html for the counter element.
This is where that createCounterElement
method is useful!
javalin.post("/increment", ctx -> {
var newCounter = createCounterElement(count.incrementAndGet());
ctx.html(newCounter.render());
});
Lastly, and most importantly, we now use htmx to call this increment
handler, and swap out the
relevant counter element on the screen.
To do so, we can define a button with special hx-*
attributes like so:
button("Increment")
.attr("hx-post", "/increment")
.attr("hx-target", "#counter")
.attr("hx-swap", "outerHTML")
To explain each attribute:
POST
request to the /increment
path.counter
.outerHTML
means htmx will swap the entire html of the counter element.Putting all the code we have together, we should have something that looks like the following:
public static void main(String[] args) {
var javalin = Javalin.create(config -> {
config.staticFiles.enableWebjars();
}
);
var counter = new AtomicInteger();
javalin.get("/", ctx -> {
var content = html(
head(
script().withSrc("/webjars/htmx.org/1.9.2/dist/htmx.min.js")
), (
body(
h1("Hello world"),
createCounter(counter.get()),
button("Increment")
.attr("hx-post", "/increment")
.attr("hx-swap", "outerHTML")
.attr("hx-target", "#counter")
)
)
);
var rendered = "<!DOCTYPE html>\n" + content.render();
ctx.html(rendered);
});
javalin.post("/increment", ctx -> {
var newCounter = createCounter(counter.incrementAndGet());
ctx.html(newCounter.render());
});
}
private static H2Tag createCounterElement(int count) {
return h2("count: " + count)
.withId("counter");
}
If we run the code, we should see something like the following:
Now press ‘increment’ and see what happens!
(Spoilers: the number should increment!)
If we have the network tab open, we can see the request to /increment
, with the html being
returned.
The counter will persist even if you refresh the page, as the number is stored on the server!
I hope you have enjoyed learning a bit about Javalin, j2html and htmx!
If you want to see see an example of a todo app using Javalin, you can have a look at this github repository: java-htmx-todo
]]>However, something that I have noticed is that you don’t have much control over what Jekyll and ruby version is used. This seems to be getting a little bit out of date as time goes on. GitHub lists the dependencies on this page. At time of writing, it uses Jekyll 3.9.3 (latest version is 4.3.2), and ruby 2.7.4 (latest version is 3.2.2).
Additionally, GitHub restricts what Jekyll plugins you can use and actually
enables certain plugins that can’t be disabled. For instance, it brings in jekyll-coffeescript
…
which is used to convert coffeescript…even though my site doesn’t have any coffeescript (it’s 2023!).
For these reasons, I looked into alternatives, and I found out that you can use GitHub actions to deploy a site!
I couldn’t find a nice guide on how to do this, so after working things out, I decided to write this guide.
It’s pretty straightforward, we only really need to do 2 things:
Firstly, we need toggle the deployment setting from the ‘default’ GitHub pages deploy to GitHub actions.
We can do this via Settings -> Pages. We just need to change the ‘Source’ as shown in the screenshot below:
Note that this won’t really do anything, until we do the next step!
The workflow is how we tell GitHub how to build and deploy the site. You can read a bit more about workflows in the GitHub docs (there’s a bunch more cool things you can do with workflows!)
To start, we need to define a YAML file in the path <repo-root>/.github/workflows/<workflow-name>.yml
We can call the workflow file anything. I just went with the very creative name: jekyll.yml
.
The contents of the file should look something like the below. For those interested, I will explain it further down below.
name: Jekyll Build and Deploy
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: '2.7.4'
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- run: bundle exec jekyll build
- uses: actions/upload-pages-artifact@v1
with:
path: "_site/"
deploy:
# Add a dependency to the build job
needs: build
if: github.ref == 'refs/heads/master' # Only deploys on master
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
# Deploy to the github-pages environment
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
# Specify runner + deployment step
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
Side-note: this requires a Gemfile
to be defined in the repository root. I’m not sure if my one
was created when I first set up the GitHub pages (many years ago!), or I added it afterwards. In
case you don’t have one, here’s mine:
source 'https://rubygems.org'
gem 'github-pages', group: :jekyll_plugins
gem 'jekyll-seo-tag'
gem 'rouge'
gem 'jekyll-feed'
I’ll break it down section by section:
name: Jekyll Build and Deploy
The name of the workflow, which is shown in GitHub’s UI.
on: [push]
Indicates that the workflow will run on any push to the GitHub repository. This includes commits in PRs.
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: '2.7.4'
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- run: bundle exec jekyll build
- uses: actions/upload-pages-artifact@v1
with:
path: "_site/"
The build job will:
actions/checkout@v3
)bundle install
for us!
(ruby/setup-ruby@v1
)bundle exec jekyll build
. This runs Jekyll and produces the generated site in the folder _site/
.actions/upload-page-artifacts@1
, which is a requirement
to deploy the site. deploy:
# Add a dependency to the build job
needs: build
if: github.ref == 'refs/heads/master' # Only deploys on master
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
# Deploy to the github-pages environment
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
# Specify runner + deployment step
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
It’s important to note that the deploy job:
master
, which is my repository’s default branch. Newer repositories will have
main
as their default branch.The only step that this job has is: actions/deploy-pages@v2
. This deploys the site that we
uploaded in the build step with actions/upload-pages-artifact@v1
.
When you next push to your default branch, you should see the workflow running in the actions page of your repository.
Here is an example of mine:
And the fact that you can read this page, means that the workflow is deploying the site. Yay!
Now, you can run any version of ruby and Jekyll you want, use any plugin you want, and I can finally get rid of that weird coffeescript plugin. Double yay!
For reference, please take a look at my PR, which converted this site to use Github Actions.
]]>Recently, I’ve been using Kotlin for a project at work. As someone coming from a Java background, I’ve been taking notes on certain patterns that are used in Java, that can be done nicer in Kotlin. I feel like when using a new language, it’s easy to fall into the trap of writing non-idiomatic code simply because it’s what I would’ve done in another language.
I wrote this article with the idea that this is what I would’ve wanted when starting with Kotlin, and I plan on updating it as I learn more techniques. Anyway, let’s begin!
Sometimes, it is nice to embed SQL or have HTML snippets in our
application. In these cases, we want to be able to have a String
that spans
multiple lines. If we had it on a single line, it would be near impossible to
read!
In Java 11 and below, we have to resort to simple String
+
concatenation. Make sure you don’t forget
to add new line endings \n
or else when the String is built, it will all end up
on one line!
// Java 11 and older
String query = "SELECT w.id, w.title, w.date, we.weight, e.name\n" +
"FROM workouts as w\n" +
"LEFT JOIN workout_exercises as we ON w.id = we.workout_id\n" +
"LEFT JOIN exercises as e on we.exercise_id = e.id\n" +
"WHERE w.user_id = ?";
However, starting from Java 13, we have a much nicer way of writing this!
// Java 13 and above
String query = """
SELECT w.id, w.title, w.date, we.weight, e.name
FROM workouts as w
LEFT JOIN workout_exercises as we ON w.id = we.workout_id
LEFT JOIN exercises as e on we.exercise_id = e.id
WHERE w.user_id = ?
""";
This is an example of a Text Block, which is a preview feature in Java 13 and 14. At the time of writing, this feature will be finalised in Java 15.
For Kotlin, the syntax is similar to what is available in Java 13+.
val query = """
SELECT w.id, w.title, w.date, we.weight, e.name
FROM workouts as w
LEFT JOIN workout_exercises as we ON w.id = we.workout_id
LEFT JOIN exercises as e on we.exercise_id = e.id
WHERE w.user_id = ?
""".trimIndent()
You might be asking why we have to call the trimIndent
function at the end.
This is because if we don’t, Kotlin will construct the String
including the
initial whitespace indentation on each line. As we are only inserting that
indentation for readability purposes, we have to call trimIndent
which will
remove this initial whitespace from each line.
I think this is a case where the Java way of Text Blocks is a bit better, as it will automatically trim the whitespace for us. However, Kotlin is here now and (at the time of writing) Java 15 is still a month or so away!
Another common thing we like to do with String
s is to construct them with
variables. For instance, we receive some input from the user and we want to
create a message based on that input.
Unfortunately, Java does not have a nice, modern way to do this and we have to
resort to simply using +
to build our String.
String name = "bob";
int age = 18;
String message = "My name is " + name + " and my age is" + age;
We do have other options that are useful in certain situations, such as
StringBuilder
and
String#format. But for simple, straight forward
situations, we can only use +
.
In Kotlin, we can use template expressions inside a String
. This greatly improves
readability when a String
is concatenated with multiple values.
val name = "bob";
val age = 18;
val message = "My name is $name and my age is $age"
// Can also use ${expression} for more complex usages
val message = "My name is $name and my age in 10 years will be ${age + 10}"
When we want utility methods that we want to use without having create a new Object, it is common practice to add them as static methods on a class.
Frequently, ‘Util’ classes exist that only contain static methods. This is a pattern employed by popular libraries like Google Guava and Apache Commons.
public class StringUtils {
public static char getLastLetter(String str) {
if (str.isEmpty()) {
throw new IllegalArgumentException("Provided string must not be empty");
}
return str.charAt(str.length() - 1);
}
}
StringUtils.getLastLetter("abc") // => c
In Kotlin, we have a few options.
Firstly, we can have a top-level function. That is, a function that is not attached to a class. This language feature does not exist in Java.
We can call the function from anywhere we want, without needing to create a new object, or prefix a class name in front of the function call.
// Using a top-level function
fun getLastLetter(str: String): Char {
if (str.isEmpty()) {
throw IllegalArgumentException("Provided string must not be empty")
}
return str[str.length - 1]
}
getLastLetter("abc") // => c
Next, we can add a method to an object
. This is roughly equivalent to the static
method way we saw in Java, and the calling code is the same.
// Using an Object
// https://kotlinlang.org/docs/tutorials/kotlin-for-py/objects-and-companion-objects.html
object StringUtils {
fun getLastLetter(str: String): Char {
if (str.isEmpty()) {
throw IllegalArgumentException("Provided string must not be empty")
}
return str[str.length - 1]
}
}
StringUtils.getLastLetter("abc") // => c
Finally, we have an extension function. This is a cool feature that allows us to attach a method to an existing class, without the need of creating a subclass or a new wrapped type!
// Using an extension function
// https://kotlinlang.org/docs/reference/extensions.html
// Preferred!
fun String.getLastLetter(): Char {
if (this.isEmpty()) {
throw IllegalArgumentException("Provided string must not be empty")
}
return this[this.length - 1]
}
"abc".getLastLetter() // => c
This extension function feature was one the initial features I saw when looking at Kotiln where I thought that it was really useful!
In some cases, we want to be able to define and use singleton’s in our code.
With Java, we can do this by creating a class with a private constructor. The class then provides a public static field that can be accessed from calling code.
public class BeanFactory {
public static final BeanFactory INSTANCE = new BeanFactory();
private BeanFactory() {
// Prevent outside world creating a new BeanFactory
}
public Beans createBakedBeans() {
return new BakedBeans();
}
}
In Kotlin, we greatly reduce boilerplate code by simply defining a new object
type.
object BeanFactory {
fun createBakedBeans(): Beans {
return BakedBeans()
}
}
For more information about object
, please read the relevant
docs.
I’ve covered how to write common Java techniques in idiomatic Kotlin. Often, the equivalent Kotlin code is shorter and more readable.
My advice for Java developers starting with Kotlin: always be learning! If you find yourself encountering a new problem in Kotlin and you solve it by writing Java-ish code, slow down and see if there’s a better way to do it in Kotlin. Have a search on Google or talk to your favourite coworker about it. This way, you will continuously learn best practices while still being productive!
]]>Recently (yes, I say recently even though it happened last year!) I attended the very first edition of DDDAdelaide. It’s awesome finally seeing Adelaide getting a software development conference. It was really well put together, and I had a great time. I would highly recommend anyone going to the next one!
This article covers my key takeaways from some of the talks I saw. I’ve also included each presenter’s Twitter and a link to the slides where possible.
Fantastic talk about moving security testing from near/after the release stage, to the development stage. As a programmer by trade, I know security is important but it sometimes feels like it is left behind a bit in the engineering process. The suggestion to add security testing as part of automated CI/CD is definitely something I want to explore doing.
Rob initially goes into the history of API technology, with some funny commentary on how we think the newest thing that comes out is the ‘best’ (‘SOAP is dead, long live REST’ to ‘REST is dead long live GraphQL’)
Main takeaway: There is no universal best API style, but there is always a best API style for you problem.
Dasith Wijesiriwardena - Slides
A nice overview of how to handle authentication. Dasith provided an in-depth description on the problems with the classic model of authentication, and described modern alternatives.
As a Java guy, TypeScript is something that really resonates with me. I’m always eager to hear more about it!
Jaime showed some cool things that are achievable in TypeScript. The keyof
feature was something that found immediate use for me for a project I have at
home.
The speaker also had a good sense of humor, with a couple of digs at JavaScript’s ‘type’ system.
Like security, I feel like accessibility is one of those things that are an after thought in web dev. Jess brings some stats to show that things shouldn’t be that way!
What I like about this talk, is while there was a focus on React, the techniques shown can be applied to any front end framework. Also, I’ll always love a web dev talk that promotes the use of semantic HTML!
]]>We’ll go through the steps of enabling RSS on a GitHub pages site, and then we’ll link it up to a Dev.to blog.
Adding RSS support to a GitHub Pages is very simple. All we have to do is add
the following line to the _config.yml
file in the root directory of the project.
plugins:
- jekyll-feed
To test locally, we can add the following entry to the project’s
Gemfile
. (If you haven’t yet set up a local environment for your GitHub pages
site, please follow this
guide.)
gem 'jekyll-feed'
We can do a bundle install
, which will install the required gem.
When we run the site using bundle exec jekyll serve
, go to the page
localhost:4000/feed.xml
. You should see something like this:
<feed>
<generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator>
<link href="https://yoursite.com/feed.xml" rel="self" type="application/atom+xml"/>
<link href="https://yoursite.com/" rel="alternate" type="text/html"/>```
<!-- Full xml omitted -->
Side note: Technically, this is an Atom feed but this will work fine for our use case.
Once we have confirmed it works, we can push it to GitHub via the following
command:
git commit -am "Add jekyll-feed gem"; git push
Firstly, we need to go to https://dev.to/settings/publishing-from-rss.
We then just have to paste in ‘https://yoursite.com/feed.xml’ into the box, and press ‘update’.
I did enable the ‘Mark the RSS source as canonical URL by default’. This means it will mark my blog posts on my website as the original source, which helps my website appear in Google.
After a small wait, posts from GitHub pages should appear in the Dashboard. They initially come in as drafts and posts can be published individually.
While the RSS integration works really well, there’s a couple of small issues I encountered.
When I initially set up RSS on the Dev.to side, it said it fetched my feed but I didn’t see any entries in my dashboard. It wasn’t until I checked a bit later that posts were sent across from my blog. I certainly don’t have a problem with waiting, but I thought I did something wrong as there was no clear messaging that it takes a little while.
Another thing is that I have some entries from my blog that I don’t want to publish on Dev.to. However, if I delete the entries from my dashboard, they just come right back. It’d be good if there was some way to ‘ignore’ a blog post from an RSS feed.
To reiterate the steps:
- jekyll-feed
to the plugins section in _config.yml
I’ve created a page on my website http://anthonybruno.dev/last-update that simply has a Unix timestamp of the last time the site was built.
The task is simple, create some code that requests this page and returns the timestamp!
Below is the code that uses URLConnection
.
// 1. Create URL object
URL updateUrl = new URL("http://anthonybruno.com.au/last-update");
// 2. We use openConnection() on the url to get a HttpURLConnection,
// that we have to cast(?!). Also, this doesn't actually make a
// network request(?!?!?)
HttpURLConnection connection = (HttpURLConnection) updateUrl.openConnection();
// 3. We can then set things like set request methods, headers.
connection.setRequestMethod("GET");
// 4. Then we actually connect! Note: connect doesn't return anything, it
// mutates the connection object!
connection.connect();
int statusCode = connection.getResponseCode();
if (statusCode != 200) {
throw new RuntimeException("Got non 200 response code! " + statusCode);
}
// 5. Content is returned in an InputStream (Don't forget to close it!)
InputStream content = connection.getInputStream()
Instant timestamp = processIntoInstant(content)
// 6. Remember to disconnect! Note: HttpURLConnnection is not autoclosable!
connection.disconnect()
After creating the URL
object, things quickly go awry. It’s extremely
counter-intuitive to use a method called openConnection()
, that doesn’t
actually open a connection! Having to cast the returned URLConnection
object to
HttpURLConnection
to access methods like setRequestMethod
and disconnect
is plain silly. Finally, calling connect()
(which actually makes a network
request!) doesn’t return anything, instead, you have to get response information
from the connection
object itself.
Below is the code that uses HttpClient
. You’ll see a big difference.
// 1. Create HttpClient object
HttpClient httpClient = HttpClient.newHttpClient();
// 2. Create URI object
URI uri = URI.create(updateUrl);
// 3. Build a request
HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
// 4. Send the request and get a HttpResponse object back!
// Note: HttpResponse.BodyHandlers.ofString() just parses the response body
// as a String
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
if (statusCode != 200) {
throw new RuntimeException("Got non 200 response code! " + statusCode);
}
Instant timestamp = processIntoInstant(response.body())
Now, isn’t that much nicer than the URlConnection
code we saw before? We first
set up a HttpClient
object, which will send our requests. We then instantiate a HttpRequest
object,
which holds the request method, headers, etc. We send the HttpRequest
, using
the previously created HttpClient
, giving us a nice HttpResponse
object
back.
The second parameter in httpClient.send
is a BodyHandler
, which is
responsible for parsing the response body into the format you want. Java
provides a bunch of default ones in BodyHandlers
, that covers common use cases
like parsing to String
, File
and InputStream
. Of course, it’s possible to
create your own, which deserves an article by itself.
The idea of creating a client, creating requests and receiving responses is
quite a bit more intuitive than using URlConnection
! HttpClient
also supports
asynchronous requests, HTTP/2 and websockets. It’s an enticing reason to migrate
from 8 to 11!
Code used in this article can be found here
]]>Firstly, you must add the file paths to the web_accessible_resources
property
in the manifest.json
file. The file paths are relative to the extension’s root (where
the manifest.json
is located). For instance, if I wanted to include a file
called info.json
that is located in a folder data
, it would look like:
"web_accessible_resources": [
"data/info.json"
]
A cool feature is that these paths support wildcards. For example:
"web_accessible_resources": [
"data/*.json"
]
will allow access to any json file in the data folder.
The next step is to read the data from the file. To do this, we need to get the URL of the file and make a request to it.
To get the URL of the file we can use chrome.runtime.getURL('path/to/file')
.
Then we make a GET request to the URL. In this example, we will use the ES6 feature Fetch but methods such as XmlHttpRequest will also work.
const url = chrome.runtime.getURL('path/to/file');
fetch(url)
.then((response) => {response.json()}) //assuming file contains json
.then((json) => doSomething(json));
And there we have it!
To reiterate the steps simply:
web_accessible_resources
property in the manifest.json
filechrome.runtime.getURL('path/to/file')
Another year down! In this post I look back on what I did last year, what I need to improve on and plans for the future.
SDGen is a Java library that helps developers generate randomised data files for testing purposes. It supports CSV and Fixed Width formats, with more formats such as JSON planned for the future.
This guide will show you how to generate a simple CSV file using SDGen and Faker. Faker will be used to assist creating random values.
For a Maven project, we can add the required libraries by inserting the following xml into the pom.xml file of a project.
<dependencies>
<dependency>
<groupId>au.com.anthonybruno</groupId>
<artifactId>SdGen</artifactId>
<version>0.3.0</version>
</dependency>
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>0.14</version>
</dependency>
</dependencies>
Firstly, we need to get the Faker instance by writing:
Faker faker = Faker.instance();
We can then use the faker instance to generate values such as URLs
faker.internet().url()
and planet names faker.space().planet()
.
Next, we’ll use SDGen
’s fluent builder to create the schema for the CSV file
we want to create. To begin, we write:
Gen.start()
We can then add fields (aka columns) using the addField
method. addField
takes 2
parameters: A String
name, which will be to identify the field in the produced
file and a Generator
. A Generator
is a simple interface with a single method
generate
. This is the way that random values are created and added to a field.
We are going to make a simple CSV file of people. To do that, we will add a
‘First Name’ and a ‘Last Name’ column using the corresponding Faker
methods to
generate values for these:
Gen.start()
.addField("First Name", () -> faker.name().firstName())
.addField("Last Name", () -> faker.name().lastName())
Note: Using lambdas (e.g. () -> faker.name().firstName()
is the equivalent of
writing:
new Generator() {
@Override
public Object generate() {
return faker.name().firstName();
}
}
We also want to add an ‘Age’ field. To do this, we can use SDGen
’s inbuilt
IntGenerator
. We can give it a sensible minimum and maximum value to limit the
range of numbers it will generate. SDGen
provides generators for all primitive types.
Gen.start()
.addField("First Name", () -> faker.name().firstName())
.addField("Last Name", () -> faker.name().lastName())
.addField("Age", new IntGenerator(18, 80))
Next, we specify how many rows to generate by using the generate
method. We also want to select the format of the generated data. We
will be using asCsv
to generate the data in CSV format. SDGen
also supports
the Fixed Width format and will support other data formats such as JSON in the future.
Gen.start()
.addField("First Name", () -> faker.name().firstName())
.addField("Last Name", () -> faker.name().lastName())
.addField("Age", new IntGenerator(18, 80))
.generate(1000) //1000 rows will be generated
.asCsv()
Finally, we specify how the data will be output. We will use the toFile
method
to put the information into a file.
Gen.start()
.addField("First Name", () -> faker.name().firstName())
.addField("Last Name", () -> faker.name().lastName())
.addField("Age", new IntGenerator(18, 80))
.generate(1000)
.asCsv()
.toFile("people.csv");
And that’s it! Running the code will produce a CSV file in the project’s working directory. Here is some data that was produced when I ran it:
First Name,Last Name,Age
Corrine,Berge,78
Gerald,Carter,63
Enid,Padberg,66
Eleanora,Murray,79
Coy,Okuneva,76
Jovan,Reynolds,77
Lane,Haag,48
For more information about SDGen, please visit it on Github.
int
into a method,
change it, and then get the changed variable after the method ends. Apparently simply returning it was not an option! I suggested wrapping
the variable in an Object
with a getter and setter. Another coworker suggested
creating a single element int array containing the value.
A somewhat heated discussion occurred as I debated it’s more semantically correct to use an object, while my coworker suggested that creating and using an array is faster.
But we’re programmers, let’s write some code to figure out which is faster!
Here’s the testing code that simply runs the test, records how long it takes and prints the results.
To test mutating the variable using an array, we have this code:
Finally, to test mutating the variable with an object, we have this:
After running each test a billion times, 10 times each, the results are surprising. There is practically no difference in speed when using an array vs an object. This shows how efficient object creation is in Java, demonstrating that java programmers shouldn’t be scared to create objects.
It also shows that I was right! ;)
]]>