I'm using xtext 2.13/java8 to create a DSL with IDE as described in "Implementing Domain-Specific Languages with Xtext and XTend 2nd edition".
The IDE includes a new project wizard, and the DSL includes a code generator that produces java code. The generated java code depends on some helper classes in another support plugin that is provided as part of the DSL project.
I can export the update site and install into a fresh eclipse.
There, I can create a new DSL project that compiles the DSL file into java.
I would like to extend the new project wizard so that I can automatically add the dependency on my support plugin to the generated MANIFEST file in the new project. I can add it manually after the project is created (the plugin is present in the installed feature), but I don't want users to have to do that.
org.eclipse.xtext.ui.wizard.AbstractPluginProjectCreator has code that adds the dependencies on logging packages, but I don't see any way to extend or override that logic using any extension points. Is there a way to do this?
This turned out to be not too hard, though it took a half-day of experimenting to find it.
The xtext project defines a generated MyDSLProjectCreator class in the *.ui plugin under src-gen in the .ui.wizard package that defines the method we need to override:
#Override
protected List<String> getRequiredBundles() {
return Lists.newArrayList(DSL_PROJECT_NAME);
}
By default, this adds just the DSL project bundle to the dependencies of the new project. I need to add also the support plugins. I can't edit this generated file, but I can extend it, so I defined MyExtendedProjectCreator class in the src folder of the same .ui.wizard package that extends this class (java source):
public class MyExtendedProjectCreator extends MyDslProjectCreator {
#Override
protected List<String> getRequiredBundles() {
return Lists.newArrayList(DSL_PROJECT_NAME,
"my.plugin.id");
}
}
To invoke that project creator instead of the default, I had to override another method in the MyDslUiModule class. This can be found in the .ui package under src (xtend file):
#FinalFieldsConstructor
class MyDslUiModule extends AbstractMyDslUiModule {
public def override Class<? extends IProjectCreator> bindIProjectCreator() {
MyExtendedProjectCreator;
}
}
Related
I'm developing plugin for IntelliJ IDEA. How can plugin get the name and version of libraries that are imported to the project that is being checked by plugin? I have PsiClass of the project, but cannot convert it to java.lang.Class. Maybe there's the way to get ClassLoader from PsiElement?
super.visitImportStatement(psiImport);
Class importedClass = Class.forName(psiImport.getQualifiedName(), true, psiImport.getClass().getClassLoader());
PsiImport.getClass().GetClassLoader() - returns ClassLoader of class PsiImportStatementImpl instead of ClassLoader of class that I've imported.
IntelliJ does mostly static analysis on your code. In fact, the IDE and the projects you run/debug have completely different classpaths. When you open a project, your dependencies are not added to the IDE classpath. Instead, the IDE will index the JARs, meaning it will automatically discover all the declarations (classes, methods, interfaces etc) and save them for later in a cache.
When you write code in your editor, the static analysis tool will leverage the contents of this index to validate your code and show errors when you're trying to use unknown definitions for example.
On the other hand, when you run a Main class from your project, it will spawn a new java process that has its own classpath. This classpath will likely contain every dependency declared in your module.
Knowing this, you should now understand why you can't "transform" a PsiClass to a corresponding Class.
Back to your original question:
How can plugin get the name and version of libraries that are imported to the project that is being checked by plugin?
You don't need to access Class objects for this. Instead, you can use IntelliJ SDK libraries. Here's an example:
Module mod = ModuleUtil.findModuleForFile(virtualFile,myProject);
ModuleRootManager.getInstance(mod).orderEntries().forEachLibrary(library -> {
// do your thing here with `library`
return true;
});
I am trying to write one custom Gradle plugin and intent is we have good number of microservice.
Those microservices use lots of common library. So instead of declaring those library in each sub-project.
I want to create one custom Gradle plugin where I will add all library and other project just need to use that plugin.
I am done with custom plugin and its integration with other project and looks fine.
But not sure how to add common dependencies in plugin. either implementing Plugin interface or something else.
In my plugin class I am trying to the following things and its not working.
Can someone suggest me how can achieve this task. is it something I need to change here or need to follow some different approach.
public class CommonResourcesPlugin implements Plugin<Project> {
#Override
public void apply(Project project) {
log.info("Applying depdencies ");
project.getDependencies().add("implementation", "org.springframework.boot:spring-boot-starter-web");
project.getDependencies().add("implementation", "org.springframework.boot:spring-boot-starter-actuator");
}
}
I have been researching on how to develop an application that can load plugins.
So far, I've seen that this can be done by defining an Interface, and have the plugins implement it.
However, my current issue is on how to load the plugins when they're packed in Jars. Is there a "best" way to do it?
The current logic I'm thinking of is to get each plugin and inside their Jar look for the class that implements the Interface. But I don't know how to do such lookup. I think that this logic may not be a good one, but I couldn't find any useful information on this specific topic.
**Edit1: **
Adding more information:
The intended plugins would be Jar files contained inside a subdirectory where the main application's Jar would be located, like this:
Application's folder
|- Main_Application.jar
|- Plugins
|- Plugin1.jar
|- Plugin2.jar
|- Steve's_plugin.jar
And so on.
What I expect is that the Application will be able to load all plugins inside the folder at runtime. So in the code, it would only be aware that the plugin's folder should exist and there should be Jars inside such folder.
Let's say I have a plugin interface like this:
interface Plugin
{
public void run();
}
Plugins would be identified by a class that implements such interface, like so
class Plugin1 implements Plugin
{
//attributes and other methods
#override
public void run()
{
//something happens here
}
}
class Plugin2 implements Plugin
{
//attributes and other methods
#override
public void run()
{
//something happens here
}
}
The Application should be compiled only once, and be able to load any Plugins added to the folder when it is executed.
For the Application to be able to load any Plugin, do I need to establish rules on the contents of the Jar, like package name and the class that implements the interface? Or it is expected that the class implementing the plugin interface could be in any package within the Jar, and have any name?
This is the more generic approach to what I would like to do with such plugins. In short, I'm planning to build an Application that will have tabs, and each plugin will provide the Interface and Functionality of each tab. I'm trying this because I want to be able to maintain each tab separately, and don't want to recompile the whole application because of changes in only one component that don't affect the others at all.
Get the list of plugin jars:
File[] jars = new File("Plugins").listFiles();
Then, use the code from this answer about loading all classes from a JAR file, but run it once for each file in jars whose name ends in ".jar". At the bottom of the loop body, after
Class c = cl.loadClass(className);
continue with
if (Plugin.class.isAssignableFrom(c)) {
Plugin plugin = (Plugin) c.newInstance();
// And then, do something with the plugin here
}
I share #Mifeet's concerns about security - you might want to use a SecurityManager to limit what the plugin code is allowed to do.
Very old question, but still relevant if some one searches.. Adding to the accepted answer,
Use OSGI framework
Refer Apache Felix for a reference implementation
If you wanted to have a light version of OSGi, try to use apache connect - pojosr
This question has been asked before, but have no satisfactory answer yet!
I have a Java Main.java class in a project full of other unrelated classes. I would like to export that Main.java into an executable jar file, containing only the dependencies it ACTUALLY uses.
Is this possible, if so how?
Both Eclipse( create runnable jar ) and Intellij ( create artifact ) will include all dependencies defined in the module containing the Main.java class.
You should really be using a dependency management system, instead of the ones provided by default in Eclipse and IDEA. Many Java developers (including me) use Maven. If you're working in Eclipse, it includes m2eclipse
You don't want to have all the dependencies in one project because it can get really bloated. However, if you have a Maven parent pom that uses the <dependencyManagement> tag, you can easily just reference this parent pom and then easily only make references to the dependencies you need in that sub project. This keeps everything separate that actually is separate, and provides an easy organization mechanism - the reason why people use Maven.
How to use <dependencyManagement> in Maven
Maven also has plugins that manage your jar creation for you, e.g. maven-assembly-plugin that allow you to construct your dependencies exactly how you want them in the jar and so forth.
You have to do this yourself somehow. What do you expect any IDE / dependency management system to do with the following code:
Test.java
public class Test {
public static void main(String... args) {
System.exit(0);
new Foo(null);
}
}
Foo.java
import com.google.common.base.Preconditions;
public class Foo {
public Foo(String s) {
Preconditions.checkNotNull(s);
}
}
The Guava dependency is not needed here... but you only know that in RUNTIME. If you include all the import statements of all the classes, then you include all the dependencies. If you don't, then you need to do runtime analysis. Your problem is akin to the Turing halting problem.
I have a custom type of archive that I want to build with gradle, the structure is equals to a standard java project so I'd like to use it but then I have other resources that go to a custom location, additionally I'd like to package the archive as a zip and not as a jar, I'm thinking of creating a subclass of the Java gradle plugin but I'm not sure if this is the way to go. What would be the appropriate way of creating this new plugin that inherits the Java functionality?
if you want to create a custom java plugin that has conventions, that differ from the standard gradle plugin, I recommend to start with the java-base plugin. The java-base plugin does provide the functionality of sourcesets but does not already any of them.
Instead of inheriting a plugin you should apply it in your custom plugin:
class YourCustomJavaPlugin implements Plugin<Project> {
void apply(Project project){
// 1st apply the 'java-base' plugin
project.apply(plugin:'java-base')
// 2nd apply your own conventions on top
project.sourceSets.create("customSourceSet")
Zip myZip = project.tasks.create("zip", Zip)
...
}
}
cheers,
René