diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml
index f3be329..840a7e6 100644
--- a/.github/workflows/hugo.yml
+++ b/.github/workflows/hugo.yml
@@ -40,6 +40,14 @@ jobs:
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
- name: Install Dart Sass
run: sudo snap install dart-sass
+ - name: Install ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 2.7
+ - name: Install Asciidoctor
+ uses: reitzig/actions-asciidoctor@v2.0.1
+ with:
+ version: 2.0.18
- name: Checkout
uses: actions/checkout@v3
with:
@@ -75,4 +83,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
- uses: actions/deploy-pages@v2
\ No newline at end of file
+ uses: actions/deploy-pages@v2
diff --git a/config.yml b/config.yml
index a1b4850..74a087e 100644
--- a/config.yml
+++ b/config.yml
@@ -27,3 +27,12 @@ menu:
name: Categories
url: /categories/
weight: 10
+
+security:
+ exec:
+ allow:
+ - ^(dart-)?sass(-embedded)?$
+ - ^go$
+ - ^npx$
+ - ^postcss$
+ - ^asciidoctor$
diff --git a/content/posts/maven-build-tips.md b/content/posts/2023-04-25-quick-repeatable-maintainable-maven-builds/maven-build-tips.md
similarity index 100%
rename from content/posts/maven-build-tips.md
rename to content/posts/2023-04-25-quick-repeatable-maintainable-maven-builds/maven-build-tips.md
diff --git a/content/posts/2024-05-30-using-jackson-deduction-to-simplify-deserialisation/using-jackson-deduction-to-simplify-deserialisation.adoc b/content/posts/2024-05-30-using-jackson-deduction-to-simplify-deserialisation/using-jackson-deduction-to-simplify-deserialisation.adoc
new file mode 100644
index 0000000..d599204
--- /dev/null
+++ b/content/posts/2024-05-30-using-jackson-deduction-to-simplify-deserialisation/using-jackson-deduction-to-simplify-deserialisation.adoc
@@ -0,0 +1,116 @@
+---
+date: 2024-05-30
+title: Using Jackson Deduction to Simplify Deserialisation
+cover:
+ image: posts/2024-05-30-using-jackson-deduction-to-simplify-deserialisation/cover.jpeg
+tags:
+- java
+- jackson
+---
+
+I find the documentation for Jackson is on the terse side, and dare I say
+obstructively self-referential. If you aren't moved fully to tears by the Javadoc
+entries for `JsonTypeInfo.As`, you deserve an ACM award.
+
+In short: I need a helpful and up-to-date guide, so I'm writing one.
+
+== What are we trying to do?
+
+We often want to vary the content of our JSON. It's integral to the https://www.enterpriseintegrationpatterns.com/patterns/messaging/EnvelopeWrapper.html[Envelope pattern] for instance. Varying the content looks like this.
+
+Here's an example of an intergalactic animal.
+
+[source,json]
+----
+{
+ "created": "1977-05-25T12:00:00Z",
+ "animal": {
+ "galaxy": "Far Far Away",
+ "name": "Womp Rat"
+ }
+}
+----
+
+And here's an example of a provincial animal.
+
+[source,json]
+----
+{
+ "created": "1835-09-15T06:00:00Z",
+ "animal": {
+ "province": "Galápagos Islands",
+ "name": "Galápagos tortoise"
+ }
+}
+----
+
+In our Java code, we want to be able to deserialise Animals, and we want to handle either `IntergalacticAnimals`,
+or `ProvincialAnimals`. We might write some transport code that looks like this.
+
+[source,java]
+----
+record AnimalSpottedEvent(Instant created, A animal) {}
+
+interface Animal {}
+
+record IntergalacticAnimal(String galaxy, String name) implements Animal {}
+
+record ProvincialAnimal(String province, String name) implements Animal {}
+----
+
+When it's called to handle deserialisation of an Animal over the wire, Jackson needs to work out
+what's the "message inside the envelope?" Is it an `IntergalacticAnimal`, or is it a `ProvincialAnimal`?
+Without this knowledge, Jackson can't instantiate the right kind of object.
+
+There is a (truly excellent) resource, https://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html[Deserialize JSON with Jackson into Polymorphic Types - A Complete Example],
+which describes how to do this using `JsonTypeInfo`, but it was written in 2011 for Jackson 1.7.
+
+== State of the Art
+
+You may have missed the 2.12.0 release of Jackson Databind in Novemeber 2020. The world was
+generally busy with other things around then. In which case the https://fasterxml.github.io/jackson-annotations/javadoc/2.12/com/fasterxml/jackson/annotation/JsonTypeInfo.Id.html#DEDUCTION[`JsonTypeInfo.Id#DEDUCTION`]
+could have slipped by you unnoticed.
+
+The newer "deduction" mode takes away the need to tell Jackson _how_ to read the incoming data; instead
+Jackson will take a list of possible choices you give it, and it will determine the best match for
+deserialisation.
+
+What does that look like? You can follow these steps:
+
+1. add `@JsonTypeInfo(use = DEDUCTION)` to the envelope property
+2. add `@JsonSubTypes(@Type(...))`
+
+Here is our updated example code.
+
+[source,java]
+----
+record AnimalSpottedEvent(
+ Instant created,
+ @JsonTypeInfo(use = DEDUCTION)
+ @JsonSubTypes({
+ @Type(IntergalacticAnimal.class),
+ @Type(ProvincialAnimal.class)})
+ A animal) {}
+
+interface Animal {}
+
+record IntergalacticAnimal(String galaxy, String name) implements Animal {}
+
+record ProvincialAnimal(String province, String name) implements Animal {}
+----
+
+https://github.com/TomRegan/jackson-deduction-demo[I've created a demo project] as a companion to provide a working example.
+
+Happy deserialisation!
+
+== Appendix
+
+=== Dependencies
+
+`jackson-annotations` provides `@JsonTypeInfo` and associated annotations which you'll use in your transport code.
+
+`jackson-databind` provides the "invisible" deserialisers. You'll need these available on the classpath in your server
+or client application.
+
+There are any number of ways to get `jackson-annotations` and `jackson-databind` on your classpath. `spring-boot-starter-web`
+includes many Jackson components; alternatively the Jackson project provides a https://mvnrepository.com/artifact/com.fasterxml.jackson/jackson-bom[BOM].
diff --git a/content/posts/code-shame.md b/content/posts/code-shame.md
index ac66503..6418d5d 100644
--- a/content/posts/code-shame.md
+++ b/content/posts/code-shame.md
@@ -14,7 +14,7 @@ when I came back to change the code. This is something I know inside-out,
so the point of this post is to shame me into never making the same mistake
again.
-{% highlight diff %}
+```diff
--- a/src/resource_handler.c
+++ b/src/resource_handler.c
@@ -27,16 +27,18 @@ uint16_t
@@ -45,7 +45,7 @@ service_request(struct request *req, char *rtrv_buf, const size_t len)
}
return RINTERNAL;
-{% endhighlight %}
+```
In the original code I'm deferencing a field in a struct (`req->method`)
without first finding out whether the struct had been assigned.