just lerning
just lerning

Reputation: 866

Applying maven groupId naming convention

I am developing a number of projects (currently organized as eclipse projects). There is a core project which mainly provides the core API and some secondary implementations and abstract classes. All other projects depend on this project.

When integrating the projects into our maven repository, we got problems with the maven naming conventions. As discussed on SO, the groupId should usually be the reverse company domain name (com.example) plus the project name (com.example.foo). The maven naming conventions suggest an additional postfix for sub-projects such as plugins (com.example.foo.plugin).

In our case, we have not got plugins, but multiple (mostly independent) implementations of the API provided by the core project. Our current naming suggestion is:

The key point is that (although our projects are spread accross packages as described above) they are not really sub-projects of the API core project.

Does this suggestion comply with the maven naming conventions?

Just in case: This question is not asking for opiniated responses but for an argumentative answer to the above question.

Upvotes: 8

Views: 4391

Answers (5)

Garret Wilson
Garret Wilson

Reputation: 21316

I just want to add a comment regarding naming conventions for the parent POM. Several responses, including the answer by carlspring and the answer by by Steve K, indicated naming the parent pom simply parent:

com.example.foo:parent
com.example.foo:foo
com.example.foo:foo-bar
com.example.foo:foo-bat
com.example.foo:foo-baz

I completely agree with the sentiment, because the parent POM is not a sub-module, which is what foo-parent would seem to imply.

Option 1: com.example.foo:parent

There is however a big problem using simply parent as the artifact ID, besides the fact that it doesn't give much info when searching for it in the Maven Repository. If you import the project into Eclipse, the IDE will use parent for the project name!! This is unsightly, and trying to import two projects that use this convention will cause pain.

But I also don't want to name the artifact foo-parent, because as I mentioned it's not a submodule. Additionally, it will likely be sorted in the middle of the submodules, making it hard to find it in my IDE.

Option 2: com.example.foo:foo-.parent

After much thought and experimentation, I decided I'd like to propose a convention for parent POM artifact IDs: project-.parent. (Yes, this identifier is allowed by Maven.) This shows that the artifact is part of "project", but by beginning with a . it shows that it is a special POM, sort of like a metadata file or a configuration directory. Plus it sorts it to the front of the modules (although not in front of the single project artifact ID). So the module coordinates would look like this:

com.example.foo:foo
com.example.foo:foo-.parent
com.example.foo:foo-bar
com.example.foo:foo-bat
com.example.foo:foo-baz

There's a drawback, though: many tools don't seem to support thing. It looks like having dots in the artifact ID causes issues with JitPack, JFrog Artifactory, and OSGi Bnd, for example.

Option 3: com.example.foo:foo--parent

I then thought about using foo--parent, or even just foo--. But as - is used as semantically a component separator within the artifact ID, I was worried that a tool might hiccup if two dashes were next to each other. Plus adding a version to the end of the artifact (e.g. foo---1.0.0.jar) would look a little odd.

Option 4: com.example.foo:foo_

Then I stumbled across a blog entry that pointed out that Eclipse has an option for viewing projects hierarchically!! I suddenly realized that my main issue was with a specific use case: that where the aggregate POM is the same as the parent POM, and the main project artifact is in the subdirectory. For example, in repository foo, the project is found inside foo/foo, so what do I name the aggregate POM artifact ID?

Suddenly sorting wasn't such a big deal anymore, because Eclipse would show the root project in a tree.

  • For a standalone parent project, I could yield to convention and use foo-parent.
  • For a project in which the main artifact was at the root, there is no problem, as the root artifact ID would simply be named foo.

So the remaining problem is for a project like this:

…/foo/pom.xml #com.example.foo:???
…/foo/foo/pom.xml #com.example.foo:foo
…/foo/foo-bar/pom.xml #com.example.foo:foo-bar
…/foo/foo-bat/pom.xml #com.example.foo:foo-bat
…/foo/foo-baz/pom.xml #com.example.foo:foo-baz

I would like to give it an artifact ID of foo, but I can't do that as the main foo artifact is in a subdirectory. So for this special case, I'm leaning towards foo_.

…/foo/pom.xml #com.example.foo:foo_
…/foo/foo/pom.xml #com.example.foo:foo
…/foo/foo-bar/pom.xml #com.example.foo:foo-bar
…/foo/foo-bat/pom.xml #com.example.foo:foo-bat
…/foo/foo-baz/pom.xml #com.example.foo:foo-baz

This shows up as foo_ at the root of the tree in Eclipse, and there is not much chance a tool will have problems with a trailing underscore (at least less of a chance than a dot or duplicated dashes).

I'd be interested to get feedback on this discussion and my (current) conclusion.

Upvotes: 0

