Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PWM provider not found #238

Open
Ghozti opened this issue Aug 17, 2022 · 15 comments
Open

PWM provider not found #238

Ghozti opened this issue Aug 17, 2022 · 15 comments

Comments

@Ghozti
Copy link

Ghozti commented Aug 17, 2022

Hello, after a few days of not touching my project I came to this error which seemingly happened out of nowhere despite it working numerous times before,
com.pi4j.provider.exception.ProviderNotFoundException: Pi4J provider [pigpio-pwm] could not be found. Please include this 'provider' JAR in the classpath.
I have not made any changes to the code that "breaks" my program, and it is actually taken right from the pi4j website:

public static com.pi4j.io.pwm.PwmConfig buildPwmConfig(Context pi4j, int address, PwmType type) {//pwm config builder
return Pwm.newConfigBuilder(pi4j)
.id("BCM" + address)
.name("Buzzer")
.address(address)
.pwmType(type)
.provider("pigpio-pwm")
.initial(0)
.shutdown(0)
.build();
}

@RLEO94
Copy link

RLEO94 commented Sep 27, 2022

Hi, did you create a fat jar? I have a similar issue #237

@FDelporte
Copy link
Member

Did you include all dependencies for the PiGpio provider?
See https://pi4j.com/documentation/providers/pigpio/

@RLEO94
Copy link

RLEO94 commented Sep 28, 2022

Hi, I have included all the dependecies.

I tried to start a new Maven project like in your description: https://pi4j.com/documentation/building/fat-jar/
With the inputs from your pi4-example-fatjar, I was able to generate a fatjar which works.

With gradle I was not able to generate a working jar file. I had the same Exception like above, with pigpio-output instead of pigpio-pwm(I use GPIO Output and Input in my code).

I looked at these 2 jar Files to find the difference. For the one which is not working:

  • There is only "com.pi4j.plugin.raspberrypi.RaspberryPiPlugin" written in the META-INF/services/com.pi4j.extension.Plugin.

  • The line "com.pi4j.plugin.pigpio.PiGpioPlugin" is missing

Could this be the problem? You mentioned (same link in this comment), that the maven-shade-plugin includes the plugins in META-INF/services/com.pi4j.extension.Plugin. and this works
But it seems that for a reason gradle is not able to do this correctly

@FDelporte
Copy link
Member

Indeed PiGpioPlugin contains pigpio-pwm, so without it this is the expected exception.
Is this the place and time to start a discussion about Maven versus Gradle? ;-)

Screenshot 2022-09-28 at 13 47 06

@RLEO94
Copy link

RLEO94 commented Sep 28, 2022

Hi and thanks for your help
No thanks it's ok for me :)

Anyway I would like to share my solution. Maybe it's useful for others.
I removed the pi4j-plugin-raspberrypi from my build.gradle

When I generated the jar, the line: "com.pi4j.plugin.pigpio.PiGpioPlugin"
was inserted in the META-INF/services/com.pi4j.extension.Plugin
then it worked

Probably this line was overwritten because of the other plugin

@taartspi
Copy link
Collaborator

taartspi commented Sep 30, 2022

@FDelporte With changes in the build.gradle the uberJar has all the code you identified above and I figured out how to add the class path to the manifest in case that was the problem But this is useless as it is an uberJar not individual jars.

So I did add a print in the Example code and the classPath is the uberJar.

If you run with verbose you can see the code IS looking in the looking in the uberJar Issue #237 mentions hack of removing the Rpi default code and then the pigpio is added. Can you think of any common attributes Pi4j uses to identify these providers in case there is a duplicate value that is then used as a key, so only one provider is added and not both the Rpi and concrete.
And printing the providers does not list these needed pigpio providers.

tasks.register('uberJar', Jar) {
archiveClassifier = 'uber'
manifest {
attributes 'Main-Class': 'com.pi4j.example.MinimalExample'
attributes(
"Class-Path": configurations.runtimeClasspath.collect { it.getName() }.join(' ')) No value as it lists individual jars
}
from sourceSets.main.output
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
dependsOn configurations.runtimeClasspath
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}

@taartspi
Copy link
Collaborator

Found what the bug is, don't understand why
The example code prints out the providers.
Changing the Dependencies to the following by moving pigpio above the raspberry entry:

