String Templates, JavaFX 19, Deserialization, and more at JavaOne - Inside Java Newscast #32

String templates make it easy and safe to embed variables and expressions in strings; JavaFX 19 comes with many improvements, chief among them derived observables; and the deserialization filter can keep apps safe from certain attacks. More on all of this at JavaOne!

Always embed videos

(and give me a cookie to remember - privacy policy)

Watch on YouTube

Intro

Welcome everyone to the Inside Java Newscast, where we cover recent developments in the OpenJDK community. I'm Nicolai Parlog, Java developer advocate at Oracle, and today I have another JavaOne-inspired mix of topics for you, namely string templates, the deserialization filter, and JavaFX 19.

Like last episode, where I talked about sequenced collections and pure functions, all links are in the description, even some that don't exist yet. Other than that, be sure to check out oracle.com/javaone and I'll hopefully see you in Las Vegas, October 17th to 20th.

Ready?

Nope, not yet. Nicolai in the editing room here and .. No I'm not gonna turn the camera on ... Because I'm not wearing pants ... I'm working from home - who wears pants for that? Anyway, if you get a ticket for JavaOne, use code INSIDEJAVA (all caps, no spaces) for a hefty 400 $ discount. Now we're ready.

Then let's dive right in!

String Templates

Let's start with something very cool that Java will hopefully get next year and that we briefly talked about in the recent OpenJDK Q&A: string templates. When you have variables and want to put them into a string, Java offers various ways to do that, for example concatenation with a + or calling String::format or Message::format.

String property = "last_name";
String name = "Doe";

// needed:
//     SELECT * FROM Person p
//     WHERE p.last_name='Doe'

// concatenation
String query = "SELECT * FROM Person p WHERE p."
		+ property + " = '" + value + "'";

// formatting
String query = "SELECT * FROM Person p WHERE p.%s = '%s'"
		.formatted(property, value);

They're all a bit cumbersome, though, but that's not even their main drawback. In most cases, we're not creating text for people to read but structured text for other systems, like HTML, JSON, SQL, etc. - and blindly concatenating strings and variables can not only easily create invalid strings, in cases like SQL it can even lead to vulnerabilities. String templates aim to rectify both of these problems.

They make inserting variables and expressions into strings much easier by introducing a syntax to do just that. When creating a one-line string or a text block, simply use \{ as opening and just } as closing delimiter for the expression you want to embed. Using the otherwise illegal sequence \{ ensures that no existing string is suddenly interpreted as an interpolation and serves as an easy differentiator between strings and string templates.

//                                 VARIABLES    ↓↓↓    AND    ↓↓↓
var query = "SELECT * FROM Person p WHERE p.\{property} = '\{value}'";

Because here's the thing: Such a stringy-looking construct won't actually be an instance of String but of TemplatedString.

// ↓↓↓ NOT A STRING!
TemplatedString query = "SELECT *  [...]  p.\{property} = '\{value}'";

To turn a templated string into a regular string, you need a policy and that policy will be domain-specific: Dealing with JSON? Use a JSON policy. Dealing with SQL? Use an SQL policy. And so on.

// ↓↓↓ STRING  ↓↓↓ POLICY
String query = SQL."SELECT * FROM  [...]  p.\{property} = '\{value}'";

The policy will be able to validate the string and make sure it's formed as expected. And even better, it doesn't have to return a string. When you're already parsing JSON or SQL to validate it - why not turn it into a JSON node or SQL statement? Right, no reason not to! So policies allow that as well!

// alternative policy that creates java.sql.Statement
Statement query = SQL."SELECT * FROM [...] p.\{property} = '\{value}'";

I'm pretty exited about that feature! And at JavaOne, Gavin Bierman and Jim Laskey from the Java Platform Group will tell us all about it in their talk String Template Pondering.

Deserialization Filter

There are quite a few sessions on security, but the one I want to recommend the most is the Java Security Q&A with JPG security experts Sean Mullan and Brad Wetmore. If you have any questions regarding security in Java, be sure to ask them there!

But there are a lot of other promising talks as well. For example Brian Vermeers Deserialization Exploits in Java: Why Should I Care? - I'll leave it to him to explain why you should, but assuming you do, I can show you a little bit what you can do against them - Brian will fill in the details.

Java 9 introduced a deserialization filter, a mechanism that you can use to limit what bytestreams will be deserialized. You can create allow-lists and deny-lists for class names and class name patterns, you can limit the object graph's depth and the number of internal references as well as array size and input stream length. If an input stream violates these requirements, it will be rejected and often quickly.

  • maxdepth=value: maximum depth of graph
  • maxrefs=value: maximum number of internal references
  • maxarray=value: maximum array size allowed
  • maxbytes=value: maximum number of bytes in the input stream

You can statically configure the filter for all deserializations with the system property jdk.serialFilter or the security property of the same name in the JDK file conf/security/java.security. Alternatively, you can dynamically create ObjectInputFilter instances at run time and set them on the respective ObjectInputStream instances. Since Java 17, you can also configure a JVM-wide filter factory to reach those places where you don't control the ObjectInputStream and that are tough to configure with the global option - with it, you can create filters specifically for the context in which they will be applied. If your app uses serialization, I recommend to closely read the secure coding guidelines and also attend Brian's talk - there are links to both below.

// -Djdk.serialFilter=maxdepth=5

ObjectInputFilter filter = ObjectInputFilter.Config.createFilter("maxdepth=5");
ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(serializedList));
inputStream.setObjectInputFilter(filter);

