Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDK9 support #9

Open
stokito opened this issue Mar 2, 2018 · 6 comments
Open

JDK9 support #9

stokito opened this issue Mar 2, 2018 · 6 comments

Comments

@stokito
Copy link

stokito commented Mar 2, 2018

Hello, thank you for your great tool. Looks like it wasn't updated for long and it doesn't support JDK9. On start of my webapp I got the following:

>> jHades - scanning classpath for overlapping jars: 

Mar 02, 2018 5:37:56 PM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.jhades.JHadesServletListener
java.lang.NoClassDefFoundError: sun/misc/Launcher
	at org.jhades.model.ClazzLoaderFactory.createBootstrapClassLoader(ClazzLoaderFactory.java:34)
	at org.jhades.service.ClasspathScanner.findAllClassLoaders(ClasspathScanner.java:236)
	at org.jhades.service.ClasspathScanner.findAllClassLoaders(ClasspathScanner.java:233)
	at org.jhades.service.ClasspathScanner.findAllClassLoaders(ClasspathScanner.java:233)
	at org.jhades.service.ClasspathScanner.findAllClasspathEntries(ClasspathScanner.java:68)
	at org.jhades.service.ClasspathScanner.findAllClasspathResources(ClasspathScanner.java:107)
	at org.jhades.service.ClasspathScanner.findOverlappingJars(ClasspathScanner.java:262)
	at org.jhades.JHades.overlappingJarsReport(JHades.java:189)
	at org.jhades.JHadesServletListener.runJHades(JHadesServletListener.java:35)
	at org.jhades.JHadesServletListener.contextInitialized(JHadesServletListener.java:27)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
	at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
	at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: java.lang.ClassNotFoundException: sun.misc.Launcher
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1702)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
	... 20 more

Mar 02, 2018 5:37:56 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext

P.S. http://jhades.org seems not working anymore

@vorburger
Copy link
Contributor

@jhades this has just come up on https://jira.opendaylight.org/browse/INFRAUTILS-52 by @skitt ...

Do you have any plans to look into and fix this? Or, if someone were to raise a PR with a fix, would you merge and push a new release to Maven Central? @stokito would you consider contributing to this open source project with a Pull Request which fixes this?

@stokito
Copy link
Author

stokito commented Sep 24, 2018

Hi, @vorburger I can try to find some hotfix but actually, I think that from a practical point of view this not needed. Let me explain what I mean. The only one way to fix dependency hell is to engage microservices:

  1. Division by domain and deployment cycle: it's ok for the Admin Panel to use some legacy Tapestry 4 while main processing server using latest Guava i.e. it's ok to update/redeploy the admin panel rarely while the Processing Server often and keep it up to date. Also, different domains have different load/usage profiles and all of them sharing the same CPU cache which is some nature bottleneck.
  2. When you have two libraries and both use transitively another lib but with different mayor version (aka ambient dependency) then you got a serious dependency hell. If your service is small then it's unlikely happens.
  3. If you writing a microservice then just use the most popular framework i.e. Spring Boot. In fact, SB is a collection of right versions of different libraries. Using SB means that you don't have to solve dependencies hell - this is their job. Just update SB itself.

So finally,
If you were able to upgrade your application to JDK9 then you likely don't have such a big dependency hell or your app is quite small. You can use JHades to fix the biggest problems even before migrating to JDK9.
But if you migrated to JDK9 and you still think it's ok to live with the big monolith then you will fail anyway.
Maybe not now but eventually you will face the problems again (i.e. business will be changed and you need fully replace part of your system) and you'll anyway rewrite your system to microservices.

@vorburger
Copy link
Contributor

@stokito thanks for your thoughts. I want it anyway... 😄

@jhades I've looked into this, and unless I'm missing something realized this is far less trivial than I thought... while one could perhaps replace the use of sun.misc.Launcher & sun.misc.URLClassPath in org.jhades.model.ClazzLoaderFactory by java.lang.ClassLoader either getSytemClassLoader() or the Java 9 only getPlatformClassLoader() to avoid the ClassNotFoundException shown above, that is actually the least of all problems...

The real issue is that in Java 9+ the application classloader is no longer an URLClassLoader - but JHades is pretty much built on the assumption of an URLClassLoader ...

@vorburger
Copy link
Contributor

While there may be a way to signficantly adapt JHades to fix this, I've instead opted to build something quite like it on top classgraph, another existing library which is very convenient for any sort of classpath scanning in general (which duplicate detection is basically an application of) - see classgraph/classgraph#256.

@lukehutch
Copy link

ClassGraph has not only support for JDK9+, but support for an extremely wide array of different classpath specification mechanisms. Maybe it makes sense to rebase JHades on top of ClassGraph, for maximum compatibility with a wide range of projects? Feel free to test that out.

https://github.com/classgraph/classgraph/wiki/Classpath-Specification-Mechanisms

At @vorburger's suggestion, I added this mechanism to ClassGraph to find duplicated classfiles (or drop ".classFilesOnly()" if you want to find all duplicated resources):

new ClassGraph().scan().getAllResources().classFilesOnly().findDuplicatePaths()

@vorburger has a list of common duplicated resource names that should be ignored.

@vorburger
Copy link
Contributor

@vorburger has a list of common duplicated resource names that should be ignored.

see the ClasspathHellDuplicatesChecker in OpenDaylight's infrautils

http://blog2.vorburger.ch/2019/02/how-to-find-duplicate-classes-and.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants