Skip to content

jaju/spring-boost-classic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

What is spring-boost-classic?

Ever wished to introduce Clojure into your SpringBoot app (organization)? And, want to start very small - nrepl and a ring-like sub-module - and then use REPL-power for live-coding and adding new functionality?

Then, spring-boost-classic simplifies it for you!

Note: This is a version for Spring MVC. For something that goes with Spring WebFlux, look at spring-boost.

Caveat

For the web-endpoints, the library assumes Spring WebMVC. It will not work with reactive spring-boot. But nREPL will work just fine irrespective.

The Pitch: Sample Application Code

Here’s how you can write Clojure code, using Compojure, with Springboot. The interface is ring like - Mostly ring, but with a few quirks that should not matter for most common use-cases.

Very specifically, it makes some limiting choices for the Clojure web-app - the `body` in the `request` map is not an InputStream but one of

  • Map (for media-type APPLICATION_JSON)
  • org.springframework.util.MultiValueMap (for media-type APPLICATION_FORM_URLENCODED)
  • String (for all other cases)

What will my Clojure look like?

Here is an example code that you can use in your SpringBoot application! It works along-side your existing Java code, without interfering, and you can access Clojure from your Java.

The following code shows

  1. Setting up end-points - routes and all - with Compojure
  2. Some examples of querying the ApplicationContext and via it, beans.
(ns org.msync.spring-clj.core
  (:require [org.msync.spring-boost :as boost]
            [compojure.core :refer :all]
            [compojure.route :refer [not-found]]
            [clojure.string])
  (:import [java.util.logging Logger]
           [org.springframework.context ApplicationContext]))

(defonce logger (Logger/getLogger (str *ns*)))

(defroutes app
  "Root hello-world GET endpoint, and another echo end-point that handles both GET and POST.
  The :body entry in the request-map comes in either as a map for JSON requests, or as a String
  for other types."
  (GET "/" [:as {query-string :query-string}]
       (str "<h1>Hello World.</h1>"
            (if-not (clojure.string/blank? query-string) (str "We received a query-string " query-string))))
  (GET "/echo/:greeter" [greeter]
       {:status 200
        :headers {:content-type "application/json"}
        :body {:greeting (str "Hello, " greeter)}})
  (POST "/echo/:greeter" [greeter :as request]
        {:status 200
         :headers {:content-type "application/json"}
         :body {:greetings (str "Hello, " greeter)
                :echo (:body request)}})
  (not-found "<h1>Page not found</h1>"))

(defn main
  "Set this as your entry-point for the Clojure code in your spring-boot app.
  Gets the ApplicationContext object as an argument - which you are free to ignore or use."
  [^ApplicationContext application-context]

  (.info logger (str "[spring-clj] Initializing clojure app..."))
  (boost/set-handler! app))

Note that the paths are relative to the base path set in application.yml. Hence, /echo/:greetings will be accessible at /clojure/echo/:greetings.

Configure Gradle

Modify build.gradle.kts (or, build.gradle)

This is the Gradle-Kotlin version.

repositories {
    maven {
        name = "Clojars"
        url = uri("https://clojars.org/repo")
    }
}

dependencies {
    developmentOnly("org.msync:spring-boost-classic:0.3.0-alpha3")
    developmentOnly("compojure:compojure:1.7.1")
}

Ensure your clojure code is copied to the classpath

Assuming you will write your clojure code in src/main/clojure

sourceSets {
    main {
        resources {
            srcDir("src/main/clojure")
        }
    }
}

Modify application.yml (or application.properties)

By default, port 7888 is used. But add clojure-component.nrepl-port to your application.yml (or equivalent) file as follows

# ...
clojure-component:
  nrepl-port: 8190
  nrepl-start: true
  root-path: /clojure
  init-symbol: org.msync.spring-clj.core/main
# ...

Run “bootRun”

And, run!

./gradlew bootRun

And you should see something like the following

...
2024-10-02T14:00:27.125+05:30  INFO 76260 --- [           main] org.msync.spring_boost.Boost             : nREPL server started on port = 8190
2024-10-02T14:00:27.126+05:30  INFO 76260 --- [           main] o.m.spring-boost.application-context     : Initializing the ClojureComponent
2024-10-02T14:00:27.126+05:30  INFO 76260 --- [           main] org.msync.spring_boost.Boost             : Initializing clojure code: org.msync.spring-clj.core/main
2024-10-02T14:00:27.639+05:30  INFO 76260 --- [           main] org.msync.spring-clj.core                : [spring-clj] Initializing configured clojure web-app...
...

Connect to the NREPL

Starting nREPL by default can be controlled via configuration. But you can easily start/stop nREPL using two exposed end-points, that take POST requests.

For your convenience, there’s a namespace you can switch to and get hold of the ApplicationContext object via the state atom’s :ctx key.

user> @org.msync.spring-boost.application-context/state
;; =>
{:ctx #object[org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
              0x6986bbaf
              "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6986bbaf, started on Wed Oct 02 14:00:26 IST 2024"]}
flowchart TB
  nrepl-client-->nrepl-server
  subgraph server [server]
  nrepl-server
  end
Loading

Control the NREPL server

Start it

curl -XPOST http://host:port/clojure/nrepl-start

Stop it

curl -XPOST http://host:port/clojure/nrepl-stop

License

Copyright © 2022-2024 - Ravindra R. Jaju

This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0.

This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors