Class loading issue for a Buggy Jar - java

Short Question
I have the same class (fully qualified com.example.pkg.cls.ClassName) in a jar and my web application code base. When my application loads, I want to load the class in my Web application instead of the one at the jar in classpath.
How should I do that?
Long Question
I have a situation like this here:
I have a web application with a JAR A as a dependency. The jar is a third party jar (some Amazon SDK). JAR A has a dependency on JAR B (some commons-lang).
Recently I upgraded the Web application to run Java 11 from Java 7. There is some bug in JAR B which is failing a code flow (specific to Java 11, tries to parse the java.version string). I have already checked for different versions of JAR A which might fix the problem but it doesn't. Infact, JAR A is deprecated and is no more available.
The part that is failing in JAR B is a toString method and in JAR A is a log statement. I am totally ok if that toString method doesn't return anything or returns a blank String.
After trying multiple solutions over days, I have been suggested to do this:
1 - Write a class with the same fully qualified class name as the failing class in B, copy the code and change the toString method.
2 - Load the class explicitly at startup, so that when the API is hit my class is already loaded over the class inside JAR B.
I have two questions here:
1 - Is there a problem with this approach?
2 - How can I load a class in my own project. Can anyone provide a code sample for this.

Related

JasperReport cannot find symbol JREvaluator in WildFly, works without server

