add metadata to a Java Object in clojure - clojure

I am working with a Java library in clojure and I would like to attach some extra information to those objects while I do stuff to them. I was thinking of stashing the info as metadata although I'm not committed to that and if you have any better suggestions, I would love to hear them.
The basic example would be to add a name to a BufferedImage and store it as metadata. The goal is to process the image and then be able to pull the name back out.
(ns test.clj
(:import [java.awt BufferedImage]))
; define a new image and try to attach data
(let [image (new BufferedImage 200 200 1)]
(with-meta image {:name "myawesomepicture"}))
;generates the following error
;ClassCastException java.awt.image.BufferedImage
;cannot be cast to clojure.lang.IObj
;clojure.core/with-meta (core.clj:214)
There is a recent post that defines a type that can attach metadata to an array but this wraps the values which will trigger type errors when trying to use the object as shown below. (box is a metadata wrapping function from the previous link; show is a function from mikera's imagez library that displays a BufferedImage).
(use 'mikera.image.core)
(def image1 (new BufferedImage 200 200 1))
(show image1) ; no problem
(def image2 (box image1 {:name "test"})) ; add metadata using box wrapper function
(show image2) ; ClassCastException Box cannot be cast to java.awt.image.BufferedImage
I would appreciate any thoughts on using clojure to tag Java objects with custom data - whether as metadata or fields or whatever.
thanks,
zach cp

Related

How to I get the body text of a Response object returned by the fetch API in ClojureScript?

I'm trying to use the Github Gist API to get a list of all of my Gists like so:
(ns epi.core)
(.then (.fetch js/window "https://api.github.com/users/seisvelas/gists")
(fn [data] (.log js/epi data)))
js/epi is just console.log except provided by the blogging platform I'm using (epiphany.pub).
When I call that API from curl it works fine; however, when done in cljs instead of giving me the body of the response, this gives me [object Response]. Does anyone know how I can get the body text of the response?
TL;DR
(-> (.fetch js/window "https://api.github.com/users/seisvelas/gists")
(.then #(.json %)) ; Get JSON from the Response.body ReadableStream
(.then #(.log js/epi %))
is what I'd write
From ClojureScript, a JavaScript call like data.body() can be invoked with
(.body data)
and a JavaScript property access like data.body with
(.-body data)
One of those should work in your case. However, the fetch API requires a bit more if you want to get JSON from the body, which I assume you do based on the endpoint.
If you're dealing with promise chains, you might also want to consider using -> (thread-first) so it reads top to bottom.
See this Gist for more about threading promise chains.
There is a library wrapping js fetch API called lamdaisland.fetch. This library uses transit as default encoding format, so you need to specify accept format when working with github API.
This library contains kitchen-async.promise as its dependency, so you can require the kitchen-async.promise in your ClojureScript source code.
(ns fetch.demo.core
(:require [kitchen-async.promise :as p]
[lambdaisland.fetch :as fetch]))
(p/try
(p/let [resp (fetch/get
"https://api.github.com/users/seisvelas/gists"
{:accept :json
:content-type :json})]
(prn (:body resp)))
(p/catch :default e
;; log your exception here
(prn :error e)))
Seems like .fetch returns a Response object, and you need to get the attribute body from it for the body. https://developer.mozilla.org/en-US/docs/Web/API/Response
Something like (.body data)

Clojure: How to Serialize a Function and Reuse it Later

(defn my-func [opts]
(assoc opts :something :else))
What i want to be able to do, is serialize a reference to the function (maybe via #'my-func ?) to a string in such a way that i can upon deserializing it, invoke it with args.
How does this work?
Edit-- Why This is Not a Duplicate
The other question asked how to serialize a function body-- the entire function code. I am not asking how to do that. I am asking how to serialize a reference.
Imagine a cluster of servers all running the same jar, attached to a MQ. The MQ pubs in fn-reference and fn-args for functions in the jar, and the server in the cluster runs it and acks it. That's what i'm trying to do-- not pass function bodies around.
In some ways, this is like building a "serverless" engine in clojure.
Weirdly, a commit for serializing var identity was just added to Clojure yesterday: https://github.com/clojure/clojure/commit/a26dfc1390c53ca10dba750b8d5e6b93e846c067
So as of the latest master snapshot version, you can serialize a Var (like #'clojure.core/conj) and deserialize it on another JVM with access to the same loaded code, and invoke it.
(import [java.io File FileOutputStream FileInputStream ObjectOutputStream ObjectInputStream])
(defn write-obj [o f]
(let [oos (ObjectOutputStream. (FileOutputStream. (File. f)))]
(.writeObject oos o)
(.close oos)))
(defn read-obj [f]
(let [ois (ObjectInputStream. (FileInputStream. (File. f)))
o (.readObject ois)]
(.close ois)
o))
;; in one JVM
(write-obj #'clojure.core/conj "var.ser")
;; in another JVM
(read-obj "var.ser")
As suggested on the comments, if you can just serialize a keyword label for the function and store/retrieve that, you are finished.
If you need to transmit the function from one place to another, you essentially need to send the function source code as a string and then have it compiled via eval on the other end. This is what Datomic does when a Database Function is stored in the DB and automatically run by Datomic for any new additions/changes to the DB (these can perform automatic data validation, for example). See:
http://docs.datomic.com/database-functions.html
http://docs.datomic.com/clojure/index.html#datomic.api/function
As similar technique is used in the book Clojure in Action (1st Edition) for the distributed compute engine example using RabbitMQ.

Serve a BufferedImage by a Ring handler

I'm looking for a way to let a ring server - by request - grab an image from an URL, process it and serve the modified version.
This is how I got so far:
(require '[clj-http.client :as client]
'[ring.adapter.jetty :refer [run-jetty])
(import javax.imageio.ImageIO)
(def handler (-> (client/get "http://.../some-img.jpg" {:as :stream})
:body
ImageIO/read
.. ;; do some processing with the BufferedImage here
.. ;; and serve the modified version))
(run-jetty handler {:port 55555})
Especially I'm having troubles performing the last step inside the threading macro.
To return bytes as the response in Ring you need to provide either java.io.File or java.io.InputStream as the body content:
(defn jpeg-response [image-data]
(-> image-data
(ring.util.response/response)
(ring.util.response/content-type "image/jpeg")))
I haven't found a way to obtain an InputStream from BufferedImage directly without creating an intermediate byte arrays. Maybe this is a limitation of the Java Image API due to complexity required to implement a "pull" approach to get a stream of image bytes in the desired format.
Instead there is a "push" API where ImageIO.write method requires some kind of output for image bytes. It might be a java.io.File or java.io.OutputStream. Thus you need to first store the bytes somewhere (java.io.File or java.io.ByteArrayOutputStream) and then use them as your response body:
With file (so storing the image on the disk first - you need to remember to clean it up):
(let [image (ImageIO/read "...")
image-file (java.io.File. "...")]
(ImageIO/write image "jpg" image-file)
(jpeg-response image-file))
In-memory byte array:
(let [image (ImageIO/read "...")
image-output-stream (ByteArrayOutputStream.)]
(ImageIO/write image "jpg" image-output-stream)
(jpeg-response (ByteArrayInputStream. (.toByteArray image-output-stream))))

Testing components with async api calls by mocking the request

I'm still in a learning phase for Cljs and Om. I'm looking into writing comopnent test. Some components have cljs-http calls to an API I created. When testing, I do not want those API calls to actually send the request, so I'm looking into mocking the request and returning a fixture. Here's an example component I have:
(defn async-component [data owner]
(reify
IWillMount
(will-mount [_]
(let [resp (go ((<! (async-call "/") :body))]
(om/update! data [:objects] resp)))
IRender
(render [_]
[:ul
(om/build-all item-component data)])))
(defn async-call [path]
(http/get path {:keywordize-keys true}))
Please don't mind if the code is actually syntactically correct, I'm just showing the gist of it.
What I now want to do is test this async-component and the API call to see if it will render the fixture that I mock the request with. How is this done? I know cljs.test has the async block to test async code with, but all example show it testing actual code blocks that only have a go in it, not in a larger context.
Here is a way you might use mocking to test your component:
(deftest test-async-component
(cljs.test/async done
(with-redefs
[async-call (fn [path]
(let [mock-ch (async/chan 1)
fixture-data {:body {:fixture-with path :and "foobar"}})]
(async/put! mock-ch fixture-data)
mock-ch)]
; At this point we successfully mocked out our data source (the API call)
; the only task that remains is to render our Om component into DOM and inspect it.
; As this task requires utility fns I will reuse the ones in this blog post:
; http://lab.brightnorth.co.uk/2015/01/27/unit-and-browser-testing-om-clojurescript-applications/
(let [c (new-container!)
initial-data {:objects [{:initial-object 42}]}]
; This will mount and render your component into the DOM residing in c.
(om/root async-component initial-data {:target c})
(testing "fixture data gets put into the DOM"
(is (= "foobar" (text (sel1 c :ul)))))
; You can add more tests in this manner, then finally call 'done'.
(done)))))
The steps taken in the above code in English:
Write async-call's mock fn that returns a channel (the same interface as the original one) prefilled with fixture data.
Mock out the original fn (you need to refer it or fully qualify the ns).
Create a new virtual DOM for unit testing purposes.
Specify the mock data that doesn't come from the API, if any.
Render your component into DOM (this will call async-call when om/will-mount runs, taking the fixture-data off the chan).
Observe DOM contents.

Can't load FXML in Clojure using FXMLLoader

I'm trying to implement the basic JavaFX example shown here: http://docs.oracle.com/javafx/2/get_started/fxml_tutorial.htm . I was able to get the basic stuff working (programmatically creating the gui) and using css, but I'm having trouble with the FXMLLoader.
The java version is this:
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("fxml_example.fxml"));
stage.setTitle("FXML Welcome");
stage.setScene(new Scene(root, 300, 275));
stage.show();
}
I'm not a Java expert, but I don't think an FXMLLoader object is instantiated ie. there is not a new FXMLLoader(); statement. So where is the load coming from?
When i try the following clojure code:
(ns jfxtwo.core
(:gen-class
:extends javafx.application.Application)
(:import (javafx.application Application)
(javafx.fxml FXMLLoader)
(javafx.scene Parent Scene)
(javafx.stage Stage)))
(defn -main []
(javafx.application.Application/launch jfxtwo.core (into-array String [])))
(defn -start [this primaryStage]
(let [loc (clojure.java.io/resource "fxml_example.fxml")
root (.load FXMLLoader ^java.net.URL loc)
scene (Scene. root 300 250)]
(.setScene primaryStage scene)
(.show primaryStage)))
...i get Caused by: java.lang.IllegalArgumentException: No matching method found: load for class java.lang.Class .
So I put a dot after the FXMLLoader to create an instance: (FXMLLoader.) I get this: ClassCastException java.net.URL cannot be cast to java.io.InputStream
So this tell me I'm onto something since one of the load methods for FXMLLoader supports an InputStream. I tried forcing the compiler to know the resource is a java.net.URL because that's one of the supported overloads for FXMLLoader.load, by placing the call to (clojure.java.io/resource...) directly in the call to (.load...) but it still doesn't like it (I knew it was a long shot). I also tried type-hinting, (.load (FXMLLoader.) ^java.net.URL loc) and (.load (FXMLLoader.) #^java.net.URL loc), but no dice; it still tries to use the java.io.InputStream version of load.
There is also the getClass() call in java which I think is getting the superclass of Application, but I'm not sure what to do with that in clojure-land.
Any ideas on how to load the fxml file?
After that, the java code has #FXML annotation for allowing the FXML into private class members. Is this necessary in clojure (java code breaks when I remove it)? The #Override annotation doesn't seem to be used in clojure.
thanks
Given the Java syntax, the load method being called here appears to be a static method of the FXMLLoader class. To call static methods in Clojure, you need to use (ClassName/methodName args...) syntax:
(FXMLLoader/load ...)
(Just checked: FXMLLoader has both static and instance load methods with multiple signatures. You'll want to call the same method the Java code does; static methods will be called with the FXMLLoader.load syntax in Java, instance methods -- someFXMLLoaderInstance.load.)
As for the getClass method call, it's target is implicitly this in Java; in Clojure, you'll have to make the target explicit ((.getClass this)).
I was able to work around my problem by creating the FXMLLoader separately from setting the location.
(defn -start [this primaryStage]
(let [loc (clojure.java.io/resource "fxml_example.fxml")
fxmlloader (FXMLLoader.)]
(.setLocation fxmlloader loc)
(let [root (.load fxmlloader )
scene (Scene. root 300 250)]
(.setScene primaryStage scene)
(.show primaryStage))))