How to change the bootclasspath? - java

In a project I use Bazel 0.11.1 running Oracle Java 8 to produce Java 7 compatible .class files. While there are other ways to achieve this, I simply added the necessary source/target options with --javacopt to my .bazelrc.
This works fine, but it is good practice to change the bootclasspath as well, in order to avoid unwanted dependencies to creep in. But how do I achieve this with Bazel?
Adding -bootclasspath to --javacopt does not seem to take effect. So it seems I would have to resort to a custom java_toolchain, but I'm having trouble to get it running at all!
java_toolchain(
name = "__jdk7",
bootclasspath = ["#bazel_tools//tools/jdk:bootclasspath"],
encoding = "UTF-8",
extclasspath = ["#bazel_tools//tools/jdk:extclasspath"],
genclass = ["#bazel_tools//tools/jdk:genclass"],
header_compiler = ["#bazel_tools//tools/jdk:turbine"],
ijar = ["#bazel_tools//tools/jdk:ijar"],
javabuilder = ["#bazel_tools//tools/jdk:javabuilder"],
javac = ["#bazel_tools//third_party/java/jdk/langtools:javac_jar"],
javac_supports_workers = True,
jvm_opts = [
"-XX:+TieredCompilation",
"-XX:TieredStopAtLevel=1",
],
singlejar = ["#bazel_tools//tools/jdk:singlejar"],
source_version = "8",
target_version = "8",
visibility = ["//visibility:public"],
)
yields
Exception in thread "main" java.lang.NoSuchFieldError: ANNOTATION_PROCESSOR_MODULE_PATH
at com.sun.tools.javac.file.Locations.initHandlers(Locations.java:1976)
at com.sun.tools.javac.file.Locations.<init>(Locations.java:145)
at com.sun.tools.javac.file.BaseFileManager.createLocations(BaseFileManager.java:115)
at com.sun.tools.javac.file.BaseFileManager.<init>(BaseFileManager.java:76)
at com.sun.tools.javac.file.JavacFileManager.<init>(JavacFileManager.java:147)
at com.sun.tools.javac.file.JavacFileManager.lambda$preRegister$0(JavacFileManager.java:139)
at com.sun.tools.javac.util.Context.get(Context.java:150)
at com.sun.tools.javac.util.Context.get(Context.java:187)
at com.sun.tools.javac.comp.Enter.<init>(Enter.java:140)
at com.sun.tools.javac.comp.Enter.instance(Enter.java:112)
at com.sun.tools.javac.comp.DeferredAttr.<init>(DeferredAttr.java:109)
at com.sun.tools.javac.comp.DeferredAttr.instance(DeferredAttr.java:99)
at com.sun.tools.javac.comp.Resolve.<init>(Resolve.java:123)
at com.sun.tools.javac.comp.Resolve.instance(Resolve.java:159)
at com.sun.tools.javac.comp.Check.<init>(Check.java:116)
at com.sun.tools.javac.comp.Check.instance(Check.java:104)
at com.sun.tools.javac.comp.Modules.<init>(Modules.java:184)
at com.sun.tools.javac.comp.Modules.instance(Modules.java:174)
at com.sun.tools.javac.code.Symtab.<init>(Symtab.java:481)
at com.sun.tools.javac.code.Symtab.instance(Symtab.java:88)
at com.sun.tools.javac.comp.Attr.<init>(Attr.java:128)
at com.sun.tools.javac.comp.Attr.instance(Attr.java:119)
at com.sun.tools.javac.comp.Annotate.<init>(Annotate.java:105)
at com.sun.tools.javac.comp.Annotate.instance(Annotate.java:80)
at com.sun.tools.javac.jvm.ClassReader.<init>(ClassReader.java:252)
at com.sun.tools.javac.jvm.ClassReader.instance(ClassReader.java:245)
at com.sun.tools.javac.code.ClassFinder.<init>(ClassFinder.java:183)
at com.sun.tools.javac.code.ClassFinder.instance(ClassFinder.java:176)
at com.sun.tools.javac.main.JavaCompiler.<init>(JavaCompiler.java:379)
at com.google.devtools.build.buildjar.javac.BlazeJavaCompiler.<init>(BlazeJavaCompiler.java:41)
at com.google.devtools.build.buildjar.javac.BlazeJavaCompiler.<init>(BlazeJavaCompiler.java:32)
at com.google.devtools.build.buildjar.javac.BlazeJavaCompiler$1.make(BlazeJavaCompiler.java:76)
at com.google.devtools.build.buildjar.javac.BlazeJavaCompiler$1.make(BlazeJavaCompiler.java:67)
at com.sun.tools.javac.util.Context.get(Context.java:150)
at com.sun.tools.javac.main.JavaCompiler.instance(JavaCompiler.java:110)
at com.google.devtools.build.buildjar.javac.BlazeJavacMain.compile(BlazeJavacMain.java:117)
at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder$2.invokeJavac(SimpleJavaLibraryBuilder.java:121)
at com.google.devtools.build.buildjar.ReducedClasspathJavaLibraryBuilder.compileSources(ReducedClasspathJavaLibraryBuilder.java:54)
at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.compileJavaLibrary(SimpleJavaLibraryBuilder.java:124)
at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.run(SimpleJavaLibraryBuilder.java:132)
at com.google.devtools.build.buildjar.BazelJavaBuilder.processRequest(BazelJavaBuilder.java:105)
at com.google.devtools.build.buildjar.BazelJavaBuilder.runPersistentWorker(BazelJavaBuilder.java:67)
at com.google.devtools.build.buildjar.BazelJavaBuilder.main(BazelJavaBuilder.java:45)
Am I doing something wrong?

