阿里巴巴 fastjson-1.2.12.jar json解析異常java.lang.ClassFormatError: Invalid method Code length 66865 in cla

承接上篇:fastjson反序列化LocalDateTime失敗的問題java.time.format.DateTimeParseException: Text '2019-05-24 13:52:11' could not be parsed at index 10html

以前在線上用的版本是fastjson-1.2.7.jar 一切正常,更換之後時間解析看似一切正常。java

由於在系統中設計json反序列化的地方比較多,剛剛放到生產環境,app那邊的接口報錯了git

 java.lang.ClassFormatError: Invalid method Code length 66865 in class file com/alibaba/fastjson/serializer/ASMSerializer_6_UserKdlb
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at com.alibaba.fastjson.util.ASMClassLoader.defineClassPublic(ASMClassLoader.java:174)
    at com.alibaba.fastjson.serializer.ASMSerializerFactory.createJavaBeanSerializer(ASMSerializerFactory.java:396)
    at com.alibaba.fastjson.serializer.SerializeConfig.createASMSerializer(SerializeConfig.java:95)
    at com.alibaba.fastjson.serializer.SerializeConfig.createJavaBeanSerializer(SerializeConfig.java:163)
    at com.alibaba.fastjson.serializer.SerializeConfig.createJavaBeanSerializer(SerializeConfig.java:117)
    at com.alibaba.fastjson.serializer.SerializeConfig.getObjectWriter(SerializeConfig.java:504)
    at com.alibaba.fastjson.serializer.SerializeConfig.getObjectWriter(SerializeConfig.java:320)
    at com.alibaba.fastjson.JSON.toJSON(JSON.java:884)
    at com.alibaba.fastjson.JSON.toJSON(JSON.java:812)
    at com.alibaba.fastjson.JSON.toJSON(JSON.java:853)
    at com.alibaba.fastjson.JSON.toJSON(JSON.java:812)
    at com.alibaba.fastjson.JSON.toJSON(JSON.java:840)
    at com.alibaba.fastjson.JSON.toJSON(JSON.java:812)
    at com.alibaba.fastjson.JSON.toJSON(JSON.java:892)
    at com.alibaba.fastjson.JSON.toJSON(JSON.java:812)
    at com.netmarch.pointlocationapp.controller.AppPointLocationControllerNew.getList(AppPointLocationControllerNew.java:204)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:832)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:743)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:94)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1152)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1539)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1495)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

找到相應的方法,簽名以下github

@RequestMapping("/list")
    @ResponseBody
    public JSONObject getList(@RequestBody String body, UserKdlb userKdlb, Pager<UserKdlb> pagers,
            HttpServletRequest request, HttpServletResponse response) {
        AppUtils.setHeader(request, response);
        JSONObject obj = null;
        ReturnParam rp = new ReturnParam();
...
               obj = (JSONObject) JSON.toJSON(rp); 
return obj;
}

這是一直運行的代碼,按常理來講若是有bug早就反應出來了。web

codereview發現,這個json對象以前的步驟中插入一個list,相關代碼以下spring

List<UserKdlb> list = null;

public class UserKdlb implements Serializable{

    
    private Byte pre_distribution_work_for_outsourcing_companies;//建設外包公司預分配工做
    private String company_employees_must_complete_the_commissioning_time;//公司員工調試必須完成時間
    
    //室外週報關聯查詢列表添加頁面顯示字段
    private Integer number_of_points_entered_into_outdoor_construction_sites;
    
    //室外點位資料字表對應字段;
    private List<PointLocationFaultRecord> ltPLFR;
    
    //管理合同表查詢此字段進而在頁面顯示樣式,點位表f_htbh 存的多是合同關聯字段,也多是項目關聯字段,因此要查詢兩次;
    private String whxfxq;
    
    //關聯點位子記錄最新一條添加記錄顯示列
    private String estimated_date_of_repair;//預計修復日期
    private String dname;//同一故障點位名稱
    private String application_stop_instruction;//申請停用說明
    private String son_estimated_date_of_repair;//子記錄最新預計修復日期
    private String son_application_stop_instruction;//子記錄申請停用說明
    //最新鏈接時間
    private String ping_time;
    