David Roussel
David Roussel

Reputation: 5916

I'd say it's okay to have all your artifacts in the same groupId. But you should use the sub project pattern where appropriate.

For example, Spring has all its main artifacts in one groupId, org.springframework. That includes the core of spring and the JMS, ORM and WMV subprojects. But then bigger sub-projects like Spring Boot have a separate groupId, org.springframework.boot. I would say this is a good pattern to follow.

Upvotes: 1

carlspring
carlspring

Reputation: 32567

I would say this is a matter of your own taste and preference.

Normally, you would group similar sets of modules under the same groupId. For example, you could have the following:

com.foo.bar:parent                          (parent pom for all projects)
com.foo.bar:core-api                        (some very core classes)
com.foo.bar:commons                         (some common classes)
com.foo.bar:io                              (some IO classes)
com.foo.bar:utils                           (some utility classes)
com.foo.bar.messaging:messaging-core        (messaging core classes)
com.foo.bar.messaging:messaging-rest-api    (REST API for messaging)
com.foo.bar.messaging:messaging-jms         (some JMS code)
com.foo.bar.web:rest-api                    (your restlets)
com.foo.bar.web:web-core                    (core classes to be used by web modules)
com.foo.bar.web:web-parent                  (a parent pom for all your web projects)
com.foo.bar.web:web-ui                      (UI stuff like css/images/js/etc)
com.foo.bar.web:web-assembly                (a web assembly that bundles all modules)
... (I hope by now you get my drift) ...

You don't necessarily need to group all modules whose classes start with a common package under the same groupId. You could do that, if you like, but that's rarely how people really use it in real life. The level of strictness and magnitude of detail is up to you, but in the case of artifacts, it usually doesn't matter that much as there's nothing to tie the package name to the groupId.

Furthermore, using a prefix for your modules is also helpful, but up to you. If you like, you could have:

com.foo.bar:bar-parent
com.foo.bar:bar-core-api
com.foo.bar:bar-commons

This is really up to you. Some will argue that if you have a groupId like com.foo.bar, then you don't need to have a bar- prefix in bar-parent. To some extent this is true. But then you could have com.foo.bar:parent and com.foo.bar.web:parent and when you're using a repository manager like Nexus, Archiva or Artifactory and you're searching for parent, (or some other common name like... commons, for example), you might end up with a rather long list of results, as opposed to bar-parent.

In the end, what matters is to what level of detail you're willing to go and what will really suit your needs. Maven allows you all the freedom you need in this regard.

Upvotes: 12

Steve K
Steve K

Reputation: 4921

The naming of things is really important, and the names should convey important information right away. For this reason, the conventions my company have used state that group Id should be the same for all implementations of a specific thing: each one's group Id is com.example.foo, because they're all implementations of that. The project names should refer to the interface, and hyphenated with the name for their particular implementation, with the main parent pom labeled prominently as 'parent':

com.example.foo:parent
com.example.foo:foo-bar
com.example.foo:foo-bat
com.example.foo:foo-baz

This way, you can tell at a glance from the names exactly how these things are related, and the artifact names also individually denote that they are different types of foo. This also means that imports in the java code follow exactly the same structure. It also makes imports very legible and understandable in the java code as well.

Upvotes: 2

Michael Wiles
Michael Wiles

Reputation: 21186

So as I see it you have a bunch of options which follow maven naming conventions...

Foo refers to the core API and bar refers to the implementation.

  1. com.example.foo (referring to the core api) as the group and then the implementation being foo-bar (convention says you include a hook back to the group in your artifact name).

  2. com.example.bar as thr group and the artifact id is bar-impl or some other appropriate suffix

  3. com.example.foo.bar as the group and bar-impl or some other appropriate suffix.

For 1 you are saying to the unfamiliar: the implementation is closely coupled to the API and has a closely related release cycle. When a new versio of the core API is released a version of the implementation is also released. Furthermore the implementation is a child of the core API and does not really stand alone. You are also saying the core business of bar is to be an implementation of bar and has little value apart from it (it doens't do much else).

In 2 you are saying the implementation of the core API does have it's own lifecycle and generally is not released on the same cycle as the API. Furthermore it is not a sub project of the core API and can thus stand alone. In other words, it's core business and usage is not only as an implentation of foo. If bar can have siblings this is especially attractive.

3 is a middle road between the two. It says bar has value by itself as well as having significance as an implementation of foo and also potentially allows for siblings. It slightly improves on 2 as it does provide some feedback that this artifact is an implementation of foo. Again, if bar can have siblings this makes more sense.

So I guess you'd need to select where your implementations of the API sit. The biggest driver is probably whether bar can have siblings.

Upvotes: 3

Related Questions