Update: this technique no longer works since name reflection was removed in later versions of Java. Here is another approach. Another use of lambda parameter reflection could be to write html inline in Java. It allows us to create builders like this, in Java, where we’d previously have to use a language like Kotlin and a library like Kara.
String doc =
html(
head(
meta(charset -> "utf-8"),
link(rel->stylesheet, type->css, href->"/my.css"),
script(type->javascript, src -> "/some.js")
),
body(
h1("Hello World", style->"font-size:200%;"),
article(
p("Here is an interesting paragraph"),
p(
"And another",
small("small")
),
ul(
li("An"),
li("unordered"),
li("list")
)
)
)
).asString();
Which generates html like
Hello World
Here is an interesting paragraph
And anothersmall
- An
- unordered
- list
Code Generation
Why would you do this? Well we could do code generation. e.g. we can programmatically generate paragraphs.
body(
asList("one","two","three")
.stream()
.map(number -> "Paragraph " + number)
.map(content -> p(content))
)
Help from the Type System
We can also use the Java type system to help us write valid code.
It will be a compile time error to specify an invalid attribute for link rel.
It’s a compile time error to omit a mandatory tag
It’s also a compile time error to have a body tag inside a p tag, because body is not phrasing content.
We can also ensure that image sizes are in pixels
Safety
We can also help reduce injection attacks when inserting content from users into our markup, by having the DSL html-encoding any content passed in.
e.g.
assertEquals(
"<script src="attack.js"></script>
",
p("").asString()
);
How does it work?
See this previous blogpost that shows how to get lambda parameter names with reflection. This allows us to specify the key value pairs for html attributes quite cleanly.
I’ve created an Attribute type that converts a lambda to a html attribute.
public interface Attribute extends NamedValue {
default String asString() {
return name() + "=\"" + value()+"\"";
}
}
For the tags themselves we declare an interface per tag, with a heirarchy to allow certain tags in certain contexts. For example Small is PhrasingContent and can be inside a P tag.
public interface Small extends PhrasingContent {
default Small small(String content) {
return () -> tag("small", content);
}
}
To make it easy to have all the tag names available in the context without having to static import lots of things, we can create a “mixin” interface that combines all the tags.
public interface HtmlDsl extends
Html,
Head,
Body,
Link,
Meta,
P,
Script,
H1,
Li,
Ul,
Article,
Small,
Img
...
Then where we want to write html we just make our class implement HtmlDsl (Or we could staticly import the methods instead.
We can place restrictions on which tags are valid using overloaded methods for the tag names. e.g. HTML
public interface Html extends NoAttributes {
default Html html(Head head, Body body) {
...
and restrict the types of attributes using enums or other wrapper types. Here Img tag can only have measurements in pixels
public interface Img extends NoChildren {
default Img img(Attribute src, Attribute dim1, Attribute dim2) {
...
All the code is available on github to play with. Have a look at this test for executable examples. n.b. it’s just a proof of concept at this point. Only sufficient code exists to illustrate the examples in this blog post.
What other creative uses can you find for parameter reflection?