PyFlink "pipeline.classpaths" vs $FLINK_HOME/lib - java

What is the difference between class loading classes passed as part of PyFlink pipeline.classpath config and putting them into a $FLINK_HOME\lib directory?
When I want to use flink-sql-connector-kafka-*.jar it works fine just passing it using pipeline.classpath but when I want to use something that has some external dependencies like flink-avro-*.jar that needs avro-*.jar jars. It seems to load flink-avro-*.jar but it looks like it fails to load avro-*.jar and throws:
java.lang.NoClassDefFoundError: Could not initialize class org.apache.avro.SchemaBuilder
When I am dding avro-*.jar to $FLINK_HOME\lib it works just fine.

NoClassDefFoundError and ClassNotFoundException are different
java.lang.ClassNotFoundException This exception indicates that the
class was not found on the classpath. This indicates that we were
trying to load the class definition, and the class did not exist on
the classpath.
java.lang.NoClassDefFoundError This exception indicates that the JVM
looked in its internal class definition data structure for the
definition of a class and did not find it. This is different than
saying that it could not be loaded from the classpath. The point is,
a NoClassDefFoundError is not necessarily a classpath problem.
flink-sql-avro-*.jar is a shaded jar which will relocate the path of org.apache.flink:flink-avro org.apache.avro:avro
Judging from the NoClassDefFoundError, there may be a conflict between the avro version dependencies

Related

Resolving to correct dependencies when loading classes with custom classloaders

So I have this generic backend server that loads shaded jars in memory and then loads it through a custom Classloader.
E.g.
MyClass class = c.newInstance();
It works fine until the shaded Jar dependencies conflicts with the server classes.
E.g.
Server contains (with Custom Classloader):
com.fasterxml.jackson.jackson-databind:2.6.0
While the shaded jar contains
com.fasterxml.jackson.jackson-databind:2.9.9
When the method in the class that requires the said library e.g. class.doSomeThing(); it throws an error Caused by java.lang.NoSuchFieldError: because the loaded jackson-databind is 2.6.0 instead of 2.9.9
The question here is when the class is loaded from the shaded jar is there a way to make sure that the shaded dependencies are the ones used?
The question here is when the class is loaded from the shaded jar is there a way to make sure that the shaded dependencies are the ones used?
If you are using the default Class loader then the order of resolution will work as the order of the classpath. Within your code you can use
System.out.println(System.getProperty("system.class.path").replaceAll(":", "\n"));
And inspect the classpath. Usually such runtime environment (for example apache spark) has such features to allow you to prepend the classpath. You can check with your runtime server environment for such feature.

Classloader issues when looking up ejb jndi names tomcat 6

