Browse Source
Split packages are a well-known anti-pattern for OSGi and a blocker for Eclipse Virgo (which prevents split packages being accessed via its Import-Library construct). Split packages are also unhelpful with a traditional linear classpath as a split package name does not uniquely identify the Spring framework JAR from which it came, thus complicating problem diagnosis and maintenance. Juergen Hoeller supports this position in the following comment in SPR-9990: >FWIW, I generally find split packages a bad practice, even without >OSGi in the mix. For the Spring Framework codebase, I consider a >split-package arrangement a design accident that we want to detect >in any case - and that we're willing to fix if it happened. > >I'm actually equally concerned about the source perspective: After >all, we want a package to be comprehensible from a single glance >at the project, not requiring the developer to jump into several >source modules to understand the overall layout of a package. Split packages have crept into Spring framework twice in recent months - see SPR-9811 and SPR-9988. Currently, they are only detected once the Spring framework has been converted to OSGi bundles and these bundles have been tested with Eclipse Virgo. This commit adds a build-time check for split packages to the Spring framework build. Issue: SPR-9990 Conflicts: build.gradlepull/214/head
2 changed files with 91 additions and 0 deletions
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
/* |
||||
* Copyright 2013 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.build.gradle |
||||
|
||||
class SplitPackageDetector { |
||||
|
||||
private static final String HIDDEN_DIRECTORY_PREFIX = "." |
||||
|
||||
private static final String JAVA_FILE_SUFFIX = ".java" |
||||
|
||||
private static final String SRC_MAIN_JAVA = "src" + File.separator + "main" + File.separator + "java" |
||||
|
||||
private final Map<File, Set<String>> pkgMap = [:] |
||||
|
||||
private final logger |
||||
|
||||
SplitPackageDetector(baseDir, logger) { |
||||
this.logger = logger |
||||
dirList(baseDir).each { File dir -> |
||||
def packages = getPackagesInDirectory(dir) |
||||
if (!packages.isEmpty()) { |
||||
pkgMap.put(dir, packages) |
||||
} |
||||
} |
||||
} |
||||
|
||||
private File[] dirList(String dir) { |
||||
dirList(new File(dir)) |
||||
} |
||||
|
||||
private File[] dirList(File dir) { |
||||
dir.listFiles({ file -> file.isDirectory() && !file.getName().startsWith(HIDDEN_DIRECTORY_PREFIX) } as FileFilter) |
||||
} |
||||
|
||||
private Set<String> getPackagesInDirectory(File dir) { |
||||
def pkgs = new HashSet<String>() |
||||
addPackagesInDirectory(pkgs, new File(dir, SRC_MAIN_JAVA), "") |
||||
return pkgs; |
||||
} |
||||
|
||||
boolean diagnoseSplitPackages() { |
||||
def splitFound = false; |
||||
def dirs = pkgMap.keySet().toArray() |
||||
def numDirs = dirs.length |
||||
for (int i = 0; i < numDirs - 1; i++) { |
||||
for (int j = i + 1; j < numDirs - 1; j++) { |
||||
def di = dirs[i] |
||||
def pi = new HashSet(pkgMap.get(di)) |
||||
def dj = dirs[j] |
||||
def pj = pkgMap.get(dj) |
||||
pi.retainAll(pj) |
||||
if (!pi.isEmpty()) { |
||||
logger.error("Packages $pi are split between directories '$di' and '$dj'") |
||||
splitFound = true |
||||
} |
||||
} |
||||
} |
||||
return splitFound |
||||
} |
||||
|
||||
private void addPackagesInDirectory(HashSet<String> packages, File dir, String pkg) { |
||||
def scanDir = new File(dir, pkg) |
||||
def File[] javaFiles = scanDir.listFiles({ file -> !file.isDirectory() && file.getName().endsWith(JAVA_FILE_SUFFIX) } as FileFilter) |
||||
if (javaFiles != null && javaFiles.length != 0) { |
||||
packages.add(pkg) |
||||
} |
||||
dirList(scanDir).each { File subDir -> |
||||
addPackagesInDirectory(packages, dir, pkg + File.separator + subDir.getName()) |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue