Fork me on GitHub
#beginners
<
2019-02-18
>
chocksmith10:02:32

Good morning guys. I really would appreciate some help configuring gradle-clojure plugin on a Grails project. Is there anyone out there with some experience on that?

arnoha19:02:10

Hi, anyone have experience integrating Clojure into an existing java code base workflow? In order to get buy in for bringing in Clojure into our code base I need to demonstrate that it can be part of our build process and that if/when other people start to contribute Clojure code the build process would at least catch any compile-time errors. Realize that this is going against the dynamic nature of Clojure and since at the moment I’m the only one using the language there’s not much of a benefit but from a business risk mitigation perspective it makes sense. I’m looking at the ahead-of-time compiler and/or just calling load-file or load-script on all *.clj files in the build tree. Anyone have experience doing this? Any suggestions what the best approach would be? Thanks in advance.

alexmiller20:02:58

I’d suggest using aot, and building a jar artifact that you include like any other artifact

alexmiller20:02:21

the big question is about how people call into this code. You can use the Clojure Java API (http://clojure.github.io/clojure/javadoc/clojure/java/api/package-frame.html) but it's pretty low-level. The ideal is to actually have well-defined Java interfaces (in Java) with docstring etc and then just have Clojure provide the implementation. That way consumers largely don't know or care that it's Clojure.

arnoha20:02:30

thank you @U064X3EF3!

mathpunk16:02:22

I would be interested in how you manage this, @UA1L0L4M7. My situation may be similar --- we have a Java app at work, and I'm the new quality engineer. I am much more familiar with Clojure than Java, and I am interested in developing, like, a "testing" build of our app that does some generative testing on the objects my co-workers make. But I haven't yet put in the work to figure out how gradle and the Java build chain operate.

Ian20:02:07

Hello everybody, I am a clojure newbie so every advice on how I am writing this at any level would be more than useful. I am building a small server with http-kit that writes on a mongo db The main file is the server, which calls default-push in order to push data into the mongodb:

(ns skincare-server.core
  (:gen-class)
  (:require [org.httpkit.server :as http-server]
            [clj-time.local :as l]
            [compojure.core :refer :all]
            [compojure.route :as route]
            [compojure.handler :as handler]
            [skincare_server.database :refer [default-push]]
            [ring.middleware.json :refer [wrap-json-body wrap-json-response]]
            [ring.util.response :only [response]]
            ))

(def port 8000)


(defn handle-push-data
  [request]
  (let
    [decorated-request (assoc request :time (str (l/local-now)))
     document (default-push decorated-request)]
    {:status 200 :body document}))

(defroutes app-routes
           (GET "/" [] "Maronn, I am running! Try cache me!")
           (POST "/post-data" req (handle-push-data req))
           (route/not-found "404 page not found"))

(def app
  (-> (handler/site app-routes)
      (wrap-json-body)
      (wrap-json-response)
      ))

(defn -main [& args]
  (http-server/run-server  app {:port port})
  (println (format "Server started on port %s" port)))
  
And in this file I define the function to write on mongo.
(ns skincare_server.database
  (:require [monger.core :as mg]
            [monger.collection :as mc]
            [dotenv :refer [env]])
  (:import [org.bson.types ObjectId]))

;; Connects to default port
(defn mongo-pusher-factory
  "A factory that returns a function that pushes onto mongo"
  [& [dbname collection-name]]
  (let [dbname (or dbname (env "DB_NAME"))
        collection-name (or collection-name (env "COLLECTION_NAME"))
        conn (mg/connect)
        db (mg/get-db conn dbname)]
    (fn [post-data]
      (let [post (assoc post-data :_id (ObjectId.))
            document (mc/insert-and-return db collection-name post)]
        document))))


(def default-push (mongo-pusher-factory))
The code compiles and all good until, when i get a POST request it raises Mon Feb 18 21:22:50 CET 2019 [worker-1] ERROR - POST /post-data org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class org.httpkit.server.AsyncChannel. My interpreting Java errors is not the best so i can’t figure out where the mistake is. Thank you for your help!

dpsutton20:02:28

your default factory never seems to get a dbname or collection name?

Ian20:02:18

It could be badly written but I thought that: (let [dbname (or dbname (env "DB_NAME")]) defaults to the env variable such that e.g. DB_NAME=test in .env

dpsutton20:02:56

oh i'm sorry. i didn't notice those. i just saw unused arguments

dpsutton20:02:59

can you post the full stack trace in a snippet here?

dpsutton20:02:11

the stacktraces look like a lot of noise but usually are quite helpful

Ian20:02:21

Thank you for your help, I tried to read through this error but it isn’t that clear what is happening.

dpsutton20:02:33

ok. so it looks like you are correctly getting things into monger. so the problem is you are getting the wrong thing there

dpsutton20:02:24

you're putting the entire request object into it. maybe rather than inserting things, return the post-data as json so you can see what you are actually doing

dpsutton20:02:11

your handler assoces a time onto the request and then passes that into your monger stuff, which stamps an id (on the request, not the post-data) and tries to put that big thing into the db. you probably need to grab the post params out of it

Ian20:02:36

I’ll try and let you know, thank you!

skykanin23:02:22

So I've setup this clojure project in lein with the default template, but I'm getting some exceptions when I use Java 11. It works fine with Java 8.

/usr/lib/jvm/java-11-openjdk/bin/java  ...
Exception in thread "main" Syntax error compiling at (org/httpkit/server.clj:1:1).
	at backend.core$eval138$loading__6706__auto____139.invoke(core.clj:16)
	at backend.core$eval138.invokeStatic(core.clj:16)
	at backend.core$eval138.invoke(core.clj:16)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
	at clojure.lang.DynamicClassLoader.findClass(DynamicClassLoader.java:69)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
	at clojure.lang.DynamicClassLoader.loadClass(DynamicClassLoader.java:77)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:398)
	at clojure.lang.RT.classForName(RT.java:2207)
	at clojure.lang.RT.classForNameNonLoading(RT.java:2220)
	at org.httpkit.server$eval144$loading__6706__auto____145.invoke(server.clj:1)
	at org.httpkit.server$eval144.invokeStatic(server.clj:1)
	at org.httpkit.server$eval144.invoke(server.clj:1)

dpsutton23:02:13

are you on ubuntu

skykanin23:02:14

This is the only code I have atm except the default test lein generates and a resource folder with a json file in it

skykanin23:02:22

I'm on Manjaro

skykanin23:02:52

and this is my project.clj

skykanin23:02:29

Does Clojure perhaps not support Java 11 yet?

seancorfield23:02:41

@UFSTV75C6 Clojure supports it, yes. What version of Leiningen are you using? lein version

skykanin23:02:50

Leiningen 2.9.0 on Java 11.0.2 OpenJDK 64-Bit Server VM

skykanin23:02:35

I fixed it by updating http-kit to version 2.3.0 instead of 2.2.0

alexmiller23:02:00

As of Java 9, xml.bind was classified as a Java EE package and its module was not loaded automatically in the jdk. It was removed entirely from the JDK distribution in Java 11, so you need to bring it in explicitly as either a module or a lib.

caleb.macdonaldblack23:02:10

Is it a good idea to avoid loop/recur and use simple function call recursion when I only need it to recur a hand full of times?

caleb.macdonaldblack23:02:13

For some context I'm making a http request that could fail and I want to wait and retry up to 5 times

seancorfield23:02:10

@caleb.macdonaldblack I would say, in that case, whatever you find most readable.

seancorfield23:02:38

I have functions at work that do exactly that and most do it as a simple recursive call, passing the number of retries made so far or a flag indicating whether a retry should be done (for places where we perform a single retry). But then the retry count/flag needs to be exposed in the functions arguments so that's a trade off.

seancorfield23:02:14

We also have functions that do that internally via loop/`recur` -- which I find easier to read overall (since it's an internal implementation detail).

caleb.macdonaldblack23:02:58

Actually after considering a simple recursive call for retry I ran into exactly that. The binding for loop/recur is really useful for keeping a count and keeps it out of the function args