Is it possible to extend a parameterized type using gen-class?

901 views
Skip to first unread message

sim

unread,
Mar 2, 2012, 12:53:54 AM3/2/12
to clo...@googlegroups.com
Hi all,


that says it isn't possible, but that was back in 2009, is it still not possible?  Any work arounds apart from doing some of it in Java?

I would like to be able to write some xWiki Macros in clojure, I have some in java already but moving it all to clojure would be better.

The java example is as follows:

public class ExampleMacro extends AbstractMacro<ExampleMacroParameters> 


Any help/pointers would be greatly appreciated.

-- sim

Daniel Solano Gomez

unread,
Mar 2, 2012, 8:04:21 AM3/2/12
to clo...@googlegroups.com

Yes, it is possible. At the byte-code level there is (at least at
run-time) no difference between a generic and a non-generic class. All
methods take/return the generic type just use Object.

For example, take the following implementation of AbstractCollection<E>:

--- begin ExampleCollection.clj ---

(ns ExampleCollection
(:gen-class :extends java.util.AbstractCollection))

(def some-numbers [2 3 5 7 11 13])

(defn -size [_] (count some-numbers))

(defn -iterator [_] (.iterator some-numbers))


--- end ExampleCollection.clj ---

You can use it as in the following:

--- begin Example.java ---
import java.util.Collection;

public class Example {
public static void main(String[] args) {
Collection<Long> foo = new ExampleCollection();
for (Long bar : foo) {
System.out.println(bar);
}
}
}
--- end Example.java ---

The Java file will compile and run, though it will complain about doing
an unsafe conversion. This means that if the type that occurs at
runtime is wrong, you'll get a ClassCastException.

In any case, you can also use proxies to accomplish the same task if you
don't want to gen-class.

I hope this helps.

Sincerely,

Daniel

signature.asc

sim

unread,
Mar 4, 2012, 6:50:52 PM3/4/12
to clo...@googlegroups.com
Hi Daniel,

Thanks for that but what if the type your extending is parameterised?  For example using your example:

(ns ExampleCollection
  (:gen-class :extends java.util.AbstractCollection<SomeItemType>)) 

How do I do the <SomeItemType> bit?  Forgive me if this is obvious my java foo is weak :)

-- sim

Jim Blomo

unread,
Mar 29, 2012, 1:27:01 AM3/29/12
to clo...@googlegroups.com
sim, I don't think it is possible right now. I am not an expert, but...

On Fri, Mar 2, 2012 at 5:04 AM, Daniel Solano Gomez <clo...@sattvik.com> wrote:
> Yes, it is possible.  At the byte-code level there is (at least at
> run-time) no difference between a generic and a non-generic class.  All
> methods take/return the generic type just use Object.

This is mostly true, but for the use case needed, deriving from a
parameterized superclass, the JVM does track the parameterized
generic. Class.getGenericSuperclass returns a ParameterizedType for
Classes extending a parameterized generic.

I would like this functionality as well for writing a Dropwizard
service in Clojure. The Dropwizard framework relies on reflecting on
the parameter of a parent, and this doesn't seem possible in Clojure
right now. Writing a Java shim to do the inheritance also won't work
with the current version of Dropwizard (though perhaps that is a
design bug in the framework).

I've taken a look at how annotations are done in generate-class, and
would like input on the best way to add this functionality. My rough
plan is:

- Create an implementation of ParameterizedType for Clojure
- Add a metadata argument to the symbol passed to gen-class :extends
or :implements
- when that metadata is present, override getGenericSuperclass in the
generated class to return the ParameterizedType

Is this reasonable? Are there other areas that need to expose generic
parameters?

Jim

http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getGenericSuperclass()
https://github.com/codahale/dropwizard/blob/master/dropwizard-core/src/main/java/com/yammer/dropwizard/AbstractService.java#L75

Jim Blomo

unread,
Apr 1, 2012, 1:02:36 AM4/1/12
to clo...@googlegroups.com
I have this feature implemented in my 1.3.x branch in github. I'll be
sending in the contributor agreement Monday and hopefully getting some
developer feedback thereafter.

The solution was to add a class signature when parameterized generics
are used. Signatures are stored along with the bytecode in .class
files and used by Java's reflection capabilities, though not strictly
used by the JVM. Parameters are specified by adding metadata
information to the :extends and :implements arguments to gen-class.

sim's use case should be solved with

(ns ExampleCollection
(:gen-class :extends ^{:parameters [SomeItemType]}
java.util.AbstractCollect))

Note that neither the types nor constraints are checked when writing
the signature.

https://github.com/jblomo/clojure/commit/15ff4f96840788253c5af66a2265387d880bad80

Jim

Reply all
Reply to author
Forward
0 new messages