The Java ecosystem is home to an enormous and diverse range of open source projects developed to meet almost every imaginable need. It’s easy to miss some of these great projects. Here’s a look at seven open source Java projects for everything from full-stack application development to microservices, Wasm, and an alternative to the JVM.
Vaadin’s Hilla
Hilla is a full-stack framework with a Java-based back end and a JavaScript front end. It supports the reactive front-end frameworks React and Lit.
Hilla lets you scaffold a new full-stack project with a command as simple as: npx @vaadin/cli init --hilla foundry-hilla
. It’s an NPM command, but it’ll deploy a standard Maven layout with a Vite-built front-end directory and everything is ready to run together with the ./mvnw
script.
Hilla enforces typing between the two application halves, meaning your IDE can detect and propagate changes across the Java API and the TypeScript front end that consumes it. In this framework, auto-complete and refactor just work. This functionality is similar in feel to tRPC in the all-TypeScript world.
Hilla also integrates persistence via JPA (on Hibernate) with a number of SQL databases like MySQL and PostgreSQL.
It's a bit like jHipster, but more opinionated. That means Hilla is less flexible in terms of the technologies it can glue together, but it gives you a more paved road to move across. Hilla is well-maintained and documented. If you need to build a full-stack app with Java, and if you like React or Lit for your front end, Hilla is a great framework to consider.
jHipster
Continuing with the theme of full-stack frameworks, we have jHipster. jHipster takes a very flexible approach that can unite a multitude of different technologies into one cohesive stack using Java as the API middleware. You can choose from several reactive front ends and a variety of SQL and NoSQL data stores.
Like Hilla, jHipster begins by generating an application with an NPM package, the jhipster-generator tool. The generator will walk you through a questionnaire that gives you a good idea about its capabilities. (If you happen to get the error ERR_PACKAGE_PATH_NOT_EXPORTED
, see the solution here.)
jHipster begins by letting you choose between a monolithic application, a microservices architecture, or a gateway, giving you some idea of the range of this framework. If you choose monolithic, you are then able to make it a reactive-style application with Spring WebFlux. Next, you can pick different styles of authentication like JWT or Oauth 2. Then you get to choose from several datastores like SQL, MongoDB, and Cassandra, followed by a second-level application cache like Ehcache, Memcached, or Redis.
The jHipster generator next allows adding a handful of other technologies: Elasticsearch for your search engine, WebSockets using Spring WebSocket, Apache Kafka as an asynchronous message broker, and API-first development using OpenAPI-generator. Next, you can pick from several front-end frameworks and generate an Admin UI if you so choose, along with several themes.
jHipster also features internationalization and testing, and it supports both Maven and Gradle.
That’s quite a lot of power. There’s also the ability to generate domain models and the data structures and the UI to go with them. jHipster is great choice for building many types of Java applications.
GraalVM
The GraalVM project was started in March 2018 with the mission of providing a more expansive implementation of the virtual machine. GraalVM does everything a JVM can do and then some: it allows for consuming a variety of languages and outputting to a variety of target execution environments. It also incorporates several compiler styles, including a JIT (just in time) compiler that can enhance performance.
GraalVM can run any language that compiles to LLVM, which includes C, C++, Rust, Swift, and many more. It also handles bytecode languages like Java, Scala, Kotlin, and Groovy. And it supports the JavaScript, Python, Ruby, and R languages. (In the future, we can hope to see GraalVM support Zig.)
That means we get all the write-once, run-anywhere goodness of the JVM for all kinds of languages. For example, GraalVM can take a C program compiled to LLVM bytecode (like with GCC) and run it with the lli
command. Or, GraalVM can compile the C code straight to an executable with clang
. GraalVM outputs standalone execution versions for many (but not all) languages and platforms.
It also includes support for many target binaries like Wasm, Linux variants, macOS, Windows, iOS, and Android. For many targets, GraalVM supports native images that run without any need to install GraalVM. It also allows developers to select execution modes—like JIT compilation, AOT compilation, and interpretation—to fine-tune performance profiles.
GraalVM is well maintained and documented with an active community. Taken as a whole, it is a compelling project that is edging toward becoming a kind of universal language tool. See the GraalVM project homepage to learn more about it.
Micronaut
Micronaut is a new take on Java development, aiming at modern cloud and serverless environments. It sports a wealth of features like command-line tooling for scaffolding, building, executing, and testing projects with a range of integrated technologies. Perhaps most importantly, Micronaut is designed around an AOT-enabled inversion-of-control (IOC) framework that maintains startup times in the face of large codebases.
Add to this microservices-oriented support like service discovery, tracing, and containerized deployments, and Micronaut is a well-thought-out and compelling option for modern Java development.
Micronaut offers a web-based project designer that you can use to get a sense of the range of tools that can be plugged in to the Micronaut core. This tool is similar in spirit to Spring Initializr or jHipster’s online generator, but it takes its own spin on things. Micronaut is reactive at its heart, supporting reactive implementations like RxJava and Reactor, and everything else is built on top of this central pillar. Micronaut includes its own reactive HTTP client.
Each node in Micronaut is a reactive component that can be composed into a larger microservices architecture, using a central service broker like ZooKeeper or Eureka.
Micronaut makes it easy to adopt best-practices in a one-stop-shopping framework that is similar in breadth to Spring, but more focused on concrete implementation details. It's a tempting choice for developers working on Java-based cloud and serverless environments.
MicroStream
In the evolution of Java-based object-oriented persistence, MicroStream may represent the final conceptual refinement. It takes your runtime object graph as-is and allows it to be persisted with object-oriented programming semantics to any number of underlying data stores.
MicroStream allows you to remain in the thought realm of objects and properties while the framework does much of the work of saving and recovering them. As a developer, you still have to consider meta concerns like fetching strategies and persistent boundaries, but these are defined simply and largely without interfering with application code, which works just like it would without thinking about persistence.
MicroStream includes the concept of a root, which defines the root of a persistence tree. An application can have more than one root, as shown in Listing 1.
Listing 1. Saving and restoring with MicroStream
// Saving
EmbeddedStorageManager manager = EmbeddedStorage.start();
manager.setRoot(myObject);
manager.storeRoot();
//Restoring
EmbeddedStorageManager storageEngine = EmbeddedStorage.start();
myObject = (MyClass) storageEngine.root();
MicroStream is an interesting new take on object persistence in Java, and definitely worth a look for any new project.
TeaVM
Compiling Java to Wasm (WebAssembly) is still something of a frontier, but TeaVM makes it possible to do today. TeaVM supports transpiling Java bytecode to both JavaScript (similar to Google Web Toolkit) and to Wasm. These can be used to create web applications that use Java code and libraries from inside the browser.
TeaVM works by first compiling code to a low-level intermediate representation, which is then further optimized and translated to WebAssembly instructions. The resulting code is highly efficient and can be run in any modern browser that supports WebAssembly.
One of the main benefits of TeaVM is its support for popular Java frameworks like Spring and Hibernate. Developers can use these frameworks to build complex, full-stack web applications, then compile the code to Wasm for web-based deployment.
Although TeaVM is still something of a budding project—the creator uses it for his day job and then pushes the fixes and improvements to the open-source repo—it seems to offer the best path, currently, from Java to Wasm.
Overall, TeaVM is a powerful and flexible tool for developing web applications in Java, and it offers an interesting avenue to working with Java in browsers and other Wasm environments.
Apache Flink
Flink was started in 2011 and has grown to become a leading event processing framework. It’s used by many household names like Airbnb and Netflix for real-time processing and puts a lot of power into your hands in a package that is relatively easy to manage.
Apache Flink incorporates fault tolerance and state management into a distributed, container-friendly form. It can automatically scale up and down to handle load with dynamic scaling.
Although running Flink in Docker with Kubernetes is typical, Flink can also run on serverless infrastructure like AWS Lambda, Azure Functions, and Google Cloud Functions using a framework like Apache Beam. This provides the benefit of only paying for the computing resources used during processing, and allows for easier and more efficient scaling.
Flink has a lot of capability under the hood, but simple things are fairly easy to grasp. In Listing 2, for example, Flink watches a socket on port 9999 and counts words in the text received there, outputting the data to the console.
Listing 2. Simple text handling with Flink
DataStream<String> text = env.socketTextStream("localhost", 9999);
DataStream<Tuple2<String,Integer>> wordCounts = text
.flatMap(new FlatMapFunction<String, Tuple2<String,Integer>>() {
public void flatMap(String value, Collector<Tuple2<String,Integer>> out) {
for (String word : value.split(" ")) {
out.collect(new Tuple2<String,Integer>(word, 1));
}
}
})
.keyBy(0)
.sum(1);
wordCounts.print();
You can see that Flink works with a functional style, and the platform itself handles expanding the functionality out to cloud infrastructure in a scalable, fault-tolerant way. All in all, it’s an impressive project for handling real-time event processing.