15

Spring's @ComponentScan offers a type-safe basePackageClasses attribute - seems a good thing to use especially as it isn't uncommon for packages to be renamed on the project I'm working on. The documentation says:

Consider creating a special no-op marker class or interface in each package that serves no purpose other than being referenced by this attribute.

... but offers no further guidance on the name of such a class. Am wondering if there are any conventions around this. package-info.java already exists in all packages (as enforced by Checkstyle) - would have preferred to reuse this but sadly Java doesn't allow a class of this name.

(If no such standards exist am thinking perhaps PackageInfo, BasePackage, PackageMarker or similar but would prefer to follow convention if there is one.)

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • 2
    I feel this is kind of opinion based. What I typically do, for example, is store my `@Controller` types in one package, so I'll name the corresponding class or interface `Controllers` in `Controllers.java`. – Sotirios Delimanolis Dec 02 '14 at 16:44
  • 3
    Agree it may involve opinion but was hoping someone might be able to point me towards evidence of a standard or widely used approach. – Steve Chambers Dec 02 '14 at 16:46
  • Does basePackageClasses take just the class name, or the fully qualified one? in the latter case, it isn't much more useful than basePackages – guido Dec 02 '14 at 16:49
  • 2
    It is useful because it is type safe - a class is specified rather than a String so if the package name were to change it wouldn't matter. – Steve Chambers Dec 02 '14 at 16:50
  • 1
    This does appear to be primarily opinion, though you could rephrase (perhaps asking for best practices). I don't think there are any standards, though. – chrylis -cautiouslyoptimistic- Dec 03 '14 at 09:07
  • 1
    OK, thought the question already gave that gist but have slightly reworded and bracketed the last sentence to make this clearer. – Steve Chambers Dec 03 '14 at 10:47

1 Answers1

16

No answers yet and had to make a decision so here it is:

Marker class:

package com.companyname.appname.projectname.package1name;

/**
 * Empty marker class used to identify this package when using type-safe basePackageClasses in Spring @ComponentScan.
 */
public class PackageMarker {
    // Empty marker class
}

Usage:

@ComponentScan(basePackageClasses = {
    com.companyname.appname.projectname.package1name.PackageMarker.class,
    com.companyname.appname.projectname.package2name.PackageMarker.class,
    /* ...etc... */
})

PackageMarker naming justification:

  1. Seems sensible for all such classes to have the same name so they can be easily identified.
  2. Seems sensible for it to start with "Package" (in the same way as package-info.java).
  3. Seems sensible for it to end with "Marker" since the documentation refers to a "marker class".
  4. Opted not to include the word "Base" so it isn't confused with base classes.
  5. Opted not to include the word "Info" as it doesn't contain any info like package-info.java does.
  6. Opted not to include any other words (e.g. "NoOp") to keep it snappy and flexible for other possible uses.

Would still be interested if anyone can give examples of marker classes used in a more trail-blazing context...

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • One drawback of this approach is that the usage is very verbose. – Bogdan Calmac May 05 '15 at 21:28
  • It's just reflecting the package structure, which can be as terse or verbose as needed to guarantee uniqueness. – Steve Chambers May 06 '15 at 08:08
  • 1
    Yes, but you can also give the marker interface a name unique to your project and then the annotation can look like @ComponentScan(basePackageClasses = {TwitterClient.class, EvernoteClient.class}) – Bogdan Calmac May 06 '15 at 16:30
  • 1
    Each to their own but not sure I'd adopt this strategy. The marker class identifies the whole package and this would allow the name to deviate from the package name. There could be issues with name uniqueness later down the line as the number of marker classes grows. – Steve Chambers May 08 '15 at 06:59
  • 4
    I would also prevent instantiation of the PackageMarker class by making it final and its constructor private: `public final class PackageMarker { private PackageMarker() { throw new AssertionError("Don't instantiate " + PackageMarker.class); } }` – Arend v. Reinersdorff Dec 29 '16 at 09:50