Is there anything similar to Python virtualenv for Java or JVM Languages?
From what I understand, virtualenv enables you to have separate library installation paths, effectively separate "virtual" Python installations.
Java doesn't have the concept of a "system-wide installed" library(*): It always searches the classpath for the libraries to be loaded. Since the classpath can be (and needs to be!) defined for each application, each application can pick-and-choose which libraries and which versions it wants to load.
If you go down one level deeper and have a single application that somehow needs two different versions of the same library at the same time, then you can do even that with some classpath trickery. It can get complicated, but it's definitely possible (OSGi is one example where this is supported, even Tomcat with two separate webapplications does this).
I've seens some references to security in the virtualenv description: Java has a pretty thorough security system built in. In server applications it's often turned off because it's just easier to configure this way, but you can easily configure what exactly a Java application is allowed to do.
(*) Almost, there are extensions or extension libraries, but they aren't used a lot and even those can easily be loaded from arbitrary directories.
Build tools like Ant, Maven, and gradle are the the closest thing to pip or easy_install.
The concept of virtualenv is done by the classpath. So there is no real need of virtualenv for Java
Yes(see http://www.jenv.be/), like many other languages (Ruby, Python, Go, R, Php, etc. etc.).
I know this may be a little late , but Groovy/Java has gvm http://gvmtool.net/ which is the Groovy version of Ruby's renv.
I would respectfully agree with Gautam K, luthur. Dependency and package version management for projects is not the same as an isolated self-contained virtual environment to maintain different project.
My 2 cents
-W
I have also been looking for a similar solution to simplify switching context between projects that use different Maven versions/settings and/or Java SDKs without having to modify M2_HOME and JAVA_HOME settings every time.
To this end, I developed a solution that helps execute mvn commands with the appropriate configuration based on per-project settings (stored in a .mvn folder).
See: https://github.com/AlejandroRivera/maven-env
Be aware that this only helps if you're using Maven to build and/or run your project.
I'm confused by the assertion that "Java doesn't have the concept of a 'system-wide installed' library". What would you call the jar files in $JAVA_HOME/jre/lib and $JAVA_HOME/jre/lib/ext?
Regardless of whether or not Java "needs" a tool like virtualenv, it seems that something that allowed you to quickly switch between different Java environments (e.g. Java 6 with such-and-such security extensions, Java 7, etc.) would be handy - even if all it was actually doing under the covers was manipulating the PATH, JAVA_HOME, and CLASSPATH env variables.
Maven, you can explicitly specify which packages you would use in a java project
Java as a language does not need the sandboxing features of virtualenv but a JVM Language like Jython can have VirtualEnv to use different environments without any conflict.
It is outlined in this blog post
Quote:
Get virtualenv installed for Jython. Just type "jeasy_install
virtualenv". Once that finishes you should have a 'virtualenv' tool in
the Jython installation's bin folder.
So when using Jython different frameworks and packages can be used without any conflict with global packages.
Related
In Python, to install a package, you can use pip install package. Is there a similar concept for Java and if so how does one do this? Is this done by adding a dependency to build.gradle? Is a library for Java the equivalent of a package in Python?
I think it's a good question. Mainly because the difference between Java and python.
Let's start at the beginning:
When I develop via python, I'm using https://pypi.org/ in order to explore 3rd-party libraries. Once I find a good candidate I install it via pip install as mentioned in the question. Easy as pie.. thon.. I guess
In Java things are "slightly" different. Although the libraries in java are built the same way (as jar files) there are various building tools provided for Java. That is to say - when you ask "how to import and install a library in java?" it actually depends on you project's configuration
I, in person, loves https://mvnrepository.com/ when using Java. It is clear, informative and most important - it provides (for each library) various build solutions that you can easily use. Didn't find what you are looking for? Getting into trouble? You can always manually download the library jar file and embed it into your project (not ideal for most use-cases but - it is possible)
I attach here an image to make it clear where to find each of the options that I mentioned above in order to make more sense
Happy coding!
Is this done by adding a dependency to build.gradle
Assuming you're actually using Gradle, then yes.
Otherwise, curl/wget JAR files from Maven Central and export CLASSPATH to the location of those JARs is the closest CLI-only equivalent. This approach is error prone because it won't grab transitive dependencies.
Java libraries include packages, yes. Java modules don't work like Python modules, though.
I'm trying to run the open-source Java cookbook using chef-solo and although it shouldn't require any other cookbooks, chef keeps saying that a cookbook required to run this one is missing. First it asked me to install apt, then homebrew, then _build_essentials_. It seems like a never ending list of cookbooks. What am I doing wrong?
This is how I'm running the cookbook:
chef-solo -c solo.rb -o recipe[java]
Where solo.rb is a configuration file with the path to the cookbooks folder.
The same thing also happens when I try to run the WAS cookbook.
In short: Chef does not (yet) support conditional dependencies. That's why all cookbooks that provide resources or recipes that might be used need to be declared as dependency.
The Java cookbook uses resources from many other cookbooks to install Java on different systems, e.g., Windows, Linux, MacOS etc. Therefore, it makes use of other cookbooks, that provide resources for e.g. installing a package under Windows, adding an APT repository etc.
In order to allow the cookbook to either include a recipe or use a resource (e.g. apt_repository) from another cookbook, this one has to be specified as dependency so that it is loaded prior to executing the cookbook (e.g. Java). Otherwise, this resource/recipe would not be known to Chef.
So all of these cookbooks will be loaded during the Chef run, but their code will not be executed. While this feels a bit annoying, esp. in your case when you obviously manually download the cookbooks, this isn't so disturbing when you use Berkshelf for dependency resolution. This is highly recommended.
I was wondering how to include Java itself with a jar file so that people don't have to have Java installed already. Is it possible and if so, how do you do it?
To execute the jar in the first place you'd need to have java installed. So it would be best to include a JRE installer in a separate file if you'r including one. Also, you'd have to have a different installer for each target platform so this would be somewhat impractical for general distribution because of the inflated file size.
This is like asking "Can we include the chicken that lays the egg, in the egg?". Answer, no.
As to solving the bigger problem though, there is at least one strategy that might work well for applets, JWS apps. and (possibly) single Jars of desktop apps. that are launched from a link (I've never tried that, though). This approach uses JS to check for the right JRE before providing a link to the Jar.
In order to get a computer to do something, you need to have code that the operating system knows how to handle. Most modern operating systems do not know how to handle Java code unless you install a Java Runtime Engine - to them JAR files are just ZIP files.
Hence you need some code which can be executed directly (without Java) and the simplest is just to use a Java launcher. Many exist - see Java packaging tools - alternatives for jsmooth, launch4j, onejar - but e.g. launch4j is maintained and supports the <path> tag to specify a relative path to an included JRE. Those are unfortunately rather large, but you could provide two versions. One with the JRE, and one without (which then prompts the user to install a JRE).
What's the best option for packaging and distributing a command line application written in Java, targetting OS/X and Unix?
The executable jar option seems fairly robust, and my distribution doesn't need to be super fancy, so right now I'm just thinking of plonking a bash script next to that with the relevant java invocation and being done with it.
I'm wondering if there's something similar to python's bdist package that would let me easily make nice installers for both target platforms. Or if there's some more obvious way that I'm missing where I can turn the entire distribution in to a executable file that wraps the jar in some way.
Since you are providing a CLI application it may be easiest to just provide the script you already mentioned. I usually try to keep it self-contained, e. g. not referencing external paths / using only relative paths etc. And maybe a readme.txt file.
If you would like to provide a full-blown installer, you might want to take a look at IzPack, a tool for generating installers for Java deliverables. It also allows the wizard to run in console mode, if you do not have a graphical environment available for installation (see the "Features" page in the link above).
In this post, using -jar option ignores all the -cp and $CLASSPATH.
In this post, using -cp option also ignores the $CLASSPATH.
Is there any good reason for them?
It's to avoid clashes in the classpath whenever you distribute your application to run on different environments. In most of the cases you'd like your application to be independent from the platform specific configuration. If the $CLASSPATH contains references to classes with (either unawarely or awarely) the same package and classname, it would get precedence in classloading before the classes which you included in your application's classpath. This may lead to unexpected application behaviour or potential security holes.
jar is supposed to be a standalone program with self-contained libraries. If you want to include other classpaths, you may need to do something like
java -cp jar1:jar2:$CLASSPATH some.class.with.main
BalusC answered the other question.
In both cases, the reason for the restrictions it to avoid1 accidental or wanton / ill-considered overriding of the effective classpath.
If you really want an application to be launchable using "-jar" and to also pick up classes via the user's $CLASSPATH environment variable, you should be able to do this by having the application create its own classloader, or using a custom launcher. (You could even make your application look for a "-cp" argument after the "-jar" argument.)
Likewise, you could modify the behavior in the first case.
However, I think it would be bad idea to do that. The main point of executable JAR files is to isolate the application from the vagaries of the environment in which the user happens to launch the application.
If you want to do hacky things with your application classpath, a simpler approach is to create a wrapper script that assembles the effective classpath however you want to, then launches the application with a "-cp" option. You could even pull the "Class-path" out of various JAR files' manifests and incorporate that ...
1 - Clearly, it doesn't stop someone changing the classpath entirely. But stopping that would be a bad idea, and probably isn't technically possible if we assume that the user can get local admin privilege, etcetera.
There are several reasons why the environment variable CLASSPATH is (and should be) ignored:
A global CLASSPATH for all projects makes no sense at all. It can't be the same for all projects, and you don't want one massive one that's reapplied to all projects.
You can't count on it being set, so depending on it is a bad idea. Code that works on one machine suddenly doesn't work when it's moved. How do you communicate the necessary environment settings? Better not to use them.
Java EE app servers all have their own conventions (e.g., all JARs in WEB-INF/lib and all .class files in WEB-INF/classes are automatically in the CLASSPATH for a web app).
Java EE app servers all ignore global CLASSPATH. They don't count on it.
Java IDEs all have their own conventions for setting a project CLASSPATH. Learn them.
All Java IDEs ignore global CLASSPATH. They don't count on it.
I don't have a global CLASSPATH on any machine that I use. It's not necessary. I'd recommend learning how CLASSPATH works and stop relying on environment variables.
Correct or not, I long for a -jar-cp flag. That would be obvious and direct enough to not be a security risk or break current behavior.
With APIs like java.util.ServiceLoader, it is entirely reasonable to wish to add/remove services from the classpath. You shouldn't have to loose that functionality because you used Main-Class in your manifest.
There is no sane enough reason to explain this apparent "absurdity", in my words. From one of the bugs in the Sun bug database, one can only infer that a developer did not account for the fact that the classpath could be specified via the CLASSPATH environment variable, or via the -cp option. By the time the issue was found, the release was more or less public, with the effect that the fix would cause backward compatibility issues.