Try using default_java_toolchain:
load("#bazel_tools//tools/jdk:default_java_toolchain.bzl", "default_java_toolchain")
default_java_toolchain(
name = "__jdk7",
jvm_opts = [
"-Xbootclasspath/p:$(location #bazel_tools//third_party/java/jdk/langtools:javac_jar)",
"-XX:+TieredCompilation",
"-XX:TieredStopAtLevel=1",
],
javac = ["#bazel_tools//third_party/java/jdk/langtools:javac_jar",],
bootclasspath = ["#bazel_tools//tools/jdk:platformclasspath.jar",],
visibility = ["//visibility:public",],
source_version = "7",
target_version = "7",
)
In your .bazelrc file add a reference to the toolchain, e.g.,
build --java_toolchain=//:__jdk7
test --java_toolchain=//:__jdk7

This is the working solution:
default_java_toolchain(
name = "jdk7",
jvm_opts = [
"-Xbootclasspath/p:$(location #bazel_tools//third_party/java/jdk/langtools:javac_jar)",
"-XX:+TieredCompilation",
"-XX:TieredStopAtLevel=1",
],
javac = ["#bazel_tools//third_party/java/jdk/langtools:javac_jar"],
bootclasspath = ["jdk7.jar"],
visibility = ["//visibility:public"],
source_version = "7",
target_version = "7",
)
jdk7.jar has been manually created with the help of DumpPlatformClassPath.java provided below bazel_tools/tools/jdk.

Related

Neovim setting up jdtls with lsp-zero/mason

