Build single class in IntelliJ using dependencies previously built by maven - java

I have a application using a maven build and am using IntelliJ IDEA. Both Maven and IntelliJ build classes into the same target folder, however whenever I choose to rebuild a single class in IntelliJ it complains that it cannot find it's dependencies, even if maven just built them and they are in the output folders. If I do a full rebuild in IntelliJ it will build the class.
How do I make IntelliJ use the classes maven built as dependencies for the single class it is building?

If it's purely class files, I'm not sure why it'd be complaining if they're all under the directory you have configured IntelliJ to use for the project's compiled classes.
More frequently, what I've run into is the build creates some things other than class files and you have to create a library that points at that other stuff so that IntelliJ knows about them. Another wrinkle are resource files as those are hunted for relative to the project's working directory which is, by default, usually the root directory of the project which is rarely correct as most resources are dumped under a "build" or "deploy" directory.
If all else fails, you should be able to spit out verbose Maven build info and compare the classpath it's using at compile time to the one that IntelliJ uses to try and figure out where they differ.

Related

Steps to change IntelliJ GitHub project to download and build source code for dependencies

Using IntelliJ IDEA, it is often a straight-forward task to check out a project from GitHub and get it to build locally.
Once the base project is imported from GitHub, the IDE will download artifacts which will allow the main project to run. The dependencies can be examined by using File > Project Structure... > Libraries.
So the IDE downloads dependencies to allow running, but not to build from source. The IDE is able to decompile classes, but the IDE will not automatically download the source code for those dependency libraries so that the programmer can alter the code.
This question is about the steps required in the IDE and project configuration such that a selected dependency will be built locally, and thus allow the programmer to alter the code.
What I tried was to import the project on which the main project was dependent, as a separate project, then configure the main project to utilize the local project instead of the downloaded artifact. The first step, downloading the sub-project and getting it to compile, was completed successfully.
So I ended-up with two projects, the main one, and the one on which the main project depended. The task at hand, if this was the appropriate way to get this done, would be to open the main project and take some action to convince the main project to use the local build, rather than the downloaded runtime "jar".
First, I edited the POM.xml to comment out the dependency for the sub project. Checking File > Project Structure... > Libraries, I could see that it was gone, and the build now failed (as expected).
I went to File > Project Structure... > Libraries > + (plus sign) and poked around with New Module, and Import Module, but I was not able to convince the original project to use the locally available sub project. The result from various attempts was that code in the base project was not able to import from the sub project (unable to compile).
What are the specific steps to take in the IDE to get what was a runtime dependency "jar file" to instead to build locally, and use that instead?
Use a SNAPSHOT version for the dependency (you'll need to change this in both your project's pom.xml and the dependency's pom.xml, so if the current version is 2.0.0 change it to 2.0.0-SNAPSHOT)
Then you can edit the dependency's code and run mvn install in the dependency to provide the new version of the dependency to your project.
TLDR: there is no simple and straight-forward way of downloading a project's code and the code of its dependencies to rebuild it in one go as a complete chain.
Your project depends on several other artifacts. From the screenshot, we may assume that this is a maven project, at least we can be sure that there artifacts with compiled classes available for download, because this happends during build. You can view the compiled classes of your dependencies, because Intelli has the capability of decompressing jars and decompiling code, obviously, but the contents you are viewing is read-only.
Sidenote: Maven convention is to create 3 separate jars for each project. One with compiled classes, one with source files only and one with generated documentation. By default intellij may not download these, but you can force it (right-click on pom.xml -> maven -> Download sources and documentation). This will attach the actual source code instead of decompiled classes to your IDE, so it's much easier to understand the code - but still, there is no option to modify it - it's still read-only extract from some jar.
So what if you want to actually edit the source? You have 3 options, all with its own set of problems that need human intelligence to solve:
You extract the decompiled source from classes jar
You extract the attached source from sources jar
You check out git repository of the dependency
Now, beware of the downsides of each approach:
You can be sure that the decompiled source matches your project dependency 1:1. But decompiled code is not easy to read, missing comments, etc. Also, some projects may not ship their build scripts with the classes jar. Anything more complex than mvn clean install may turn out to be a blocker.
You can be reasonably sure the code matches your project dependency, but this actually is not a given. There is a chance of human error, causing the sources to actually not match the compiled classes (build from different revision or whatnot). Much depends on the quality of the project, the discipline put into the build process and care to avoid environment specific configuration that is not part of the source. The larger and older is the project, the less chances are you are able to recompile it successfully using only src jar.
A sane man's approach. You should have your build scripts, readmes, tutorials, etc. Except, of course, if we are talking some obscure company internal project with zero effort put in its maintenance. Surely, there are the same issues as before: not all projects are rebuilt easily on any environment. There may be steps upon steps required for your workstation to be configured as expected. Hopefully, self-respecting open-source java projects are easy to build, but again - not a given - not all project are open-source, not all are self-respecting.
Important note: When checking out the git repo of your dependency - you must also make sure that you are using correct revision. If the project is maintained with respect for git tags/branches naming convention - you are in luck. Not a given by any means.
All the above is enough to discourage any attempts to automatically decompose dependencies to compilable units by your IDE, and all the burden is put into you. So let's assume the best - our dependency is a simple, self-contained java application that is easily built using simple mvn clean install. You have it checked out in a separate project in your IDE. You identified correct git revision that matches version your project depends on.
Now let's apply your little change and test it. First thing you want to do is change pom.xml of your project to use a made up version of your dependency. It should be a -SNAPSHOT version for clarity and tidiness. You may of course build your modified dependency with real release version - but please be wary of how maven manages dependencies. If you install version 1.0 yourself - it stays in your local repo forever. You will forget about it, and will be using your fake 1.0 version when building all other dependent projects unless you manually locate and remove it from repo. So stick to 1.1-SNAPSHOT.
Now every time you need to apply a small fix to your dependency, execute mvn clean install in its repo, then make sure your actual project depends on the correct new SNAPSHOT version, execute your maven clean install and that's it.
Note that all this has very little to do with Intellij. You are not expected to modify any library paths, advanced project settings, or links to jars. Stick to modifying pom.xml and you are set.

How to separate subproject classpaths in Eclipse?

I know that there is a Git plugin for Eclipse ("Egit"), but I like to do Git stuff on the command line, and I like to code in Eclipse, so I want to keep them separate.
I cloned a Git repo (I don't think its important, but for good measure, it was https://github.com/spinscale/dropwizard-jobs.git). I then opened up Eclipse (Juno) and created a new Java project, and selected the root of the cloned repo as the base path to my project. Eclipse asked me if I wanted to associate the project with the Java facet, and I clicked 'OK'.
This project has a large dependency tree (if you like, check out its 4 POM files). I don't use Maven to build (I use Gradle) so I just ran a script that resolves the dependencies of these POMs into a directory, and then I created a lib directory in this Eclipse project and copied all the JARs into it. I then added all these JARs to the project's classpath.
I am now seeing 10 errors in the Problems view in Eclipse, and they're all similar errors:
The type ApplicationStartTestJob is already defined ApplicationStartTestJob.java /dropwizard-jobs/dropwizard-jobs-core/src/test/java/de/spinscale/dropwizard/jobs line 10 Java Problem
The type ApplicationStartTestJob is already defined ApplicationStartTestJob.java /dropwizard-jobs/dropwizard-jobs-guice/src/test/java/de/spinscale/dropwizard/jobs line 10 Java Problem
8 more all like this, etc.
Sure enough, when I expand the entire project, I see it has the following structure:
dropwizard-jobs/
dropwizard-jobs-core/
src/test/java/
de.spinscale.dropwizard.jobs
ApplicationStartTestJob.java
dropwizard-jobs-guice
src/test/java/
de.spinscale.dropwizard.jobs
ApplicationStartTestJob.java
dropwizard-jobs-spring
src/test/java/
de.spinscale.dropwizard.jobs
ApplicationStartTestJob.java
So it seems that the maintainers of this project like to rename their unit tests with the exact same package/class names, and for some reason, Eclipse sees them as all belonging inside the same package. To test this I renamed dropwizard-jobs-core/src/main/java/de.spinscale.dropwizard.jobs.ApplicationStartTest to something else, and did the same for dropwizard-jobs-guice/src/main/java/de.spinscale.dropwizard.jobs.ApplicationStartTest and sure enough, all the errors associated with ApplicationStartTest being already defined went away.
So my suspicion is confirmed: The intention of these subfolders (dropwizard-jobs-core, dropwizard-jobs-guice and dropwizard-jobs-spring) is that they are sub-projects with separate classpaths. Eclipse thinks all of these source folders are part of the same project, and so it is lumping all of their classes into the same classpath. Since each subproject uses the same unit test naming conventions (same package/class names for each subproject), Eclipse see multiple classes in the same package as having the same name.
OK, good! I figured out the problem. But what's the solution? Ideally I would be able to keep all of these inside the same project, but perhaps modify the .classpath file or do something similar that instruct Eclipse to keep the subprojects separated from a classpath perspective. Any ideas?
SImply download eclipse m2e plugin, then import the project(considering you have already checked-out at your workstation), and do spend sometime learning MAVEN commands. here you can find an pverview of maven parent project and modules. Maven parent pom vs modules pom
One possible solution would be to introduce maven, which allows to naturally define a parent project and sub-projects in a multi-module maven project.
You can actually test that configuration outside of Eclipse, and then use M2Eclipse in order to import parent and its dependencies, at the same time (as commented in this answer) in your Eclipse.
Actually, the M2Eclipse project itself has guice test project, which you can use as model for your own guive subproject, in the repo sonatype/m2eclipse-guice, with an adequate pom.xml.

How to build Java project using IntlliJ IDE instead of via shell?

I cloned a GitHub repo onto my disk an successfully built the project by:
ant clean-all resolve create-dot-classpath
within the projects root directory.
I assume this should also be possible from IntelliJ IDE but that fails by doing nothing at all - it simply states "All files are up-to-date" ... what I do is:
"Make module 'pentaho-kettle'"
"Compile module 'pentaho-kettle'"
I could use a hint where to look for a solution or what configuration is most likely missing.
As the project is a multi module project based on Ant and Ivy, you have to
import the project from sources
configure modules (like core, ui, the plugins, …) with the right directories for main and test sources and resources (they seem to overlap with java sources in that project)
setup the class path using an Ivy plugin (I recommend IvyIDEA), use the context menu on the ivy.xml file
and have luck to build. It will be some try and error!
You may also have a try importing from Eclipse as those .project and .classpath files are checked in. But than you also have to check the module directories, the import is more a partial guess and I worry that IntelliJ will not get any information about Ivy from the Eclipse setup.

Adding a Maven project to Eclipse compiled project

I am trying to add java code from a Maven project (called docx4java) which I checked out from svn to an existing Eclipse project (called DocumentManager). I have tried the normal way, that I thought would work, i.e.:
Right Click on eclipse project>Properties>Java Build Paths> Projects > Add (here I add the Maven project) and >Libraries (here I specify Native Library location e.g. docx4/trunk/docx4/src/) but I still can't get the 'Maven' classes to be recognised in eclipse. I get the message
import docx4j.src.main.java.org.docx4j.convert.out.flatOpcXml.FlatOpcXmlCreator cannot be resolved
I have tried adding a test project that was compiled in Eclipse and that works fine, Eclipse seems to recognise it i.e. import org.me.TestProject works fine.
How can I get the code from the Maven project docx4java to work in the Eclipse compiled project DocumentManager?
You can generate eclipse poject files (which you can just import into your Workspace) using the maven eclipse plugin
Take a look at these ecplise plugins for a more direct integration of maven into eclipse
You should create a eclipse project for docx4java as #Attila has commented. Once that is done, you should have two projects on your workspace: docx4java and DocumentManager. At this point, what you are doing now (adding a project reference to the Java Build Paths) should work.
It seems that the source path is not configured correctly, this is why the compiler cannot find your "Maven classes".
docx4java.src.main.java...
Maven has a different directory structure and you have to tell Eclipse where to find your sources.
For a "vanilla" eclipse project, remove the standard eclipse build path src and add the maven source path src/main/java (or whereever you added the code), the compiler should correctly pick up your sources.
Note that you still have to add all jars mentioned in the dependencies section of the maven pom.xml file. Otherwise it won't compile, even if it finds your added java classes.
(Addendum: I would recommend to use maven in your existing project as well.)

Adding additional java files to playframework classpath

I have a project that shares models with my android project. I have a separate eclipse project just for models and other shared code. I add this to my play project as a dependency in eclipse.
In eclipse, play compiles and starts without problem. However, I went to deploy to GAE and found that the compilation stage of play's packaging fails because it can't find the models.
I suspect I could hack the ant build files, but that seems brittle.
Is there a standard way to add extra directories to the play compilation source tree or the classpath?
Make a jar-file with your classes and put it in /lib. That's where I put my libraries.
Files in the application /lib folder is automatically added to the class path by Play Framework. See Classpath settings
From Anatomy: "The app directory contains all executable artifacts: Java and Scala source code, templates and compiled assets’ sources" ... and further: "You can of course add your own packages, for example an app/utils package"
You can copy java source files to make a hierarchy of packages under /app, e.g.:
/app/sharedcode/project2/models/domain1 and import that in WhateverController.scala as:
import sharedcode.project2.models.domain1._

Categories