dependencies {
implementation 'org.slf4j:slf4j-api:1.7.32'
implementation 'org.slf4j:slf4j-simple:1.7.32'
implementation 'com.pi4j:pi4j-core:2.1.1'
implementation 'com.pi4j:pi4j-plugin-pigpio:2.1.1'
implementation 'com.pi4j:pi4j-plugin-raspberrypi:2.1.1'
}
Now printing the providers hits class not found, comment out the printing providers and the example runs.

@FDelporte I don't know if this is a gradle bug/feature the Pi4j stumbles onto or specific to Pi4j. Your thoughts

@taartspi
Copy link
Collaborator

taartspi commented Oct 2, 2022

shadow.txt
Note: mvn clean package -Ddetail=true
Building via maven shows the shadow process kicks in to clean up duplicates. In gradle this requires added configuration changes in the build.gradle. Maybe with those changes the uberJar will work properly. As usual there are many discussion on the correct way to config the shadow, if anyone has a proven means please share.

pi@raspi464alt:/Example/pi4j-example-minimal $ mvn clean package -Ddetail=true
[INFO] Scanning for projects...
[WARNING]
[WARNING] Some problems were encountered while building the effective model for com.pi4j:pi4j-example-minimal:jar:0.0.1
[WARNING] 'build.plugins.plugin.(groupId:artifactId)' must be unique but found duplicate declaration of plugin org.apache.maven.plugins:maven-jar-plugin @ line 185, column 21
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
[INFO]
[INFO] -------------------< com.pi4j:pi4j-example-minimal >--------------------
[INFO] Building Pi4J :: MINIMAL EXAMPLE :: Sample minimal project 0.0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ pi4j-example-minimal ---
[INFO] Deleting /home/pi/Example/pi4j-example-minimal/target
[INFO]
[INFO] --- maven-dependency-plugin:2.8:copy-dependencies (copy-dependencies) @ pi4j-example-minimal ---
[INFO] Copying slf4j-api-1.7.32.jar to /home/pi/Example/pi4j-example-minimal/target/distribution/slf4j-api-1.7.32.jar
[INFO] Copying jsch-0.1.55.jar to /home/pi/Example/pi4j-example-minimal/target/distribution/jsch-0.1.55.jar
[INFO] Copying slf4j-simple-1.7.32.jar to /home/pi/Example/pi4j-example-minimal/target/distribution/slf4j-simple-1.7.32.jar
[INFO] Copying pi4j-plugin-pigpio-2.1.1.jar to /home/pi/Example/pi4j-example-minimal/target/distribution/pi4j-plugin-pigpio-2.1.1.jar
[INFO] Copying pi4j-core-2.1.1.jar to /home/pi/Example/pi4j-example-minimal/target/distribution/pi4j-core-2.1.1.jar
[INFO] Copying pi4j-plugin-raspberrypi-2.1.1.jar to /home/pi/Example/pi4j-example-minimal/target/distribution/pi4j-plugin-raspberrypi-2.1.1.jar
[INFO] Copying pi4j-library-linuxfs-2.1.1.jar to /home/pi/Example/pi4j-example-minimal/target/distribution/pi4j-library-linuxfs-2.1.1.jar
[INFO] Copying pi4j-plugin-linuxfs-2.1.1.jar to /home/pi/Example/pi4j-example-minimal/target/distribution/pi4j-plugin-linuxfs-2.1.1.jar
[INFO] Copying pi4j-library-pigpio-2.1.1.jar to /home/pi/Example/pi4j-example-minimal/target/distribution/pi4j-library-pigpio-2.1.1.jar
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ pi4j-example-minimal ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/pi/Example/pi4j-example-minimal/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ pi4j-example-minimal ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 4 source files to /home/pi/Example/pi4j-example-minimal/target/classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ pi4j-example-minimal ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/pi/Example/pi4j-example-minimal/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ pi4j-example-minimal ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ pi4j-example-minimal ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:3.1.2:jar (default-jar) @ pi4j-example-minimal ---
[INFO] Building jar: /home/pi/Example/pi4j-example-minimal/target/distribution/pi4j-example-fatjar.jar
[INFO]
[INFO] --- maven-shade-plugin:3.2.4:shade (default) @ pi4j-example-minimal ---
[INFO] Including org.slf4j:slf4j-api:jar:1.7.32 in the shaded jar.
[INFO] Including org.slf4j:slf4j-simple:jar:1.7.32 in the shaded jar.
[INFO] Including com.pi4j:pi4j-core:jar:2.1.1 in the shaded jar.
[INFO] Including com.pi4j:pi4j-plugin-raspberrypi:jar:2.1.1 in the shaded jar.
[INFO] Including com.pi4j:pi4j-plugin-pigpio:jar:2.1.1 in the shaded jar.
[INFO] Including com.pi4j:pi4j-library-pigpio:jar:2.1.1 in the shaded jar.
[INFO] Including com.pi4j:pi4j-plugin-linuxfs:jar:2.1.1 in the shaded jar.
[INFO] Including com.jcraft:jsch:jar:0.1.55 in the shaded jar.
[INFO] Including com.pi4j:pi4j-library-linuxfs:jar:2.1.1 in the shaded jar.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] jsch-0.1.55.jar, pi4j-core-2.1.1.jar, pi4j-example-fatjar.jar, pi4j-library-linuxfs-2.1.1.jar, pi4j-library-pigpio-2.1.1.jar, pi4j-plugin-linuxfs-2.1.1.jar, pi4j-plugin-pigpio-2.1.1.jar, pi4j-plugin-raspberrypi-2.1.1.jar, slf4j-api-1.7.32.jar, slf4j-simple-1.7.32.jar define 1 overlapping resource:
[WARNING] - META-INF/MANIFEST.MF
[WARNING] pi4j-core-2.1.1.jar, pi4j-library-linuxfs-2.1.1.jar, pi4j-library-pigpio-2.1.1.jar, pi4j-plugin-linuxfs-2.1.1.jar, pi4j-plugin-pigpio-2.1.1.jar, pi4j-plugin-raspberrypi-2.1.1.jar define 3 overlapping resources:
[WARNING] - LICENSE.txt
[WARNING] - NOTICE.txt
[WARNING] - README.md
[WARNING] maven-shade-plugin has detected that some class files are
[WARNING] present in two or more JARs. When this happens, only one
[WARNING] single version of the class is copied to the uber jar.
[WARNING] Usually this is not harmful and you can skip these warnings,
[WARNING] otherwise try to manually exclude artifacts based on
[WARNING] mvn dependency:tree -Ddetail=true and the above output.
[WARNING] See http://maven.apache.org/plugins/maven-shade-plugin/
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /home/pi/Example/pi4j-example-minimal/target/distribution/pi4j-example-fatjar.jar with /home/pi/Example/pi4j-example-minimal/target/pi4j-example-minimal-0.0.1-shaded.jar
[INFO] Dependency-reduced POM written at: /home/pi/Example/pi4j-example-minimal/dependency-reduced-pom.xml
[INFO]
[INFO] --- maven-antrun-plugin:3.0.0:run (copy) @ pi4j-example-minimal ---
[INFO] Executing tasks
[INFO] [copy] Copying 1 file to /home/pi/Example/pi4j-example-minimal/target/distribution
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 15.241 s
[INFO] Finished at: 2022-10-02T11:31:18-05:00
[INFO] ------------------------------------------------------------------------
pi@raspi464alt:
/Example/pi4j-example-minimal $ mvn clean package -Ddetail=true

