Replace jar and redirect import statements - java

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

Related

How can I perform Hot Code Replace in Tomcat web application running outside eclipse?

I am using Hot Code Replace feature when Tomcat is running from eclipse and it works great.
But, how can I do this manually when Tomcat is running outside eclipse?
After some searching, I have found that I need to use an agent like HotswapAgent. But, they are using this agent with modified JDK called DCEVM. I don't want to use modified JDK. I want to achieve the same thing with OpenJDK.
I know that modification will be limited to method body only but, that's not a problem for me. How can I achieve the exact same thing eclipse is doing for Hot Code Replace for an externally running Tomcat without using IDE?
Edit : Eclipse example is just to clarify what I want to achieve. I do not want to use eclipse at all. I just want to do Hot Code Replace in an application running in Tomcat.
Yes, it's possible to perform Hot Code Replace in a running JVM. This involves several steps.
Prepare (compile) the new version of classes you want to replace. Let's say, you want to replace org.pkg.MyClass, and the new version of this class is located at /new/path/org/pkg/MyClass.class
Create a Java Agent that uses Instrumentation API to redefine the given class. Here is how the simplest agent may look like:
import java.lang.instrument.*;
import java.nio.file.*;
public class HotCodeReplace {
public static void agentmain(String args, Instrumentation instr) throws Exception {
Class oldClass = Class.forName("org.pkg.MyClass");
Path newFile = Paths.get("/new/path/org/pkg/MyClass.class");
byte[] newData = Files.readAllBytes(newFile);
instr.redefineClasses(new ClassDefinition(oldClass, newData));
}
}
Compile the above agent and pack it into .jar with the following MANIFEST.MF
Agent-Class: HotCodeReplace
Can-Redefine-Classes: true
The command to create HotCodeReplace.jar:
jar cvfm HotCodeReplace.jar MANIFEST.MF HotCodeReplace.class
Load the agent .jar into the target JVM. This can be done with Attach API or simply with jattach utility:
jattach <pid> load instrument false /path/to/HotCodeReplace.jar
More about Java agents »

Codename One: Annotation Processing

I have a Codename One project on Netbeans using their plugin.
Is there a way to make it work? I enabled it in project's settings and still doesn't show in final jar.
The annotations are in the libraries of the project. and I can see it being done in the output:
warning: Supported source version 'RELEASE_6' from annotation processor 'org.netbeans.modules.openide.util.ServiceProviderProcessor' less than -source '1.8'
I used instructions here: https://netbeans.org/kb/docs/java/annotations-lombok.html
Update:
I thought it was clear but seems it's not. All this is using Netbean's Lookup. Let's say I have one jar as project dependency with one interface in it, let's say ITest. Also a class implementing the interface, for example:
#ServiceProvider(service=ITest.class)
public class Test implements ITest{
..
}
So in the Codenamone Project I call it like this:
Lookup.getDefault().lookupAll(ITest.class);
But it come up empty. I know the system works as it does in other projects, just porting it to Codename one. Seems like it is not seeing the annotations in the dependencies.
I don't know if that will work and I'm pretty curious about it myself. Make sure you created a Java 8 version of the project and you are running on top of Java 8 to get started.
In the past things like this were done using bytecode manipulation e.g. see this code from the work done by Steve.

How can I create and Import Libraries in Netbeans - A Full Documented Q

It's me again. So here's the deal, I still don’t really grasp if I am doing something wrong.
I am trying to create my own Personal Library, in which I have certain string methods and so on.
I’ve started by creating a new Project as a Java library:
Then I've added a package to that library:
After that I've created a class in said package:
Here the code of my class:
And cleaned and built that Class//Library. Run -> Clean and Build
And afterwards created the JavaDoc Run -> Generate JavaDoc(MyTestLibrary)
After doing this i decided to add my newly created Library to the Libraries under Tools - > Libraries:
After that I’ve added a new Library (bottom right) and named it TestLibrary:
SO decided to add the .jar File first. I clicked on the “Add JAR/Folder... ” Option and searched for my Projekt Folder (from MyTestLibrary) and went in to the “dist” folder and selected the .jar file:
After that I’ve added the “src”-Folder in “Sources” and the “javadoc”-Folder in “Javadoc”.
After i was finished it was time to create a new Project, to be precise a new Java Application, and try to import my freshly created library. I rightclicked on Libraries and clicked on “Add Library...”:
And imported my Test Library and adding it:
Happy that I've added my Library to my application I decided to import it
import TestPackage.TestClass;.
If I try
public static void main(String[] args)
{
TestClass.
}
The only suggestion is TestClass.class and not TestClass.TestMethod.
Why can't I access the methods of the “TestClass” directly?
How can I see them?
I've tried being as specific as possible. I hope this time I can fully understand what is going on and why I can't access them.
The solution was fairly simple and obvious.
To access the methods without the need of creating an instance of the class i just had to declare them static.

