Fork me on GitHub
#clojure
<
2024-03-13
>
seb23112:03:39

Hello can anyone give any advice on using a particular Java Enum in Clojure? https://poi.apache.org/apidocs/dev/org/apache/poi/sl/usermodel/PictureData.PictureType.html I want to use PictureData.PictureType.PNG but can't work out how to "translate" it. I thought it should be PictureType/PNG but that doesn't seem to work

lassemaatta12:03:19

perhaps PictureData$PictureType/PNG might work?

dpsutton13:03:50

.usermodel.PictureData$PictureType/GIF works for me

Nundrum13:03:44

I just recently learned this myself, but when the javadocs say "enclosing interface" indicating this is nested class, you need $ as the separator instead of ..

seb23113:03:26

okay thanks for this. In the end using the full address worked as per @U11BV7MTK. I was able to use PictureData$PictureType/PNG when importing the Java library like this: .usermodel.PictureData$PictureType whereas previously I was reading it in just as .usermodel.PictureData

dpsutton13:03:28

Clojure interops with any jvm bytecode, not a Java language construct. Java gives some nice sugar to make sibling classes, but you think of them as containing classes So if you import PictureData, if you think in “java”, you can use PictureData’s child class PictureType and you would think you could reference it as PictureData$PictureType. But that’s a java-ism and the bytecode is just making another class and using the $ as the indicator

dpsutton13:03:26

you can import it thought if you like

(import org.apache.poi.sl.usermodel.PictureData$PictureType
        org.apache.poi.sl.usermodel.PictureData)
org.apache.poi.sl.usermodel.PictureData
lexer=> [PictureData$PictureType PictureData]
[org.apache.poi.sl.usermodel.PictureData$PictureType
 org.apache.poi.sl.usermodel.PictureData]

agorgl16:03:38

What is the best practice for requiring a namespace when needing it only for development in a (comment)? E.g. In my app namespace I so far had [integrant.repl.state :as repl-state] in my :require in order to have

(comment
  (def client (-> repl-state/system ::system/client))
  ...)
in the bottom of the file, and while I do have integrant/repl in my :dev alias I don't have it in my main aliases list, thus resulting in uberjar builds failing What is the proper way to go about this? Should I remove the [integrant.repl.state :as repl-state] from the app namespace :require and add a (:require [integrant.repl.state :as repl-state]) inside the comment? Is there a better way to do this?

Samuel Ludwig16:03:53

Its pretty common for clojure project to have a separate dev file/directory (which you would include with :extra-paths in your :dev alias), where you can have your utility/test functions/calls

agorgl16:03:41

Yeah I also have that, but I want to have a (comment) with relevant shortcuts in each file / namespace I work on

agorgl16:03:14

Now it happens that one of those comments need a dev/tooling namespace too

p-himik16:03:31

Are you sure it's that comment that's the issue? It cannot be repl-state/system since the symbol is discarded by the comment form and thus isn't resolved. It might be because you have some ::repl-state/... keyword in there. But those you can fix by either using a full ns or by using :as-alias in the :require form as it doesn't require for that ns to actually exist.

wevrem16:03:27

I do that a lot. Not sure if it could call it best practice, but it works for me.

(comment
  (do
    (require '[integrant.repl.state])
    (let [datomic (:services/datomic integrant.repl.state/system)
          ...]
      ...
    )
  )

agorgl16:03:32

Yeah the issue is not the comment per-se but the require I have in the top of the file:

(ns com.example.app
  (:require
   [clojure.string :as str]
   [clojure.tools.logging :as log]
   [integrant.repl.state :as repl-state]
  ...

...

...

(comment
  (def client (-> repl-state/system ::system/client))
  ...

magnars16:03:48

With integrant.repl.state required in the dev namespace, I just use the fully qualified name in comments, no need to require.

agorgl16:03:23

^ hmm this could be one good solution

p-himik16:03:53

Ah. Well, don't have that vector in there then. :) Either do what wevrem does and use require or use requiring-resolve. What magnars suggests will also work, but only if the dev namespace is already loaded and you're sure you'll remember that it needs to be loaded prior to running code in that comment block.

agorgl16:03:39

@U07FCNURX how do you tackle the clojure-lsp warning about the unresolved namespace then?

magnars16:03:44

With

(ns user (:require [integrant.repl.state]))
in dev/user.clj , you won't even have to remember.

magnars16:03:32

@U03PYN9FG77 Add this to .clj-kondo/config.edn :

{:linters {:unresolved-namespace {:exclude [integrant.repl.state]}}}

agorgl16:03:49

good one, will try this thanks!

wevrem16:03:52

#_{:clj-kondo/ignore [:unresolved-namespace]}

p-himik16:03:49

@U07FCNURX Heh, you will most definitely remember, only from a completely different perspective, when you're bitten by that autoloading user namespace. :) The fact that it hasn't happen to you yet doesn't mean that it'll always be the case or that it won't happen to someone else. The advice not to use user is common and for good reasons.

magnars16:03:32

For your own code, for sure. I wouldn't be worried about loading very stable external dependencies like integrant that way tho.

wevrem16:03:58

Oh. Wait. I just realized that I don’t have any unresolved namespace issues with Integrant repl. Why is that? I only use that ignore macro on the frontend CLJS code like this:

(comment
  #_{:clj-kondo/ignore [:unresolved-namespace]}
  (-> @re-frame.db/app-db ::rules))
But then I went and looked in .clj-kondo/config.edn and found this awesome nugget :config-in-comment, which I’m sure someone on here suggested:
{:lint-as {byt.utils.macros/doall-for clojure.core/for
           org.httpkit.client/defreq clojure.core/def
           reagent.core/with-let clojure.core/let}
 :config-in-comment {:linters {:duplicate-require {:level :off}
                               :unused-binding {:level :off}}}}
                               ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1
p-himik16:03:06

@U07FCNURX It raises the probability of failure for any kind of code. It's trivial to have user unexpectedly become a part of your uberjar and then get surprised_pikachu.jpg'ed when you remove who-knows-what-it's-for.jar from your uberjar and the code stops working, only to later on learn that Integrant REPL was a transitive dependency of that jar. IMO just that cognitive load of "`user` is loaded implicitly, so I have to juggle the classpath and be careful" is not worth it.

magnars16:03:30

That sounds like experience talking, so yeah, a valid concern. I generally no longer create uberjars, and certainly not with my dev folder in it, but I can see that my habits are not everyone else's habits, and that the "here be dragons"-signs are there for a reason. 🙂

p-himik16:03:47

Not my direct experience but I remember at least three instances when that very same thing happened to someone on this server. :) I've had my own share of other issues with uberjars as well, so I don't use them either.

vemv18:03:56

One pattern that helps is having short helper defns in dev.clj (or less preferably, user.clj) with commonly needed objects e.g. defn db for returning a db conn Then, in a comment , I can (dev/db) which needs no require and is pleasant to type A handy kondo config setting for that sort of usage would be:

:config-in-comment {:linters {:unresolved-var       {:level :off}
                               :unresolved-namespace {:level :off}}}

1
👌 1