5

In My Clojure-code I'd like to generate a class-file that contains a static method (named staticMethod), which is later on called by in a static context from a Java-program.

I tried (Clojure):

(ns com.stackoverflow.clojure.testGenClass
  (:gen-class
     :name com.stackoverflow.clojure.TestGenClass
     :prefix "java-"
     :methods [
               [#^{:static true} staticMethod [String String] String]
              ]))

(def ^:private pre "START: ")

(defn #^{:static true} java-staticMethod [this text post]
  (str pre text post))

and (Java):

package com.stackoverflow.clojure;

public class TestGenClassTest {

    private TestGenClassTest() {
    }

    public static void main(String[] args) {
        TestGenClass.staticMethod("Static call from Java!", " :END");
    }
}

On https://kotka.de/blog/2010/02/gen-class_how_it_works_and_how_to_use_it.html I read:

By adding metadata – via #^{:static true} – to a method declaration you can also define static methods.

No matter where I put the #^{:static true} the Java compiler always says:

Cannot make a static reference to the non-static method staticMethod(String, String) from the type TestGenClass

How can I define static methods in Clojure? Would #^{:static true} and ^:static mean the same? Where is this documented?

Edward
  • 4,453
  • 8
  • 44
  • 82
  • 1
    Where exactly have you tried to put the metadata? BTW answer to your last question is easy: http://clojure.org/metadata – Marko Topolnik Oct 17 '14 at 12:43
  • First in the `:methods`-part of `:gen-class` and Second in the definition of the function (`defn`). – Edward Oct 17 '14 at 13:05
  • 1
    OK---if the only way you have tried it is the way your current question states, then try the following: `:methods [^:static [staticMethod [String String] String] ]` – Marko Topolnik Oct 17 '14 at 13:18
  • @MarkoTopolnik All combinations of the Clojure-code above: once without the `#^{:static true}`, once only in the `:methods`, once only in the `defn` and (as shown above) in both. It seems that I don't understand how Metadata work. I e.g. tried `(def ^:static test "Test")` and then `(meta test)` Shouldn't this give me "static" instead of "nil"? – Edward Oct 17 '14 at 13:20
  • 3
    Try annotating as I specify in my comment above: not the symbol, but the vector. – Marko Topolnik Oct 17 '14 at 13:22
  • @MarkoTopolnik OK, that works. For me its a bit confusing, because http://clojure.org/metadata says, that metadata work for symbols. Moreover https://kotka.de/blog/2010/02/gen-class_how_it_works_and_how_to_use_it.html says I should add it to the function definition (which is obviously not true). Please write an answer from your comments, so that I can accept it. – Edward Oct 17 '14 at 13:31
  • 1
    Actually, the opening sentence says "Symbols and collections support metadata". – Marko Topolnik Oct 17 '14 at 13:36
  • There's a complete working example [here][1]. [1]: http://stackoverflow.com/questions/2181774/calling-clojure-from-java/2187427#2187427 – clartaq Oct 17 '14 at 14:04
  • @MarkoTopolnik So the **and** means: "in combination with" and not "as well as" - is that right? So the metadata need to be declared in front of a collection and not in front of a symbol. `(def m ^:static [1 2 3 4])` works, while `(def ^:static m [1 2 3 4])` does not work. – Edward Oct 17 '14 at 14:06
  • 1
    No, it means that both symbols and collections can hold metadata. You just need to be careful about what is annotated with metadata. When you say `(meta m)`, you enquire the metadata of the object referenced by `m`, not the symbol `m`. This follows from the fact that just `m` evaluates to the collection, not the symbol. – Marko Topolnik Oct 17 '14 at 14:12

1 Answers1

10

When kotka said to annotate the method declaration, he "obviosly" meant the entire vector holding the declaration:

:methods [^:static [staticMethod [String String] String] ]

This kind of laconic wording is unfortunately typical of Clojure documentation.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436