How to implement a java library in Robot Framework

How can I create a library in Eclipse and then import it in Robot FrameWork?
I am searching a lot now and none of the guides out to help me out.
You need to do the following:
Create your java library
Add it to the classpath when running robot framework jython edition
Creating your java library:
Define a new java class. At this point try not to use a constructor yet (although it is possible to support constructors with fields)
Define the ROBOT_LIBRARY_SCOPE static String variable in the class.
public static final String ROBOT_LIBRARY_SCOPE = "GLOBAL";
Define public methods (not static) that will be used as the keywords
Adding your library to the class path
Compile your classes - ideally to a jar
Add the jar to the class path when running jython. The easiest way to do this is with the MVN Robot Framework plugin. Another option is to wrap the jybot run in a batch file and add CLASSPATH definition to it. There are other options as well (gradle or ant for example).
Using your library in your code
You need to import your library using the full package path
import library org.robot.sample.keywords.MyLibrary
https://blog.codecentric.de/en/2012/06/robot-framework-tutorial-writing-keyword-libraries-in-java/
You can see the full example of how to add a jar when using ride in this article
https://blog.codecentric.de/en/2012/04/robot-framework-tutorial-a-complete-example/

Running Java class with JMeter (Bean Shell)

I have written a Java Class for use in JMeter, packaged the project as a .jar file and moved that file into the lib/ext folder in the jmeter directory. I have seen documentation on how to proceed but they give contradictory answers.
The first way is to use the BeanShell Sampler to import my package and class, create an object of the class and run the methods that way. I have used this method using example classes with more simple file structures than that of class I want to run. The example classes work with the following BeanShell script.
import tools.JmeterTools;
JmeterTools jt = new JmeterTools();
jt.foo();
When I try to use this method for the class I want to run, it states that the variable declaration is an error and the Class cannot be found. I assume this is because I do not understand what to import exactly, as the file structure in my project is a little odd.
The second uses the BeanShell PreProcessor to add the jar to the class path. This method I have not been able to get to work at all, but have read many accounts of others finding success. It works as follows:
addClassPath("directory path to jar\lib\ext\foo.jar");
JMeterTest jtm = new JMeterTest();
jmt.test();
Would anyone have any knowledge of which way would work better or any ideas on how to fix the import?
The import I have been using in the BeanShell script is the following:
import client.JMeterTest;
The package line at the top of my class is the following
import com.x.foo.client;
You need to have your jar file in JMETER_HOME/lib folder.
lib/ext is for JMeter extensions/plugins etc.
Once you have placed your jar, you might have to restart JMeter.
Running external classes from Beanshell should work fine given the following preconditions met
Your test with dependencies is located in JMeter classpath.
JMeter restart is required to pick new libraries up
You need to provide full package name plus full class name (or wildcard) for import.
Either
import com.x.foo.client.JMeterTest;
or
import com.x.foo.client.*;
And finally it is recommended to use JSR223 Sampler and use "groovy" as a language. Beanshell interpreter has severe performance issues so use it for something very "light" like variable amendment, converting variable to property, etc. For generating the real load use JSR223 and groovy as it implements Compilable interface and hence you can achieve performance similar to native Java code. See Beanshell vs JSR223 vs Java JMeter Scripting: The Performance-Off You've Been Waiting For! guide for detailed explanation, benchmarking and instructions on installation of groovy scripting engine support.
For anyone who has this issue in the future. The answers given by others are correct. It wasn't working for me because I had forgotten that Maven does not package files in the test directory when a jar is made.
This link may help if anyone ever does this in the future.
Generate test-jar along with jar file in test package

Categories

Resources