Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

jaju/spring-boost

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
52 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

What is spring-boost?

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 simplifies it for you!

A complete example of how it works can be found at jaju/spring-boost-example.

Caveat

For the web-endpoints, the library assumes Spring Webflux. It will not work with standard, thread-ed 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.

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. Setting up a websocket handler - builds on top of Springboot’s websocket infrastructure.
(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 web-socket-handler [session]
  (pr-str session)
  ;; Use the session as you wish - to create session-specific handlers
  (fn [^String message]
    (str "Hello, " (.toUpperCase message))))

(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)
  (boost/set-websocket-handler! web-socket-handler))

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:0.2.0-SNAPSHOT")
    developmentOnly("compojure:compojure:1.6.3")
}

Ensure your clojure code is copied to the classpath

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

tasks.register<Copy>("copyClojure") {
    into("build/classes/java/main") {
        destinationDir = file(".")
        from("src/main/clojure")
    }
}

tasks.getByName("bootRun").dependsOn("copyClojure")
tasks.getByName("bootJar").dependsOn("copyClojure")

Hint Springboot using @ComponentScan

package com.company.my_application;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("org.msync.spring_boost")
// And other standard stuff
public class YourApplication {
    // Your code here
}

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
  ws-path: /ws
  init-symbol: org.msync.spring-clj.core/main
# ...

Run “bootRun”

And, run!

./gradlew bootRun

And you should see something like the following

...
[2021-09-10 12:08:14,182] INFO  [main] org.msync.spring_boost.application_context$_component_init::invokeStatic Initializing the ClojureComponent
[2021-09-10 12:08:14,984] INFO  [main] org.msync.spring_boost.Boost::startNrepl nREPL server started on port = 8190
[2021-09-10 12:08:14,986] INFO  [main] org.msync.spring_boost.Boost::setupAppInit Initializing clojure code: org.msync.spring-clj.core/main
[2021-09-10 12:08:21,097] INFO  [main] jdk.internal.reflect.NativeMethodAccessorImpl::invoke0 [spring-clj] Initializing clojure app...n
...

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.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
              0x333bd779
              "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext@333bd779, started on Wed Sep 01 21:47:28 IST 2021"]}

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 © 2020-22 - 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

Introduce Clojure and live-coding power to your Spring Boot application!

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.