I have class A, and class B that inherits A in Eclipse workspace.
The issue that I have is that I got nothing when I tried to get the super types of type B using eclipse JDT API. This is the code (I got the code from - List all subclasses with fully qualified names):
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
java.io.File workspaceDirectory = root.getLocation().toFile();
// 1. The name of the project in the workspace
IProgressMonitor pm = new NullProgressMonitor();
IProject orig = root.getProject(this.projectName);
orig.open(pm);
this.javaProject = JavaCore.create(orig);
orig.refreshLocal(IResource.DEPTH_INFINITE, pm);
// 2. Find the type
IType type = this.javaProject.findType("p.B"); <-- returns correct type info
ITypeHierarchy hier = type.newSupertypeHierarchy(new NullProgressMonitor());
IType[] types = hier.getAllSuperclasses(type);
System.out.println(types); <-- Returns []
I also added the code to refresh/update the resources in package.
IPackageFragmentRoot[] packageFragmentRoots = this.javaProject.getPackageFragmentRoots();
for (IPackageFragmentRoot proot: packageFragmentRoots)
{
proot.getResource().refreshLocal(IResource.DEPTH_INFINITE, null);
}
Everything works fine except getting the hierarchical type information.
What might be wrong? Did I miss any setup before executing the API?
Mine is a headless RCP application.
This may be a temporary solution, but it worked for me.
Short Answer
Make a lib directory, and copy this rtstubs.jar into the directory.
You may need to refresh(F5) the eclipse IDE to see the jar file is included in the project.
Then, in "Java Build Path", you need to add this jar file.
After the inclusion of the jar file in package fragment, you'll get the class hierarchy.
Long Answer (why does this solve the issue)
CompilationUnitDeclaration (org.eclipse.jdt.internal.compiler.ast) and Hierarchy Resolver (org.eclipse.jdt.internal.core.hierarchy)
It has a field ignoreFurtherInvestigation, and a method hasErrors() returns this field.
org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver#resolve() method invokes hasError() to add type information to cache. However, without the inclusion of the jar file, the hasError() method always returns false to prevent any class hierarchical information is stored.
org.eclipse.jdt.internal.core.JavaProjectElementInfo
This class has cache initialization methods such as initializePackageNames and getProjectCache. In getProjectCache() method, package fragment element roots are loaded and added to the cache.
With the rtstubs.jar in the package fragment, the cache now contains all the Java class hierarchy. Without this setup, in the course of cache build up, the ignoreFurtherInvestigation filed is on, and hasError() method returns true not to contain the class hierarchical information to return just nothing.
ADDED
The other solution can be using IRegion.
How can I set the region (=set of java Elements) parameter in JDT TypeHierarchy?
Related
I have been trying to do a kind of plugin-system using the ServiceLoader. There are 2 modules, the first provides the abstract class LoadedRealmPlugin. The second one extends this class. I have added the file corresponding to the full name of the ServiceProvider and added the service-class to it. IntelliJ does not find any errors (but when changing the filename or classname it does). Here is the structure:
MainModule
src
main
java
com.interestingcompany.mainmodule
LoadedRealmPlugin
MainModule.iml
Plugin
META-INF
services
com.interestingcompany.mainmodule (-> Content: "PluginExtension")
src
PluginExtension
Plugin.iml
(This is simplified, I left out classes that (I think) are not important to the ServiceLoader. I can post a screenshot of the actual structure if anyone needs it)
Here is the code I use to load the Service:
File file = new File("Plugins/Plugin.jar");
URLClassLoader c = new URLClassLoader(new URL[]{file.getAbsoluteFile().toURI().toURL()});
ServiceLoader<LoadedRealmPlugin> loader = ServiceLoader.load(LoadedRealmPlugin.class, c);
LoadedRealmPlugin p = loader.iterator().next(); // Throws a java.util.NoSuchElementException
p.Initialize(RealmPath); // Abstract method implemented in the service
return p;
When trying to run it, I always get an empty ServiceLoader. I looked at this post, but I was not quite sure about how to apply that answer since I am trying to load my plugin from a file. In addition, I found this post. Yet, there was no answer, just some comments that did not seem to have answered the question.
As you might have been able to tell, this is my first time working with classloaders. If there is any additional information needed, just ask me. Thank you for reading through my beginner troubles.
package-less classes are in the unnamed package, which is inaccessible to rather a lot of code, notably including here.
Put PluginExtension.java in a package, make sure the content of your META-INF/services/com.ic.mainmodule file reflects this (content should be pkg.PluginExtension), and it'll work fine.
In a Tomcat 7 I have a pretty standar jar file on WEB-INF/lib. Inside this jar I have this class called Parser, and next to it (on the same dir) I have another one called AutomaticLocalLoader. Compilation gives no problem at all. In run time the AutomaticLoader class is found, and when It needs the Parser class, I get a NoClassDefFoundError
The Parser and AutomaticLoader class have been working without this problem for 15 years!! in many diferent vers of java and tomact; and now out of the blue, I am getting this NoClassDefFoundError, only for the Parser class. I already put a copy on a directory inside the WEB-INF/classes path and still got the same error. I already created my own ClassLoader to see if I get some error loading the class from the WEB-INF/classes directory by myself, but I can load it without problems.
log.info("Leer " + aFlInstructions[i].getAbsolutePath());
LoaderTest A = new LoaderTest();
A.test("com.hds.resolve.model.aguila.AutomaticLocalLoader");
LoaderTest B = new LoaderTest();
B.test("com.hds.resolve.model.aguila.Parser");
if(!bOverrideInputDir)
Psr = new Parser(aFlInstructions[i]);
else
Psr = new Parser(aFlInstructions[i], new String[] { StrLocalDirectory } );
The LoaderTest class, try to create the Class Object for the given name using Class.forName. If NoClassDefFoundError, then try to load the class using my own classloader and then create the class.
For the AutomaticLoader, it succed at the first try. For the Parser class if fails, then successfully load it with the custom classloader. Of course when the code reach the "new Parser" part, the old webclassloader still fails and throws the NoClassDefFoundError.
Both Parser and AutomaticLocalLoader belong to the same package and are stored on the same jar inside WEB-LIB.
Funny enough, the error does always happen on production... but never in my machine. I do not use customs classloaders except for doing this debug. Also, trying an old version of the software seems to fix the error. No idea why.
I think I can hack a solution messing with the tomcat's webclassloader, but I really would prefer to understand what is going wrong with this code.
I have a problem integrating Java code into KNIME. Similar posts on Knime forum (http://tech.knime.org/forum/knime-general/using-external-jar-in-java-snippet-node-workflow-not-able-to-initialize-class-of) were of little help and I also posted a question there but have not got answer so far, so I'm trying my luck here.
I am trying to integrate my code into KNIME workflow using JavaSnippet. I have exported the code into a jar and put it into the KNIME jre/lib/endorsed folder. The code references CDK 1.4.19 and I have also placed the corresponding jar file into the same directory. I do not have CDK node extensions installed in KNIME and using them is also not an option in my case.
The code starts with:
IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
SmilesParser sp= new SmilesParser(builder);
When I try to execute JavaSnippet I get the following exception message:
Evaluation of java snippet failed for row "Row0". Exception message: Could not initialize class org.openscience.cdk.smiles.SmilesParser
When I just try
IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
It works and I get no exception message. I have checked, the builder is not a null. However, when I try to initialize SmilesParser, it fails. This class is public. It has no default constructor and has one public constructor that takes IChemObjectBuilder as a parameter.
I have tried to use class loader:
URL[] classLoaderUrls = new URL[]{new URL("file:///path on my computer/knime_2.9.4/jre/lib/endorsed/cdk-1.4.19.jar")};
URLClassLoader urlClassLoader = new URLClassLoader(classLoaderUrls);
Class<?> parserClass = urlClassLoader.loadClass("org.openscience.cdk.smiles.SmilesParser");
Class[] classParameters = new Class[] {IChemObjectBuilder.class};
Constructor<?> constructor = parserClass.getConstructor(classParameters); //until this line there are no problems
Object parser = constructor.newInstance(builder); //fails here with the same exception message: Could not initialize class org.openscience.cdk.smiles.SmilesParser
I am sure that this is not a CDK error because I can execute the code in Eclipse.
Why can a constructor of one class be called from KNIME without any problems and a constructor of another class can not??
I would be very grateful if you could suggest a solution or a probable reason why this happens.
Thank you!
Ok, finally solved the problem myself. Cleaned project meta data, cleaned endorsed library directory, switched KNIME workspace to another directory, put all jars into one folder and added them as external libraries. Now it works:)
I have a .java file which contains a class. I want to add a method to that class but I can't find a real useful "HOWTO" or examples around.
I'm using Eclipse and its JDT plugin for AST.
I tried a code that creates an ICompilationUnit from a project
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("ProjName");
IJavaProject javaProject = JavaCore.create(project);
IPackageFragment package1 = javaProject.getPackageFragments()[0];
ICompilationUnit unit = package1.getCompilationUnits()[0];
then add a method with astrewrite.
But it seems to work only if I run all as a Plugin Project and not a simple Java Application.
I need to write an application in java that "simply" parse a java file and adds method to its class.
What I supposed to do is:
1) Create an ICompilationUnit directly form the .java file I want to parse (eventually located in my own project's directory)
2) Using another way
Both case I can't go further. Anyone can help me?
When you need to make a change by adding something to the compilation unit, you will have to use the functions provided by CompilationUnit to create new nodes.
To add a method to "unit" you will have to :
Create a MethodDeclaration node using your compilation unit :
MethodDeclaration md = unit.getAST().newMethodDeclaration();
Customize this method declaration to your requirements :
md.setName( unit.getAST().newSimpleName( "newMethod" ) );
md.setBody( unit.getAST().newBlock() );
this will produce : void newMethod() {}
Obtain the TypeBinding from "unit" :
TypeDeclaration typeDeclaration = ( TypeDeclaration )unit.types().get( 0 );
Add your newly created MethodDeclaration to the body declarations :
typeDeclaration.bodyDeclarations().add( md );
There's a method called getMethods() on TypeDeclaration but it doesn't return a live list of MethodDeclarations, therefore you can't modify that directly.
It's really easy to read the source file as text and replace the last } with the method declaration plus }. Obviously this doesn't work if someone puts multiple top-level classes in one file (which is extremely rare and I doubt you'll have a problem with that).
I'm trying to obtain details of an Eclipse user's structured selection in the Navigator Tree view. At present I have the following which is based on the org.eclipse.ui.popMenus extension point:
public void run(IAction action) {
Shell shell = new Shell();
ISelection selection = workbenchPart.getSite().getSelectionProvider().getSelection();
if (structuredSelection instanceof org.eclipse.jface.viewers.TreeSelection) {
org.eclipse.jface.viewers.TreeSelection treeSelection = (org.eclipse.jface.viewers.TreeSelection) structuredSelection;
IAdaptable firstElement = (IAdaptable) treeSelection.getFirstElement();
// Relies on an internal API, bad juju
if (firstElement instanceof org.eclipse.jdt.internal.core.CompilationUnit) {
org.eclipse.jdt.internal.core.CompilationUnit compilationUnit = (org.eclipse.jdt.internal.core.CompilationUnit) firstElement;
String editorSelection = new String(compilationUnit.getContents());
}
}
The problem with this is that it's currently coupled to the JDT compilation unit API, which is internal and too specific for what I want.
Ideally I want to be able to get the underlying file name, type and contents without having to rely on:
An internal API
The JDT Compilation Unit Code.
This would then allow me to obtain the properties of a generic file when the user right clicks on a file in the navigator view.
Can somebody provide me with any pointers on how I go about doing this please?
[EDIT: I added the following alternative - the original answer is father down]
First: if you select something in the Package Explorer, the selected items are all Java Model objects - you have to deal with them at some level. There are two ways you can handle this:
Use the ICompilationUnit directly (see farther down)
Create an Eclipe adapter factory to automate the conversion
Adapter Factory Approach
You can create an adapter factory (which can live in your main plugin or a different one) that eclipse can use to automatically convert from an ICompilationUnit to an IFile.
Note: if you create the adapter factory in a different plugin, you'll probably need to set up an early-startup for it to get the adapter factory loaded. Otherwise, you'll need to have your plugin that will work with the selection depend on the plugin that provides the adapter.
There's some great details on adapters at http://www.eclipse.org/resources/resource.php?id=407, but I'll go over an implementation for this problem here.
Dependencies
The plugin that will host the adapter needs the following dependencies
org.eclispe.core.resources
org.eclipse.jdt.core
The adapter factory class
Define the following class in your new plugin
package com.javadude.foo;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.jdt.core.ICompilationUnit;
public class CompilationUnitToFileAdapter implements IAdapterFactory {
#Override
public Object getAdapter(Object adaptableObject, Class adapterType) {
if (adaptableObject instanceof ICompilationUnit)
// note: "adapting" it here just means returning the ref'd IFile
return (IFile) ((ICompilationUnit)adaptableObject).getResource();
return null;
}
#Override
public Class[] getAdapterList() {
return new Class[] {IFile.class};
}
}
The extension
In the plugin that will host the adapter factory, add the following to your plugin.xml:
<extension point="org.eclipse.core.runtime.adapters">
<factory
adaptableType="org.eclipse.jdt.core.ICompilationUnit"
class="com.javadude.foo.AdapterFactory1">
<adapter type="org.eclipse.core.resources.IFile" />
</factory>
</extension>
Using the Adapter
With the above in place, you can now write:
Object firstElement = ((ITreeSelection) selection).getFirstElement();
IFile file = (IFile) Platform.getAdapterManager().
getAdapter(firstElement, IFile.class);
if (file == null)
// adapter not present; cannot use as IFile
else
// adapter present - you can use it as an IFile
Using this approach, you can add additional adapters to convert other types to IFile and your selection code doesn't care.
Direct ICompilationUnit Approach
[EDIT: I've changing the answer, but leaving the following as reference information b/c it's the standard way to explore the content of a compilation unit that was selected in the package explorer]
This is actually the preferred way to get the contents of a file in the package explorer...
Rather than use CompilationUnit, you should use ICompilationUnit. Most of the eclipse APIs use interfaces for public consumption, and classes for internal details.
If you change your code to
if (firstElement instanceof ICompilationUnit) {
ICompilationUnit unit = (ICompilationUnit firstElement;
String contents = new String(unit.getContents());
}
You'll be in good shape.
To see details of examining/modifying the Java Model and source code:
(In Eclipse)
Help->
Help Contents->
JDT Plug-in Developer's Guide->
Programmer's Guide->
JDT Core
That shows how to work with the Java Model appropriately
To isolate where you reference the java model, you can create an (eclipse) adapter that will convert Java Model objects into files. Assuming such an adapter exists, you can then ask the AdapterManager to convert it to a java file for you. I'll take a peek and see if one exists.
That (decoupling Resource from JDT) was one of the goals of E4 (Eclipse 4).
The plugin list for REsources doesn't mention JDT anymore (again, Eclipse 4.x only):
org.eclipse.core.filesystem - An abstract, generic file system API, including an implementation of this API for the local file system. This is the API through which the resources plugin accesses an underlying file system.
org.eclipse.core.resources - Contains the API and implementation of the resource model
org.eclipse.core.resources.compatibility - A plug-in providing migration support for users opening old workspaces in Eclipse 3.1 or greater
A Demo project like e4photo don't require any JDT for accessing IResource from the selection of an IContainer.
void setSelection(#Named(IServiceConstants.ACTIVE_SELECTION)
IResource selection) {
...
IResource[] members = input.members();
...
IResource resource = members[i];
if (resource.getType() == IResource.FILE) {
InputStream contents = ((IFile) resource).getContents();
What are you trying to achieve? Do you want to get file contents? Then you can try:
IAdaptable firstElement = (IAdaptable) treeSelection.getFirstElement();
IFile file = (IFile) firstElement.getAdapter(IFile.class);
if (file != null && file.isAccessible()) {
// Use getContents API
....
}
It looks like the JDT is already defining an IAdapterFactory for all Java elements including compilation unit (org.eclipse.jdt.internal.ui.JavaElementAdapterFactory). The adapter is defined for IResource rather than IFile so you should be able to do:
Object firstElement = treeSelection.getFirstElement();
IResource resource = (IResource)Platform.getAdapterManager().getAdapter(firstElement, IResource.class);