This question already has answers here:
Unable to derive module descriptor for auto generated module names in Java 9?
(2 answers)
Closed 5 years ago.
I want to use Java 9 in my app. One of my dependencies has a jar name:
sdk-http-ahc-2_0
Unfortunately, when I try to change it to automatic module, the name for the module is not valid.
requires sdk.http.ahc.2_0; // not valid
Am I missing something with naming the module? What are my other options here?
The problem is that the module system does not identify 2_0 as a version number and hence doesn't strip it when determining the automatic module name. Unfortunately, 2_0 is not a valid Java identifier and can hence not be used as a segment in a module name.
The solution is to either rename the JAR or add the Automatic-Module-Name entry to the JAR's manifest:
Create a file manifest.txt with the following content:
Automatic-Module-Name: sdk.http.ahc
Then use jar to append that line to the existing manifest:
jar --update --file sdk-http-ahc-2_0.jar --manifest=manifest.txt
Note that locally modifying existing JARs (name or manifest) can cause problems down the road. Consider changing the Maven version of the file to something like 2.0-patched-auto-name (or similar) and add it to your local Maven repository. If the project is shared with other developers and you have a local Nexus, you can put it in there. Otherwise send a mail to everyone with the steps to add it to their local repo. 😜
Related
I am trying to create a Spigot plugin that allows players to use a compass to track other players. While exporting and running the server, I noticed that it was giving me an error:
[21:57:15 ERROR]: Could not load 'plugins\Manhunt.jar' in folder 'plugins'
org.bukkit.plugin.InvalidDescriptionException: Invalid plugin.yml
at org.bukkit.plugin.java.JavaPluginLoader.getPluginDescription(JavaPluginLoader.java:172) ~[patched_1.16.5.jar:git-Paper-683]
at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager.java:148) ~[patched_1.16.5.jar:git-Paper-683]
at org.bukkit.craftbukkit.v1_16_R3.CraftServer.loadPlugins(CraftServer.java:389) ~[patched_1.16.5.jar:git-Paper-683]
at net.minecraft.server.v1_16_R3.DedicatedServer.init(DedicatedServer.java:252) ~[patched_1.16.5.jar:git-Paper-683]
at net.minecraft.server.v1_16_R3.MinecraftServer.w(MinecraftServer.java:1066) ~[patched_1.16.5.jar:git-Paper-683]
at net.minecraft.server.v1_16_R3.MinecraftServer.lambda$a$0(MinecraftServer.java:290) ~[patched_1.16.5.jar:git-Paper-683]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_291]
Caused by: java.io.FileNotFoundException: Jar does not contain plugin.yml
... 7 more
I have never seen this error before and I'm not sure how to fix it. I have made sure to export the .yml file while in Eclipse, but it still shows me this error.
The plugin.yml file is a required part of a SpigotMC plugin that defines some basic information about the plugin like its name and the version of the Spigot API that it uses. For example, here's one for a Minecraft plugin I'm currently working on.
The error you're getting comes from that file not getting bundled into the jar. As a result, when the Spigot server tries to load your plugin, it can't find the plugin.yml because it's literally not present in your compiled jar.
I recommend setting up a build system like Gradle or Maven that will handle the complexities of building the jar for you independent of the IDE you use.
Set up a SpigotMC plugin using Maven
Set up a SpigotMC plugin using Gradle
I personally use Gradle, so feel free to see how I implemented it in one of my plugins. If you'd prefer Maven, there are many examples available including the popular Multiverse-Core.
You need the plugin.yml to run your plugin. If you're using spigot or bukkit, you should make your plugin.yml inside the src folder, in there, you need to include a minimum of:
name: (plugin name, no spaces allowed in name)
author: (your name)
version: (your plugin version)
api-version: (use 1.14)
main: (your main class)
description: (optional description, otherwise delete this line)
then you can export or rebuild the jar
This is an example of what my plugin.yml looks like:
name: ThornsPlugin
version: 1.0
author: MOREORLESS
api-version: 1.14
main: com.MOREORLESS.plugin.plugin
description: MC Stuff
Learn more about Plugin.yml here: https://www.spigotmc.org/wiki/plugin-yml/
How can we create a Maven test jar with Java 11 modules?
The only way I found is to add a module-info.java file to test/java and change the module name (e.g. append ".test"). Then provide the class in a separate package (e.g. append ".test") and export that package:
module my.module.test {
requires my.module;
exports my.module.test;
}
Otherwise the classes are not visible or I get split package issues.
But this isn't really the purpose of the test-jar goal and it limits access to "my.module".
What is the proper way to use test-jar with Java 11 modules? Or should it be avoided?
I want to migrate my old java code to the java9 modules. E.g. in the classpath there is a jar-file named org.eclipse.jface.3.7.0.v20110928.jar. In the classpath it is referenced as org.eclipse.jface_3.7.0.v20110928.jar. The point in the filename after jface is replaced with an underscore in the classpath. Don't know how it works. Maybe it is because .3.7.0. is not a legal java identifier.
But now I want to use it as a module. I get an error for the modulename. The part '.7.0.' is not allowed, because a number can not be a java identifier. The underscore is a reserved word in java9.
First I used the same name for the module as it saw it in the classpath (org.eclipse.jface_3.7.0.v20110928.jar). But it is an error. The I tried to use the name of the file (org.eclipse.jface.3.7.0.v20110928.jar), same error.
module iDEpdf.src
{
exports org.idepdf.ri.common.utility.annotation;
...
requires org.eclipse.jface.3.7.0.v20110928;
}
'.3.7.0' is marked and the error is 'illegal token'. When I use org.eclipse.jface_3.7.0.v20110928 the marked substring is '.7.0'. The error is the same.
If it is possible I don't want to rename the jar-file. I don't understand how it works for the classpath and I don't understand why it does not work for the module. How should I handle this?
I think you are using a very old library of JFace. You probably need to update or add Automatic-Module-Name.
Since the library doesn’t have a module descriptor yet, the module isn’t recognized as valid.
My question is also: why migrate to the module system before updating libraries to recent versions?
Please also see this question or this one.
I need some help in compiling my java project through an ANT file.
Lets there are five subproject in my complete project.
Each subproject has its own ant file to compile it.
for example:
subprojectA
subprojectB
subprojectC
subprojectD
subprojectE
Now the situation is :
I am using some classes of "subprojectC" in "subprojectA" but as my compilation sequence is 1,2 3,4,5, I am getting error as class can not be resolved while compiling subprojectA.
So, the question is, is it possible to somehoe specify or tell ANT file of "subprojectA" that these classes will be present in future in suppose jarx.
I am looking some kind of forward lookup in ant file.
Thank You
A project runs on Google App Engine. The project has dependency that uses a class that can't be invoked on App Engine due to security constraints (it's not on the whitelist). My (very hacky) solution was to just copy a modified version of that class into my project (matching the original Class's name and package) that doesn't need the restricted class. This works on both dev and live, I assume because my source appears in the classpath before my external dependencies.
To make it a bit cleaner, I decided to put my modified version of that class into it's own project that can be packaged up in a jar and published for anyone else to use should they face this problem.
Here's my build.gradle:
// my jar that has 'fixed' version of Class.
compile files('path/to/my-hack-0.0.1.jar')
// dependency that includes class that won't run on appengine
compile 'org.elasticsearch:elasticsearch:1.4.4'
On my local dev server, this works fine, the code finds my hacked version of the class first at runtime. On live, for some unknown reason, the version in the elasticsearch dependency is loaded first.
I know having two versions of the same class in the classpath isn't ideal but I was hoping I could reliably force my version to be at the start of the classpath. Any ideas? Alternatively, is there a better way to solve this problem?
Not really sure if this is what people visiting this question were looking for, but this was what my problem and a solution that I reached at.
Jar A: contains class XYZ
Jar B: also contains class XYZ
My Project needs Jar B on the classpath before Jar A to be able to get compiled.
Problem is Gradle sorts the dependencies based on alphabetical order post resolving them which meant Jar B will be coming after Jar A in the generated classpath leading to error while compiling.
Solution:
Declare a custom configuration and patch the compileClasspath. This is how the relevant portion of build.gradle might look like.
configurations {
priority
sourceSets.main.compileClasspath = configurations.priority + sourceSets.main.compileClasspath
}
dependencies {
priority 'org.blah:JarB:2.3'
compile 'org.blah:JarA:2.4'
...
}
It's the app engine classloader I should have been investigating, not gradle...
App Engine allows you to customise the class loader JAR ordering with a little bit of xml in your appengine-web.xml. In my case:
<class-loader-config>
<priority-specifier filename="my-hack-0.0.1.jar"/>
</class-loader-config>
This places my-hack-0.0.1.jar as the first JAR file to be searched for classes, barring those in the directory war/WEB-INF/classes/.
...Thanks to a nudge in the right direction from #Danilo Tommasina :)
UPDATE 2020:
I just hit the same problem again and came across my own question... This time, live appengine was loading a different version of org.json than was being loaded in dev. Very frustrating and no amount of fiddling the build script would fix it. For future searchers, if you're getting this:
java.lang.NoSuchMethodError: org.json.JSONObject.keySet()Ljava/util/Set;
It's because it's loading an old org.json dependency from god-knows-where. I fixed it by adding this to my appengine-web.xml:
<class-loader-config>
<priority-specifier filename="json-20180130.jar"/>
</class-loader-config>
You'll also need a matching dependency in build.gradle if you don't already have one:
compile 'org.json:json:20180130'
According to gradle dependencies documentation, the order of dependencies defines the order in the classpath. So, we can simply put the libraries in the correct order in "dependencies".
But beware! here are two rules with higher priorities:
For a dynamic version, a 'higher' static version is preferred over a 'lower' version.
Modules declared by a module descriptor file (Ivy or POM file) are preferred over modules that have an artifact file only.