@FDelporte

@FDelporte
Copy link
Member

I'm a Maven user, so, unfortunately, my Gradle knowledge is very limited...
The only Gradle we have in Pi4J was also contributed by others to prove it also works with Pi4J V2, see https://github.com/Pi4J/pi4j-example-minimal/blob/main/build.gradle.

BTW I'm very interested in the Maven output you mentioned about the clean up, can you add it to your comment?

@toboche
Copy link

toboche commented Dec 17, 2023

The issue comes from the fact that different Pi4J maven modules come with different values defined in META-INF/services/com.pi4j.extension.Plugin files. Depending on how you have your fat jar built, this might result in, by default, overriding the other values provided in this file by other modules.

I am using "com.github.johnrengelman.shadow" plugin to build the fat jar. I had to add

tasks.withType<ShadowJar> {
    mergeServiceFiles()
}

in my build.gradle file. With this, while the fat jar is built, whenever new content is defined for INF/services/com.pi4j.extension.Plugin thet values are merged, not overriden.

@FDelporte
Copy link
Member

Thanks @toboche for the info! Can you please validate if this Gradle example is correct? It doesn't use that Shadow plugin, but when we created this minimal example, it was working as expected...

https://github.com/Pi4J/pi4j-example-minimal/blob/main/build.gradle

@toboche
Copy link

toboche commented Dec 18, 2023

hey @FDelporte , when running ./gradlew build locally on my Mac and then uploading the .jar to my Raspberry and running it via sudo java -jar /home/toboche/pi4j-example-minimal-0.0.1.jar I'm getting:

