I mixed the the answers from @Grodriguez and @bemace and added my own strategy to come up with a best-effort solution. This solution imitates at runtime the auto-import feature available at compile time.
The full code of my solution is here. Given a simple name, the main steps are:
- Get a list of packages accessible from the current classloader.
- For each package, try to load the fully qualified name obtained from package + simple name.
Step 2 is easy:
public List<String> getFQNs(String simpleName) {
if (this.packages == null) {
this.packages = getPackages();
}
List<String> fqns = new ArrayList<String>();
for (String aPackage : packages) {
try {
String fqn = aPackage + "." + simpleName;
Class.forName(fqn);
fqns.add(fqn);
} catch (Exception e) {
// Ignore
}
}
return fqns;
}
Step 1 is harder and is dependent on your application/environment so I implemented various strategies to get different lists of packages.
Current Classloader (may be useful to detect dynamically generated classes)
public Collection<String> getPackages() {
Set<String> packages = new HashSet<String>();
for (Package aPackage : Package.getPackages()) {
packages.add(aPackage.getName());
}
return packages;
}
Classpath (good enough for applications that are entirely loaded from the classpath. Not good for complex applications like Eclipse)
public Collection<String> getPackages() {
String classpath = System.getProperty("java.class.path");
return getPackageFromClassPath(classpath);
}
public static Set<String> getPackageFromClassPath(String classpath) {
Set<String> packages = new HashSet<String>();
String[] paths = classpath.split(File.pathSeparator);
for (String path : paths) {
if (path.trim().length() == 0) {
continue;
} else {
File file = new File(path);
if (file.exists()) {
String childPath = file.getAbsolutePath();
if (childPath.endsWith(".jar")) {
packages.addAll(ClasspathPackageProvider
.readZipFile(childPath));
} else {
packages.addAll(ClasspathPackageProvider
.readDirectory(childPath));
}
}
}
}
return packages;
}
Bootstrap classpath (e.g., java.lang)
public Collection<String> getPackages() {
// Even IBM JDKs seem to use this property...
String classpath = System.getProperty("sun.boot.class.path");
return ClasspathPackageProvider.getPackageFromClassPath(classpath);
}
Eclipse bundles (domain-specific package provider)
// Don't forget to add "Eclipse-BuddyPolicy: global" to MANIFEST.MF
public Collection<String> getPackages() {
Set<String> packages = new HashSet<String>();
BundleContext context = Activator.getDefault().getBundle()
.getBundleContext();
Bundle[] bundles = context.getBundles();
PackageAdmin pAdmin = getPackageAdmin(context);
for (Bundle bundle : bundles) {
ExportedPackage[] ePackages = pAdmin.getExportedPackages(bundle);
if (ePackages != null) {
for (ExportedPackage ePackage : ePackages) {
packages.add(ePackage.getName());
}
}
}
return packages;
}
public PackageAdmin getPackageAdmin(BundleContext context) {
ServiceTracker bundleTracker = null;
bundleTracker = new ServiceTracker(context,
PackageAdmin.class.getName(), null);
bundleTracker.open();
return (PackageAdmin) bundleTracker.getService();
}
Examples of queries and answers in my Eclipse environment:
- File: [java.io.File, org.eclipse.core.internal.resources.File]
- List: [java.awt.List, org.eclipse.swt.widgets.List, com.sun.xml.internal.bind.v2.schemagen.xmlschema.List, java.util.List, org.hibernate.mapping.List]
- IResource: [org.eclipse.core.resources.IResource]