2

I have a misunderstanding about a certain Clojure/Java interop.

I'm using the Pi4J library and I want to get a listener on a GPIO Pin.

The usage documentation: https://pi4j.com/1.2/usage.html (under "Listen for Pin Changes") gives the following example:

public static class GpioUsageExampleListener implements GpioPinListenerDigital {
    @Override
    public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
        // display pin state on console
        System.out.println(" --> GPIO PIN STATE CHANGE: " + event.getPin() + " = "
                + event.getState());
    }
}

// create and register gpio pin listener
myButton.addListener(new GpioUsageExampleListener());

There is also an example application: https://pi4j.com/1.2/example/listener.html

Which has:

myButton.addListener(new GpioPinListenerDigital() {
    @Override
    public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
        // display pin state on console
        System.out.println(" --> GPIO PIN STATE CHANGE: " + event.getPin() + " = " + event.getState());
    }
});

So, I'm trying the following bit of Clojure code:

(import [com.pi4j.io.gpio GpioFactory GpioPinDigitalInput PinPullResistance RaspiPin]
        [com.pi4j.io.gpio.event GpioPinListenerDigital])

(def gpio (GpioFactory/getInstance))
(def mybutton (.provisionDigitalInputPin gpio RaspiPin/GPIO_02 PinPullResistance/PULL_DOWN))

(def gpio-listener (reify GpioPinListenerDigital
                    (handleGpioPinDigitalStateChangeEvent [this event]
                      (println "GPIO Event Occured"))))

(.addListener mybutton gpio-listener)

But I get:

No matching method addListener found taking 1 args for class com.pi4j.io.gpio.impl.GpioPinImpl

Using reflection, I have a look at the methods available to the mybutton instance, and I can see the method is there:

(clojure.reflect/reflect mybutton)

 :members
 #{{ 
    ;;; Stuff trimmed
   {:name addListener,
    :return-type void,
    :declaring-class com.pi4j.io.gpio.impl.GpioPinImpl,
    :parameter-types [java.util.List],
    :exception-types [],
    :flags #{:public :synchronized}}
   {:name addListener,
    :return-type void,
    :declaring-class com.pi4j.io.gpio.impl.GpioPinImpl,
    :parameter-types [com.pi4j.io.gpio.event.GpioPinListener<>],
    :exception-types [],
    :flags #{:varargs :public :synchronized}}}}

I've checked the type of gpio-listener against GpioPinListener with success.

(cast com.pi4j.io.gpio.event.GpioPinListener gpio-listener)
#object[user$reify__7404 0x11251bd "user$reify__7404@11251bd"]

I tried type hinting the parameter to GpioPinListener, but I get the same result.

My lack of Clojure and Java knowledge is failing me here, so I'm a little lost where to look next, but I'm sure it's something really basic.

1 Answer 1

3

I can't test this, but if you note the docs, you'll see that addListener is actually var-arg, and dealing with var-arg methods can be confusing due to misunderstandings of how var-arg methods in Java work .

addListener is expecting an array of listeners (which is sugared away by Java var-arg syntax). Try

(.addListener mybutton
              (into-array [gpio-listener])) 

Or, since addListener actually has a List overload, this may work too

(.addListener myButton [gpio-listener])
Sign up to request clarification or add additional context in comments.

1 Comment

Both work. :) I had not noticed the var-args at all. I'll have to remember it in the future. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.