How to use different bootclasspaths in Bazel workspace? - java

I'm currently trying to build a Bazel 0.11.1 workspace with projects that use different Java language levels. The actual application uses Java 7, but for some code that won't ship, I want to settle with a more recent Java version to be able to use the new language features.
I can solve this to some extent by using --javacopt in .bazelrc, setting -source 1.7 -target 1.7 and override the defaults on a project level with the javacopts attribute, but this is not enough to ensure proper Java 7 compatibility when compiling with a more recent Java version. For this I really need to compile Java 7 projects against a Java 7 classpath as well.
The only way to use a custom bootclasspath seems to be via java_toolchain. It works. But I could not found a way to use different bootclasspaths for different projects, because the toolchain affects all projects and unlike with javacopts cannot be overridden at the project level.
Is this a usecase that is simply not (yet?) possible with Bazel? Or is there some trickery to make it work?

It turns out there is a way: write a custom rule that performs compilation.
The java_common module provides an interface to the compiler.
library.bzl
def _impl(ctx):
deps = []
for dep in ctx.attr.deps:
if java_common.provider in dep:
deps.append(dep[java_common.provider])
output_jar = ctx.new_file("lib{0}.jar".format(ctx.label.name))
runtime = java_common.JavaRuntimeInfo
compilation_provider = java_common.compile(
ctx,
source_jars = ctx.files.srcs_jars,
source_files = ctx.files.srcs,
output = output_jar,
javac_opts = ctx.attr.javac_opts,
deps = deps,
strict_deps = ctx.attr.strict_deps,
java_toolchain = ctx.attr.toolchain,
host_javabase = ctx.attr._host_javabase,
resources = ctx.files.resources,
neverlink = ctx.attr.neverlink,
)
return struct(
files = depset([output_jar]),
providers = [compilation_provider],
)
library = rule(
implementation = _impl,
attrs = {
"srcs_jars": attr.label_list(allow_files=True),
"srcs": attr.label_list(allow_files=True),
"javac_opts": attr.string_list(default=[]),
"deps": attr.label_list(),
"strict_deps": attr.string(default="ERROR"),
"toolchain": attr.label(default=Label("#bazel_tools//tools/jdk:toolchain")),
"sourcepath": attr.label_list(),
"resources": attr.label_list(),
"neverlink": attr.bool(default=False),
"_host_javabase": attr.label(default=Label("#local_jdk//:jdk")),
},
fragments = ["java"],
)
This rule I can now use to set a different toolchain for compilation.
BUILD
load('//build/jdk:library.bzl', 'library')
library(
name = "test",
srcs = glob(["src/main/java/**/*.java"]),
# data = glob(["src/main/resources/**"]),
toolchain = "//build/jdk:jdk8",
deps = ["..."],
)
Unfortunately I'm not 100% there yet. java_common.compile does not seem to have an equivalent for the data attribute of java_library, but for the most part the toolchain problem is solved.

Related

No such field exception while loading "scl" field from Classloader

I am moving my code from JDK 8 to Open JDK 12. While doing so, I am facing following issue :
java.lang.NoSuchFieldException: scl
while trying to call ClassLoader.class.getDeclaredField("scl"). This was working fine in Java 8 but no longer works in newer Java versions.
I did some findings and believe it has got to do with the way working of reflection and use of internal Java packages have changed since Java 8.
Set<URL> classLoaderUrls = computeClassLoaderUrls();
ClassLoader bootstrapClassLoader = ClassLoader.getSystemClassLoader().getParent();
this.classLoader = new URLClassLoader(classLoaderUrls.toArray(new URL[classLoaderUrls.size()]), bootstrapClassLoader);
Field systemClassLoaderField = ClassLoader.class.getDeclaredField("scl");
systemClassLoaderField.setAccessible(true);
this.initialSystemClassLoader = (ClassLoader) systemClassLoaderField.get(null);
systemClassLoaderField.set(null, this.classLoader);
I want to know , if the way to access these classloader and its fields has changed or should I use some other field instead of scl. Thanks

I am trying to draw a line using an svg libraray in Java , but I am not able to create OMSVGPathSegList

