Logo

dev-resources.site

for different kinds of informations.

Calling Clojure from Java using a real example (Clojure + Quarkus)

Published at
10/1/2024
Categories
clojure
programming
quarkus
java
Author
gcamargosilva
Categories
4 categories in total
clojure
open
programming
open
quarkus
open
java
open
Author
13 person written this
gcamargosilva
open
Calling Clojure from Java using a real example (Clojure + Quarkus)

The challenge

Last weekend, I decided to explore more about how Clojure can interact with the existent Java ecosystem, the challenge was simple:

Create a simple web framework in Clojure using the Quarkus framework as a base.

Premises:

  • The Quarkus does not know what will be executed by route, even not how many routes exist.
  • I should be able to create routes and handlers using Clojure as simply as possible:
(defn send-hello-world [] "Hello World")

(defn routes [] [{:method "GET"
                  :path "/hello" 
                  :handler send-hello-world}])
Enter fullscreen mode Exit fullscreen mode

Some definitions:

  • Quarkus: Quarkus is a full-stack, Kubernetes-native Java framework made for Java virtual machines (JVMs) and native compilation, optimizing Java specifically for containers.
  • Clojure: Is a dynamic, general-purpose programming language

Step 1: Creating a Quarkus app

It is very easy to start an app in Quarkus you can follow this tutorial, as you can see your last command will be quarkus create && cd code-with-quarkus after that you can open the folder code-with-quarkus with your favorite IDE, the command created the basic structure of a Quarkus app, and you can run with quarkus dev

Step 2: Enable the project to recognize clj files

You need to configure Quarkus to include .clj files in target folder (The folder with your compiled app), and you can do it by adding this configuration in pom.xml inside <project>

<resources>
        <resource>
            <directory>/</directory>
            <includes>
                <include>*.clj</include>
            </includes>
        </resource>
    </resources>
Enter fullscreen mode Exit fullscreen mode

Step 3: Create Clojure file

As I mentioned earlier, I defined one structure to declare my routes, in the same location of the folder main. Then I created a folder named quarkus_clj with a file called core with the code below:

(ns quarkus-clj.core)

(defn send-hello-world [] "Hello World")

(defn routes [] [{:method "GET"
                  :path "/hello" 
                  :handler send-hello-world}])
Enter fullscreen mode Exit fullscreen mode

Step 4: Enabling Quarkus to handle my Clojure program

Here is where the magic happens ๐ŸŽฉ๐Ÿช„!

First of all, you should install the Clojure inside your Quarkus app; you can do it by adding a dependency in pom.xml

<dependency>
      <groupId>org.clojure</groupId>
        <artifactId>clojure</artifactId>
        <version>1.11.1</version> 
</dependency>
Enter fullscreen mode Exit fullscreen mode

Now, you can delete the file GreetingResource.java and its tests. In the same place, create a file Starting.java

I write some comments explaining how it works

