A maioria dos principais hits do google para "chamar clojure de java" está desatualizada e recomenda o uso clojure.lang.RT
para compilar o código-fonte. Você poderia ajudar com uma explicação clara de como chamar o Clojure a partir do Java, assumindo que você já criou um jar a partir do projeto Clojure e o incluiu no caminho de classe?
java
clojure
clojure-java-interop
Arthur Ulfeldt
fonte
fonte
Respostas:
Atualização : desde que esta resposta foi publicada, algumas das ferramentas disponíveis foram alteradas. Após a resposta original, há uma atualização incluindo informações sobre como criar o exemplo com as ferramentas atuais.
Não é tão simples como compilar em um jar e chamar os métodos internos. Parece haver alguns truques para fazer tudo funcionar. Aqui está um exemplo de um arquivo Clojure simples que pode ser compilado em um jar:
Se você executá-lo, verá algo como:
E aqui está um programa Java que chama a
-binomial
função notiny.jar
.Sua saída é:
A primeira peça de mágica está usando a
:methods
palavra - chave nagen-class
declaração. Isso parece ser necessário para permitir que você acesse a função Clojure, como métodos estáticos em Java.A segunda coisa é criar uma função de invólucro que pode ser chamada pelo Java. Observe que a segunda versão
-binomial
tem um traço na frente.E, é claro, o próprio jar Clojure deve estar no caminho da classe. Este exemplo usou o jar Clojure-1.1.0.
Atualização : Esta resposta foi testada novamente usando as seguintes ferramentas:
A parte de Clojure
Primeiro, crie um projeto e uma estrutura de diretórios associada usando Leiningen:
Agora, mude para o diretório do projeto.
No diretório do projeto, abra o
project.clj
arquivo e edite-o para que o conteúdo seja como mostrado abaixo.Agora, verifique se todas as dependências (Clojure) estão disponíveis.
Você pode ver uma mensagem sobre o download do jar Clojure neste momento.
Agora edite o arquivo Clojure para
C:\projects\com.domain.tiny\src\com\domain\tiny.clj
que ele contenha o programa Clojure mostrado na resposta original. (Este arquivo foi criado quando Leiningen criou o projeto.)Grande parte da mágica aqui está na declaração do espaço para nome. O comando
:gen-class
diz ao sistema para criar uma classe nomeadacom.domain.tiny
com um único método estático chamadobinomial
, uma função que recebe dois argumentos inteiros e retorna um duplo. Existem duas funções com nomes semelhantesbinomial
, uma função tradicional do Clojure-binomial
e um wrapper acessível a partir de Java. Observe o hífen no nome da função-binomial
. O prefixo padrão é um hífen, mas pode ser alterado para outra coisa, se desejado. A-main
função apenas faz algumas chamadas para a função binomial para garantir que estamos obtendo os resultados corretos. Para fazer isso, compile a classe e execute o programa.Você deve ver a saída mostrada na resposta original.
Agora, embrulhe-o em uma jarra e coloque-o em algum lugar conveniente. Copie o frasco Clojure também.
A parte Java
Leiningen tem uma tarefa interna,,
lein-javac
que deve poder ajudar na compilação do Java. Infelizmente, parece estar quebrado na versão 2.1.3. Ele não consegue encontrar o JDK instalado e o repositório Maven. Os caminhos para ambos têm espaços incorporados no meu sistema. Presumo que esse seja o problema. Qualquer IDE Java também pode lidar com a compilação e o empacotamento. Mas para este post, estamos indo para a velha escola e fazendo isso na linha de comando.Primeiro, crie o arquivo
Main.java
com o conteúdo mostrado na resposta original.Para compilar parte java
Agora crie um arquivo com algumas meta-informações para adicionar ao jar que queremos construir. Em
Manifest.txt
, adicione o seguinte textoAgora empacote tudo em um arquivo jar grande, incluindo nosso programa Clojure e o jar Clojure.
Para executar o programa:
A saída é essencialmente idêntica à produzida apenas por Clojure, mas o resultado foi convertido em um Java duplo.
Como mencionado, um Java IDE provavelmente cuidará dos argumentos confusos de compilação e do empacotamento.
fonte
A partir do Clojure 1.6.0, há uma nova maneira preferida de carregar e chamar funções do Clojure. Agora, esse método é preferido para chamar diretamente o RT (e substitui muitas das outras respostas aqui). O javadoc está aqui - o principal ponto de entrada é
clojure.java.api.Clojure
.Para procurar e chamar uma função Clojure:
As funções
clojure.core
são carregadas automaticamente. Outros namespaces podem ser carregados via exigem:IFn
s podem ser passados para funções de ordem superior, por exemplo, o exemplo abaixo passaplus
pararead
:A maioria dos
IFn
s no Clojure refere-se a funções. Alguns, no entanto, referem-se a valores de dados não funcionais. Para acessá-los, use emderef
vez defn
:Às vezes (se você estiver usando outra parte do tempo de execução do Clojure), pode ser necessário garantir que o tempo de execução do Clojure seja inicializado corretamente - chamar um método na classe Clojure é suficiente para esse fim. Se você não precisar chamar um método no Clojure, basta fazer com que a classe carregue é suficiente (no passado, havia uma recomendação semelhante para carregar a classe RT; isso agora é preferido):
fonte
Clojure.read("'(1 2 3")
. Seria razoável arquivar isso como uma solicitação de aprimoramento para fornecer um Clojure.quote () ou fazê-lo funcionar como uma var.'(1 2 3)
escreva algo parecidoClojure.var("clojure.core", "list").invoke(1,2,3)
. E a resposta já tem um exemplo de como usarrequire
: é apenas uma var como qualquer outra.EDITAR Esta resposta foi escrita em 2010 e funcionou na época. Veja a resposta de Alex Miller para uma solução mais moderna.
Que tipo de código está chamando de Java? Se você tem classe gerada com gen-class, basta chamá-lo. Se você deseja chamar a função a partir do script, veja o exemplo a seguir .
Se você deseja avaliar o código da string, dentro de Java, é possível usar o seguinte código:
fonte
RT.var("namespace", "my-var").deref()
.RT.load("clojure/core");
no início. Qual o comportamento estranho?Edição: Eu escrevi esta resposta há quase três anos. No Clojure 1.6, existe uma API adequada exatamente com o objetivo de chamar o Clojure a partir de Java. Por favor , responda a resposta de Alex Miller para obter informações atualizadas.
Resposta original de 2011:
A meu ver, a maneira mais simples (se você não gerar uma classe com a compilação AOT) é usar o clojure.lang.RT para acessar funções no clojure. Com ele, você pode imitar o que você faria no Clojure (não é necessário compilar as coisas de maneiras especiais):
E em Java:
É um pouco mais detalhado em Java, mas espero que fique claro que as partes do código são equivalentes.
Isso deve funcionar desde que o Clojure e os arquivos de origem (ou arquivos compilados) do seu código Clojure estejam no caminho de classe.
fonte
Concordo com a resposta da clartaq, mas achei que os iniciantes também poderiam usar:
Então, eu cobri tudo isso nesta postagem do blog .
O código Clojure é assim:
A configuração do projeto leiningen 1.7.1 é assim:
O código Java fica assim:
Ou você também pode obter todo o código deste projeto no github .
fonte
Isso funciona com o Clojure 1.5.0:
fonte
Se o caso de uso for incluir um JAR criado com o Clojure em um aplicativo Java, descobri que ter um espaço para nome separado para a interface entre os dois mundos é benéfico:
O namespace principal pode usar a instância injetada para realizar suas tarefas:
Para fins de teste, a interface pode ser stubbed:
fonte
Outra técnica que também funciona com outros idiomas na JVM é declarar uma interface para funções que você deseja chamar e, em seguida, usar a função 'proxy' para criar uma instância que as implemente.
fonte
Você também pode usar a compilação AOT para criar arquivos de classe que representam seu código de clojure. Leia a documentação sobre compilação, classe gen e amigos nos documentos da API Clojure para obter detalhes sobre como fazer isso, mas, em essência, você criará uma classe que chama funções de clojure para cada chamada de método.
Outra alternativa é usar a nova funcionalidade defprotocol e deftype, que também exigirá compilação AOT, mas proporcionará melhor desempenho. Ainda não sei os detalhes de como fazer isso, mas uma pergunta na lista de discussão provavelmente faria o truque.
fonte