As part of the upcoming 2023 new year I wanted to try and move my development environment to vim or neovim. I have gone through a bit of setup already and have go and js/ts setup and appearing to work just fine. Autocomplete, linting and import management.
Trying to get lsp-zero and java working though is turning out to be a nightmare (because of course java would be a problem child). I opened a java file lsp-zero was baller and asked to install the jdtls which appears to have worked and voila nothing... I just have code highlighting. No auto-complete or importing management.
I added the following to test
-- configure an individual server
lsp.configure('jdtls', {
flags = {
debounce_text_changes = 150,
},
on_attach = function(client, bufnr)
print('lsp server (jdtls) attached')
end
})
lsp.configure('gopls', {
flags = {
debounce_text_changes = 150,
},
on_attach = function(client, bufnr)
print('lsp server (gopls) attached')
end
})
Java is not picking up the lsp server
Go picks up just fine
Does anyone know of additional configs that are needed. I am not seeing anything specifically called out.
--- Config edit ---
I updated the config to call the windows version of the scripts. I also added a data path and root_dir. The lsp still never triggers.
require'lspconfig'.jdtls.setup{
cmd = {
'jdtls-win.cmd',
"-configuration",
"C:\\Users\\Coury\\AppData\\Local\\nvim-data\\mason\\packages\\jdtls\\config_win",
"-jar",
"C:\\Users\\Coury\\AppData\\Local\\nvim-data\\mason\\packages\\jdtls\\plugins\\org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar",
"-data",
"C:\\Users\\Coury\\Documents\\Code\\interviews\\truleo\\app",
},
single_file_support = true,
root_dir = function()
return "C:\\Users\\Coury\\Documents\\Code\\interviews\\truleo\\app"
end,
flags = {
debounce_text_changes = 150,
},
on_attach = function(client, bufnr)
print('lsp server (jdtls) attached')
end
}
First, include java path to your bashrc. And retry the installation using Mason.nvim
Else: Do below
Install eclipse.jdt.ls by following their Installation instructions.
Add the plugin:
vim-plug: Plug mfussenegger/nvim-jdtls
packer.nvim: use mfussenegger/nvim-jdtls
To solve this you'd have to create your personal jdlts config file in your plugins directory like so
-- Java.lua
local config = {
cmd = {
--
"java", -- Or the absolute path '/path/to/java11_or_newer/bin/java'
"-Declipse.application=org.eclipse.jdt.ls.core.id1",
"-Dosgi.bundles.defaultStartLevel=4",
"-Declipse.product=org.eclipse.jdt.ls.core.product",
"-Dlog.protocol=true",
"-Dlog.level=ALL",
"-Xms1g",
"--add-modules=ALL-SYSTEM",
"--add-opens",
"java.base/java.util=ALL-UNNAMED",
"--add-opens",
"java.base/java.lang=ALL-UNNAMED",
--
"-jar",
"/path/to/jdtls_install_location/plugins/org.eclipse.equinox.launcher_VERSION_NUMBER.jar",
"-configuration", "/path/to/jdtls_install_location/config_SYSTEM",
"-data", "/Users/YOUR_MACHINE_NAME/local/share/nvim/java"
},
settings = {
java = {
signatureHelp = {enabled = true},
import = {enabled = true},
rename = {enabled = true}
}
},
init_options = {
bundles = {}
}
}
Source the new config and open any java file.
I recommend using mfussenegger/nvim-jdtls to run and configure the language server.
Its simply a matter of setting up a FTPlugin for java that calls jdtls.start_or_attach(jdtls_config) whenever a java file/repo is opened which will start the language server and attach it to your buffer which can be verified by :LspInfo.
ftplugin/java.lua:
local jdtls_config = require("myconfig.lsp.jdtls").setup()
local pkg_status, jdtls = pcall(require,"jdtls")
if not pkg_status then
vim.notify("unable to load nvim-jdtls", "error")
return
end
jdtls.start_or_attach(jdtls_config)
and the corresponding config using jdtls (installed via mason)
You may want to provide your own capabilities and on_attach functions but otherwise it should give you a good nudge in the right direction.
myconfig/lsp/jdtls.lua
local opts = {
cmd = {},
settings = {
java = {
signatureHelp = { enabled = true },
completion = {
favoriteStaticMembers = {},
filteredTypes = {
-- "com.sun.*",
-- "io.micrometer.shaded.*",
-- "java.awt.*",
-- "jdk.*",
-- "sun.*",
},
},
sources = {
organizeImports = {
starThreshold = 9999,
staticStarThreshold = 9999,
},
},
codeGeneration = {
toString = {
template = "${object.className}{${member.name()}=${member.value}, ${otherMembers}}",
},
useBlocks = true,
},
configuration = {
runtimes = {
{
name = "JavaSE-1.8",
path = "/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home",
default = true,
},
{
name = "JavaSE-17",
path = "/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home",
},
{
name = "JavaSE-19",
path = "/Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home",
},
},
},
},
},
}
local function setup()
local pkg_status, jdtls = pcall(require,"jdtls")
if not pkg_status then
vim.notify("unable to load nvim-jdtls", "error")
return {}
end
-- local jdtls_path = vim.fn.stdpath("data") .. "/mason/packages/jdtls"
local jdtls_bin = vim.fn.stdpath("data") .. "/mason/bin/jdtls"
local root_markers = { ".gradle", "gradlew", ".git" }
local root_dir = jdtls.setup.find_root(root_markers)
local home = os.getenv("HOME")
local project_name = vim.fn.fnamemodify(root_dir, ":p:h:t")
local workspace_dir = home .. "/.cache/jdtls/workspace/" .. project_name
opts.cmd = {
jdtls_bin,
"-data",
workspace_dir,
}
local on_attach = function(client, bufnr)
jdtls.setup.add_commands() -- important to ensure you can update configs when build is updated
-- if you setup DAP according to https://github.com/mfussenegger/nvim-jdtls#nvim-dap-configuration you can uncomment below
-- jdtls.setup_dap({ hotcodereplace = "auto" })
-- jdtls.dap.setup_dap_main_class_configs()
-- you may want to also run your generic on_attach() function used by your LSP config
end
opts.on_attach = on_attach
opts.capabilities = vim.lsp.protocol.make_client_capabilities()
return opts
end
return { setup = setup }
These examples are yanked from my personal neovim config (jdtls config). Hope this helps get you rolling.
Also make sure you have jdk17+ available for jdtls (i launch neovim with JAVA_HOME set to my jdk17 install)
(your code can still be compiled by and run on jdk8 -- I successfully work on gradle projects that are built with jdk8 no problems w/ this config)

