Skip to content

Commit 17aad03

Browse files
committed
up
1 parent dba1c40 commit 17aad03

File tree

2 files changed

+119
-2
lines changed

2 files changed

+119
-2
lines changed

README.md

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ Here's your text with grammar and spelling corrections:
22

33
# Hello, Java 22
44

5-
Hi, Spring fans! Happy [Java 22](https://blogs.oracle.com/java/post/the-arrival-of-java-22) release day, to those who celebrate! Did you get the bits already? Go, go, go! Java 22 is a _significant_ improvement that I think is a worthy upgrade for everyone. I love Java 22, and of course, I love GraalVM, and both have releases today! Java is of course our favorite runtime and language, and GraalVM is a high-performance JDK distribution that supports additional languages and allows ahead-of-time (AOT) compilation (they're called GraalVM native images). GraalVM includes all the niceties of the new Java 22 release, with some extra utilities, so I always recommend just downloading that one. I'm interested, specifically, in the GraalVM native image capability. The resulting binaries start almost instantly and take considerably less RAM compared to their JRE cousins. GraalVM isn't new, but it's worth remembering that Spring Boot has a great engine to support turning your Spring Boot applications into GraalVM native images.
5+
Hi, Spring fans! Happy [Java 22](https://blogs.oracle.com/java/post/the-arrival-of-java-22) release day, to those who celebrate! Did you get the bits already? Go, go, go! Java 22 is a _significant_ improvement that I think is a worthy upgrade for everyone. There are some big, final released features, like Project Panama, and a slew of even-better preview features. I couldn't hope to cover them all, but I did want to touch on a few of my favorites.
6+
7+
I love Java 22, and of course, I love GraalVM, and both have releases today! Java is of course our favorite runtime and language, and GraalVM is a high-performance JDK distribution that supports additional languages and allows ahead-of-time (AOT) compilation (they're called GraalVM native images). GraalVM includes all the niceties of the new Java 22 release, with some extra utilities, so I always recommend just downloading that one. I'm interested, specifically, in the GraalVM native image capability. The resulting binaries start almost instantly and take considerably less RAM compared to their JRE cousins. GraalVM isn't new, but it's worth remembering that Spring Boot has a great engine to support turning your Spring Boot applications into GraalVM native images.
68

79

810

@@ -453,6 +455,20 @@ These features are in preview in Java 22. I don't know that they're worth showin
453455

454456
Virtual threads give you the amazing scale of something like `async`/`await` in Python, Rust, C#, TypeScript, JavaScript, or `suspend` in Kotlin, but without the inherent verbosity of code and busy work required to use those language features. It's one of the few times where, save for maybe Go's implementation, Java is just straight-up better in the result. Go's implementation is ideal, but only because they had this baked in to the 1.0 version. Indeed, Java's implementation is more remarkable precisely because it coexists with the older platform threads model.
455457

458+
## Implicitly Declared Classes and Instance Main Methods
459+
460+
This preview feature is huge quality-of-life win, even though the resulting code is smaller, and I warmly welcome it.
461+
Unfortunately doesn't really work with Spring Boot, at the moment. The basic idea is that one day you'll be able to just
462+
have a top-level main method, without all the ceremony inherent in Java today. Wouldn't this be nice as the entry point
463+
to your application? No `class` definition, no `public static void`, no unneeded `String[]` args.
464+
465+
```java
466+
void main() {
467+
System.out.println("Hello, world!");
468+
}
469+
470+
```
471+
456472
## Statements Before Super
457473

458474
This is a nice quality of life feature. Basically, Java doesn't let you access `this` before invoking the super
@@ -617,6 +633,105 @@ The example above demonstrates that gatherers are also composable. We actually h
617633

618634
Still don't quite understand? I get the feeling that's going to be okay. This is a bit in the weeds for most folks, I'd imagine. Most of us don't need to write our own Gatherers. But you _can_. My friend [Gunnar Morling](https://www.morling.dev/blog/zipping-gatherer/) did just that the other day, in fact. The genius of the Gatherers approach is that now the community can scratch its own itch. I wonder what this implies for awesome projects like Eclipse Collections or Apache Commons Collections or Guava? Will they ship Gatherers? What other projects might? I'd love to see a lot of common sense gatherers, eh, well, _gathered_ into one place.
619635

636+
## Class Parsing API
637+
638+
Yet another really nice preview feature, this new addition to the JDK is really tuned to framework and infrastructure
639+
folks. It answers questions like how do I build up a `.class` file, and how do I read a `.class` file? Right now the
640+
market is saturated with good, albeit incompatible and alway, by definition, ever so slightly out of date options like
641+
ASM (the 800 lb. gorilla in the space), ByteBuddy, CGLIB, etc. The JDK itself has three such solutions in its own
642+
codebase! These sorts of libraries are everywhere, and critical for developers who are building frameworks like Spring
643+
that generate classes at runtime to support your business logical. Think of this as a sort of reflection API, but
644+
for `.class` files - the literal bytecode on the disk. Not an object loaded into the JVM.
645+
646+
Here's a trivial example that loads a `.class` file into a `byte[]` array and then introspects it.
647+
648+
```java
649+
650+
package com.example.demo;
651+
652+
import org.springframework.aot.hint.RuntimeHints;
653+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
654+
import org.springframework.context.annotation.ImportRuntimeHints;
655+
import org.springframework.core.io.ClassPathResource;
656+
import org.springframework.core.io.Resource;
657+
import org.springframework.stereotype.Component;
658+
659+
import java.lang.classfile.ClassFile;
660+
import java.lang.classfile.FieldModel;
661+
import java.lang.classfile.MethodModel;
662+
663+
@Component
664+
@ImportRuntimeHints(ClassParsing.Hints.class)
665+
class ClassParsing implements LanguageDemonstrationRunner {
666+
667+
static class Hints implements RuntimeHintsRegistrar {
668+
669+
@Override
670+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
671+
hints.resources().registerResource(DEFAULT_CUSTOMER_SERVICE_CLASS);
672+
}
673+
674+
}
675+
676+
private final byte[] classFileBytes;
677+
678+
private static final Resource DEFAULT_CUSTOMER_SERVICE_CLASS = new ClassPathResource(
679+
"/simpleclassfile/DefaultCustomerService.class");
680+
681+
ClassParsing() throws Exception {
682+
this.classFileBytes = DEFAULT_CUSTOMER_SERVICE_CLASS.getContentAsByteArray();
683+
}
684+
685+
@Override
686+
public void run() {
687+
// this is the important logic
688+
var classModel = ClassFile.of().parse(this.classFileBytes);
689+
for (var classElement : classModel) {
690+
switch (classElement) {
691+
case MethodModel mm -> System.out.printf("Method %s%n", mm.methodName().stringValue());
692+
case FieldModel fm -> System.out.printf("Field %s%n", fm.fieldName().stringValue());
693+
default -> {
694+
// ...
695+
}
696+
}
697+
}
698+
}
699+
700+
}
701+
702+
```
703+
704+
This example is made a bit more complicated because I am reading a resource at runtime, so I implemented a Spring
705+
AOT `RuntimeHintsRegistrar` that results in a `.json` file with information about which resource I am reading,
706+
the `DefaultCustomerService.class` file itself. Ignore all that. It's just for the GraalVM native image compilation.
707+
708+
The interesting bit is at the bottom, where we enumerate the `ClassElement` instances and then use some pattern matching
709+
to tease out individual elements. Nice!
710+
711+
## String Templates
712+
713+
Yet another preview feature, String templates bring String interpolation to Java! We've had multiline Java `String`
714+
values for a while. This new feature lets the language interpose variables available in scope in the compiled `String`
715+
value. The best part? In theory, the mechanism itself is pluggable! Don't like this syntax? Write your own.
716+
717+
```java
718+
package com.example.demo;
719+
720+
import org.springframework.stereotype.Component;
721+
722+
@Component
723+
class StringTemplates implements LanguageDemonstrationRunner {
724+
725+
@Override
726+
public void run() throws Throwable {
727+
var name = "josh";
728+
System.out.println(STR."""
729+
name: \{name.toUpperCase()}
730+
""");
731+
}
732+
733+
}
734+
```
620735

621736
## Conclusion
622737

src/main/java/com/example/demo/StringTemplates.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ class StringTemplates implements LanguageDemonstrationRunner {
88
@Override
99
public void run() throws Throwable {
1010
var name = "josh";
11-
System.out.println(STR."name: \{name.toUpperCase()}");
11+
System.out.println(STR."""
12+
the name is: \{name.toUpperCase()}
13+
""");
1214
}
1315

1416
}

0 commit comments

Comments
 (0)