directory

  • 1. Bugs
  • 2. Try to solve the case
  • 3. The truth emerges
  • 4. To summarize
  • Update record

1. Bugs

Jetty 9.4.19 failed to migrate the war package running in Tomcat 8.5 to jetty 9.4.19:

org.springframework.context.ApplicationContextException: Failed to start bean 'stompWebSocketHandlerMapping'; nested exception is java.lang.NoSuchMethodError: org.eclipse.jetty.websocket.server.WebSocketServerFactory.init(Ljavax/servlet/ServletContext;) V at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:176) ~ [spring - the context - RELEASE 4.2.3. Jar: 4.2.3 RELEASE]... .Copy the code

NoSuchMethodError is probably the most obvious error to see: “The currently called method cannot be found in the corresponding class loaded into the JVM”.

If the corresponding class does not have a corresponding method in the compilation environment, the compilation will not succeed (the INTEGRATED development environment will report an error). If NoSuchMethodError is reported during deployment after successful compilation, it indicates that the classes depend on at runtime and compile time are inconsistent.

By “compile-time dependencies” I mean the classes that the build tool relies on in its CLASSPATH at compile time; Runtime dependency refers to classes loaded into the JVM at runtime. For the same class loader, the class is successfully loaded only once.

The exception stack above shows: Class org. Eclipse. Jetty. Websocket. Server WebSocketServerFactory no constructor WebSocketServerFactory (javax.mail. Servlet. ServletContext). Take a look to see if the classes that the runtime depends on have corresponding constructors.

In the case of the field, only javap command can be used, but first you need to find the jar package from which the class was loaded, how to find the jar package path according to the class will be further explained in the next attempt to solve the case.

Javap - cp/lib/websocket websocket server - 9.4.41. V20210516. Jar org. Eclipse. Jetty websocket. Server WebSocketServerFactoryCopy the code

