How to use a patch jar to override existing Java class files temporarily

Suppose you have a large application running in production. A production issue has been reported to you. You are not sure what the problem is. You want to add some log statements to the code. Perhaps you want to try out a small fix too – a 3 line change in the code of a single Java file. How would you go about using the logging code or the updated class file in your app? You don’t want to go through a complex and formal “Install” procedure for your new version.

One way to do this is –

Make the code changes in your Eclipse workspace (or whatever IDE you use). Use the ‘Export as Jar’ option for the changed source file(s) – export only the compiled class files. Eclipse will put them in the appropriate package structure. Add the the jar onto the beginning of your classpath – how to do this will depend on your application. The easiest way is to just drop it into the $JAVA_HOME\lib\ext folder – the CLASSPATH won’t matter then.

Or you could try something from this list that works for you -

  • Modify a start script.
  • Change an environment variable.
  • Add to a properties file.
  • Maybe change a Jar file manifest.

Of course, you’ll also need to restart your app. Hot-Swapping is also a possibility – that doesn’t need a restart to update classes in many cases. And Java Rebel brings to the table a much more powerful form of Hot-Swapping that requires far fewer restarts. But neither are recommended for production systems.

The class files within your patch jar should now be used rather than your original class files since the class loader will pick what it finds first. When you are done with your testing, you can simply remove the patch jar and restart again. You can even leave the configuration in place – a missing patch jar shouldn’t cause any trouble.



Tags: , , , ,
This entry was posted on Wednesday, March 3rd, 2010 at 1:15 am and is filed under Uncategorized. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

7 Responses to “How to use a patch jar to override existing Java class files temporarily”

  1. Sonika Arora

    I think this is really useful,we often face such situations

  2. Kien Pham

    what a useful article!

  3. paul

    Some more ways are
    1. Make the jar as you said and copy it to the $JAVA_HOME\lib\endorsed folder. If the endorsed folder is not present you can create an endorsed folder and copy the jar files.
    2. Copy the jar file in any directory and set the JVM argument java.endorsed.dirs and point to the folder where the jar lies.
    3. If the application is a web application, then copy the class files directly to the WEB-INF/classes folder with the package structure. Or copy the jar to the WEB-INF/lib and make sure that the name of the patched jar comes first in the alphabetical order.

  4. VIVEK BISWAS

    THANKS PAUL

  5. Onkar Joshi

    “…comes first in alphabetical order.”

    Does the spec guarantee anywhere that alphabetical order will be used? I am under the impression that it doesn’t.

  6. Pratap

    Hi,

    Good stuff. I tried the same, but encountered an error.

    java.lang.reflect.InvocationTargetException
    at sun.reflect.GeneratedMethodAccessor144.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.csxwt.zodiac.client.ui.vesselplanning.ZPPrintContainerAttributeUtil.getValueOfAttribute(ZPPrintContainerAttributeUtil.java:139)
    at com.csxwt.zodiac.client.ui.vesselplanning.ZPDetailedStackPlan$ZPDetailedStackCellRenderer.drawContainerAttributes(ZPDetailedStackPlan.java:446)
    at com.csxwt.zodiac.client.ui.vesselplanning.ZPDetailedStackPlan$ZPDetailedStackCellRenderer.paint(ZPDetailedStackPlan.java:210)
    at com.csxwt.zodiac.client.ui.vesselplanning.ZPVesselPosition.paint(ZPVesselPosition.java:59)
    at com.csxwt.zodiac.client.ui.vesselplanning.StackSection.paintComponent(StackSection.java:1368)
    at javax.swing.JComponent.paint(Unknown Source)
    at javax.swing.JComponent.paintChildren(Unknown Source)
    at javax.swing.JComponent.paint(Unknown Source)
    at com.csxwt.zodiac.client.ui.vesselplanning.ZPDetailedStackPlan.print(ZPDetailedStackPlan.java:1218)
    at sun.print.RasterPrinterJob.printPage(Unknown Source)
    at sun.print.RasterPrinterJob.print(Unknown Source)
    at sun.print.RasterPrinterJob.print(Unknown Source)
    at com.csxwt.zodiac.client.ui.vesselplanning.ZPDetailedStackPrint$1.run(ZPDetailedStackPrint.java:306)
    Caused by: java.lang.NoClassDefFoundError: com/csxwt/zodiac/client/ui/vesselplanning/ContainerValueObjectWrapper
    at com.csxwt.zodiac.client.ui.vesselplanning.ZPContainerValueObjectWrapper.getTemperatureRequiredWithUoM(ZPContainerValueObjectWrapper.java:265)
    … 16 more
    ———–
    But ContainerValueObjectWrapper is available in the existing jar, so why there should be such an exception?

    Kindly help

    Regards
    Pratap

  7. Onkar Joshi

    @Pratap
    Things I would think about:

    - Is the right jar being used where I see the error?
    - I would look into the jar to see if the class is present.
    - Put your jar into the jvm ext folder and then try. – This really should work (as far as there is no confusion about which jvm is being used by the app.)
    - Is there some kind of customized classloader being used?

Leave a Reply

Your comment