    private int prediction_and_debugging_amount;//(預-調試完)總量
    private int debugging_completion_difficulty;//調試完成難度
    private int count;//項目數量
    private int sum;//項目和
    
    private int count_percent;
    private float total_commissioning_percent;
    private float debugging_completion_difficulty_percent;
    private float prediction_and_debugging_amount_percent;
    private float prediction_and_debugging_difficulty_percent;
    
    private Float projectPoints;//項目金額
    private Integer projectCount;//項目個數

網上的說法是方法名太長,超過了65535(2^16-1,64K),裏面有不少參數名比較長,可能在生成Getter/Setter時候過長,報錯了。apache

因爲記錄這篇博文的時間比較倉促,筆者沒有時間去深究java中方法(method)相關的結構信息,各位看官能夠去了解一下json

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6tomcat

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.3websocket

 

通過在網上一番搜索,說是非java編譯生成的類,在運行時被進行檢測,防止有惡意代碼被注入。

Start-up time, I'd say. Verification that classes are correct takes some time when the class is loaded. Since classes might be loaded in a lazy fashion (not on app start, but when being used for the first time), this might cause unexpected and undesired runtime delays.

Actually the class does not need to be checked in general. The compiler will not emit any invalid bytecode or class construct. The reason for verification is that the class may be build on one system, get hosted online and is transmitted to you through the unprotected internet. On this path, a malicious attacker might modify the bytecode and create something the compiler might never create; something that can crash the JVM or possibly circumvents security restrictions. Thus the class is verified before it is used. If this is a local application, there is usually no need to check the bytecode again.

 

JVM加載class文件時會作字節碼校驗(bytecode verification)。這篇文檔很是詳細地講了JVM會作哪些校驗。 若是你的class文件是由java源文件經過javac編譯出來的,那麼基本上不用擔憂bytecode verification。 若是class文件是由asm、cglib等動態生成出來的或者由其它編譯器生成的,那麼JVM在校驗它的bytecode時就有可能失敗。 失敗的緣由多是你生成的bytecode有bug,也多是因爲新版本的JVM加入了新的驗證條件後致使原來能夠經過驗證的bytecode如今不能經過了。

不少Java框架都會動態生成class文件,再加上JVM版本也會時不時地修改它的bytecode verification行爲。 因此,運行代碼時偶爾會遇到java.lang.VerifyError錯誤。 在不能修改框架代碼或者切換JVM實現的狀況下,JVM提供了一些選項可讓你改變或者繞過bytecode verification。

-XX:-UseSplitVerifier

-XX:-UseSplitVerifier可讓JVM不開啓「type-checking verifier」。 這樣就不強制要求class文件含有StackMapTable(全部Java 7 version 51以後的class文件默認要求含有StackMapTable)。

-noverify

-noverify選項能夠關閉bytecode verification。

有的觀點認爲某些bytecode verification除了給動態生成bytecode增長麻煩以外,並無什麼大用。 可是這篇文章強烈建議不要關閉bytecode verification,特別是在生產環境裏。 由於bytecode verification能夠檢測到惡意代碼或者代碼中的bug。 特別是代碼中的bug,由於沒有人能夠保證(動態產生的)字節碼是百分百bug free的。

回到個人問題,因爲PactProviderRule類來自於外部依賴,CI上的JVM也不能替換 (CI上用的是非oracle的JVM實現,該測試代碼在本地的官方JVM上是能夠運行經過,因此CI上的失敗有必定多是其用的JVM實現的緣由), 因此一個簡單的方法是在maven跑測試代碼時,給JVM加上-noverify選項。

按照以上方法給jvm加了參數 -noverify  -XX:-UseSplitVerifier啓動後並未湊效也沒解決問題。

最終放棄添加jvm參數,按照官方的bug修復跟蹤,替換成了1.2.13版本了,修復代碼在167行,至此,線上正常接口運行了。

相關參考:

Ensuring JVM method size limit is never exceeded #661

一個fastjson轉換JSON字符串的報錯排查

Use of -noverify when launching java apps

相關文章
相關標籤/搜索