How to generate generate static methods with clojure's Gen-class?
Asked Answered
D

1

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?

Damoiselle answered 17/10, 2014 at 12:31 Comment(10)
Where exactly have you tried to put the metadata? BTW answer to your last question is easy: clojure.org/metadataPeppy
First in the :methods-part of :gen-class and Second in the definition of the function (defn).Damoiselle
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] ]Peppy
@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"?Damoiselle
Try annotating as I specify in my comment above: not the symbol, but the vector.Peppy
@MarkoTopolnik OK, that works. For me its a bit confusing, because clojure.org/metadata says, that metadata work for symbols. Moreover kotka.de/blog/2010/02/… 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.Damoiselle
Actually, the opening sentence says "Symbols and collections support metadata".Peppy
There's a complete working example [here][1]. [1]: https://mcmap.net/q/142141/-calling-clojure-from-java/…Chairmanship
@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.Damoiselle
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.Peppy
P
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.

Peppy answered 17/10, 2014 at 13:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.