@ApplicationScoped
public class Starting {
    //Setup app routes
    public void setupRouter(@Observes Router router) {
        // Load Clojure core;
        IFn require = Clojure.var("clojure.core", "require");
        // Load quarkus-clj.core namespace
        require.invoke(Clojure.read("quarkus-clj.core")); 

        // Load the route list function
        IFn routesFn = Clojure.var("quarkus-clj.core", "routes");

        // Invoke the function with no parameters
        PersistentVector routesVector = (PersistentVector) routesFn.invoke();

        //For each route in routes vector 
        for (Object route : routesVector) {
            /**Get the route map, example
            {:method "GET"
             :path "/hello" 
             :handler send-hello-world}
             */
            PersistentArrayMap routeMap = (PersistentArrayMap) route;

            //Get :path value
            String path = (String) routeMap.valAt(Clojure.read(":path"));
            //Get :handler function
            IFn handlerRoute = (IFn) routeMap.valAt(Clojure.read(":handler"));
            //Get :method value
            String method = (String) routeMap.valAt(Clojure.read(":method"));
            //Create a handler to exec handler function
            Handler<RoutingContext> handlerFn = (RoutingContext context) -> {
            String result = (String) handlerRoute.invoke();  
            context.response().end(result);
        };
            //Config the route in quarkus
            router.route(HttpMethod.valueOf(method), path).handler(handlerFn);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Now you can just run: quarkus dev open your declared route and see the result!

Conclusion

This was a quick example of how to use Clojure inside a Quarkus app to create dynamic routes. With just a few steps, we connected the two ecosystems and set up a basic routing system. Feel free to expand on this foundation and explore other possibilities with Clojure and Quarkus!

quarkus Article's
30 articles in total
Favicon
Java Can Be Serverless Too: Using GraalVM for Fast Cold Starts
Favicon
Building Robust REST Client with Quarkus: A Comprehensive Guide
Favicon
Choosing the Right Java Microservices Framework: Spring Boot, Quarkus, Micronaut, and Beyond
Favicon
Agente de IA confiรกvel em prod com Java + Quarkus + Langchain4j - Parte 2 - Memรณria
Favicon
Agente de IA confiรกvel em prod com Java + Quarkus + Langchain4j - Parte 1 - AI as Service
Favicon
Calling Clojure from Java using a real example (Clojure + Quarkus)
Favicon
Turbocharge Java Microservices with Quarkus and GraalVM Native Image
Favicon
Introduction to Quarkus: Java Native for Kubernetes
Favicon
Effective Project Structuring for Microservices with Quarkus
Favicon
Unlock Lightning-Fast Web Services: Mastering Quarkus for Agile, Scalable, and Responsive RESTful APIs
Favicon
Harnessing Automatic Setup and Integration with Quarkus Dev Services for Efficient Development
Favicon
Why we discarded Reactive systems architecture from our code?
Favicon
Unveiling Challenges with @Named
Favicon
Exploring Synthetic Beans in Quarkus. A Powerful Extension Mechanism
Favicon
Registering Reflection in Quarkus Extensions
Favicon
Creating Custom Configuration in Quarkus Loaded from JSON File
Favicon
Extending Quarkus: When and How to Write Your Own Extensions
Favicon
Demystifying Quarkus Extension Development: Jandex vs. AdditionalBeanBuildItem
Favicon
๐— ๐—ถ๐—ฐ๐—ฟ๐—ผ๐˜€๐—ฒ๐—ฟ๐˜ƒ๐—ถ๐—ฐ๐—ฒ๐˜€ ๐—ถ๐—ป ๐—๐—ฎ๐˜ƒ๐—ฎ: ๐—”๐—ฟ๐—ฐ๐—ต๐—ถ๐˜๐—ฒ๐—ฐ๐˜๐˜‚๐—ฟ๐—ฒ, ๐—•๐—ฒ๐—ป๐—ฒ๐—ณ๐—ถ๐˜๐˜€, ๐—ฎ๐—ป๐—ฑ ๐—œ๐—บ๐—ฝ๐—น๐—ฒ๐—บ๐—ฒ๐—ป๐˜๐—ฎ๐˜๐—ถ๐—ผ๐—ป
Favicon
Spring Boot vs Quarkus: Pick one for Java!
Favicon
Deploying native Quarkus REST API's in AWS Lambda
Favicon
เน€เธฃเธดเนˆเธกเธ•เน‰เธ™ Quarkus 3 part 2.3 Renarde
Favicon
เน€เธฃเธดเนˆเธกเธ•เน‰เธ™ Quarkus 3 part 2.2 web bundler
Favicon
How to enable mongodb query logging in reactive java for quarkus with panache
Favicon
Beyond JWT: Unlocking PASETO for Secure Token Management
Favicon
เน€เธฃเธดเนˆเธกเธ•เน‰เธ™ Quarkus 3 part 1
Favicon
Exploring Quarkus vs Spring Boot
Favicon
Secure Quarkus application with ezto
Favicon
Spring Boot vs Quarkus: Pick one for Java
Favicon
Why Quarkus Native (probably) does not fit your project

Featured ones: