I think you are right. The ClassLoader is a likely culprit here. There's a 
simple way to set a ClassLoader for Cayenne runtime:

  Thread.currentThread().setContextClassLoader(..);

For something more advanced (e.g. to ensure it works across all threads), you 
might define a custom implementation of ClassLoaderManager
DI service [1].

Andrus

[1] https://cayenne.apache.org/docs/4.2/cayenne-guide/#customization-strategies


> On Mar 29, 2022, at 1:00 AM, Stefan Stegic <stefanste...@gmail.com> wrote:
> 
> I think I may have figured it out! I switched to MongoDB with Morphia ODM and 
> had the same problem: works when I run it through main, but throws a 
> ClassNotFound when ran by Spigot. Morphia couldn't locate my entity classes 
> package via its path and I solved it by supplying the class loader of the 
> calling class like so:
> 
> MapperOptions mapperOptions = 
> MapperOptions.builder().classLoader(this.getClass().getClassLoader()).build();
> datastore = Morphia.createDatastore(MongoClients.create(connectionUri), 
> dbName, mapperOptions);
> datastore.getMapper().mapPackage("path.to.my.models.package");
> 
> Could there be a similar problem with Cayenne? Is there a way to change the 
> class loader before initialization in a similar matter? 
> 
> On Wed, Mar 23, 2022 at 5:53 PM Stefan Stegic <stefanste...@gmail.com 
> <mailto:stefanste...@gmail.com>> wrote:
> Yup, it's in there:
> 
> ##################################################################
> #   Licensed to the Apache Software Foundation (ASF) under one
> #  or more contributor license agreements.  See the NOTICE file
> #  distributed with this work for additional information
> #  regarding copyright ownership.  The ASF licenses this file
> #  to you under the Apache License, Version 2.0 (the
> #  "License"); you may not use this file except in compliance
> #  with the License.  You may obtain a copy of the License at
> #
> #    http://www.apache.org/licenses/LICENSE-2.0 
> <http://www.apache.org/licenses/LICENSE-2.0>
> #
> #  Unless required by applicable law or agreed to in writing,
> #  software distributed under the License is distributed on an
> #  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> #  KIND, either express or implied.  See the License for the
> #  specific language governing permissions and limitations
> #  under the License.
> ##################################################################
> 
> org.apache.cayenne.configuration.server.MainCayenneServerModuleProvider
> 
> On Wed, Mar 23, 2022 at 5:47 PM Andrus Adamchik <aadamc...@gmail.com 
> <mailto:aadamc...@gmail.com>> wrote:
> Ok, shading can be tricky. Do you have this file inside the shaded jar:
> 
> >> "META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider"
> 
> And if you do, can you check the contents of it? It is a simple text file, so 
> once you extract it form the  jar, you can check it in any text editor.
> 
> Andrus
> 
> 
> 
> > On Mar 23, 2022, at 5:26 PM, Stefan Stegic <stefanste...@gmail.com 
> > <mailto:stefanste...@gmail.com>> wrote:
> > 
> > Ok, just tried maven-shade-plugin, but no luck - still the same error... It
> > seems that the shading is working as expected: when I run maven package,
> > the output jar really has cayenne's stuff in there, but DI is still failing
> > when I copy the plugin into the server and start it.
> > 
> > Michael, in response to your question:
> > 
> >> Have you tried updating your "java -cp myPlugin.jar path.to.Main" command
> >> to have more classpaths?
> > 
> > 
> > When I run Main, it works, so that's not the problem. The problem arises
> > when my plugin is called by Spigot, the custom Minecraft server I'm writing
> > the plugin for.
> > 
> > On Wed, Mar 23, 2022 at 5:20 PM Stefan Stegic <stefanste...@gmail.com 
> > <mailto:stefanste...@gmail.com>>
> > wrote:
> > 
> >> Hi Michael,
> >> 
> >> Oh, I wasn't aware, thanks. Here's the screenshot from my last e-mail:
> >> https://imgur.com/QJoBGAV <https://imgur.com/QJoBGAV> .
> >> Right, I'll give maven-shade-plugin a try now and check if it works that
> >> way, thanks.
> >> 
> >> On Wed, Mar 23, 2022 at 5:18 PM Michael Gentry <blackn...@gmail.com 
> >> <mailto:blackn...@gmail.com>>
> >> wrote:
> >> 
> >>> If you aren't using a shaded JAR (which merges all JARs into a single
> >>> JAR),
> >>> then you'll need more JARs listed on your Java command.
> >>> 
> >>> 
> >>> On Wed, Mar 23, 2022 at 12:16 PM Stefan Stegic <stefanste...@gmail.com 
> >>> <mailto:stefanste...@gmail.com>>
> >>> wrote:
> >>> 
> >>>> PS: I'm not using maven-shade (just opened the link you sent)
> >>>> 
> >>>> On Wed, Mar 23, 2022 at 5:10 PM Stefan Stegic <stefanste...@gmail.com 
> >>>> <mailto:stefanste...@gmail.com>>
> >>>> wrote:
> >>>> 
> >>>>> My knowledge of Java is not so deep, so excuse stupid questions - if
> >>> any.
> >>>>> I believe I am using shading because I'm exporting dependencies into my
> >>>>> JAR. IntelliJ does this for me in the build process by publishing the
> >>> JAR
> >>>>> as an artifact. All I did was specify which dependencies I want to
> >>> package
> >>>>> in there like this:
> >>>>> 
> >>>>> [image: image.png]
> >>>>> 
> >>>>> So, I build the project, grab the published JAR artifact and put the
> >>> file
> >>>>> in the plugins folder of the Spigot server. I then run the Server and
> >>> it
> >>>>> tries to load each plugin JAR that's in there. That's when each of the
> >>>>> onEnable methods are called, including that of my plugin
> >>>>> (FirstSpigotPlugin). The example code that creates the CayenneRuntime
> >>> is in
> >>>>> my onEnable method.
> >>>>> 
> >>>>> Should I be packaging these dependencies differently then?
> >>>>> 
> >>>>> On Wed, Mar 23, 2022 at 4:56 PM Andrus Adamchik <aadamc...@gmail.com 
> >>>>> <mailto:aadamc...@gmail.com>>
> >>>>> wrote:
> >>>>> 
> >>>>>> This is not a common problem with Cayenne. In fact this is the first
> >>>>>> time I see it happen in any environment. So Spigot is special in this
> >>>>>> respect. I found this link:
> >>>>>> https://bukkit.fandom.com/wiki/Using_External_Libraries_with_Plugins 
> >>>>>> <https://bukkit.fandom.com/wiki/Using_External_Libraries_with_Plugins>
> >>> <
> >>>>>> https://bukkit.fandom.com/wiki/Using_External_Libraries_with_Plugins 
> >>>>>> <https://bukkit.fandom.com/wiki/Using_External_Libraries_with_Plugins>>
> >>>>>> It doesn't answer the question, but provides some hints. So how do you
> >>>>>> package your own code and third-party dependencies like Cayenne for
> >>>>>> Spigot/Bukkit? Do you use "shading"?
> >>>>>> 
> >>>>>> Andrus
> >>>>>> 
> >>>>>>> On Mar 23, 2022, at 4:51 PM, Stefan Stegic <stefanste...@gmail.com 
> >>>>>>> <mailto:stefanste...@gmail.com>>
> >>>>>> wrote:
> >>>>>>> 
> >>>>>>> Hi,
> >>>>>>> 
> >>>>>>> Thanks for your quick responses! I'm using version 4.1.1.
> >>>>>>> Right, so you're saying Spigot is somehow blocking the execution of
> >>>>>> said
> >>>>>>> code, or it's circumventing it somehow so that those steps of
> >>>>>>> initialization are never actually executed? Also, you mean that
> >>> it's a
> >>>>>>> common problem with Cayenne or with Spigot and other jars?
> >>>>>>> 
> >>>>>>> How would we go about understanding how the Spigot classpath works?
> >>> It
> >>>>>>> might help to know that the plugin API is called Bukkit, so Spigot
> >>> is
> >>>>>> kind
> >>>>>>> of the parent entity (it's a customized Minecraft server, while
> >>> Bukkit
> >>>>>> is
> >>>>>>> the interface for plugins, as I've come to understand). It's source
> >>>>>> code
> >>>>>>> should be here:
> >>>>>>> https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/browse 
> >>>>>>> <https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/browse>
> >>> .
> >>>>>>> 
> >>>>>>> On Wed, Mar 23, 2022 at 4:33 PM Andrus Adamchik <
> >>> aadamc...@gmail.com <mailto:aadamc...@gmail.com>>
> >>>>>> wrote:
> >>>>>>> 
> >>>>>>>> The bootstrap code is as vanilla as it can get:
> >>>>>>>> 
> >>>>>>>>>> ServerRuntime cayenneRuntime = ServerRuntime.builder()
> >>>>>>>>>>            .addConfig("cayenne-project.xml")
> >>>>>>>>>>            .build();
> >>>>>>>> 
> >>>>>>>> Missing ObjectContextFactory means ServerModule is not loaded in
> >>> the
> >>>>>>>> environment. Since 4.1 (BTW, which version of Cayenne are we
> >>> talking
> >>>>>>>> about?), ServerModule is loaded by processing
> >>>>>>>> 
> >>>>>> 
> >>> "META-INF/services/org.apache.cayenne.configuration.server.CayenneServerModuleProvider"
> >>>>>>>> files from the classpath jars. So there's something about Spigot's
> >>>>>>>> classpath that prevents this code in ModuleLoader from returning
> >>>>>> proper
> >>>>>>>> resources:
> >>>>>>>> 
> >>>>>>>> for (ModuleProvider provider : ServiceLoader.load(providerClass)) {
> >>>>>> ... }
> >>>>>>>> 
> >>>>>>>> We need to understand how Spigot classpath works. Cursory Googling
> >>>>>> shows
> >>>>>>>> that this is a common problem, just don't immediately see a
> >>> solution.
> >>>>>>>> 
> >>>>>>>> Andrus
> >>>>>>>> 
> >>>>>>>> 
> >>>>>>>>> On Mar 23, 2022, at 4:03 PM, Andrus Adamchik <aadamc...@gmail.com 
> >>>>>>>>> <mailto:aadamc...@gmail.com>
> >>>> 
> >>>>>>>> wrote:
> >>>>>>>>> 
> >>>>>>>>> Actually the stack shows that there's already an instance of
> >>> Cayenne
> >>>>>>>> runtime available to the code, but the runtime is in a bad state
> >>> (not
> >>>>>> clear
> >>>>>>>> why). So thread binding should not be required.
> >>>>>>>>> 
> >>>>>>>>> Andrus
> >>>>>>>>> 
> >>>>>>>>> 
> >>>>>>>>>> On Mar 23, 2022, at 4:00 PM, John Huss <johnth...@gmail.com 
> >>>>>>>>>> <mailto:johnth...@gmail.com>>
> >>> wrote:
> >>>>>>>>>> 
> >>>>>>>>>> You have to bind the DI injector to the thread (and unbind it
> >>>>>> later):
> >>>>>>>>>> 
> >>>>>>>>>> 
> >>> CayenneRuntime.*bindThreadInjector*(cayenneRuntime.getInjector());
> >>>>>>>>>> 
> >>>>>>>>>> If you are using servlets, then CayenneFilter will do this for
> >>> you.
> >>>>>>>>>> Otherwise you can bind it at the start of a request and unbind it
> >>>>>> at the
> >>>>>>>>>> end.
> >>>>>>>>>> 
> >>>>>>>>>> On Wed, Mar 23, 2022 at 9:10 AM Stefan Stegic <
> >>>>>> stefanste...@gmail.com <mailto:stefanste...@gmail.com>>
> >>>>>>>>>> wrote:
> >>>>>>>>>> 
> >>>>>>>>>>> Hi Andrus,
> >>>>>>>>>>> 
> >>>>>>>>>>> Of course:
> >>>>>>>>>>> 
> >>>>>>>>>>> org.apache.cayenne.di.DIRuntimeException: DI container has no
> >>>>>> binding
> >>>>>>>> for
> >>>>>>>>>>> key <BindingKey:
> >>>>>> org.apache.cayenne.configuration.ObjectContextFactory>
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> org.apache.cayenne.di.spi.DefaultInjector.getProvider(DefaultInjector.java:158)
> >>>>>>>>>>> ~[?:?]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> org.apache.cayenne.di.spi.DefaultInjector.getProvider(DefaultInjector.java:144)
> >>>>>>>>>>> ~[?:?]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> org.apache.cayenne.di.spi.DefaultInjector.getInstance(DefaultInjector.java:134)
> >>>>>>>>>>> ~[?:?]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> org.apache.cayenne.configuration.CayenneRuntime.newContext(CayenneRuntime.java:124)
> >>>>>>>>>>> ~[?:?]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> io.github.phuskus.firstspigotplugin.StatisticsController.reportPlayerConnectionEvent(StatisticsController.java:20)
> >>>>>>>>>>> ~[?:?]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> io.github.phuskus.firstspigotplugin.FirstSpigotPlugin.onEnable(FirstSpigotPlugin.java:29)
> >>>>>>>>>>> ~[?:?]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>> org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:264)
> >>>>>>>>>>> ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:342)
> >>>>>>>>>>> ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:480)
> >>>>>>>>>>> ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> org.bukkit.craftbukkit.v1_18_R1.CraftServer.enablePlugin(CraftServer.java:521)
> >>>>>>>>>>> ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3443-Spigot-699290c-2c1e499]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> org.bukkit.craftbukkit.v1_18_R1.CraftServer.enablePlugins(CraftServer.java:435)
> >>>>>>>>>>> ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3443-Spigot-699290c-2c1e499]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> net.minecraft.server.MinecraftServer.loadWorld0(MinecraftServer.java:612)
> >>>>>>>>>>> ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3443-Spigot-699290c-2c1e499]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> net.minecraft.server.MinecraftServer.loadLevel(MinecraftServer.java:414)
> >>>>>>>>>>> ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3443-Spigot-699290c-2c1e499]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>>>> 
> >>>>>> 
> >>> net.minecraft.server.dedicated.DedicatedServer.e(DedicatedServer.java:262)
> >>>>>>>>>>> ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3443-Spigot-699290c-2c1e499]
> >>>>>>>>>>>     at
> >>>>>>>> net.minecraft.server.MinecraftServer.w(MinecraftServer.java:994)
> >>>>>>>>>>> ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3443-Spigot-699290c-2c1e499]
> >>>>>>>>>>>     at
> >>>>>>>>>>> 
> >>>>>> 
> >>> net.minecraft.server.MinecraftServer.lambda$0(MinecraftServer.java:304)
> >>>>>>>>>>> ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3443-Spigot-699290c-2c1e499]
> >>>>>>>>>>>     at java.lang.Thread.run(Thread.java:833) [?:?]
> >>>>>>>>>>> 
> >>>>>>>>>>> On Wed, Mar 23, 2022 at 11:49 AM Andrus Adamchik <
> >>>>>> aadamc...@gmail.com <mailto:aadamc...@gmail.com>>
> >>>>>>>>>>> wrote:
> >>>>>>>>>>> 
> >>>>>>>>>>>> Hi Stefan,
> >>>>>>>>>>>> 
> >>>>>>>>>>>> Could you include a full stack trace please?
> >>>>>>>>>>>> 
> >>>>>>>>>>>> Thanks,
> >>>>>>>>>>>> Andrus
> >>>>>>>>>>>> 
> >>>>>>>>>>>>> On Mar 23, 2022, at 1:04 AM, Stefan Stegic <
> >>>>>> stefanste...@gmail.com <mailto:stefanste...@gmail.com>>
> >>>>>>>>>>>> wrote:
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> Hi,
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> First some context: I'm working on a custom Minecraft server
> >>>>>> (Spigot)
> >>>>>>>>>>>>> plugin. It's just a JAR that you export and place somewhere in
> >>>>>> the
> >>>>>>>>>>>> server's
> >>>>>>>>>>>>> folder structure.
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> I wrote a simple insert query via Cayenne's API. It works
> >>> when I
> >>>>>> run
> >>>>>>>>>>> the
> >>>>>>>>>>>>> example JAR directly via executing Main from the command line
> >>>>>> (java
> >>>>>>>> -cp
> >>>>>>>>>>>>> myPlugin.jar path.to.Main), but it fails with the following
> >>> error
> >>>>>>>> when
> >>>>>>>>>>>>> executed by the server in my plugin's OnEnable lifecycle hook:
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> org.apache.cayenne.di.DIRuntimeException: DI container has no
> >>>>>> binding
> >>>>>>>>>>> for
> >>>>>>>>>>>>> key <BindingKey:
> >>>>>>>> org.apache.cayenne.configuration.ObjectContextFactory>
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> My initial theory was that it's being executed from a
> >>> different
> >>>>>>>> thread,
> >>>>>>>>>>>> so
> >>>>>>>>>>>>> the DI system might not have access to that dependency for
> >>> some
> >>>>>>>> reason,
> >>>>>>>>>>>> but
> >>>>>>>>>>>>> it seems like the server executes this lifecycle hook from the
> >>>>>> main
> >>>>>>>>>>>> thread
> >>>>>>>>>>>>> as well (though they've named the thread "Server thread", and
> >>> I
> >>>>>> don't
> >>>>>>>>>>>> know
> >>>>>>>>>>>>> how to check if it's the main thread for sure). Not sure if
> >>> this
> >>>>>> is a
> >>>>>>>>>>>>> promising direction to pursue, but I got the hunch by looking
> >>> at
> >>>>>> the
> >>>>>>>>>>>>> threadInjector bits of Cayenne's DI container docs.
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> My example looks like this:
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> ServerRuntime cayenneRuntime = ServerRuntime.builder()
> >>>>>>>>>>>>>            .addConfig("cayenne-project.xml")
> >>>>>>>>>>>>>            .build();ObjectContext ctx =
> >>>>>>>>>>> cayenneRuntime.newContext();
> >>>>>>>>>>>>> PlayerConnectionEvent newEvent =
> >>>>>>>>>>>>> ctx.newObject(PlayerConnectionEvent.class);
> >>>>>>>>>>>>> newEvent.setEventType(eType);
> >>>>>>>>>>>>> newEvent.setPlayerName(playerName);
> >>>>>>>>>>>>> newEvent.setIpAddress(ipAddress);
> >>>>>>>>>>>>> newEvent.setTimestampUnixSeconds(unixSeconds);
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> ctx.commitChanges();
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> Some help would be greatly appreciated, thanks in advance!
> >>>>>>>>>>>>> --
> >>>>>>>>>>>>> S poštovanjem,
> >>>>>>>>>>>>> *Stefan Stegić*
> >>>>>>>>>>>> 
> >>>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>>>>> --
> >>>>>>>>>>> S poštovanjem,
> >>>>>>>>>>> *Stefan Stegić*
> >>>>>>>>>>> 
> >>>>>>>>> 
> >>>>>>>> 
> >>>>>>>> 
> >>>>>>> 
> >>>>>>> --
> >>>>>>> S poštovanjem,
> >>>>>>> *Stefan Stegić*
> >>>>>> 
> >>>>>> 
> >>>>> 
> >>>>> --
> >>>>> S poštovanjem,
> >>>>> *Stefan Stegić*
> >>>>> 
> >>>> 
> >>>> 
> >>>> --
> >>>> S poštovanjem,
> >>>> *Stefan Stegić*
> >>>> 
> >>> 
> >> 
> >> 
> >> --
> >> S poštovanjem,
> >> *Stefan Stegić*
> >> 
> > 
> > 
> > -- 
> > S poštovanjem,
> > *Stefan Stegić*
> 
> 
> 
> -- 
> S poštovanjem,
> Stefan Stegić
> 
> 
> -- 
> S poštovanjem,
> Stefan Stegić

Reply via email to