Bazel equivalent of Buck's classpath

I'm trying to migrate a project from buck to bazel and looking for an equivalent of the $(classpath) macro available for genrules. Is there anything similar available in bazel to get a list of jars for the classpath of a given java_library?
The best I could come up with is iterating over the list of dependencies and using the $(execpath) macro to get the correspondent jar:
jar_deps = []
for dep in deps: # deps are the same dependencies specified for the java_library
jar_deps.append("$(execpath %s)" % dep)
genrule(
name = "test-rule",
outs = ["test-rule.txt"],
deps = deps,
cmd = "echo \"%s\" > $#" % (":".join(jar_deps)),
)
Is there a better way?
It looks like another way to achieve this is by using a custom rule accessing the Java rule's JavaInfo provider:
def _runtime_deps_providing_rule_impl(ctx):
return [
platform_common.TemplateVariableInfo({
"RUNTIME_DEPS": ":".join([f.path for f in ctx.attr.rule[JavaInfo].transitive_runtime_deps.to_list()]),
})
]
runtime_deps_providing_rule = rule(
implementation = _runtime_deps_providing_rule_impl,
attrs = {
"rule": attr.label(),
},
)
runtime_deps_providing_rule(
name = "test-providing-rule",
rule = ":test-java-rule",
)
genrule(
name = "test-rule",
outs = ["test-rule.txt"],
cmd = "echo \"$(RUNTIME_DEPS)\" > $#",
toolchains = [":test-providing-rule"],
)
The advantage of this is that there is no need to explicitly pass the list of dependencies around.

What format is this file written on?

I'm messing around with Auctionator (a WoW addon for the auction house). My application is still in development but out of curious i want to know the name for this format.
D:\Blizzard\World of Warcraft\WTF\Account\54621418#1\SavedVariables\Auctionator.lua
AUCTIONATOR_PRICE_DATABASE = {
["__dbversion"] = 4,
["Ragnaros_Horde"] = {
["Kraken's Eye of Agility"] = {
["mr"] = 6019998,
["cc"] = 3,
["H2935"] = 6019998,
["id"] = "153708:0:0:0:0",
["sc"] = 1,
},
["Tidespray Linen Pants of the Harmonious"] = {
["mr"] = 2930810,
["sc"] = 1,
["id"] = "154689:0:0:0:1715",
["L2926"] = 2930810,
["H2926"] = 19698294,
["cc"] = 4,
},
},
}
I ended up parsing the file with lots of indexOf(..) and Patters and Matchers because i couldn't find this format anywhere. Here's a screenshot of the application if you wanna see it.
A LUA file is a source code file written in Lua, a light-weight programming language designed for extending applications. It can be compiled into a program using an ANSI C compiler.
Your file looks like a table/config details
More you can have a look on https://en.wikipedia.org/wiki/Lua_(programming_language)