My gwt code in java looks like this
OMSVGDocument doc = OMSVGParser.currentDocument();
OMSVGSVGElement svg = doc.createSVGSVGElement();
OMSVGPathElement path = doc.createSVGPathElement();
OMSVGPathSegList segs = path.getPathSegList();
the return value segs is null and hence I am not able to use OMSVGPathSegList to draw.
Java Version = 1.7 and gwt version is 2.8.2. Is this a version problem?
What could be the problem ?
The problem was with the version of svg-lib , java and gwt. The following combinations worked for me java 1.8 , gwt 2.8.2 , svg-lib 0.5.14 .

Eclipse Aether not resolving `LATEST` correctly

Eclipse Aether doesn't seem to return the correct release when I try to resolve a LATEST version:
val artifact = DefaultArtifact("org.testng:testng:LATEST")
val versionResult = system.resolveVrsion(session, VersionRequest(artifact, repositories, null))
println(versionResult)
produces:
6.9.8 # maven (https://jcenter.bintray.com/, default, releases+snapshots)
However, 6.9.10 is the latest, and JCenter is reporting it correctly, both in the directory and also in the maven-metadata.xml:
<metadata>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.10</version>
<versioning>
<latest>6.9.10</latest>
<release>6.9.10</release>
Why am I getting 6.9.8 instead of 6.9.10?
There are two things which might the cause of your problem. First you assume that the magic word LATEST is supported by Aether and if i remember correctly (and looking into the code of Aether it is not supported). This means you should use a version range to get the latest.
Furthermore if you have a version range you need to call resolveVersionRange(...) instead of resolveVersion(..).
String versionRange = "[0,)";
Artifact artifact =
new DefaultArtifact( "org.testng:testng:jar:" + versionRange );
VersionRangeRequest rangeRequest = new VersionRangeRequest();
rangeRequest.setArtifact( artifact );
rangeRequest.setRepositories( remoteRepos );
VersionRangeResult rangeResult = repository.resolveVersionRange( repositorySystemSession, rangeRequest );
List<Version> versions = rangeResult.getVersions();
The above is a slightly modified version taken from a plugin i wrote. There is also a ctor of DefaultArtifact which contains only the appropriate parameters which might be a better alternative to use instead of concatenating the strings.

z3 java api using mkOptimize

I am using the optimization option of z3 in the java api via context.mkOptimize(). When I execute my code it will show me the following error:
java.lang.UnsatisfiedLinkError: com.microsoft.z3.Native.INTERNALmkOptimize(J)J
My Code:
Context context = new Context();
Optimize mkOptimize = context.mkOptimize();
IntExpr intTest = context.mkIntConst("test");
IntExpr intTen = context.mkInt(10);
BoolExpr assertInt = context.mkLe(intTest, intTen);
mkOptimize.Add(assertInt);
mkOptimize.MkMaximize(intTest);
mkOptimize.Check();
Am I doing something wrong or is this a bug in the java api?
(The exception is thrown when creating the optimize object in the second line)
Found the problem. It was due to the system path which was pointing to two different versions of z3 libraries.

SURF and SIFT algorithms doesn't work in OpenCV 3.0 Java