Note that using javap -cp lib/websocket/* XXXX to specify the classpath configured with * does not work, but it does work with the javac command.

Isn’t there a WebSocketServerFactory(ServletContext Context) constructor?

I later tried many ways to confirm this constructor exists, but an error NoSuchMethodError, a lot of online looking for “Java. Lang. NoSuchMethodError regress method exists”, fruit. Because what the Internet says finally proves that there is really no corresponding method.

But the condition of the discovery field is that it does! This is getting weird! Did I find a super bug? My gut tells me 100% not, something must be wrong with me.

2. Try to solve the case

Look at the scene, an error Java. Lang. NoSuchMethodError: org.eclipse.jetty.websocket.server.WebSocketServerFactory.init(Ljavax/servlet/ServletContext;) V, but by javap tool decompiling the constructor is there WebSocketServerFactory (javax.mail. Servlet. ServletContext)!

There are two general NoSuchMethodError exceptions:

  1. classpthThe class for this method is in multiple JARS, and the class for the JAR loaded by the JVM does not have the method.
  2. There is only onejarPackage,jarClasses in the package do not have this method.

Both cases boil down to the fact that methods are indeed missing from classes loaded by the JVM at runtime. But the problem encountered above is that the lookup load class has an error constructor.

If the JVM has multiple packages in the same class in the CLASspth, it is platform-dependent which class is loaded by the JVM (Linux and Windows systems may not have the same JAR package loaded). Note that the JVM loads the corresponding class file from the jar in the classpth, regardless of the name of the jar.

You can use the following methods to locate the loaded JAR package based on the error information:

1). The JVM uses the -verbose:class parameter, which prints the absolute path to the jar package that loaded the class.

2). Use Java code:

Class<? > clazz = null; try { clazz = Class.forName("org.eclipse.jetty.websocket.server.WebSocketServerFactory"); } catch (ClassNotFoundException e) { e.printStackTrace(); } CodeSource cs = clazz.getProtectionDomain().getCodeSource(); String location = cs.getLocation().getPath(); System.out.println(location);Copy the code

3). Use Linux command:

for file in *.jar; do
  echo $file;
  jar tvf $file |grep WebSocketServerFactory
done
Copy the code

The “1)” method is most convenient when the –verbose:class parameter is set on a JVM that allows you to restart or boot the system, and you can directly look up the class in the log.

Method “2)” can be used if restarting the JVM is not allowed, but specify the correct classpath or the corresponding class will not be loaded. Finding the CLASspath can be found in the JVM’s corresponding process.

For the SpringBoot framework into the JAR package, the general dependency into the JAR package; For war packages used by Severlet containers, dependencies include lib packages in the container installation directory in addition to web-INF /lib; For ordinary jar package, depend on the RMB may be defined in the MANIFEST file (more on the MANIFEST content can be reference: fengmengzhao. Making. IO / 2021/12/18 /… .

If you want to find which jar in a specified directory contains a class, you can use the “3)” method to list the files contained in the JAR and look for matches.

Why bother to find out from which JAR the error class was loaded? Jar packages generally provide version-related information. The javap command needs to specify the JAR package as the classpath in order to decompile successfully.

The syntax of the javap command for decompilation is as follows:

#This is done by specifying the class information and the jar package in which the class resides as classpath decompilation
javap [-verbose] -cp /some/path/to/lib/xxx.jar com.xx.SomeClass

#This method decompresses the class file from the JAR and decompiles the class file directlymkdir dir cd dir jar xvf .. /SomeClass-belong-to.jar javap [-verbose] com/xx/SomeClass.classCopy the code

The -verbose parameter of Javap displays detailed compilation information about a class file. If you only want to check whether a method exists, you can omit the -verbose parameter.

Confirm the case of this example by using the above method: obviously method exists ah, why NoSuchMethodError, puzzled!

3. The truth emerges

What to do? Problems always have to be solved.

Trying to debug code in your development environment and realizing that init in an error is a common method?

A quick look at the decompiled code shows that there really are no init normal methods, only init constructors. The problem is that jetty changed init from normal to constructor when it was upgraded from 9.3 to 9.4.

This is a myth of knowledge, the author thought WebSocketServerFactory. Init (Ljavax/servlet/ServletContext) V is a constructor. In fact, an error from a constructor would look like this:

10:24:09. 590 ERROR [main] org. Springframework. Boot. SpringApplication - Application run failed java.lang.NoSuchMethodError: org.springframework.boot.builder.SpringApplicationBuilder.<init>([Ljava/lang/Object;)VCopy the code

Normal methods and constructors are really the difference between.init() and.

().


([Ljava/lang/Object;)V. SpringApplicationBuilder(java.lang.object…), which takes the java.lang.object array as an argument. This way of writing is consistent with the internal representation of the class file

Reference types said: docs.oracle.com/javase/spec…

For a programmer, abnormal stack messages are so common that he doesn’t bother to dig into some of them. You’re gonna have to pay me back.

4. To summarize

  1. A lot of them seem metaphysicalbugCannot explain, the final reason always boils down to “knowledge blind spot”. A lot of knowledge do not have to understand very deeply, but the basic things to understand, at this time “not very understanding”, then “this is metaphysics?” .
  2. Sometimes conclusions are automatically assumed (as in this example).init()Methods are naturally considered constructors. Can not be very finalised things, to check more, more ideas.
  3. Look at the problem and have confidence in an idea that, if it doesn’t solve the problem, at least leads to the conclusion of the idea. Do not rush, careless, blind attempt. If your mind is narrow, stop and try again tomorrow to avoid a dead end.

Update record

  • 2022-01-24 16:10 wechat public account “Feng Brother painting Halberd” before the article was published reread, optimization, correction
  • 2022-01-26 15:20 Read, optimize, erratum nuggets column before publication

Wechat public account search “Feng Brother painting Halberd” to follow Feng Brother, the first time to watch more exciting content. All those times you were stuck on the “init” method!