I am in the process of migrating a legacy application from weblogic to Tomcat 6.
The application needs to access ejbs; to achieve that, I added wlclient.jar to the classpath.
When the methods in the legacy jars responsible for communicating with the ejbs are called, I get the following exception :
javax.naming.NamingException: Unhandled exception in lookup
[Root exception is org.omg.CORBA.MARSHAL: vmcid: SUN minor code: 211 completed: Maybe]
which cause is :
Caused by: java.lang.IllegalArgumentException: interface com.xxx.xxx.InterfaceName is not visible from class loader
at java.lang.reflect.Proxy.getProxyClass(Proxy.java:353)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
at weblogic.iiop.ProxyDesc.readResolve(ProxyDesc.java:45)
That Interface seems to be used to define the method called from the client to return some informations from the server where the ejbs are deployed.
When running with verbose:class, I find that the Interface is actually loaded from the local jar. The corresponding interface on the server is loaded too :
[Loaded com.xx.xx.InterfaceName_t3s99q_InterfaceNameIntf from http://192.168.x.xx:port/path/classes/]
Even though I do not have any idea how that works internally, I assumed the lookup had gone well since it finds the correct class on the server.
When putting breakpoints in Proxy.getProxyClass, I found the used classloader when the exception occurs was a Launcher$AppClassLoader; the URL's it used to lookup were those in my local classpath (a.k.a. src/main/java and such) and not the webapp's path (a.k.a. WEB-INF/lib and such).
So my question is : is it possible that the wrong ClassLoader gets used for that specific lookup (local one instead of Tomcat's webapp level one)?
Can I specify a specific ClassLoader?
Am I looking in the completely wrong direction to resolve that issue ?
Well I lost 1.5 days on this, so I'll post an answer hoping it will eventually be useful to someone.
The problem was that I included wlclient.jar in eclipse classpath, and since the oracle implementation uses super.getClass().getClassLoader() , it would return the ClassLoader used to load the Class in which the call is made a.k.a. the local ClassLoader and not the one from the Webapp, so it did not have visiblity of the webapp dependencies.
I updated my project to include the jar in WEB-INF/lib so it would be loaded by the webapp and thus super.getClass().getClassLoader() would return the right ClassLoader.
An other possibility would have been to modify that line to use Thread.currentThread.getContextClassLoader instead.

Caused By: java.lang.NoClassDefFoundError: org/apache/log4j/Logger

I've got an interesting problem in which the org.apache.log4j.Logger class is not found during runtime. I'm trying to get authorized and that is where it's failing:
OAuthAuthorizer oauthAuthorizer = new OAuthAuthorizer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET, SAML_PROVIDER_ID, userId);
I'm using JDeveloper 11.1.1.6. Here is what I know:
I've looked in my UI.war/WEB-INF/lib directory and I see the log4j-1.2.17.jar there.
The class complaining about it is org.opensaml.xml.XMLConfigurator
Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Logger
at org.opensaml.xml.XMLConfigurator.<clinit>(XMLConfigurator.java:60)
at org.opensaml.DefaultBootstrap.initializeXMLTooling(DefaultBootstrap.java:195)
at org.opensaml.DefaultBootstrap.bootstrap(DefaultBootstrap.java:91)
at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.getSAMLBuilder(SAML2AssertionGenerator.java:156)
at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.createSubject(SAML2AssertionGenerator.java:187)
at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.buildAssertion(SAML2AssertionGenerator.java:114)
at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.generateSignedAssertion(SAML2AssertionGenerator.java:83)
at com.intuit.ipp.aggcat.util.SamlUtil.createSignedSAMLPayload(SamlUtil.java:156)
at com.intuit.ipp.aggcat.util.OAuthUtil.getOAuthTokens(OAuthUtil.java:60)
at com.intuit.ipp.aggcat.core.OAuthAuthorizer.<init>(OAuthAuthorizer.java:85)
at com.incomemax.view.intuit.WebUtil.getAggCatService(WebUtil.java:91)
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:305)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:246)
... 64 more
I decomplied XMLConfigurator and oddly it doesn't import org.apache.log4j.Logger It uses org.slf4j.Logger which is also in my jars directory (slf4j-api-1.7.5.jar). Also interesting is that line 60 (see stack trace) is a blank line in my decompile.
Of course if I add Logger.xxxxx during design time, it finds it just fine.
I'm using the code/jars directly from the sample java code, but imported into my existing application.
I've been scouring the web for answers and I believe I've checked all the areas I can think of. I also referenced this very good page: http://myarch.com/classnotfound/
Given authorization is step 1 in using the Intuit Developer API, I'm kinda stuck.
Adding output from #jhadesdev suggestion:
All versions of log4j Logger:
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
All versions of log4j visible from the classloader of the OAuthAuthorizer class:
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
All versions of XMLConfigurator:
jar:file:/C:/Oracle/Middleware11116/modules/com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
All versions of XMLConfigurator visible from the class loader of the OAuthAuthorizer class:
jar:file:/C:/Oracle/Middleware11116/modules/com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
I'm still working on interpreting the results.
During runtime your application is unable to find the jar.
Taken from this answer by Jared:
It is important to keep two different exceptions straight in our head
in this case:
java.lang.ClassNotFoundException This an Exception, it indicates that the
class was not found on the classpath. This indicates that we were
trying to load the class definition, and the class did not exist on
the classpath.
java.lang.NoClassDefFoundError This is Error, it indicates that the JVM
looked in its internal class definition data structure for the
definition of a class and did not find it. This is different than
saying that it could not be loaded from the classpath. Usually this
indicates that we previously attempted to load a class from the
classpath, but it failed for some reason - now we're trying again,
but we're not even going to try to load it, because we failed
loading it earlier. The earlier failure could be a
ClassNotFoundException or an ExceptionInInitializerError (indicating
a failure in the static initialization block) or any number of other
problems. The point is, a NoClassDefFoundError is not necessarily a
classpath problem.
for similarities and differences
You can use the following maven dependency in your pom file. Otherwise, you can download the following two jars from net and add it to your build path.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
This is copied from my working project. First make sure it is working in your project. Then you can change the versions to use any other(versions) compatible jars.
For AggCat, you can refer the POM file of the sample java application.
https://github.com/IntuitDeveloperRelations/IPP_Sample_Code/blob/master/CustomerAccountData/Java/AggCatSampleApplication/pom.xml
Thanks
Check in Deployment Assembly,
I have the same error, when i generate the war file with the "maven clean install" way and deploy manualy, it works fine, but when i use the runtime enviroment (eclipse) the problems come.
The solution for me (for eclipse IDE) go to: "proyect properties" --> "Deployment Assembly" --> "Add" --> "the jar you need", in my case java "build path entries".
Maybe can help a litle!
With the suggestions #jhadesdev and the explanations from others, I've found the issue here.
After adding the code to see what was visible to the various class loaders I found this:
All versions of log4j Logger:
zip:<snip>war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
All versions of log4j visible from the classloader of the OAuthAuthorizer class:
zip:<snip>war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
All versions of XMLConfigurator:
jar:<snip>com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
zip:<snip>war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
zip:<snip>war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
All versions of XMLConfigurator visible from the classloader of the OAuthAuthorizer class:
jar:<snip>com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
zip:<snip>war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
zip:<snip>war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
I noticed that another version of XMLConfigurator was possibly getting picked up.
I decompiled that class and found this at line 60 (where the error was in the original stack trace) private static final Logger log = Logger.getLogger(XMLConfigurator.class); and that class was importing from org.apache.log4j.Logger!
So it was this class that was being loaded and used. My fix was to rename the jar file that contained this file as I can't find where I explicitly or indirectly load it. Which may pose a problem when I actually deploy.
Thanks for all help and the much needed lesson on class loading.
Based on the stacktrace, an intuit class com.intuit.ipp.aggcat.util.SAML2AssertionGenerator needs a saml jar on the classpath.
A saml class org.opensaml.xml.XMLConfigurator needs on it's turn log4j, which is inside the WAR but cannot find it.
One explanation for this is that the class XMLConfigurator that needs log4j was found not inside the WAR but on a downstream classloader. could a saml jar be missing from the WAR?
The class XMLConfigurator that needs log4j cannot find it at the level of the classloader that loaded it, and the log4j version on the WAR is not visible on that particular classloader.
In order to troubleshoot this, a way is to add this before the oauth call:
System.out.println("all versions of log4j Logger: " + getClass().getClassLoader().getResources("org/apache/log4j/Logger.class") );
System.out.println("all versions of XMLConfigurator: " + getClass().getClassLoader().getResources("org/opensaml/xml/XMLConfigurator.class") );
System.out.println("all versions of XMLConfigurator visible from the classloader of the OAuthAuthorizer class: " + OAuthAuthorizer.class.getClassLoader().getResources("org/opensaml/xml/XMLConfigurator.class") );
System.out.println("all versions of log4j visible from the classloader of the OAuthAuthorizer class: " + OAuthAuthorizer.class.getClassloader().getResources("org/apache/log4j/Logger.class") );
Also if you are using Java 7, have a look at jHades, it's a tool I made to help troubleshooting these type of problems.
In order to see what is going on, could you post the results of the classpath queries above, for which container is this happening, tomcat, jetty? It would be better to put the full stacktrace with all the caused by's in pastebin, just in case.
Had the same problem, it was indeed caused by weblogic stupidly using its own opensaml implementation. To solve it, you have to tell it to load classes from WEB-INF/lib for this package in weblogic.xml:
<prefer-application-packages>
<package-name>org.opensaml.*</package-name>
</prefer-application-packages>
maybe <prefer-web-inf-classes>true</prefer-web-inf-classes> would work too.
java.lang.ClassNotFoundException is indicate that class is not found in class path.
it could be the version of log4j is not compatible.
check for different log4j version.
I had the same issue, for me this fixed the issue:
right click on the project ->maven -> update project
Add compile 'org.apache.logging.log4j:log4j-1.2-api:2.17.1' and then it will automatically work
In my case, the error was due to some dependencies using log4j v 1.x that I removed from the classpath. So I introduced the log4j-1.2-api to bridge v 1.x to 2.x as recommended in the Apache Migration guide:
After introducing this dependency in my build.gradle, the error disappeared :
implementation 'org.apache.logging.log4j:log4j-1.2-api:2.17.+!!'
Following works for me everytime I face the problem
rightclick on project(say abc-war)-> properties -> Deployment assembly->add->java build path entries->Maven dependencies.

NoClassDefFoundError: Could not initialize class org.apache.axis2.description.AxisService

While running the application I was getting the following errors.
java.lang.NoClassDefFoundError: Could not initialize class org.apache.axis2.description.AxisService
AxisService class is in axis2-kernel-1.6.2.jar file. Some of the classes from this jar are working fine without any issues, but some classes are throwing NoClassDefFoundError from this jar file at runtime. AxisService class is present in axis2-kernel-1.6.2.jar, even it throws error.
This is working fine in local machine. But error getting in Oracle r12 server.I have already set the class path for the jar file.
I am Using Java version is 1.6 and Apache axis2.1.6.2.
Had the same issue. I had included only jars that I needed to compile the application.
When I included everything from \axis2-1.6.2\lib\ folder, this exception were gone.
I had a similar problem using Tomcat and Axis2 and after a week finding out the error I realized there was a axis configuration problem. especifically my aplication can't instantiate the class which accedded to persistence layer. I include this parameter line:
<parameter name="ServiceTCCL">composite</parameter>
in services.xml file which is used by axis2 to work.
For more information see the comments in http://wso2.com/node/1131

Classloaders and sharing .jar files with Apache Tomcat

If I have classes that need to be shared between my webapp and Tomcat (e.g. a custom realm and principal), where should the .jar file containing those classes go?
Currently I'm putting the .jar in ${CATALINA_HOME}/lib. This result is a ClassCastException when assigning references from classes of the same type. Here's an example:
MyCustomPrincipal principal = (MyCustomPrincipal)FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
The method above throws a ClassCastException. The method returns an actual MyCustomPrincipal type (since that's what my custom realm gave Tomcat when it performed authentication) that, apparently, was created by a different classloader. How do I fix this so both Tomcat and my webapp can use MyCustomPrincipal?
http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html
Any help is appreciated.
Andrew
It looks like you have 2 copies loaded, once in tomcat and once in your WEB-INF/lib jars or other classpath of your deployed application.
The reason you get classpath exception lies in the way a WAR looks for classes. Contrary to the normal Java rules, a war first looks inside the war for a class and only then passes the request to teh parent classloader.
A class's identity is dependent of the classloader and the same class loaded in 1 classloader will generate a classcast exception when it is casted in the other classloader.
The solution is to make sure that the war does not contain the classes which should be provided by the container. If you use maven you can mark these dependencies as 'provided', if you use ant, you have to split your classpath list in 2 and compile against both, but use only the ones you need for constructing the war.

Categories