13

I have a situation where I need to have a folder containing Java sources used as a source folder for several maven projects "next to each other" in a tree structure. Due to dependency differences for the maven projets I cannot create an artifact containing the compiled version of the sources, but need to have each project treat it as a source folder in addition to src/main/java.

Apparently Maven can do this easily by adding another source folder located in "../foo/src", but m2e refuses to do this, and for this to work well for us, I need to have it working in Eclipse.

How would I go at having a structure like:

/common/src
/a/pom.xml  (add source folder ../common/src)
/a/src/main/java/...
/b/pom.xml  (add source folder ../common/src)
/b/src/main/java/....

and get it working in Eclipse?

(note: I am aware of http://dev.eclipse.org/mhonarc/lists/m2e-users/msg01988.html - it is, however, from 2011)

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347

6 Answers6

10

You should not do that.

If you want to use that code in different modules, then it should also be a Maven module, used as a dependency by the other modules.

The main problem with what you're trying to do is that even though it is not an actual copy/paste of sources between the two modules, in the end it behaves like one. What would happen once you build the two jars? You'll have duplicate classes, so if you use them in the same application the classpath will be a bit wrong.

So, what exactly is it that you're trying to accomplish?

  • Reuse some code in two distinct modules? Then use it as a dependent jar.
  • Reuse code in two distinct modules, but you don't want to end up with multiple jars? Then you can use the maven-shade-plugin to embed the dependency in the final artifact.
  • Build two slightly different versions of the same library? Then you can again use the maven-shade-plugin to extend one jar with additional sources. Or you can use the aspectj-maven-plugin to inject aspects into a base set of classes.
  • Have a code design that would trigger a circular dependency, since the modules depend on the common code, which in turn depends on code from each module? The proper fix would be to extract a generic API from the modules, which would go into the shared dependency and would be implemented differently by each module.

If you really, really have to keep it as a shared source directory instead of a shared dependency, then you can look at this answer.

Community
  • 1
  • 1
Sergiu Dumitriu
  • 11,455
  • 3
  • 39
  • 62
  • I need to have a shared code source used in three projects, and for technical reasons the source also needs to be able to see the source of the project which use it. The reason is that we may have to provide slightly different versions of the same binary to different branches of the customer in question. If I just have a dependent jar, I cannot refer to the project src/main/java where the project specific class lives (but need to resort to factories and/or dependency injection which would not be needed with the simpler approach). Also duplicate classes is not an issue here. – Thorbjørn Ravn Andersen Jun 01 '13 at 17:20
  • I see, so you're trying to avoid both a circular dependency and relying on a complex framework for API⟷implementation separation. I find dependency injection to be a very good design decision for any project, which would make future development a lot more modular. But I don't know how big your project already is to recommend adapting that now. So I would recommend a simple factory, that's quite easy to implement and won't add much complexity to the code. A filesystem hack to have a shared source directory is a code smell to me, it's your decision if you want to live with it or not. – Sergiu Dumitriu Jun 01 '13 at 17:38
  • Note that this works perfectly well with Maven invoked from a command line, abeit when using an extension to add extra source jars. It is open for debate if that is a bug or a feature. Right now I agree that this doesn't look feasible. – Thorbjørn Ravn Andersen Jun 01 '13 at 18:05
3

How about a little trick with the file system? Just make symlinks to the folders and you probably be fine :)

For NTFS you can try to do mklink from command line. More explanation here: http://en.wikipedia.org/wiki/NTFS_symbolic_link

WeMakeSoftware
  • 9,039
  • 5
  • 34
  • 52
1

You should be able to use relative paths and Maven Build Helper as a solution.

In each project, or in a "parent" pom.xml that they all inherit from, add the following:

  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>1.8</version>
    <executions>
      <execution>
        <id>add-source</id>
        <phase>generate-sources</phase>
        <goals>
          <goal>add-source</goal>
        </goals>
        <configuration>
          <sources>
            <source>${basedir}/../../common/src</source>
          </sources>
        </configuration>
      </execution>
    </executions>
  </plugin>
noahlz
  • 10,202
  • 7
  • 56
  • 75
1

If you use Subversion probably the most convenient approach would be to keep the shared source folder in a separate repository and add it to all the projects that need it by means of svn:externals. On the other hand this would make creating tags and branches more complicated.

Something similar could probably be achieved with Mercurial sub-repositories, but it wouldn't be as convenient.

Nicola Musatti
  • 17,834
  • 2
  • 46
  • 55
1

Why not simply make the common lib a Maven <dependency /> in the other projects' pom.xml's and use the "Resolve dependencies from workspace projects" feature of m2e (which I believe is the default) in the dependent projects (right-click on project => project properties => Maven)?

That way the dependent projects would automatically see the classes of the common lib within the IDE, without you actually having to build/install the common lib artifact to a maven repository (local or remote).

Since you are using Git, branching would likely make it easy for you to provide distinct versions (version as in the one in pom.xml) of the common lib and reference those versions accordingly in the dependent projects' <dependency /> elements.

Jukka
  • 4,583
  • 18
  • 14
1

I would use an NTFS Junction.

I use them in my projects to share resources between projects without actually copying them. A junction is like a blackhole between drive and filesystems. They behave the same as hard links but can reference folders, even on different drives (including network drives). From your perspective, it will look like having the /common/src folder in your projects' folder (then you can tell Eclipse to use it as a source folder). Of course you can rename junction points, so that /common/src, as seen by project a, will be called common.

/common/src
/a/src
/a/common <- this is a junction to /common/src

To ease the creation of Junction I really like to use this shell extension.

namero999
  • 2,882
  • 18
  • 24