Import of Index content with ReadOnlyPDOMProvider - java

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;
}
}};
}

Related

Search and list .m2 (local) maven repository

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);
}

Equivalent of this.getClass().getClassLoader().getResource(".").toURI() from within a Jar

I'm trying to achieve a way to obtain the base path of the current classloader when runnning from within a jar.
I mean programatically, I already know it should have the shape of "jarPath+jarFile.jar!/"
Unlike file system's call, getResource(".") or .getResource("/") do not work from inside the jar.
Ideally it should be an abstract solution for any file provider, so something like:
Path BASE_PATH = Paths.get(...getResource("").toURI())
which could return the correct root path for both jars and file system so I can use relative urls to my resources without having to do any conditional statements and url manual string parsing/build.
You should be able to find out the path of the jar and or target folder containing you class or any resource by using this code:
package com.stackoverflow.test;
import java.net.URL;
import java.nio.file.Paths;
public class ClassPathUtils {
public static String getBasePath(String jarPath) {
String path = getJarPathFromClass(jarPath);
if (path == null) {
return null;
}
if (path.startsWith("jar:")) {
path = path.substring("jar:".length());
}
if (path.startsWith("file:")) {
path = path.substring("file:".length());
}
if (path.endsWith(jarPath)) {
path = path.substring(0, path.length()-jarPath.length());
}
return path;
}
public static String getBasePath(Class clazz) {
return getBasePath(classNameDotClass(clazz));
}
private static String classNameDotClass(Class clazz) {
return clazz.getName().replaceAll("\\.", "/") + ".class";
}
private static String getJarPathFromClass(String resource) {
final URL url = ClassPathUtils.class.getClassLoader().getResource(resource);
return url == null ? null : url.toString();
}
public static void main(String[] args) {
//System.out.println(Paths.get(ClassPathUtils.getBasePath("."))); // doesn't work in a jar
System.out.println(Paths.get(ClassPathUtils.getBasePath(ClassPathUtils.class)));
System.out.println(Paths.get(ClassPathUtils.getBasePath("fonts/atcitadelscript.ttf"))); // any classpath resource
System.out.println(Paths.get(ClassPathUtils.getBasePath(String.class))); // actually finds rt.jar
}
}
If you run this code from your IDE, or from maven, it will give you the paths to target/classes for your own resources, or the path to a jar for other resources (E.g. String.class).
If you call it from a jar, it will always tell you the path of the jar file.
run from IDE:
/home/alexander/projects/stackoverflow/stuff/target/classes
/home/alexander/projects/stackoverflow/stuff/target/classes
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar!`
run from JAR:
/home/alexander/projects/stackoverflow/stuff/target/test-stuff-0.1-SNAPSHOT.jar!
/home/alexander/projects/stackoverflow/stuff/target/test-stuff-0.1-SNAPSHOT.jar!
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar!
Is that what you're looking for?

NetBeans Platform: How to register hidden file types

I'm writing a NetBeans plugin and would like to register a file type. The file type is a hidden file (e.g. ".something") with mime-type text/plain and a settled name (".something"). The registration looks like this:
#MIMEResolver.ExtensionRegistration(
displayName = "#Label",
mimeType = "text/plain+something",
extension = {"something"}
)
#DataObject.Registration(
mimeType = "text/plain+something",
iconBase = "com/welovecoding/netbeans/plugin/logo.png",
displayName = "#Label",
position = 300
)
public class SomethingDataObject extends MultiDataObject {
public SomethingDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
super(pf, loader);
registerEditor("text/plain", true);
}
//...
}
The problem with this is NetBeans will only recognize the filetype if the name of the file has a name, a point and an extension (e.g. "name.something"). Just a point and an extension (e.g. ".something") is not recognized properly. Is there a solution for this kind of problem?
I solved the problem by implementing a custom non-declarative MIMEResolver. Here's the code:
#ServiceProvider(service = MIMEResolver.class, position = 3214328)
public class FilenameResolver extends MIMEResolver {
private static final String mimetype = "text/plain+something";
public FilenameResolver() {
super(mimetype);
}
#Override
public String findMIMEType(FileObject fo) {
String nameExt = fo.getNameExt();
if (".something".equalsIgnoreCase(nameExt)) {
return mimetype;
}
return null;
}
}
There's a declarative MIMEResolver too. Note that the declarative way seems to be preferred by NetBeans-Devs.

Can't load a BufferedImage

I have a form with that code:
public Form()
{
initComponents();
try
{
File file= new File("avatar.jpg");
BufferedImage image= ImageIO.read(file);
}
catch (IOException ex)
{
System.out.println("Failed to load image");
}
}
The problem is that the code always throws the IOException and enters in the catch block.
So the file isn't read.
I have created the project with Netbeans 7.2, and the directory looks like this:
What's the problem? Maybe the file shouldn't be there but in the father directory? Or what?
Is your image being packaged within your jar? to find this out, extract you jar file like you would an ordinary zip file and check if the image is anywhere there (normally located by jarname\packagename\filename. If so then you'll need to extract your image as a resource using getResourceAsStream().
It would be something like:
public class Test {
private static final String absName = "/yourpackage/yourimage.jpg";
public static void main(String[] args) {
Class c=null;
try {
c = Class.forName("yourpackage.Test");//pkg is the package name in which the resource lies
} catch (Exception ex) {
// This should not happen.
}
InputStream s = c.getResourceAsStream(absName);
// do something with it.
}
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader();
if (cl==null) {
return ClassLoader.getSystemResourceAsStream(name); // A system class.
}
return cl.getResourceAsStream(name);
}
public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader();
if (cl==null) {
return ClassLoader.getSystemResource(name); // A system class.
}
return cl.getResource(name);
}
private String resolveName(String name) {
if (name == null) {
return name;
}
if (!name.startsWith("/")) {
Class c = this;
while (c.isArray()) {
c = c.getComponentType();
}
String baseName = c.getName();
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/') + "/" + name;
}
} else {
name = name.substring(1);
}
return name;
}
}
Reference:
Accessing Resources
It looks like you have a namespace of poker.*
It all depends on where the jvm is initialized from.
Where is your main? Is it in /Users/ramy/NetBeansProjects/Poker/src?
Also, I suggest you use getResource() for all of your file loading needs, especially inside jars.
this.getClass().getResource("/resource/buttons1.png")
or
this.getClass().getResourceAsStream("/resource/TX_Jello2.ttf")
You can find out where your programs default path is by doing the following:
System.getProperty("user.dir");
Without seeing the error I would say the most likely cause is it can't find the file. So I suggest you replace "avatar.jpg" in the File constructor with the absolute file path to it. e.g.
File file = new File("INSERT_PATH_TO_FILE/avatar.jpg");
You cannot assume the image will be "there" because the relative path between your .java and the image seems ok.
Accessing a resource depends of your "kind" of project (Web, standalone....). In your case, you can try to get the image from your classpath
final File inputFile = new ClassPathResource("....").getFile();
final BufferedImage inputImg = ImageIO.read(inputFile);

Getting all Classes from a Package

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.

Categories

Resources