Here are the ways to subclass a your custom Java class from Clojure. I have been fiddling to get this to work with lein for some time now. In your lein project say you have Java source at src/java. You want to extend a class from clojure, call super class method etc. There are two ways to extend, proxy and gen-class.

It's important to note that you need to have a package structure for the Java classes. Naked classes don't work because it's getting qualified to java.lang namespace when you try to run giving a ClassNotFoundException.

// src/java/com/example/BaseClass.java
package com.example;
 
public class BaseClass {
    public String greet() {
        return "Hello from BaseClass";
    }
}

You need to specify the Java source location using :java-source-paths in project.clj. If you are using :gen-class to extend, then you need to AOT compile your Clojure file. When running project with :java-source-paths added under Windows, I am getting the following error even if JAVA_HOME is set to JDK location and bin is in path.

Java compiler not found; Be sure to use java from a JDK
rather than a JRE by modifying PATH or setting JAVA_CMD.

Adding JAVA_CMD env variable to point to java_home-path\bin\java works.

; project.clj
(defproject subclass "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :java-source-paths ["src/java"]
  :main subclass.core
  :target-path "target/%s"
  :aot [subclass.core]
  :profiles {:uberjar {:aot :all}})

Extending using :gen-class

Extending using :gen-class uses :extends keyword. If you want to call a super class method, use :expose-methods to specify an alias under which that method will be available locally. Here the greet from BaseClass is locally referred as pgreet

; src/subclass/core.clj
(ns subclass.core
  (:gen-class
   :extends com.example.BaseClass
   :exposes-methods {greet pgreet}))
 
;; greet method override. gen-class prefixes generated classes with '-' by default.
(defn -greet [this]
  ;this arg is the object of this class, i.e., subclass.core.
  (.pgreet this) ;calls super class' greet()
  (println "hi from clj"))
 
(defn -main [& args]
  (.greet (subclass.core.)))

Running the above gives:

$ lein run
subclass.core=> (-main)
Hello from BaseClass
hi from clj
nil

Extending using proxy

; src/subclass/core.clj
(ns subclass.core
  (:import com.example.BaseClass))
 
(defn my-greet []
  (proxy [BaseClass] [] ; the class to extend
    ; override greet()
    (greet []
      (proxy-super greet) ; call super class method
      (println "hi from my-greet"))))
 
(defn -main [& args]
  (.greet (my-greet))) ; calling my-greet returns a proxy object. Invoke greet method on it.

Running the proxy version gives:

$ lein repl
subclass.core=> (-main)
Hello from BaseClass
hi from my-greet
nil

Using proxy or gen-class for extending depends on your use case.