Recently I've been working on report generation with Jasper. I have created a simple program to test it and when running it via IDE it did work fine.
Then I moved the (very short) class to WildFly sever application and despite having the exact same code and library generation fails with cannot find symbol. Those symbols it cannot find are JREvaluator, JRFillVariable as well as packages such as net.sf.jasperreports.engine
In so far I have confirmed that:
Project builds (meaning those classes are visible for javac, but not jvm)
jasperreports-6.13.0.jar is added to war (it's present in /WEB-INF/lib folder alongside other libraries, like gson and hibernate
jasperreports-6.13.0.jar contains the missing classes
It looks to me like the problem doesn't lie in library not being loaded or missing classes (because in testing environment it works), but like something was preventing JBoss class loader from loading those classes
Attempted (and failed) solutions
Clean and Build
Adding -Djava.awt.headless=true to VM options - this did not changed anything
Adding -Djava.awt.headless=false to VM options - also didn't change a thing, but once caused NullPointerException inside jasperreport library. For testing program - worked in both cases
Adding commons-beanutils-1.9.4.jar, commons-digester-2.1.jar, commons-collections4-4.4.jar and commons-loggin-1.2.jar - with no changes
Adding jasper-compiler-jdt-5.5.23.jar - this caused a different error, namely NoSuchMethodError for org.eclipse.jdt.internal.compiler.ICompilerRequestor and few others. This library however should not be necessary as - from what I understand - jasperreport-6.13.0.jar already contains it's compiler and separate library for compiler is not required since a long time.
What has not been attempted:
Forcing the classes to load (http://www.java2s.com/Code/Java/Reflection/Forcethegivenclasstobeloadedfully.htm)
Dynamically loading jar during Runtime or using custom class loader
Update: after looking at this answer and applying the suggestion the missing class was different. Which suggests that the dependencies inside jasperreport.jar are not being loaded properly
I have figured it out
For some reason in server project libraries used by jasperreport.jar were not loaded, but in the testing project they were (might be due to WildFly, might be due to differences between IntelliJ and NetBeans)
Here is the list of libraries, based on pom.xml file in jasperreport.jar that I have added. Some might not be necessary and the list might not be exhaustive (I basically stopped adding libraries once report started generating) but it's good enough base if someone else runs into this problem:
commons-beanutils-1.9.4.jar
itext-2.1.7.jar
poi-ooxml-4.1.1.jar
commons-collections4-4.4.jar
jcommon-1.0.23.jar
xalan-2.7.2.jar
commons-digester-2.1.jar
jfreechart-1.0.19.jar
xmpcore-5.1.3.jar
commons-logging-1.2.jar
poi-4.1.1.jar

Oracle Rules - Imported Java Fact causes UndefinedException when deployed

In JDeveloper 12c, I have created a BPM application/project. Project SOA Settings are Composite With Business Rule.
The project has a Mediator and is exposed as a REST service. I am deploying using the IntegratedWebLogicServer
The XML Facts are rather generic including lists of fields, sub-lists, and sub-sub-lists, etc. This makes navigating the inputs more challenging.
I created a Java class with some static methods that more easily retrieve the data based on an expression. I created a jar with that class and then imported the class into the Java Facts. I then created rules that call the static methods on that Java Fact.
The rules validate just fine and I can now successfully run the rules from the "Test" tab of the rules. I get expected results. However, when I deploy the project it seems like the imported jar is not deployed along with it since I get the following exception:
oracle.rules.rl.exceptions.UndefinedException: The symbol "mypackage.MyUtil" is undefined.
at line 22 column 14 in /Ruleset(main)
I thought that importing the class in the Java Facts would cause my custom jar or at least the class that I imported to be deployed. But it seems that this may not be the case. Am I missing something? Is there somewhere in my project that I can place the jar to cause it to be deployed?
I tried adding the jar to the Libraries and Classpath entries of the project. I also tried adding it to a user library located in the project and adding that to the Libraries and Classpath list. But both had no effect.
I am new to JDeveloper and Oracle BPM, so I'm hoping there's something simple I'm missing here.
The solution was to add the jar to this directory:
MyBpmApplication\MyBpmProject\SOA\SCA-INF\lib

java.lang.NoClassDefFoundError for nested class at run-time? (Dependency problems?)

Ok, here's the situation:
I have three files:
1. TScan.java
2. Test.java
3. ScanServlet.java
I write my mail class, TScan in the TScan.java file, and inside that class, there is a nested class (not a sub-class), called TEntry. TScan has a main() used for testing and other methods that use the nested TEntry class with no problems.
Also, Test.java is a fancier testing program that uses items from TScan.java, including the TScan and TEntry classes with no problems. TScan.java and Test.java were developed and tested in Eclipse (and it compiles/runs fine from the command line as well).
So TScan is working to a useful point, and I wanted to include it in a webapp. Installed Jetty and wrote ScanServlet.java, which runs in Jetty, no problems.
I started referencing TScan and it started giving the error above for TScan. Changing the ClassPath to include the TScan.class file didn't work, so I made a JAR file and stuck it in the WEB-INF/lib/ folder of the WebApp, and now ScanServlet compiles filen, and seems to find TScan at run-time, however it gives the NoClassDefFounfError TScan$TEntry at run-time. This doesn't make sense to me, since:
1. Obviously it's finding the TScan class now (Since it's not complaining about that at compile or run-time)
2. The error occurs in the TScan.java file (TEntry isn't reference directly except by TScan), which runs fine in stand-alone mode!
3. I made TEntry public, and it still doesn't work.
I have found a lot of questions about NoClassDefFoundError, but none dealing with nested classes, especially with Jetty.
Bear in mind I am more used to Delphi, where if it compiles, it runs. (And ABAP which is more or less the same).
If someone has a solution I will be thrilled, otherwise, I am considering:
Copy-Paste the whole TScan into ScanServlet (Shouldn't have a problem finding it if it's in the same file!) (not very modular)
Move TEntry into a separate class in a separate .java file? (May be a pain to cleanly extract).
Have ScanServlet call TScan.Java as a command line program. (Slow...)
How have you created your jar file and does it contain TScan$TEntry.class in the correct folder?
An inner or nested class still produces a .class file which you need to ship
Looks like you are limping along because your not using any formal build tools that apply rigor and convention to your development. Before messing around what is where and how to manage your handful of classes...start using a real build system that produces a jar file that contains what you need. Maven, Ant, Buildr, whatever...something that applies some convention or configuration. Don't leverage anything any IDE gives you in terms of compiling or exporting something that is supposed to be runnable...you can't trust any of that bunk.
With a proper build mechanism and ideally declarative dependencies and the like you can address your issue in a iterative fashion to resolve the NCDFE. my 2 cents at least
[edit]
On your specific issue, I suspect your running into the webapp classloader configuration. By default classes in /lib are not exposed to webapp contexts. You will need to setParentLoaderPriority on the webapp context to true or bundle your classes as a war file. Also use --dry-run on the cli to help sort out what jar files are being loaded up by jetty.

java.lang.NoSuchMethodError when the method definitely exists

I have a Spring framework based Java web application, which has been built in SpringSource Tool Suite ("STS"), and a local copy of Apache Tomcat. We also have a internal production server, again running Tomcat.
When I run the application on my development machine, and carry out a specific action in the web application, everything works correctly. However, when I deploy the web application to Tomcat on the server (via a war file produced by maven), and repeat those aforementioned specific actions, I'm presented with some unexpected behaviour. When I checked the server tomcat log file, I found this...
2011-11-16 19:36:45,090 [http-8280-Processor1] ERROR [attachments] invoke - Servlet.service() for servlet attachments threw exception java.lang.NoSuchMethodError: net.wmfs.coalesce.aa.dao.MediaDao.updateAlfrescoNodeRef(Ljava/lang/Long;Ljava/lang/String;)V
at net.wmfs.coalesce.aa.service.impl.MediaServiceImpl.doFileUpload(MediaServiceImpl.java:102)
at net.wmfs.coalesce.aa.servlet.MediaServlet.doFileUpload(MediaServlet.java:83)
at net.wmfs.coalesce.aa.servlet.MediaServlet.doPost(MediaServlet.java:55)
Now, the updateAlfrescoNodeRef method definitly exists in the MediaDao class - otherwise my code would not compile in STS...
package net.wmfs.coalesce.aa.dao;
public class MediaDao extends JdbcDaoSupport {
public void updateAlfrescoNodeRef(final Long recordId, final String nodeRef) {
// java code
}
}
As you can see, the method signature is correct.
I suspected that there may have been a problem when maven produced the war file, so I extracted the war files contents. In the WEB-INF/lib folder, I found the jar file which holds the MediaDao class, and extracted its contents. I then did a...
cat ./MediaDao.class
Now, as class files are binary files, I mostly saw gobledegook. However, I was able to clearly make out references to the updateAlfrescoNodeRef method, as well as the contents of a String in that method. So, this means that the method is definitely there.
The bean configuration in the Spring framework XML files is definitely correct, or the code would not run when I execute it on my development machine.
Googling suggested a library conflict on the server, but all the referenced classes - MediaServlet, MediaServiceImpl, MediaDao - are in the main project (the one with the WEB-INF folder in it). While its conceivable there may be multiple copies of the dependencies on the server, there is definitely only one copy of the main project jar.
Does anyone have any ideas why this is happening?
The problem has now been resolved. Thank you everyone for your assistance.
It turns out that the main project had a dependency which had another MediaDao class, in exactly the same package path. Someone had basically copied the class into that dependency (as a library resource so that lots of projects could use it without specifying the main project as a dependency). However, that someone had not removed the class in the main project.
So, when I modified the class in the main project (I added the updateAlfrescoNodeRef method), and ran the application in STS on my machine, Tomcat used the version of the class in the main project, and not in the library because the library project was closed. When the application was deployed to the server however, it looks like the version of the class in the library was used instead (which, of course, didn't have the updateAlfrescoNodeRef method in it).
Expert tip if you ever find yourself in a similar situation: In STS, press CTRL+SHIFT+T to open the "Open Type" dialog, and enter the name of the problematic class to see a list of projects that have a class with that name.
If the error occured in android studio, it also can be a bug of the Instant Run. In that case: File -> Invalidate Caches/Restart. It solved my problem
If you are using Tomcat 6+, look in ~tomcat/lib for conflicting classes and jars.
In Tomcat 5, look in ~tomcat/common/classes, ~tomcat/common/lib, ~tomcat/shared/classes and ~tomcat/shared/lib.

Resolving a "duplicate definition of library class" in ProGuard

I have a Java project which includes the Xerces library.
When I process the project with Proguard, I get the warning:
Note: duplicate definition of library class [org.w3c.dom.html.HTMLDOMImplementation]
I see in Xerces that this class exists, and that a same class exists in the rt.jar of JDK 1.6.
The jar file created by ProGuard does not launch (error: "A Java Exception Has Occurred").
How can I solve this problem? Thx!
(note: I work with Netbeans)
1) Either you should remove the class from one of the library (which is not advisable as it might break other classes)
2) Find a jar withouth this class. For e.g. the class which you are using in your application might be available in a number of jars. So get the jar where this conflicting class is not present but other classes which you want are present (this might take some time)
3) (and best) just ignore the error. I don't think it should give any problem. Based on which jar occurrs first in the class path, the class will be picked up.

Categories