On Thu Aug 2 16:41 2012, David Greenberg wrote: > Hi Clojurians, > I'm finding myself far down the rabbit hole of gen-class. I am trying > to generate a class that has a bunch of static methods, and each of > those methods has many overloads of arities and types. Unfortunately, > there is no interface--this class gets called through reflection in a > legacy system. > > The class's parameter types include primitives, primitive arrays, and Objects. > > I am doing something like: > > (gen-class > :name "my.odd.Class" > :main false > :methods [^{:static true} [-myfunc ["[Lint;" String] void] > ^{:static true} [-myfunc ["[Ldouble;" int] Object]]) > > I found a post explaining that I could define method implementations > with overloads by doing -methodName-arg1type-arg2type-arg3type, but > when I try that I get an exception that the FileName is too long from > the clojure compiler. > > I can easily generate a map from signatures to implementations, but I > need to generate the class with all the overloads. > > Is there any way to do this? Should I resign myself to writing out a > .java file, and compiling that?
Hello, David, Well, gen-class certainly supports creating static methods with type hints and overloaded arities. An example using gen-class as part of ns: (ns gen-class-test.StaticTest (:gen-class :methods [^:static [foo [ints int] String] ^:static [foo [longs long] String] ^:static [foo [chars char] String] ^:static [foo [shorts short] String] ^:static [foo [booleans boolean] String] ^:static [foo [floats float] String] ^:static [foo [doubles double] String] ^:static [foo ["[Ljava.lang.Object;" Object] String] ^:static [foo ["[Ljava.lang.String;" String] String] ^:static [foo ["[Ljava.lang.String;" int] String] ^:static [foo [boolean] String] ^:static [foo [char] String] ^:static [foo [short] String] ^:static [foo [int] String] ^:static [foo [long] String] ^:static [foo [float] String] ^:static [foo [double] String] ^:static [foo [Object] String] ^:static [foo [String] String]] :main false)) This will generate a class with the following signature: public class gen_class_test.StaticTest extends java.lang.Object{ public static {}; public gen_class_test.StaticTest(); public java.lang.Object clone(); public int hashCode(); public java.lang.String toString(); public boolean equals(java.lang.Object); public static java.lang.String foo(int[], int); public static java.lang.String foo(long[], long); public static java.lang.String foo(char[], char); public static java.lang.String foo(short[], short); public static java.lang.String foo(boolean[], boolean); public static java.lang.String foo(float[], float); public static java.lang.String foo(double[], double); public static java.lang.String foo(java.lang.Object[], java.lang.Object); public static java.lang.String foo(java.lang.String[], java.lang.String); public static java.lang.String foo(java.lang.String[], int); public static java.lang.String foo(boolean); public static java.lang.String foo(char); public static java.lang.String foo(short); public static java.lang.String foo(int); public static java.lang.String foo(long); public static java.lang.String foo(float); public static java.lang.String foo(double); public static java.lang.String foo(java.lang.Object); public static java.lang.String foo(java.lang.String); } Now, when it comes to what this class is doing, it is calling the Clojure function -foo with the arguments from the static method invocation. In particular: 1. All primitive arguments will be boxed. 2. The number of arguments for -foo must match the number of arguments for the static method invocation. For multiple arities, you can have a variadic function or a function with multiple arities. 3. Unfortunately, there is no way to call a different function for each arity/type. However, you can make -foo a multimethod. The following works as an implementation for the above: (defmulti -foo (fn [& args] (apply vector (map class args)))) ; one-arg invocations (defmethod -foo [Boolean] [_] "boolean") (defmethod -foo [Character] [_] "char") (defmethod -foo [Short] [_] "short") (defmethod -foo [Integer] [_] "int") (defmethod -foo [Long] [_] "long") (defmethod -foo [Float] [_] "float") (defmethod -foo [Double] [_] "double") (defmethod -foo [Object] [_] "Object") (defmethod -foo [String] [_] "String") ; two-arg invocations (defmethod -foo [(class (boolean-array 0)) Boolean] [_ _] "booleans") (defmethod -foo [(class (char-array 0)) Character] [_ _] "chars") (defmethod -foo [(class (short-array 0)) Short] [_ _] "shorts") (defmethod -foo [(class (int-array 0)) Integer] [_ _] "ints") (defmethod -foo [(class (long-array 0)) Long] [_ _] "longs") (defmethod -foo [(class (float-array 0)) Float] [_ _] "floats") (defmethod -foo [(class (double-array 0)) Double] [_ _] "doubles") (defmethod -foo [(class (into-array [""])) String] [_ _] "Strings") (defmethod -foo [(class (to-array [])) Object] [_ _] "Objects") (defmethod -foo [(class (into-array [""])) Integer] [_ _] "Strings + int") Perhaps there is a better way to do it, but this is the best I could come up with. I hope it helps. Sincerely, Daniel
signature.asc
Description: Digital signature