Setting build path for project with multiple (maven) modules

Hi All...

I'm new to IDEA, our management has just bought us all licences for 9.0.3 and set us loose with them, but without much guidance.

I have a multi module Project created, as per the tutorials I have found. My application consists of a maven project (A)  which depends on two other maven projects (B and C). All the maven projects have been imported into the IDEA Project as modules using open from existing (maven) sources.

Most of the work I need to do is in B and C, and so I want my Project class path to use the modules in the project rather than the revisions specified in the POM. I'd like to be able to make a change in B or C, and then run A and see the change. How do I tell IDEA to do this?

Cheers,

Sean

21 comments
Comment actions Permalink

Hi Sean,

You should define B and C modules as dependencies for A module. Feel free to check this link on more information about that.

Denis

0
Comment actions Permalink

Hi Denis,

Thanks for your reply.

So, I went into the Module Settings for A, went to the dependencies tab, and added B and C as module dependencies. Then I moved them both to the top, just below the JDK, so they would be picked up before the versioned A and B from the POM file.

Made a small change in B, re-ran A, but it didn't pick up the change... it is still using the B from the .m2/repository that came in from the POM file.

Then on the dependencies tab I *removed* the B from the .m2/repository so that only the B module was there, and this time I got a ClassNotFound exception (for the first class it tried to load from B) when I tried to run. Oddly, there was no indication of a classpath error until I ran it.

Any idea what I'm doing wrong here?

Cheers,

Sean

0
Comment actions Permalink

Hi Sean,

It looks like your new classes are not included to classpath. Try to build the project before run (main menu -> build -> make project).

Also you can set 'make before launch' check box at your run configuration.

Denis

0
Comment actions Permalink

I did that, and I already had the 'make before launch' set, still no luck.

I'll try playing around with a few more settings.

0
Comment actions Permalink

SeanMitchell wrote:

I did that, and I already had the 'make before launch' set, still no luck.

I'll try playing around with a few more settings.

IDEA prints used classpath, so, you can check if your target class is actually contained there. I.e. there should be a directory that contains *.class files and you can check if the target class is compiled and put there.

0
Comment actions Permalink

Ah... the output dir (B/target/classes) is not in the classpath... seems that it is not picking up the B and C that I added to the dependencies. I do see everything else that I would expect to see in the classpath though. And it did pick up my change to remove the B that came from the POM file.

0
Comment actions Permalink

I'm not sure that target *.class files directory is 'B/target/classes'. Directory to use is defined at module settings -> 'Paths' tab

0
Comment actions Permalink

Yeah, that occurred to me too, so I did check. It is using the maven output directories. There's no mention of module B or module C at all in the class path, but I do see module A.

0
Comment actions Permalink

You can create a minimal but complete sample project that illustrates the problem and post it here, I'll take a look.

0
Comment actions Permalink

Ok, thanks.... I'm under the gun today (seems they always want us to switch to something new whenever we have a firm deadline to meet :) ) so it probably won't be until tomorrow.

Thanks again for you time!

Cheers,

Sean

0
Comment actions Permalink

Ok, I have created two maven projects (A and B) and attached them to this post.

A has a simple class:

public class ClassA {
   public static void main(String[] args) {
      System.out.println("This is A");
      ClassB b = new ClassB();
      System.out.println("B says " + b.hello());


   }
}


which depends upon B:

public class ClassB {
   public String hello() {
      return "Hello from B 1.0";  
   }
}

A's pom file is like this:

    <groupId>A</groupId>
    <artifactId>A</artifactId>
    <version>1.0</version>
    <dependencies>
        <dependency>
            <groupId>B</groupId>
            <artifactId>B</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>


B's pom has this in it, becuase it is build with an external build system (Teamcity):

    <groupId>B</groupId>
    <artifactId>B</artifactId>
    <version>${buildVersion}</version>

My local maven repo has this:

/Users/mitchells/.m2/repository/B/B/1.0/B-1.0.jar

which came from our internal maven repo, having been built by Teamcity and assigned a version number.


So now, I want to work on this project, which means I need to make changes to A and B at the same time. I don't want A to use the ClassB from B-1.0.jar, I want it to use the ClassB module in my project.

To accomplish this, I go to A's Module Settings->Dependencies and add Module B. Then I move Module B up, so that it occurs before Maven B:B:1.0.

Now I go and make a trivial change to hello() in ClassB, make module (irritates me that I have to do that manually), and run A.

My change is not picked up.



Attachment(s):
A-B.tar.gz
0
Comment actions Permalink

Hi Sean,

I tried to reproduce the problem with IDEA 9.0.2 Community Edition - everything works fine.

