Fork me on GitHub
#clojure
<
2021-10-11
>
Santiago08:10:14

Has anyone added Okta SSO to a Clojure (not -script) app before here? There’s a ring middleware out there, but it’s unmaintained.

thumbnail10:10:40

We have, iirc it's pretty much just an oauth provider

Jakub Holý11:10:06

Given that it is an oauth provider, I like to keep the login handling out of my app and run https://oauth2-proxy.github.io/oauth2-proxy/ in front of my app. YMMV 🙂

Santiago12:10:32

cool they have an example with Okta 🙂 thanks!

🎉 1
Jakub Holý11:10:49

Hello! What is the best (= least work-intensive? easiest to understand and maintain?) way to create a wrapper for a Java object implementing an interface, where I want to modify one method and pass through the rest unchanged? It is https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/javax/sql/DataSource.html, which has about 10 methods, and https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/Connection.html, which has many. The options I can think of: 1. Use IntelliJ to generate a wrapper class for the interface and use that. Likely the least amount of work. 2. Use proxy to wrap the actual class (HikariDataSource in this case) and only override the fn I need (be default it calls the superclass method, if no def provided) - not as "clean" but little work. I could do the same for Connection, though that binds me to the internals to Hikari (on the other hand, this particular impl. detail - the conn. class - is unlikely to change) 3. Bite the bullet and use reify on the interfaces, implementing all the methods 4. Write a macro that produces the reify from 3. using reflection Thoughts / experiences? Background: I want to run an extra statement whenever I check out a conn from a pool and return it back.

javahippie11:10:10

I’m not sure what you mean by “generate a wrapper”. If the class is not final, can’t you just create a subclass and override the one method you’d like to change? Edit: Did not see that you get an existing object, sorry

Jakub Holý11:10:58

Wrapper = I want to implement the https://refactoring.guru/design-patterns/decorator, to modify the behavior of an object I have and that is solely used through the interface(s) it implements. I could create a subclass, that is what 2. is about, though using clojure rather than Java, and an ad-hoc generated class rather than once defined more statically.

emccue13:10:29

bite the bullet on 3. is my approach if you don't use proxy+. At least then its explicit

Ben Sless15:10:32

Or do something completley terrible like

(defn emit-method-wrapper
  [o {:keys [name return-type parameter-types]}]
  (let [params (map
                (fn [t]
                  (cond-> (gensym)
                    (not= t 'jva.util.Object) (with-meta {:tag t})))
                parameter-types)]
    `(~name [g# [email protected]] (. ~o (~name [email protected])))))

(defn emit-wrap
  [c interfaces decls]
  (let [g (group-by first decls)]
    (concat
     (for [i interfaces
           :let [clazz (Class/forName (str i))
                 {:keys [members]} (clojure.reflect/reflect clazz)]
           {:keys [flags name] :as member} members
           :when (and
                  (flags :public)
                  (not (flags :static))
                  (get member :return-type)
                  (not (g name)))]
       (emit-method-wrapper c member))
     decls)))

(defmacro wrap-interfaces
  [c interfaces & decls]
  `(reify [email protected]
     [email protected](emit-wrap c interfaces decls)))


(wrap-interfaces
 m
 [java.util.Map]
 (get [this k] :aha!))
Obviously this is an incomplete and fragile implementation but you get the idea

👍 1
Jakub Holý15:10:00

Thank you all! I will look at proxy+

Jakub Holý15:10:10

Hm, proxy+ isn't helping, it still requires that I implement all the methods, it seems...

coltnz20:10:44

intellij does it all the hard work, you have 1 ugly class no big deal. I made TimedStatement this way wrapping PreparedStatement.

👍 1
coltnz20:10:29

and i contemplated 'prettier' and 'smarter' methods for far longer than it took to do

Jakub Holý07:10:51

Thanks, Colin. I thought that might be the simplest way forward...

Jakub Holý12:10:42

I ended up making a defdecorator macro (since my team did not want any Java in our source code) https://clojurians.slack.com/archives/C06MAR553/p1634040345143900

Ben Sless13:10:58

I feel partially responsible. Wouldn't just proxying it with Java be better?

Jakub Holý14:10:40

Yes but my team does not want to add java sources.

roklenarcic14:10:24

reflection might get problematic with the new java module rules