Fork me on GitHub
#beginners
<
2019-06-14
>
johnjelinek01:06:01

I just want to say that I so appreciate this kind of documentation:

(aws/doc secretsmanager :DescribeSecret) ; => nil

-------------------------
Request

{:SecretId string}

Required

[:SecretId]

-------------------------
Response

{:LastRotatedDate timestamp,
 :Tags [:seq-of {:Key string, :Value string}],
 :RotationEnabled boolean,
 :VersionIdsToStages [:map-of string [:seq-of string]],

 :DeletedDate timestamp,
 :KmsKeyId string,
 :ARN string,
 :Name string,
 :Description string,
 :LastChangedDate timestamp,
 :RotationLambdaARN string,
 :RotationRules {:AutomaticallyAfterDays long},
 :LastAccessedDate timestamp}

johnjelinek01:06:15

I wish more libraries would adopt this kind of pattern, it's phenomenal

johnjelinek01:06:34

or even this:

(s/describe (aws/request-spec-key secretsmanager :DescribeSecret))
; =>
(keys :req-un [:cognitect.aws.secretsmanager.DescribeSecretRequest/SecretId])

johnjelinek01:06:08

the DX (developer experience) is just so high with this capability!

johnjelinek03:06:15

what does this warning mean?

# clojure -A:aot
2019-06-13 23:35:59.486:INFO::main: Logging initialized @5114ms
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.eclipse.jetty.util.BufferUtil (file:/root/.m2/repository/org/eclipse/jetty/jetty-util/9.3.7.v20160115/jetty-util-9.3.7.v20160115.jar) to field java.nio.MappedByteBuffer.fd
WARNING: Please consider reporting this to the maintainers of org.eclipse.jetty.util.BufferUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
clj.core

johnjelinek03:06:49

must be a big deal, because when I run my application, I see this splat out:

2019-06-14 03:37:43.337:INFO:oejc.ResponseNotifier:qtp617928649-19: Exception while notifying listener [email protected]
java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;
        at cognitect.http_client$empty_bbuf.invokeStatic(http_client.clj:37)
        at cognitect.http_client$empty_bbuf.invoke(http_client.clj:34)
        at cognitect.http_client$on_headers.invokeStatic(http_client.clj:128)
        at cognitect.http_client$on_headers.invoke(http_client.clj:108)
        at clojure.lang.Atom.swap(Atom.java:51)
        at clojure.core$swap_BANG_.invokeStatic(core.clj:2353)
        at clojure.core$swap_BANG_.invoke(core.clj:2345)
        at cognitect.http_client.Client$fn$reify__8183.onHeaders(http_client.clj:228)
        at org.eclipse.jetty.client.HttpRequest$10.onHeaders(HttpRequest.java:487)
        at org.eclipse.jetty.client.ResponseNotifier.notifyHeaders(ResponseNotifier.java:103)
        at org.eclipse.jetty.client.ResponseNotifier.notifyHeaders(ResponseNotifier.java:95)
        at org.eclipse.jetty.client.HttpReceiver.responseHeaders(HttpReceiver.java:257)
        at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.headerComplete(HttpReceiverOverHTTP.java:230)
        at org.eclipse.jetty.http.HttpParser.parseHeaders(HttpParser.java:962)
        at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1188)
        at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.parse(HttpReceiverOverHTTP.java:158)
        at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:119)
        at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:69)
        at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:90)
        at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:113)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
        at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:197)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
        at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:75)
        at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:213)
        at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:147)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
        at java.lang.Thread.run(Thread.java:748)

johnjelinek03:06:09

and

java.lang.ExceptionInInitializerError
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:348)
        at clojure.lang.RT.classForName(RT.java:2207)
        at clojure.lang.RT.classForName(RT.java:2216)
        at clojure.lang.RT.loadClassForName(RT.java:2235)
        at clojure.lang.RT.load(RT.java:453)
        at clojure.lang.RT.load(RT.java:428)
        at clojure.core$load$fn__6824.invoke(core.clj:6126)
        at clojure.core$load.invokeStatic(core.clj:6125)
        at clojure.core$load.doInvoke(core.clj:6109)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at clojure.core$load_one.invokeStatic(core.clj:5908)
        at clojure.core$load_one.invoke(core.clj:5903)
        at clojure.core$load_lib$fn__6765.invoke(core.clj:5948)
        at clojure.core$load_lib.invokeStatic(core.clj:5947)
        at clojure.core$load_lib.doInvoke(core.clj:5928)
        at clojure.lang.RestFn.applyTo(RestFn.java:142)
        at clojure.core$apply.invokeStatic(core.clj:667)
        at clojure.core$load_libs.invokeStatic(core.clj:5985)
        at clojure.core$load_libs.doInvoke(core.clj:5969)
        at clojure.lang.RestFn.applyTo(RestFn.java:137)
        at clojure.core$apply.invokeStatic(core.clj:667)
        at clojure.core$require.invokeStatic(core.clj:6007)
        at clojure.core$require.doInvoke(core.clj:6007)
        at clojure.lang.RestFn.invoke(RestFn.java:512)
        at clj.core$loading__6706__auto____3.invoke(core.clj:1)
        at clj.core__init.load(Unknown Source)
        at clj.core__init.<clinit>(Unknown Source)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:348)
        at clojure.lang.RT.classForName(RT.java:2207)
        at clojure.lang.RT.classForName(RT.java:2216)
        at clojure.lang.RT.loadClassForName(RT.java:2235)
        at clojure.lang.RT.load(RT.java:453)
        at clojure.lang.RT.load(RT.java:428)
        at clojure.core$load$fn__6824.invoke(core.clj:6126)
        at clojure.core$load.invokeStatic(core.clj:6125)
        at clojure.core$load.doInvoke(core.clj:6109)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at clojure.lang.Var.invoke(Var.java:384)
        at clojure.lang.Util.loadWithClass(Util.java:250)
        at clj.core.<clinit>(Unknown Source)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:348)