I am using OpenCV 3.0 (the latest version) in Java, but when I use SURF algorithm or SIFT algorithm it doesn't work and throws Exception which says: OpenCV Error: Bad argument (Specified feature detector type is not supported.) in cv::javaFeatureDetector::create
I have googled, but the answers which was given to this kind of questions did not solve my problem. If anyone knows about this problem please let me know.
Thanks in advance!
Update: The code below in third line throws exception.
Mat img_object = Imgcodecs.imread("data/img_object.jpg");
Mat img_scene = Imgcodecs.imread("data/img_scene.jpg");
FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
MatOfKeyPoint keypoints_object = new MatOfKeyPoint();
MatOfKeyPoint keypoints_scene = new MatOfKeyPoint();
detector.detect(img_object, keypoints_object);
detector.detect(img_scene, keypoints_scene);
If you compile OpenCV from source, you can fix the missing bindings by editing opencv/modules/features2d/misc/java/src/cpp/features2d_manual.hpp yourself.
I fixed it by making the following changes:
(line 6)
#ifdef HAVE_OPENCV_FEATURES2D
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
#include "features2d_converters.hpp"
...(line 121)
case SIFT:
fd = xfeatures2d::SIFT::create();
break;
case SURF:
fd = xfeatures2d::SURF::create();
break;
...(line 353)
case SIFT:
de = xfeatures2d::SIFT::create();
break;
case SURF:
de = xfeatures2d::SURF::create();
break;
The only requirement is that you build opencv_contrib optional module along with your sources (you can download the git project from https://github.com/Itseez/opencv_contrib and just set its local path on opencv's ccmake settings.
Oh, and keep in mind that SIFT and SURF are non-free software ^^;
That is because they are not free in newer versions of OpenCV (3+). I faced that problem some time ago. You have to:
Download OpenCV (if you have not)
Download the nonfree part from opencv github repo
Generate the makefiles with cmake -DBUILD_SHARED_LIBS=OFF specifying the nonfree part with DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules option and build with make -j8 (or whatever Java version you use)
Edit features2d_manual.hpp file, including opencv2/xfeatures2d.hpp and including the necessary code for SIFT and SURF case, which are commented and not defined:
fd=xfeatures2d::SIFT::create(); for SIFT descriptor and de = xfeatures2d::SIFT::create(); for SIFT extractor. Do the same for SURF if you want to use it too.
I wrote this post explaining step by step how to compile the non-free OpenCV part in order to use privative tools like SIFT or SURF.
Compile OpenCV non-free part.
I believe changing features2d module (FeatureDetector class or any other classes from features2d_manual.hpp) to enable methods from OpenCV contrib modules is less attractive approach because it leads to circular dependency between the "core" OpenCV and extensions (which can be non-free or experimental).
There is another way to fix this issue without affecting feature2d classes. Making changes in xfeatures2d CMakeLists.txt as described here leads to generation of java wrappers for SIFT and SURF - opencv-310.jar has org.opencv.xfeatures2d package now. Some fix was required in /opencv/modules/java/generator/gen_java.py. Namely inserted 2 lines as shown below:
def addImports(self, ctype):
if ctype.startswith('vector_vector'):
self.imports.add("org.opencv.core.Mat")
self.imports.add("org.opencv.utils.Converters")
self.imports.add("java.util.List")
self.imports.add("java.util.ArrayList")
self.addImports(ctype.replace('vector_vector', 'vector'))
elif ctype.startswith('Feature2D'): #added
self.imports.add("org.opencv.features2d.Feature2D") #added
elif ctype.startswith('vector'):
self.imports.add("org.opencv.core.Mat")
self.imports.add('java.util.ArrayList')
if type_dict[ctype]['j_type'].startswith('MatOf'):
self.imports.add("org.opencv.core." + type_dict[ctype]['j_type'])
else:
self.imports.add("java.util.List")
self.imports.add("org.opencv.utils.Converters")
self.addImports(ctype.replace('vector_', ''))
After these changes wrappers are generated successfully. However the main problem still remains, how to use these wrappers from Java )). For example SIFT.create() gives the pointer to a new SIFT class but calling any class method (for instance detect()) crashes Java. I also noticed that using MSER.create() directly from Java leads to the same crash.
So it looks like the problem is isolated to the way how Feature2D.create() methods are wrapped in Java. The solution seems to be the following (again, changing /opencv/modules/java/generator/gen_java.py):
Find the string:
ret = "%(ctype)s* curval = new %(ctype)s(_retval_);return (jlong)curval->get();" % { 'ctype':fi.ctype }
Replace it with the following:
ret = "%(ctype)s* curval = new %(ctype)s(_retval_);return (jlong)curval;" % { 'ctype':fi.ctype }
Rebuild the opencv. That is it, all create() methods will start working properly for all children of Feature2D class including experimental and non-free methods. FeatureDescriptor/DescriptorExtractor wrappers can be deprecated I think as Feature2D is much easier to use.
BUT! I'm not sure if the suggested fix is safe for other OpenCV modules. Is there a scenario when (jlong)curval needs to be dereferenced? It looks like the same fix was suggested already here.

Categories

Resources