Type hinting a value in a Java annotation when generating an interface?

I am working on a little prototype project that attempts to drive a Java-based system (a workflow orchestration engine) from Clojure and running into a stumbling block. The system relies heavily on the usage of annotated Java interfaces to define the workflows to be executed; I am in the process of porting some Java-based example code to try and get a handle on how things might work:

(gen-interface
 :name com.example.flow.workflow.greeting.GreetingWorkflow
 :methods [[^{WorkflowMethod {;; FIXME needs a primitive int argument
                              :executionStartToCloseTimeoutSeconds 10
                              :taskList "HelloActivity"}}
            getGreeting [String] String]])

For reference, the example Java code looks like:

public interface GreetingWorkflow {
  @WorkflowMethod(
    executionStartToCloseTimeoutSeconds = 10, 
    taskList = TASK_LIST
  )
  String getGreeting(String name);
}

AOT-compilation is successful, but then during execution I see the following error:

Incorrectly typed data found for annotation element
public abstract int com.foobar.WorkflowMethod.executionStartToCloseTimeoutSeconds()
(Found data of type java.lang.Long[10])

The annotation parameter requires an int and doesn’t like that it’s given a Long instead. The docs for this exception state that it is:

Thrown to indicate that a program has attempted to access an element of an annotation whose type has changed after the annotation was compiled (or serialized). This exception can be thrown by the API used to read annotations reflectively.

A couple of attempts I made to coerce the value in the annotation map looked like:

:executionStartToCloseTimeoutSeconds (unchecked-int 10)

which resulted in the follow AOT compilation error:

Unexpected error (ClassCastException) macroexpanding gen-interface at (com/example/flow/workflow/greeting.clj:71:1).
class clojure.lang.Var cannot be cast to class java.lang.Class
(clojure.lang.Var is in unnamed module of loader 'app'; java.lang.Class is in module java.base of loader 'bootstrap')

Applying a type hint:

:executionStartToCloseTimeoutSeconds #^int 10

resulted in the following AOT-compilation error:

Syntax error (IllegalArgumentException) compiling at (com/example/flow/workflow/greeting.clj:77:0).
Metadata can only be applied to IMetas

If I am missing something obvious, or anyone has any suggestions for further exploration, I’d appreciate your input. As an aside, my motivation in this is that I’d eventually like to declare these workflows as edn data files that refer to Clojure functions that do the work, and generate the necessary Java interfaces and classes using (gen-interface) and (gen-class).

Is there a reproducible repo one can experiment with? Even a mockup for the workflow lib would be useful.

For primitive hints on a value like that, normally one of the cast is the way to go.

You tried unchecked-int, and it didn’t work though, it might be that the gen-interface macro doesn’t support it.

Is there a reproducible repo one can experiment with? Even a mockup for the workflow lib would be useful.

I isolated these snippets from a somewhat chunky code base, so I don’t have a smaller example repo to hand, but I think that may be the next step I take to make some headway. Thanks for the suggestion.

I suspect you’re right about gen-interface not supporting what I’m trying to do here, leaving me with an interesting puzzle as to how to proceed. I suppose in a pinch I could generate Java, but that sounds… sub-optimal. Better than sub-working, though. :smiley: Thanks for the feedback!

I have generated Java in the past lol, using cl-format no less :stuck_out_tongue:

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.