Actions:

  1. Define correct version at 'B's pom.xml from your archive (was '${buildVersion}', now '1.0');
  2. Build 'B' project by maven from the command line (mvn install);
  3. Build 'A' project by maven from the command line (mvn install);
  4. Import 'B's pom.xml from IDEA;
  5. Import 'A's pom.xml from IDEA;
  6. Define 'B' as a module dependency for 'A' and put it above B's maven-based library;
  7. Modify 'ClassB' in order to print other message from 'hello()';
  8. Start 'ClassA';

Result: modified text is printed.

I checked A.iml from your archive and didn't see 'B' module dependency there, only maven-based 'B.jar'.

About manually making module - it's not necessary, just check 'Make before launch' option at your run configuration.

Regards, Denis

0
Comment actions Permalink

Hi Denis...

My version *is* ${buildVersion}... that's a property set by Teamcity. Not clear on why it should matter, if we are overriding the classpath anyway.

If I have to fiddle with versions in the pom file then I'll just create fake version numbers and be done with it. Hopefully I won't check the munged pom files in.

Cheers,

Sean

0
Comment actions Permalink

I just pointed ${buildVersion} because the example was stated as a standalone. There is no need to hard code the version at your environment if it's defined by other means there.

The main idea is that I was not able to reproduce the problem via the steps mentioned above.

Denis

0
Comment actions Permalink

Ah, ok... well, thanks anyway, I appreciate all the time you've taken with my problem.

0
Comment actions Permalink

The Maven project you provide is not a Maven multi-module project, which is what you want to use when you are making changes to both modules.

You need a Maven project, call it AB that references both A and B using the <module> tags.

I.E.

AB/pom.xml

     <module>A</module>
     <module>B</module>

The default way to organize Maven multi-module projects is in a directory hierarchy.


AB
     A
     B

Then you open the AB/pom.xml in IDEA and it will load the 2 other modules and set the classpath correctly.


If you can't put the A and B modules under the AB directory, you can use a relative path in the <module> tag.

0
Comment actions Permalink

Hi Erik...

This is not a good candidate for a maven multi-module project.

B is a client library used by many other projects, not something that exists purely for A. A is a maven project which has many dependencies, including B.

Cheers,

Sean

0
Comment actions Permalink

I don't see why that would prevent you from creating a multi-module project so that you can work on both A and B at the same time.

We have a lot of projects that share the same modules. Each project has a multi-module project that refers to the shared modules.

0
Comment actions Permalink

Hmmm.... that's an interesting approach, I don't think I've ever seen it done like that.

How does version control work? Do you re-create the project structure on disk manually every time you set up your project?

However, I'm still not clear on how that will solve my classpath issue, where A refers to B by revision in the POM, but I want to override it to use an unrevisioned B in my project. I'd still have placeholders in my pom.xml.

Cheers,

Sean

0
Comment actions Permalink

We have a root directory for all our projects. Under this root are all the module directories. Since we use Subversion, we also have application root directories which use Subversion externals to pull in all the modules for a particular project. One has the option to check out the master root and thus get everything or checkout the application root to get a limited set of directories.

Each application has a Maven multi-project directory.

So visually, we have

root --
     moduleA
     moduleB
     moduleC
     abc_app
     bc_app

The abc_app/pom.xml is a Maven multi-module project that references moduleA, moduleB, moduleC with relative paths, <module>../moduleA</module> etc.

The bc_app/pom.xml is a Maven multi-module project that only references moduleB and moduleC.

So when working on the abc_app in IDEA, one instructs IDEA to import the Maven project from abc_app/pom.xml. And when working on the bc_app, import the bc_app/pom.xml into IDEA.

Its not a perfect solution but it works for us. All our projects are in-house applications with erratic release cycles. Our release procedures tag each application separately from other applications. We use variables in the pom.xml files for the versions of the modules which have a default value of 1.0-SNAPSHOT. A release build procedure provides a different value for the version property when building a particular application. We also use continuous  integration so that if someone working on the abc_app checks in changes to moduleB the bc_app will get rebuilt and hopefully we find any problems early on. So when developers are working on an application, the dependencies are always to local snapshots. We never put snapshot jars in our internal central repository.

We also have a root/pom.xml that brings in all modules. This allows one to see all modules, especially useful when one is making radical changes to a class such as changing method signatures.

0
Comment actions Permalink

That's a very interesting system. I shall think on it and see what parts of it I can steal :)

My problem is that we have to use Perforce, which means I'd have to create some mojos or maybe have some sort of set up scripts.

0

Please sign in to leave a comment.