no main manifest attribute, in /home/toboche/pi4j-example-minimal-0.0.1.jar
  • this is probably because there's no Main-Class attribute definition in the build.gradle file.

When running ./gradlew build on my Raspberry via sudo java -jar /home/toboche/pi4j-example-minimal-0.0.1.jar I'm getting:

Could not compile settings file '/home/toboche/pi4j-example-minimal/settings.gradle'.
> startup failed:
  General error during semantic analysis: Unsupported class file major version 61
  • this is because the bundled Raspberry Pi OS (Legacy , 32-bit) Java version is too old.

@toboche
Copy link

toboche commented Dec 18, 2023

Having fixed the issue of missing manifest, I'm getting:

Exception in thread "main" java.lang.NoClassDefFoundError: com/pi4j/util/Console
	at com.pi4j.example.MinimalExample.main(MinimalExample.java:60)
Caused by: java.lang.ClassNotFoundException: com.pi4j.util.Console
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
	... 1 more
  • this is caused by the lack of fat jar generation, as com/pi4j/util/Console is provided in one of the dependencies.

Let me know if you'd like me to open a PR with some fixes for that in the coming weeks :)

@Ir3nicuz
Copy link

Ir3nicuz commented Jul 17, 2024

I found this thread at googling for a similar issue.

At compiling/bundeling a jar package with Gradle there seems to be a wierd issue with plugins. Gradle seems to bundle all plugins listed at the dependencies to the jar package, but at least override or not append some "links" to it.
That is a problem at using more then one provider, therefore more then one plugin is needed.

My programm uses provider pigpio and linuxfs. My Gradle dependencies look like:

dependencies {
api 'org.slf4j:slf4j-api:2.0.12'
api 'com.pi4j:pi4j-core:2.6.0'
api 'com.pi4j:pi4j-plugin-raspberrypi:2.6.0'
api 'com.pi4j:pi4j-plugin-pigpio:2.6.0'
api 'com.pi4j:pi4j-plugin-linuxfs:2.6.0'
api 'com.pi4j:pi4j-plugin-gpiod:2.6.0'
}

When I run the programm, I got "ProviderNotFoundException for pigpio".

If I change the Gradle dependencies to:

dependencies {
api 'org.slf4j:slf4j-api:2.0.12'
api 'com.pi4j:pi4j-core:2.6.0'
api 'com.pi4j:pi4j-plugin-pigpio:2.6.0'
api 'com.pi4j:pi4j-plugin-linuxfs:2.6.0'
api 'com.pi4j:pi4j-plugin-gpiod:2.6.0'
api 'com.pi4j:pi4j-plugin-raspberrypi:2.6.0'
}

And I run the programm, I got "ProviderNotFoundException for linuxfs".

But the plugin folder in the .jar package looks at both dependency cases like this (all plugins present) :
package

Are there new ideas to this problem?
It seems a little bit wierd to have to learn/configure/use a third party plugin like shadow for Gradle to be able to bundle JavaPlugins?!

@Ir3nicuz
Copy link

Digging through the web to the main problem of not merged services files by Gradle,
tired of using plugins over plugins for solving every little problem,
found this neat solution at http://cmoz.me/blog/2014/11/service-files-uber-jars-and-gradle/

This can be added to every Gradle standard "Jar" Task. A Fat-Jar build with Gradle with this task addition runs all Pi4J provider services in parallel:

` tasks.register('dist', Jar) {

    group = BasePlugin.BUILD_GROUP
    dependsOn classes
    dependsOn configurations.runtimeClasspath
    
    manifest {
        attributes 'Main-Class': project.mainClassName
    }
    
    doFirst {
        // prepare the buildDir as temporary storage directrory
        def serviceDir = file("$buildDir/META-INF/services")
        serviceDir.deleteDir()
        serviceDir.mkdirs()

        // copy all service files from dependencies to buildDir, merge content if name matches
        for(file in configurations.runtimeClasspath) {
            zipTree(file).matching{ include 'META-INF/services/*' }.each { f ->
                new File(serviceDir, f.name) << f.getText("UTF-8")
            }
        }
    }

    // Merge all Dependencies to one fat-Jar, but exclude the service files
    duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
    from(configurations.runtimeClasspath.collect{ it.isDirectory() ? it : zipTree(it) }) {
        exclude 'META-INF/services/*' 
    }

    // Include the merged service files from the buildDir
    from fileTree(buildDir).matching{ include 'META-INF/services/*' }

    with jar
}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants