Further to IRC conversations:

I'm attempting to generate a JAX-WS service using Clojure. The main stumbling block was annotations; that's been removed, so I gave it a shot using deftype.

My first strike works code-wise, so I sent it to the list earlier today.

When it comes to actually integrating the output into the Java world, though, things get hairy. JAX-WS has a bunch of demands on classes in order for its tools (such as wsgen) to accept them:

<http://java.sun.com/webservices/docs/2.0/tutorial/doc/JAXWS3.html>

---
JAX-WS endpoints must follow these requirements:

* The implementing class must be annotated with either the javax.jws.WebService or javax.jws.WebServiceProvider annotation. * The implementing class may explicitly reference an SEI through the endpointInterface element of the @WebService annotation, but is not required to do so. If no endpointInterface is not specified in @WebService, an SEI is implicitly defined for the implementing class. * The business methods of the implementing class must be public, and must not be declared static or final. * Business methods that are exposed to web service clients must be annotated with javax.jws.WebMethod. * Business methods that are exposed to web service clients must have JAX-B-compatible parameters and return types. See Default Data Type Bindings. * The implementing class must not be declared final and must not be abstract.
* The implementing class must have a default public constructor.
* The implementing class must not define the finalize method.
* The implementing class may use the javax.annotation.PostConstruct or javax.annotation.PreDestroy annotations on its methods for lifecycle event callbacks.

The @PostConstruct method is called by the container before the implementing class begins responding to web service clients.

The @PreDestroy method is called by the container before the endpoint is removed from operation.
---

The classes generated by deftype are final; the javap output is

---
public final class com.example.FooBarService extends java.lang.Object implements com.example.FooBarInterface{
  public static {};
  public com.example.FooBarService();
public java.lang.String createCustomer(java.lang.String, java.lang.String, java.lang.String);
}
---

That doesn't make JAX-WS's tools happy:

---
com.sun.tools.ws.processor.modeler.ModelerException: modeler error: Classes annotated with @javax.jws.WebService must not be final.
---

Digging into the compiler, it looks like individual fields can be made non-final by flagging them as mutable. The class emitter in `compile`, however, always passes ACC_PUBLIC + ACC_SUPER + ACC_FINAL to the ClassVisitor.visit method... so classes produced in this way are always final.

From a purity perspective, this is nice: Clojure prohibits implementation inheritance because it's a Bad Idea®. However, this hampers interop (I don't *want* to do implementation inheritance, but JAX-WS demands non-final classes!), and the mutable/volatile options for fields seem to suggest that getting hands dirty is acceptable at the level of deftype… and thus having some optional way to produce non- final classes might be a reasonable feature to add.

Chouser suggested gen-class, which generates non-final classes; that's my next fallback, once annotation support for gen-class gets integrated. However, if this isn't an intentional and inflexible limitation on deftype, I thought I'd investigate removing it. So I spent a little time with the compiler, producing three patches:

* Pass options through to deftype emission (they never made it past deftype in the current code). * Propagate class accessibility flags throughout build/compile (parameterizing the ACC_FINAL/ACC_PUBLIC/ACC_SUPER flags).
   * Allow (and check for) :non-final as a boolean option for deftype.

The test suite runs without problems, and I've verified that adding `:non-final true` generates a non-final class (and the reverse). With this change I'm able to run wsgen against a jar built by Leiningen, containing no Java code, and get WSDL as output. Pretty neat, no?

I've pushed these to my GitHub fork (rather than sending patches to the list):

<http://github.com/rnewman/clojure/tree/deftype-non-final>

Opinions, thoughts, critiques, "you're insane"s, etc. welcome.

Thanks,

-Richard


--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to