Other practical talks on the topic of security are Security Vulnerabilities for Java Developers by Okkta's Brian Demers and Secure Coding Guidelines for Java SE by JPG's Chris Ries. To get a glimpse behind the scenes, check out Weijun Wang's and Sean Mullan's session Evolving the Security of the Java Platform.

Performance

There will be tons of talks on Java performance, from ZGC (twice actually) to G1, from the Vector API to a general performance benchmarking introduction, from JDK Flight Recorder to Micrometer. And almost all of them by the folks working on and improving these very technologies day in day out! So if you have questions about these technologies, this is the place to ask them.

Derived Bindings in JavaFX 19

As an ardent Linux user, I'm living in the perpetual year of Linux on the desktop and so I'm glad that Java's not standing still there either. JPG's desktop veteran Kevin Rushforth will explain in JavaFX 19 and Beyond how the desktop technology improved in recent releases. There's a number of new features and improvements:

  • JavaFX Media now has support for H.265 - that's a codec important for 4k videos
  • JavaFX Webview now supports transparent backgrounds
  • and there are now convenience methods that make JavaFX more approachable

But the one I want to focus on here is the new support for creating derived bindings directly from ObservableValue. Say you're creating an editor for an Employee instance and it has a salary slider. At that point you probably have an observable for the current employee you're editing and another for the salary slider but you want to bind them in a way that when the employee changes, the salary slider is bound to the new employee's salary. This is where derived bindings come in. ObservableValue gets methods map and flatMap that allow you to create new observables for specific properties of a value.

// goal: setting a new `Employee` updates `slider` to their salary
ObservableValue<Employee> employee = new SimpleObjectProperty<>();
ObservableValue<Number> salary = employee.map(Employee::salary);

var slider = new Slider(0, 10_000, 0);
slider.valueProperty().bind(salary);
Note:

That may sound as if moving the slider would update the salary. After all, why else use a slider?! But that's not the case: ObservableValue::map and flatMap return ObservableValue, but bidirectional binding requires a more specific subtype (Property), so that's not possible. Too bad.

Beyond this talk, Kevin will give a more general one called Building and Deploying Java Client Desktop Applications with JDK 17 and Beyond together with JPG's Phil Race and there'll be another one on JavaFX by Paul and Gail Anderson. To better understand how to ship such apps, check out Alexey Semenyuk's talk jpackage: Packaging Tool for Java Applications. And if you're a MacOs enthusiast, don't miss Project Lanai - New graphics pipeline for macOS.

Cloud

I'm the first to admit that I don't know much about cloud stuff, but if I wanted to change that - I don't think I wanna, though - JavaOne would be the place to do that. Graeme Rocher from the Graal team will give a talk Zero to Hero, where he live-codes microservices from IDE to cloud with GraalVM and Micronaut. That would probably be a good introduction. As would Modern Java App Development in the Cloud by Rustam Mehmandarov and Mads Opheim from Computas, where they talk about MicroProfile, Quarkus, and serverless. For the more advanced, there's Delightful integration tests with Testcontainers by AtomicJar's Oleg Šelajev and Secrets of Performance Tuning Java on Kubernetes by Bruno Borges from Microsoft.

And since I love podium discussions, I also want to recommend the Java in Containers birds-of-a-feather session with JPG's Larry Cable and Ioi Lam, where they will discuss challenges with tools like Docker, Podman, or Kubernetes as well as practices that can help you solve them.

Outro

And that's it for today on the Inside Java Newscast. Don't forget to check out oracle.com/javaone and I hope I get to see you in Las Vegas in October! Other than that, do all the YouTube things and I'll see you again in two weeks. So long...