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.)
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;
});
We have a Java program that relies on a specific library. We have created a second library that has a very similar API to the first library, however, this one is made in-house and we are ready to begin testing it.
To test, we would like to replace the jar in the Java program with the jar of our new library. The issue is that the new library does not have the exact same namespace, so the import statements will not align. For example,
Java program
import someLibrary.x.y.Foo;
public class Main {
public static void main(String[] args){
new Foo().bar();
}
}
New Library has the same API but different namespace
anotherLibrary.x.y.Foo;
Question: How can I use the classloader or another tool to run a Java program but replace a dependency and redirect import statements to another namespace?
[EDIT] - We do not have access to the Java program's source code. We can have this program changed to use our new library but we do not want to do that until after it has been thoroughly tested.
The only solution I can think of would involve writing a custom ClassLoader that would alter the bytecode to change the method references and field references to change the class name.
How about the straightforward solution:
Create a branch of your main program (in git or whatever source control tool you use):
Apply all the changes required to work with the new library (change all the imports)
Deploy on test environment and test extensively
Merge back to master when you feel confident enough
Another solution could be:
Create a branch out of new library
Change the imports so that it will look exactly as the old one (with all the packages)
Substitute the old library with a new one in your application
Deploy on test environment and test extensively
When you're ready with the new library deploy to production and keep working in production for a grace period of month or something (until you really feel confident)
In a month change back all the imports (basically move from branch with the "old" imports to the branch with your real imports in both library and application.
Update
Its also possible to relocate packages of your version of the library automatically if you use maven.
Maven shade plugin has relocate goal that can be used to "relocate" the packages of your library to be just like packages of existing library. See shade plugin's documentation
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) {
}
I have a basic maven project with the folder structure: -main and -test directories.
I have one package in the main source directory which consists of a few classes, say a.class b.class and c.class, all under the same package. All classes have dependencies to each other. To do proper unit testing, and to cut the dependencies from each class, I write stub classes of each a, b and c class, define them to have the same package and put them inside the test source directory. Then I run: mvn test
Fine, the stubs are now being found first from the classpath and used, but I want to modify the classpath (on the fly?) so that, when testing class a, I need to have the original a.class and stubs used for b.class and c.class. Similarly, when testing class b, I need to have the original class b and stubs used for a.class and c.class.
How do I accomplish this using Maven and JUnit?
This is kind of frustrating in Java, because in C++, one can use the makefile source path and user defined include paths in unit test header files to force the stubs to be found first and then explicitly add an include to the original class to be tested.
If you have dependent classes you schould use interface for each class. Then you can resolve dependency problems actually...
Like #khmarbaise already pointed out you are going the wrong way. In Java it is good practice to use Mocking libraries like Mockito and PowerMock if you want to test static methods.
Those libraries help you to write Stubs for your existing classes without to modify the classes themselves. Check Maven Central for Mockito. You can include it with maven via
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
Then using JUnit you end up writing Mocks for your existing classes. There are many tutorials regarding Mockito out there.
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.