How can you get 1.7-compatible output for a java_proto_library?

For a java_library, I can set the javacopts attribute on the build rule. There doesn't appear to be anything similar for java_proto_library or java_lite_proto_library.
I can work around this by setting -source and -target options to javac via the -javacopt flag to bazel, but I'd rather have it encoded in the BUILD files.
You could add a JDK7 toolchain and then build everything with it. E.g., add this to a BUILD file:
java_toolchain(
name = "jdk7",
bootclasspath = ["#bazel_tools//tools/jdk:bootclasspath"],
encoding = "UTF-8",
extclasspath = ["#bazel_tools//tools/jdk:extdir"],
genclass = ["#bazel_tools//tools/jdk:GenClass_deploy.jar"],
header_compiler = ["#bazel_tools//tools/jdk:turbine_deploy.jar"],
ijar = ["#bazel_tools//tools/jdk:ijar"],
javabuilder = ["#bazel_tools//tools/jdk:JavaBuilder_deploy.jar"],
javac = ["#bazel_tools//third_party/java/jdk/langtools:javac_jar"],
javac_supports_workers = 1,
jvm_opts = [
"-XX:+TieredCompilation",
"-XX:TieredStopAtLevel=1",
],
singlejar = ["#bazel_tools//tools/jdk:SingleJar_deploy.jar"],
source_version = "7",
target_version = "7",
visibility = ["//visibility:public"],
)
And then build with:
bazel build --java_toolchain=//whatever:jdk7 //your:target

Using Java ProcessBuilder to run native Windows .exe producing error :: The directory name is invalid

I have the following Java code to run a native Windows .exe file using ProcessBuilder
public class HMetis {
private String exec_name = null;
private String[] hmetis_args = {"hmetis.exe", "null", "2", "1", "10", "1", "1", "1", "0", "0"};
private Path path;
private File file;
public HMetis(String hgraph_exec, String hgraph_file) {
this.exec_name = hgraph_exec;
this.hmetis_args[1] = hgraph_file;
}
public void runHMetis() throws IOException {
this.path = Paths.get("C:\\hMetis\\1.5.3-win32");
this.file = new File(path+"\\"+this.exec_name+".exe");
ProcessBuilder pb = new ProcessBuilder(this.hmetis_args);
pb.directory(this.file);
try {
Process process = pb.start();
} finally {
// do nothing
}
}
}
after running this code I am getting the below error although from the message it seems the directory name is fully formed and OK !! Any suggestions please?
Cannot run program "hmetis.exe" (in directory "C:\hMetis\1.5.3-win32\hmetis.exe"):CreateProcess error=267, The directory name is invalid
You are using the complete path to the executable file as the ProcessBuilder's working directory:
this.file = new File(path+"\\"+this.exec_name+".exe");
ProcessBuilder pb = new ProcessBuilder(this.hmetis_args);
pb.directory(this.file);
^
|
++++++++ "C:\hMetis\1.5.3-win32\hmetis.exe"
should be "C:\hMetis\1.5.3-win32"
However, you want to set the working directory only, like
pb.directory(this.path.toFile());
In addition, it seems that ProcessBuilder.directory() does not set the "working directory" as one might expect - at least not to find the executable. A similar issue is described at ProcessBuilder can't find file?!. At least on Windows, executables in the current working directory are usually found first (Unix is a different thing).
An easy fix would be to add the absolute path name to the command array, like
String[] hmetis_args = {"C:\\hMetis\\1.5.3-win32\\hmetis.exe", "null", "2", "1", "10", "1", "1", "1", "0", "0"};
See also
http://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html
http://docs.oracle.com/javase/7/docs/api/java/io/File.html
http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
Did you try to replace
pb.directory(this.file);
with
pb.directory(this.file.getParentFile()); ?

Categories