For a project, I want to search the local maven repo (.m2) and list the artifacts. How I can do it in Java? I found https://github.com/apache/maven-indexer and checked whether I can use it to list my local maven repo. But still couldn't solve. If you have any idea of a simple library which I can use, please suggest?
Thanks in advance. !
Consider the use of Files.walkFileTree(Path start, FileVisitor<? super Path> visitor)
class MyM2Visitor extends SimpleFileVisitor<Path> {
private final Path root;
public MyM2Visitor(Path root) {
this.root = root;
}
//implement rest as necessary
}
//later...
//Current user's .m2 directory:
Path m2 = Path.of(System.getProperty("user.home"), ".m2");
MyM2Visitor visitor = new MyM2Visitor(m2);
try {
Files.walkFileTree(m2, visitor);
} catch(IOException e) {
e.printStackTrace();
}
See also: SimpleFilevisitor JavaDoc
You should customise the visitor to take appropriate action when encountering a directory or a file, e.g.:
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
logger.trace("File: {}", file);
int count = file.getNameCount();
Path versionPath = file.getParent();
String versionAsString = versionPath.getFileName();
//or:
versionAsString = file.getName(count-2).toString();
String artifactId = file.getName(count-3).toString();
Path groupIdPath = file.getParent().getParent().getParent();
Path relativeToM2 = root.relativize(groupIdPath);
String groupId = relativeToM2.toString().replace(File.separatorChar, '.');
//do other things
return super.visitFile(file, attrs);
}
Related
This articles describes how to generate and import a PDOM index.
After invoking the generation application GeneratePDOM I got a pdom file /home/sadik/eclipse-2019-06/eclipse/pdomExample.pdom. But I have problem importing the file.
The command to generate is this:
java -jar plugins/org.eclipse.equinox.launcher_1.5.400.v20190515-0925.jar -application "org.eclipse.cdt.core.GeneratePDOM" -target /home/sadik/eclipse-2019-06/eclipse/pdomExample.pdom -source /home/sadik/my-plugin-runtime-2019-06/CDTTest_Local/ -id cdttest_01 -indexer org.eclipse.cdt.core.myfastIndexer
Note the target and source arguments.
To test the import I wrote a class that implements IReadOnlyPDOMProvider
public class MyReadOnlyPDOMProvider implements IReadOnlyPDOMProvider {
public MyReadOnlyPDOMProvider() {
System.out.println("PDOMProvider");
}
#Override
public boolean providesFor(ICProject project) throws CoreException {
return true;
}
#Override
public IPDOMDescriptor[] getDescriptors(ICConfigurationDescription config) {
final IPath fileBase = Path.fromOSString("/home/sadik/eclipse-2019-06/eclipse/");
final IPath projectBase = Path.fromOSString("/home/sadik/my-plugin-runtime-2019-06/CDTTest_Local/");
return new IPDOMDescriptor[] { new IPDOMDescriptor() {
public IIndexLocationConverter getIndexLocationConverter() {
return new URIRelativeLocationConverter(URIUtil.toURI(projectBase));
}
public IPath getLocation() {
IPath path = fileBase.append("pdomExample.pdom");
return path;
}
}};
}
Are the paths correct? I actually don't know what location is supposed to be returned here.
I defined that class in the CDT extension point CIndex in my Plugin's plugin.xml:
<extension
point="org.eclipse.cdt.core.CIndex">
<ReadOnlyPDOMProvider
class="de.blub.plugin.MyReadOnlyPDOMProvider">
</ReadOnlyPDOMProvider>
</extension>
I'm testing with this file (/home/sadik/my-plugin-runtime-2019-06/CDTTest_Local/tests/indexer/usage.cc):
#include <declaration.h>
int main() {
int a = testThis();
}
When I right click testThis() and chose go to declaration, I expect to go to the function declaration in /home/sadik/my-plugin-runtime-2019-06/CDTTest_Local/tests/indexer/declaration.h. Both files are located in the same directory.
But what happens is that an editor is opened with an empty file. The editor even tells me the path: /home/soezoguz/rtt-plugin-runtime-2019-06/tests/indexer/declaration.h.
The path is missing the project name. So I guess the pdom file stores locations below the specified source directory. How can I tell the PDOMProvider to look into the correct directory for the indexed files?
For some reason the trailing "/" has been ommited by URIUtil.toURI(...). But in the description of URIRealtiveLocationConverter it says
Note: The supplied base URI must end with a forward slash
So I create an URI instance from String and append a "/" to the String.
#Override
public IPDOMDescriptor[] getDescriptors(ICConfigurationDescription config) {
final IPath fileBase = Path.fromOSString("/home/sadik/eclipse-2019-06/eclipse/");
final IPath projectBase = config.getProjectDescription().getProject().getFullPath();
return new IPDOMDescriptor[] { new IPDOMDescriptor() {
public IIndexLocationConverter getIndexLocationConverter() {
URI baseURI;
try {
baseURI = new URI(projectBase.toString()+"/");
return new URIRelativeLocationConverter(baseURI);
} catch (URISyntaxException e) {
e.printStackTrace();
}
baseURI = URIUtil.toURI(projectBase);
return new URIRelativeLocationConverter(URIUtil.toURI(projectBase));
}
public IPath getLocation() {
IPath path = fileBase.append("pdomExample.pdom");
return path;
}
}};
}
I need to get a list of all the files in a directory, including files in all the sub-directories. What is the standard way to accomplish directory iteration with Java?
You can use File#isDirectory() to test if the given file (path) is a directory. If this is true, then you just call the same method again with its File#listFiles() outcome. This is called recursion.
Here's a basic kickoff example:
package com.stackoverflow.q3154488;
import java.io.File;
public class Demo {
public static void main(String... args) {
File dir = new File("/path/to/dir");
showFiles(dir.listFiles());
}
public static void showFiles(File[] files) {
for (File file : files) {
if (file.isDirectory()) {
System.out.println("Directory: " + file.getAbsolutePath());
showFiles(file.listFiles()); // Calls same method again.
} else {
System.out.println("File: " + file.getAbsolutePath());
}
}
}
}
Note that this is sensitive to StackOverflowError when the tree is deeper than the JVM's stack can hold. If you're already on Java 8 or newer, then you'd better use Files#walk() instead which utilizes tail recursion:
package com.stackoverflow.q3154488;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class DemoWithJava8 {
public static void main(String... args) throws Exception {
Path dir = Paths.get("/path/to/dir");
Files.walk(dir).forEach(path -> showFile(path.toFile()));
}
public static void showFile(File file) {
if (file.isDirectory()) {
System.out.println("Directory: " + file.getAbsolutePath());
} else {
System.out.println("File: " + file.getAbsolutePath());
}
}
}
If you are using Java 1.7, you can use java.nio.file.Files.walkFileTree(...).
For example:
public class WalkFileTreeExample {
public static void main(String[] args) {
Path p = Paths.get("/usr");
FileVisitor<Path> fv = new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
};
try {
Files.walkFileTree(p, fv);
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you are using Java 8, you can use the stream interface with java.nio.file.Files.walk(...):
public class WalkFileTreeExample {
public static void main(String[] args) {
try (Stream<Path> paths = Files.walk(Paths.get("/usr"))) {
paths.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Check out the FileUtils class in Apache Commons - specifically iterateFiles:
Allows iteration over the files in given directory (and optionally its subdirectories).
Using org.apache.commons.io.FileUtils
File file = new File("F:/Lines");
Collection<File> files = FileUtils.listFiles(file, null, true);
for(File file2 : files){
System.out.println(file2.getName());
}
Use false if you do not want files from sub directories.
For Java 7+, there is also https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html
Example taken from the Javadoc:
List<Path> listSourceFiles(Path dir) throws IOException {
List<Path> result = new ArrayList<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{c,h,cpp,hpp,java}")) {
for (Path entry: stream) {
result.add(entry);
}
} catch (DirectoryIteratorException ex) {
// I/O error encounted during the iteration, the cause is an IOException
throw ex.getCause();
}
return result;
}
It's a tree, so recursion is your friend: start with the parent directory and call the method to get an array of child Files. Iterate through the child array. If the current value is a directory, pass it to a recursive call of your method. If not, process the leaf file appropriately.
As noted, this is a recursion problem. In particular, you may want to look at
listFiles()
In the java File API here. It returns an array of all the files in a directory. Using this along with
isDirectory()
to see if you need to recurse further is a good start.
You can also misuse File.list(FilenameFilter) (and variants) for file traversal. Short code and works in early java versions, e.g:
// list files in dir
new File(dir).list(new FilenameFilter() {
public boolean accept(File dir, String name) {
String file = dir.getAbsolutePath() + File.separator + name;
System.out.println(file);
return false;
}
});
To add with #msandiford answer, as most of the times when a file tree is walked u may want to execute a function as a directory or any particular file is visited. If u are reluctant to using streams. The following methods overridden can be implemented
Files.walkFileTree(Paths.get(Krawl.INDEXPATH), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
// Do someting before directory visit
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
// Do something when a file is visited
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
throws IOException {
// Do Something after directory visit
return FileVisitResult.CONTINUE;
}
});
I like to use Optional and streams to have a net and clear solution,
i use the below code to iterate over a directory. the below cases are handled by the code:
handle the case of empty directory
Laziness
but as mentioned by others, you still have to pay attention for outOfMemory in case you have huge folders
File directoryFile = new File("put your path here");
Stream<File> files = Optional.ofNullable(directoryFile// directoryFile
.listFiles(File::isDirectory)) // filter only directories(change with null if you don't need to filter)
.stream()
.flatMap(Arrays::stream);// flatmap from Stream<File[]> to Stream<File>
Hi guys I'm trying to find if a specific file is inside the project directory.
File f = new File(System.getProperty("user.dir"));
System.out.println(f);
String archivoLiga="LigaV2";
System.out.println(f.listFiles((dir1, name) -> name.startsWith(archivoLiga) && name.endsWith(".properties")).length == 0);
But this only works if the file is in the "first" level, i want it to find it even if it's inside another folder. Any ideas?
Use Java 8's find() method to recurse subdirectories:
final int MAX_DEPTH = 50; // Max depth of subdirectories to search
Path userDir = Paths.get(System.getProperty("user.dir"));
System.out.println(userDir);
String archivoLiga="LigaV2";
System.out.println(
Files.find(
userDir,
maxDepth,
(path,attr) -> path.getFileName().startsWith(archivoLiga)
&& path.getFileName().endsWith(".properties"))
.findAny()
.isPresent());
Try recursively looking inside subfolders :-
public boolean checkForFile(String dirname,String prefix,String ext){
File dir = new File(dirname);
//System.out.println(dir);
for(File f : dir.listFiles()){
if(f.isFile()){
if(f.getName().startsWith(prefix) && f.getName().endsWith(ext)){
System.out.println(f.getName());
return true;
}
}
else{
//This step starts looking inside subfolder as well
return checkForFile(f.getAbsolutePath(),prefix,ext);
}
}
return true;
}
To check a file inside a folder, You will need to use exists() method of java.io.File like this:
boolean exists = new File("FOLDER_PATH/FILE_NAME").exists();
if (exists) {
System.out.println("File exists inside given folder");
} else {
System.out.println("File does not exists inside given folder");
}
Also possible with FileVisitor:
#Getter #Setter
#RequiredArgsConstructor
public static class SearchVisitor extends SimpleFileVisitor<Path> {
private final String fileToSearch;
private boolean found=false;
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if(!file.getFileName().toString().equals(fileToSearch)) return FileVisitResult.CONTINUE;
found=true;
return FileVisitResult.TERMINATE;
}
}
public void test() throws IOException {
SearchVisitor sv = new SearchVisitor("LigaV2");
Files.walkFileTree( Paths.get(System.getProperty("user.dir")), sv);
log.info("found file {}:{}", sv.getFileToSearch(), sv.isFound());
}
Use public boolean isDirectory() in java file API following is the link to oracle documentation. Tests whether the file denoted by this abstract pathname is a directory.
https://docs.oracle.com/javase/7/docs/api/java/io/File.html#isDirectory()
I am currently trying to implement a SWT CheckBoxTreeViewer for my project. However, I am currently running into some problems with the file filtering.
I want my tree to show all files in a directory (including subdirectories) with a specific file extension (such as "txt") as well as their parent folders.
For example:
parentA
childA1.txt
childA2.txt
parentB
childB1.txt
However, I can't figure out a way how to do this. I've tried several ways of coding the FileFilter as follows:
class FileTreeContentProvider implements ITreeContentProvider {
public Object[] getChildren(Object arg0) {
return ((File) arg0).listFiles();
}
public Object getParent(Object arg0) {
return ((File) arg0).getParentFile();
}
public boolean hasChildren(Object arg0) {
Object[] obj = getChildren(arg0);
return obj == null ? false : obj.length > 0;
}
...
1)
...
public Object[] getElements(Object arg0) {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
File workspaceDirectory = workspace.getRoot().getLocation().toFile();
String[] extension = new String[] {"txt"};
Collection<File> files = FileUtils.listFiles(workspaceDirectory, extension, true);
File[] files2 = new File[files.size()];
int i = 0;
for(File file : files) {
files2[i] = file;
i++;
}
return files2;
}
...
}
The problem with this is that it only shows the files with the file extension but not its parent directories.
For example:
childA1.txt
childA2.txt
childB1.txt
2)
...
public Object[] getElements(Object arg0) {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
File workspaceDirectory = workspace.getRoot().getLocation().toFile();
return workspaceDirectory.listFiles(new FilenameFilter() {
#Override
public boolean accept(File workspaceDirectory, String name) {
if (workspaceDirectory.getName().startsWith(".") {
return false;
}
else {
return true;
}
}
});
}
...
}
This snippet removes the folders starting with "." in the root directory, but does not remove the files starting with "." in the subdirectories. Therefore, I got something like this:
parentA
.project
.settings
childA1.txt
childA2.txt
...
Also, as it does not explicitly filter in just files ending in "txt", if I were to put other file types in the workspace folder I would also see those files in the tree which is not something I want.
Is there anyway to fix this? I am using Eclipse Mars 4.5.1.
Lets say I have a java package commands which contains classes that all inherit from ICommand can I get all of those classes somehow? I'm locking for something among the lines of:
Package p = Package.getPackage("commands");
Class<ICommand>[] c = p.getAllPackagedClasses(); //not real
Is something like that possible?
Here's a basic example, assuming that classes are not JAR-packaged:
// Prepare.
String packageName = "com.example.commands";
List<Class<ICommand>> commands = new ArrayList<Class<ICommand>>();
URL root = Thread.currentThread().getContextClassLoader().getResource(packageName.replace(".", "/"));
// Filter .class files.
File[] files = new File(root.getFile()).listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".class");
}
});
// Find classes implementing ICommand.
for (File file : files) {
String className = file.getName().replaceAll(".class$", "");
Class<?> cls = Class.forName(packageName + "." + className);
if (ICommand.class.isAssignableFrom(cls)) {
commands.add((Class<ICommand>) cls);
}
}
Below is an implementation using the JSR-199 API, i.e. classes from javax.tools.*:
List<Class> commands = new ArrayList<>();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(
null, null, null);
StandardLocation location = StandardLocation.CLASS_PATH;
String packageName = "commands";
Set<JavaFileObject.Kind> kinds = new HashSet<>();
kinds.add(JavaFileObject.Kind.CLASS);
boolean recurse = false;
Iterable<JavaFileObject> list = fileManager.list(location, packageName,
kinds, recurse);
for (JavaFileObject classFile : list) {
String name = classFile.getName().replaceAll(".*/|[.]class.*","");
commands.add(Class.forName(packageName + "." + name));
}
Works for all packages and classes on the class path, packaged in jar files or without. For classes not explicitly added to the class path, i.e. those loaded by the bootstrap class loader, try setting location to PLATFORM_CLASS_PATH instead.
Here is an utility method, using Spring.
Details about the pattern can be found here
public static List<Class> listMatchingClasses(String matchPattern) throws IOException {
List<Class> classes = new LinkedList<Class>();
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(matchPattern);
for (Resource resource : resources) {
Class<?> clazz = getClassFromResource(resource);
classes.add(clazz);
}
return classes;
}
public static Class getClassFromResource(Resource resource) {
try {
String resourceUri = resource.getURI().toString();
resourceUri = resourceUri.replace(esourceUri.indexOf(".class"), "").replace("/", ".");
// try printing the resourceUri before calling forName, to see if it is OK.
return Class.forName(resourceUri);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
If you do not want to use external depencies and you want to work on your IDE / on a JAR file, you can try this:
public static List<Class<?>> getClassesForPackage(final String pkgName) throws IOException, URISyntaxException {
final String pkgPath = pkgName.replace('.', '/');
final URI pkg = Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResource(pkgPath)).toURI();
final ArrayList<Class<?>> allClasses = new ArrayList<Class<?>>();
Path root;
if (pkg.toString().startsWith("jar:")) {
try {
root = FileSystems.getFileSystem(pkg).getPath(pkgPath);
} catch (final FileSystemNotFoundException e) {
root = FileSystems.newFileSystem(pkg, Collections.emptyMap()).getPath(pkgPath);
}
} else {
root = Paths.get(pkg);
}
final String extension = ".class";
try (final Stream<Path> allPaths = Files.walk(root)) {
allPaths.filter(Files::isRegularFile).forEach(file -> {
try {
final String path = file.toString().replace('/', '.');
final String name = path.substring(path.indexOf(pkgName), path.length() - extension.length());
allClasses.add(Class.forName(name));
} catch (final ClassNotFoundException | StringIndexOutOfBoundsException ignored) {
}
});
}
return allClasses;
}
From: Can you find all classes in a package using reflection?
Start with public Classloader.getResources(String name). Ask the classloader for a class corresponding to each name in the package you are interested. Repeat for all classloaders of relevance.
Yes but its not the easiest thing to do. There are lots of issues with this. Not all of the classes are easy to find. Some classes could be in a: Jar, as a class file, over the network etc.
Take a look at this thread.
To make sure they were the ICommand type then you would have to use reflection to check for the inheriting class.
This would be a very useful tool we need, and JDK should provide some support.
But it's probably better done during build. You know where all your class files are and you can inspect them statically and build a graph. At runtime you can query this graph to get all subtypes. This requires more work, but I believe it really belongs to the build process.
Using Johannes Link's ClasspathSuite, I was able to do it like this:
import org.junit.extensions.cpsuite.ClassTester;
import org.junit.extensions.cpsuite.ClasspathClassesFinder;
public static List<Class<?>> getClasses(final Package pkg, final boolean includeChildPackages) {
return new ClasspathClassesFinder(new ClassTester() {
#Override public boolean searchInJars() { return true; }
#Override public boolean acceptInnerClass() { return false; }
#Override public boolean acceptClassName(String name) {
return name.startsWith(pkg.getName()) && (includeChildPackages || name.indexOf(".", pkg.getName().length()) != -1);
}
#Override public boolean acceptClass(Class<?> c) { return true; }
}, System.getProperty("java.class.path")).find();
}
The ClasspathClassesFinder looks for class files and jars in the system classpath.
In your specific case, you could modify acceptClass like this:
#Override public boolean acceptClass(Class<?> c) {
return ICommand.class.isAssignableFrom(c);
}
One thing to note: be careful what you return in acceptClassName, as the next thing ClasspathClassesFinder does is to load the class and call acceptClass. If acceptClassName always return true, you'll end up loading every class in the classpath and that may cause an OutOfMemoryError.
You could use OpenPojo and do this:
final List<PojoClass> pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null);
Then you can go over the list and perform any functionality you desire.