Java, create runnable jar file including ONLY used dependencies. - java

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.

Related

PsiClass to java.lang.Class

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

Referencing a function from another drl file in a separate maven project

I have multiple maven projects with DROOLs drl files in them. I would like to put things like helper functions in a central location and then have the drls in other projects be able to use them, but it isn't working.
The common project is a maven dependency in the other projects. I can prove this is working because I have access to the facts that I define in the common project, but I don't have access to functions.
I initially tried creating a file called:
helperfunctions.drl and put the functions directly in the file thinking they would be available without any imports when building and they are not found.
I then tried wrapping the functions in a declare HelperFunctions end, but this syntax doesn't work.
Finally, I tried changing the file to HelperFunctions.java and did public class HelperFunctions and made all of the methods static. Then in the other project drls I imported using the namespace com.myproject.common.
I am out of options, is there anything else I can try or is this not possible?
I'm a little unclear about what you've attempted, but Java code from a dependency (your point #3) can be invoked from the rules if you have the Jar on your classpath.
Imagine you have your project set up as follows:
|-rule-utils (project name)
|-- src\main\java\com\mycompany\common\HelperFunctions.java
|--pom.xml
And you have defined some utility function public static void doSomethingUseful() in your HelperFunctions class.
In your other project where your rules exist, you can include your project1 jar as a dependency, possibly as follows in your pom:
<dependency>
<artifactId>rule-utils</artifactId>
<groupId>com.mycompany</groupId>
</dependency>
And then you can import and use HelperFunctions and its doSomethingUseful method as you would any other Java code in your drl:
import com.mycompany.common.HelperFunctions;
rule "Example rule"
when
then
HelperFunctions.doSomethingUseful();
end
In my experience, it's pretty common to invoke third-party utility code this way, for example the Apache commons' utility classes like StringUtils and CollectionUtils (though more often on the left hand side than in the consequences.)

Is "main.class" XML element required in Maven's pom.xml if the artefact is a library?

I'm creating a pom.xml for a project that is a library.
Is <main.class> POM XML element under <properties> required for this?
(the library has a small test Main.java which I didn't really intend to include in the library JAR file in the first place, so I'd rather not use that test file as main.class unless required).
Is “main.class” XML element required in Maven's pom.xml if the artefact is a library?
No.
At the most basic level, maven creates jars from projects of a certain structure, it does not care if you have a main class or not. Using mvn clean install:
This command tells Maven to build all the modules, and to install it in the local repository. The local repository is created in your home directory (or alternative location that you created it)... (which other projects can declare as a dependency)
The only time maven cares about having a main class, is when you want to make the jar executable
What do you mean by "main.class"? A class Main? No, it's not required.
If you meant a method main, an entrypoint to execution like below, it's not required either. Unless you want to execute the code directly.
public static void main(String[] args) {
}

Developing application with plugin support in Java

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

Added jar in BootStrap location is not reflecting in My Classes using Eclipse

Please help me to understand whats wrong with this.
I added a jar in a BootStrap location of
jdk(C:\Program Files\Java\jdk1.6.0_27\lib\ext) and in jre(C:\Program
Files\Java\jre1.6.0_22\lib\ext)
but jar class is not reflecting while try to invoke methods or classes added by jar in Eclipse.
Also help me to know where I can see the printed things by static block by Logs.......
Below I included the class I used to create the JAR.
package test.classloader;
public class BootStrapTest {
static
{
System.out.println("BootStrap Jar is Loaded....................");
}
public static String checkClassLoader()
{
return "This is BootStrap Class Check ClassLoader";
}
}
I am going to take a stab at the reason behind why you think you need to do this. Excuse me if I am incorrect but you provide vague information and it is unclear what your question is.
If you need missing Java EE libs (or other 3rd party libs) in Eclipse, add one of the sofware REPOs (to your Eclipse software manager) listed on this URL and then install the Java EE libs from it: http://download.eclipse.org/tools/orbit/downloads/
Or, use Maven as a build tool and add the appropriate dependency to download the lib that your project needs.

Categories

Resources