Compiling without having to put project files under classpath - java

I want someone to be able to compile the code without then having to set the CLASSPATH to the project directory. Is this possible?

You can set the classpath to be used for the compilation as a parameter passed to the compiler instead of setting an environment variable. The parameter is -classpath or -cp.

The classpath needs to be set somehow, though using the environment variable is not recommended these days. Typically, projects that people are supposed to compile for themselves are distributed with either an Apache Ant build script or a Maven POM descriptor. Both of these build automation systems can do much more than just compilation, but both require some time to learn if you haven't used them before. However, it is time well spent, as they can save you a lot of time on all kinds of repetitive tasks, and both are very commonly used in Java projects.

Use a build tool, like Ant or Maven. They use a project descriptor of one sort or another to manage the classpath for you.

Sounds like you want to create a .jar
The jar tool in the JDK puts your .class files in an archive. Then you can just reference the archive on the classpath or with the -jar flag for the java executable.
If you create a manifest for the jar, you can make the .jar runnable with a click from Windows and most other desktop environments.

Related

how IntelliJ is able to resolve dependencies and run a spring boot (maven) application while from the command line, it is not possible?

I'm curious to know how Intellij can resolve the dependency conflicts? Let me explain my situation. I should work on the spring boot application. It uses Maven. IntelliJ can build and run the application without any problem, but when I make a jar file,
mvn clean package
and run the jar file
java -jar xxx.jar
I faced a java.lang.NoSuchMethodError. Some conflicts on dependencies caused it, and my application uses the wrong version of a jar file.
I want to know how IntelliJ can find the correct jar file which contains the method, while it uses the same pom.xml, which I face error while using with the mvn command.
And is it possible to find that which version of every jar file used by IntelliJ? (I want to use this for correcting the pom file)
Thanks
There is a big difference between runtime and compile time when it comes down to such things.
compiling code (such as mvn package), and writing code (as in, what IntelliJ is doing to ensure that your editing experience is nice; auto-complete dialogs for all the libraries you use, errors if you try to invoke non-existent methods, etcetera) are one thing (let's call it 'write time').
Running your code, as with java -jar xxx.jar is something completely different.
maven and your dependency list is a write time thing. Thus, maven and intellij know where to look for your dependencies, but when you run java -jar xxx.jar, that does not know where to look, and thus, your dependencies aren't found, and thus, NoClassDefFoundError occurs.
That's because that jar file that maven makes just contains your code, it is completely disconnected from your maven file (your maven stuff is not looked up when you run your code at all), and it does not contain your dependencies.
You'd have to ship them separately. There are 3 solutions to this problem:
Preferred solution: jar files contain a so-called manifest, which tells the JVM for example what the name of the main class is within that jar file. It can also contain the class-path (this is in fact the only class-path checked when using java -jar to run jar files; you can't specify a -classpath parameter). This lets you deploy your app such that your app installation looks like:
/usr/local/projects/YourApp/main-app.jar
/usr/local/projects/YourApp/dep/guava.jar
/usr/local/projects/YourApp/dep/mysql-jdbc-connector.jar
/usr/local/projects/YourApp/dep/jdbi.jar
etcetera, and to run this application, just run main-app.jar. This requires the manifest of main-app.jar to contain the entry:
Class-Path: dep/guava.jar dep/mysql-jdbc-connector.jar dep/jdbi.jar
When running the jar, the Class-Path entry is split on spaces, and then each entry is looked up relative to the directory that contains main-app.jar. By shipping the jars separately, it's easy to separately update them or replace them, and deploying a new version is much faster (you just ship the jar(s) that were changed, not all of them. Many apps have hundreds of MBs of deps, whereas their own jar is a few MB at most, makes a big difference for example when pushing deps from your dev machine to the test server!)
This leads to the question: How do you make maven put that Class-Path entry in the output jar file's manifest? The maven-jar-plugin can do the job - see this answer for more details.
Shade in your deps (also called striping, or fatjar, or bigjar)
This is the notion of taking all your deps, rewriting their name to avoid version conflicts, and then making one humongous jar file that contains everything. It has the considerable downside of being a much slower process, especially if you need to push this out to another system for testing. Use the shade plugin to do so.
Don't use java -jar.
java -jar x.jar cannot work unless the jar file either has a Class-Path entry in its manifest, or contains every dep it needs. However, you can also run your java code like so: java -cp main-app.jar:dep/guava.jar:dep/jdbi.jar:/dep/other-deps-here com.foo.YourMainApp. This is.. not convenient, but you could presumably write a shell script or some such. This isn't a very java-like solution, I don't recommend it.

Gradle: Create a non-executable jar and executable shell script with dependent libraries as a package distribution

I am not a big fan of creating fat executable jars for java programs as it involves a massive overhead when I have multiple executable programs from the same project.
I want to be able to create a single library-like jar and create corresponding .sh scripts which pretty much have the structure of:
java -cp classpath_libs main_class program_args...
or any other executable where I can customize it to my needs but in a similar fashion(ex: hadoop jar project_jar main_class classpath_libs program_args). Is this achievable in gradle? if so, how? Note, I need to create multiple scripts using different main classes from a single project.
Key requirement here is to be able to use final fully resolved classpath string.
UPDATE: I have seen examples of using the application plugin but it creates an executable jar with dependent libraries packaged into it. This is NOT what I am looking for.
So far as I have found, it appears there's no plugin that handles this directly. So, I used the java-library plugin, used the configurations.runtime classpath value and created the necessary scripts and the copy task to copy the libraries necessary into the necessary directories. For anyone interested, you may also try the distZip option in application plugin where gradle does create scripts for execution and package the necessary libraries in a distribution. You can take a look at the output of the script to see how the classpath is structured and create something similar.

Eclipse doesn't see CLASSPATH

I have some JAR files on my CLASSPATH environment variable. When I open cmd and enter echo %CLASSPATH%, the paths to those JARs are part of the output. When I try to compile and run a java class through cmd that imports classes from these JARs, it works, and I don't have to add the JARs with -cp.
But when I try to import these classes in Eclipse, it doesn't work. The import cannot be resolved. I have to add them to the build path.
This means that when I get a new version of a library, I have to add it to the build path, and remove the old version, for each project that uses the library. I also have to recompile the projects that I have runnable JARs of, because each uses its own separate copy of the library (which, by the way, just seems wasteful and unnecessary). If it worked as I intended, I'd only have to change the version number in CLASSPATH.
Is it possible to make it work like I intended? Or is there a better way to handle JARs and JAR updates?
You can define a User Library in the preferences and refer to that in your projects' Java Build Paths, changing the JAR files it contains as needed. For updating your runnable jars automatically, that might well be better suited to a system such as Ant or Maven. As for having redundant copies in your Runnable JARs, that's just part of what makes them "runnable."

Where to place java packages like htmlparser?

I am beginning to use java packages like HTMLParser, I have downloaded it and finding that there are many files and directories in it.
I wander, where to place them in my linux system? Is there a convention or a standard?
The quick and dirty answer is "anywhere on the classpath", where the classpath is set either as a system property on the client machine (not recommended), as a temporary system property for the CLI session used to start the JVM (workable from a startup script), or as a commandline parameter to the JVM (usually the preferred choice).
First and second set the CLASSPATH environment variable, see the JDK or JRE documentation for the exact syntax and your operating system's and/or shell scripting documentation as well. Third uses the -cp commandline variable to the Java runtime and compiler, see their documentation for exact syntax.
Where to place the files on the filesystem? For development purposes I typically use a central folder on my computer containing all such libraries and link to that from my IDE or other development environment. For deployment/packaging to end users, it is traditional to have a "lib" subfolder to the product folder that contains all distributable content, and put the jar files in that.
Java packages come in two forms. Source code - all the files and directories you mention - and packaged as jars. A common convention in Java projects is that the project has a lib directory that contains all the jars that the project depends on. These projects often use a shell script which adds all the jars to the Java classpath prior to executing the project code.
However many projects are switching from this method of dealing with dependencies to using a build tool like Apache Maven which automatically handles dependency management. Other alternatives include Ivy or Gradle. For an introduction see the 5 minute introduction to Maven or the Maven 3 tutorial.
Here you write a pom.xml (project object model file) which specifies which libraries (jars) your project uses. Maven then stores all the jars for your different projects in a .m2 directory in your local directory, keeping track of where it obtained them, and their versioning information.
This makes developing much easier as you do not need to create the lib directory or manually manage dependencies. You also avoid a lot of the complexities of setting the classpath, as Maven automatically does this for you during common lifecyle stages such as compilation and test. Recent versions of Eclipse can read the Maven pom and automatically configure your classpath from it.
Once you have built the project, Maven can also help create "fat jars" that contain all the jars your project depends on, via the assembly plugin or the Shade plugin. This makes distributing the code easier when you are building an executable that you want someone to use. If you are distributing a jar, then your pom.xml describes the dependencies of your project, avoiding the need to distribute the jars it depends on.
For laying out files in general on a Linux system consult the Linux Filesystem hierarchy standard.

Installing a new API in Java for OS X

I've downloaded a new api for Java that accesses excel files, but am unsure on how to install it so that it can be imported for use in my program. Help is appreciated. Thanks
To the point: just put it in the classpath.
A classpath is basically a collection of disk file system paths to a root folder where all classes are located like /path/to/package/root and/or paths to the JAR file itself like /path/to/file.jar. You can specify multiple paths in the classpath by a separator character. In Unix based systems like OS X the separator character is the colon : (on Windows it's the semicolon ;).
How and where to specify the classpath depends on how you're compiling and executing the program.
If you're using plain javac to compile the program, then use the -cp argument to specify the compile time classpath. Or if you're using an IDE, then add it to the project's Build Path (which covers both the compile time and runtime classpath).
If you're using java to execute the program as a simple .class file, then use the -cp argument the same way. If you're using java -jar (or doubleclicking the file in some platform specific UI explorer) to execute the program as an executabele .jar file, then you need to specify it in Class-Path entry of the JAR's MANIFEST.MF file. This one can be relative to the JAR file's location.
You don't really have to "install" it - you just have to put it inside the Classpath. For example, if you're using Eclipse, you can right-click on your project, select something like "build path"->"configure build path", then libraries.
That depends on the tools you are using for development. Basically it will have to be included on your classpath for your IDE project for development, and in your runtime classpath at deployment time.
How to accomplish this in development is specific to your project configuration, IDE and how you store dependent jar files in your development environment (i.e. shared lib directory, maven, project lib folder ...).

Categories