Caused by: java.lang.NullPointerException
        at java.io.StringReader.<init>(StringReader.java:50)
        at clojure.data.json$read_str.invokeStatic(json.clj:278)
        at clojure.data.json$read_str.doInvoke(json.clj:274)
        at clojure.lang.RestFn.invoke(RestFn.java:439)
        at clj.util$json__GT_map.invokeStatic(util.clj:15)
        at clj.util$json__GT_map.invoke(util.clj:13)
        at clj.dal$get_secret_from_aws.invokeStatic(dal.clj:29)
        at clj.dal$get_secret_from_aws.invoke(dal.clj:20)
        at clj.dal$get_secret_from_aws.invokeStatic(dal.clj:23)
        at clj.dal$get_secret_from_aws.invoke(dal.clj:20)
        at clj.dal__init.load(Unknown Source)
        at clj.dal__init.<clinit>(Unknown Source)
        ... 44 more

johnjelinek03:06:56

works fine in the repl though

johnjelinek03:06:00

any idea how to get some more details on what's causing this NullPointerException?

johnjelinek03:06:05

here's the function in question:

(defn get-secret-from-aws
  "Fetch secret from AWS SecretsManager"
  ([secret-id]
   (get-secret-from-aws secret-id "AWSCURRENT"))
  ([secret-id stage]
   (-> (aws/invoke secretsmanager {:op :GetSecretValue
                                   :request {:SecretId secret-id
                                             :VersionStage stage}})
       (get :SecretString)
       (util/json->map))))

johnjelinek04:06:52

it appears to me that maybe there's an error that I'm not catching that gets discarded in the REPL

Alexander Stavonin04:06:07

I saw same warnings with JVM 11. But there is no issues with JVM 8.

johnjelinek04:06:27

Oh, is it possible that I'm having issues because I'm building in JVM 11, but running my jar in JVM 8?

Alexander Stavonin04:06:02

From my observation - yes. I had similar error when built uberjar locally with JVM 11 and was trying to run it under AWS Lambda (they provides JVM 8 only). I'd fixed the issue by downgrading my local JVM to latest JVM 8.

johnjelinek11:06:47

That's precisely my situation!

dharrigan11:06:02

I'm seeing, in some libraries, two shapes of defining a function returned from a function, this way (defn foo [a] (fn ([b] (+ a b)))) and this way (defn foo [a] (fn [b] (+ a b))) both work, but in shape A, there is an extra set of parens surrounding the inner function parameters. Is this just a matter of style?

dharrigan11:06:01

(both functions, when eval'ed, produce the same result, i.e., ((foo 10) 20) => 30)

valtteri11:06:08

Extra parens are needed if you have multiple arities

user> (defn foo [a] 
        (fn 
          ([b] (+ a b))
          ([b c] (+ a b c))))
If you have just one arity it’s maybe more clear to not put the extra parens. This is my personal opinion.

jumar11:06:04

agree with that

introom11:06:52

drop-last is lazy

introom11:06:00

what’s the benefit of butlast?

seancorfield17:06:23

@UGC0NEP4Y Sometimes you don’t want lazy behavior. butlast guarantees linear time and eager behavior. drop-last is lazy and uses map and drop internally so it’ll be subject to the usual caveats of chunking, and producing intermediate sequences etc.

dharrigan11:06:09

understood about extra arity (just like normal functions), but in this case, there is only one arity

dharrigan11:06:14

so I suppose, just style.

valtteri11:06:18

Yeah, both are acceptable syntax. From defn docstring: >>> Same as (def name (fn [params* ] exprs*)) or (def name (fn ([params* ] exprs*)+))

dharrigan11:06:34

kk, thanks for your time 🙂

valtteri11:06:59

No problem!

Suni Masuno16:06:30

Is there a way to get a "doc" for an entire namespace? Like, all defs and their docstrings or something similar-ish?

noisesmith20:06:41

it's a one-liner I bet

noisesmith20:06:57

(ins)user=> (->> 'clojure.core ns-publics (take 3) (run! (fn [[s v]] (println s \newline (-> v meta :doc)))))
primitives-classnames 
 nil
+' 
 Returns the sum of nums. (+') returns 0. Supports arbitrary precision.
  See also: +
decimal? 
 Returns true if n is a BigDecimal
nil

👏 4
noisesmith20:06:08

you can leave out the (take 3) part of course

noisesmith20:06:02

throwing sort in the pipeline too is probably better than using the randomized hash-order you'd get otherwise

drewverlee16:06:51

i'm not sure i understand the full functionality of some of these macro characters. For example, consider:

(def z 1)

``~z
;; => joy.core/z

`'~z
;; => (quote 1)
In the form: `'z's return value makes sense to me, but i can't parse the first one. As a starting point, i would expect the form to be evaled because of .
`~z
;; => 1

`1
;; => 1

drewverlee16:06:09

come of think of it, im not sure if and `' are 3 separate macro characters each or if some combination of them make a new function.

papachan20:06:01

which is the correct way to parse a json response from an external api in clojure?

papachan20:06:38

json/parse-string ?

noisesmith20:06:45

both clojure.data.json and cheshire are "correct". Neither comes with clojure.core. I have found cheshire performs better but clojure.data.json is less likely to cause jackson version conflicts with other libs

noisesmith20:06:34

it's really up to you which to use, but those are definitely the popular options

papachan20:06:29

thank you !

noisesmith20:06:58

with a big enough project it's not unheard of to end up with both via transitive deps :/