java.lang.NoSuchFieldException: resourceEntries struts2

本文深入探讨了在使用Struts2框架时遇到的与Tomcat7.0.65版本兼容性问题,详细分析了问题根源在于WebappClassLoader的抽象变化导致的资源缓存清理失败。提供了三种解决方案,包括升级Struts2版本、修改源代码或重新打包,同时介绍了如何通过Apache Commons Lang3的FieldUtils来解决父类字段访问问题。

1、关于项目中使用struts2 报java.lang.NoSuchFieldException: resourceEntries  的问题。

当我们使用tomcat 7.0.64 及以下的版本时是不会出问题的。当我们在使用tomcat 7.0.65时会报这个问题,网上看到很多解答都是说什么tomcat 8之类的。

实际出现问题在tomcat 7.0.65 就开始了 。出现这个问题的根源是因为。在64到65 的时候,org\apache\catalina\loader\WebappClassLoader.java 这个类进行了抽象,抽象出了org\apache\catalina\loader\WebappClassLoaderBase.java.

2、在我们用的struts2 的xwork 包内 \com\opensymphony\xwork2\util\LocalizedTextUtil.java内的清除tomcat 缓存的地方有问题。问题就初夏这个clearMap。java自带的getDeclaredField 是取不到父类的属性的。所以这里会一直报错。

最新版的这两个方法:

private static void clearTomcatCache() {
        ClassLoader loader = getCurrentThreadContextClassLoader();
        // no need for compilation here.
        Class cl = loader.getClass();
        try {
            if ("org.apache.catalina.loader.WebappClassLoader".equals(cl.getName())) {
                clearMap(cl, loader, TOMCAT_RESOURCE_ENTRIES_FIELD);
            } else {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("class loader " + cl.getName() + " is not tomcat loader.");
                }
            }
        } catch (NoSuchFieldException nsfe) {
            if ("org.apache.catalina.loader.WebappClassLoaderBase".equals(cl.getSuperclass().getName())) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Base class #0 doesn't contain '#1' field, trying with parent!", nsfe, cl.getName(), TOMCAT_RESOURCE_ENTRIES_FIELD);
                }
                try {
                    clearMap(cl.getSuperclass(), loader, TOMCAT_RESOURCE_ENTRIES_FIELD);
                } catch (Exception e) {
                    if (LOG.isWarnEnabled()) {
                        LOG.warn("Couldn't clear tomcat cache using #0", e, cl.getSuperclass().getName());
                    }
                }
            }
        } catch (Exception e) {
            if (LOG.isWarnEnabled()) {
        	    LOG.warn("Couldn't clear tomcat cache", e, cl.getName());
            }
        }
    }
    private static void clearMap(Class cl, Object obj, String name)
            throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        Field field = cl.getDeclaredField(name);
        field.setAccessible(true);

        Object cache = field.get(obj);

        synchronized (cache) {
            Class ccl = cache.getClass();
            Method clearMethod = ccl.getMethod("clear");
            clearMethod.invoke(cache);
        }
    }

3、遇到这个问题的时候,我们往往在处理老项目,很多项目是因为扫描除了漏洞而不得不使用新版本的tomcat。我们可以选择升级struts2的版本,可是版本的升级会带来很多意想不到的问题。摆在我们面前三条路①、用最新版本的struts2.②、拿出这个类,重新一下这两个方法。③、更改一下这两个方法,再放到jar包里面。

参考:

apache commons  lang3包下的FieldUtils.getAllFields()可以获取类和父类的所有(public、protected、default、private)属性。

 

https://blog.youkuaiyun.com/wangjun5159/article/details/79289244

 

转载于:https://my.oschina.net/u/1863561/blog/2964141

<think>好的,我现在需要帮用户解决在小米设备上出现的WebView异常问题,具体是java.lang.NoSuchFieldException: windowConfiguration。根据用户提供的引用资料,特别是引用[2]和[4],这通常是因为反射调用时找不到指定的字段。让我先理清楚可能的原因和解决方案。 首先,用户提到的问题出现在Android 5.1系统,但这里的小米设备可能运行的是更高版本?可能需要确认Android版本,但问题的核心是NoSuchFieldException,所以重点在字段是否存在。根据引用[4],字段名不一致会导致这个问题,比如实体类和数据库列名不匹配,但这里的情况是WebView相关的windowConfiguration字段,可能涉及系统内部类或SDK版本差异。 接下来,引用[2]提到反射异常的处理,需要检查字段是否存在。如果系统类(比如某个WebView相关的类)在小米的定制ROM中修改了字段名或移除了该字段,就会导致反射调用失败。例如,某些厂商可能修改了Android框架的代码,导致原本存在的字段不存在了。 可能的解决步骤包括: 1. 确认引发异常的代码位置,找到具体是哪个类缺少windowConfiguration字段。 2. 检查该字段是否存在不同版本或厂商ROM中的不同名称。 3. 避免直接使用反射访问系统内部类,因为这在不同设备上不稳定。 4. 寻找官方API替代方案,或者使用其他兼容性更好的方法。 另外,引用[3]提到WebView方法需要在同一线程调用,虽然当前问题不是线程问题,但需要注意是否其他线程操作导致异常。可能需要确保所有WebView操作在主线程执行。 具体到解决方案,可能需要用户检查代码中是否有通过反射访问windowConfiguration字段的地方。如果有,考虑是否必须使用反射,或者是否有官方API可以替代。如果必须使用反射,可能需要根据设备厂商或API版本进行条件判断,避免在小米设备上调用该代码。 此外,查看堆栈跟踪的详细信息,确定具体哪个类触发了异常。例如,是否是某个第三方库或自定义代码中使用了反射获取windowConfiguration。如果是,可能需要联系库的维护者或修改代码以适应小米设备的特殊情况。 总结来说,解决方案可能包括:避免反射调用内部字段,使用官方API替代,检查并适配不同厂商的ROM,以及处理多线程问题。同时,测试在不同设备和系统版本上的兼容性也很重要。</think>针对小米设备上WebView出现`java.lang.NoSuchFieldException: windowConfiguration`异常,以下是分步解决方案: --- ### **问题原因分析** 1. **反射调用字段缺失**:该异常表明代码中通过反射尝试访问的`windowConfiguration`字段在目标类中不存在,可能是由于: - 小米定制ROM修改了Android系统内部类的字段命名规则[^2][^4] - 系统API版本差异导致字段被移除或重命名 - 第三方库或代码中硬编码了非公开字段的反射调用 2. **线程调用问题**:若WebView操作未在主线程执行,可能触发线程相关的异常[^3] --- ### **解决方案** #### **1. 定位反射调用代码** - 检查项目中是否包含类似代码: ```java Class<?> clazz = SomeClass.class; Field field = clazz.getDeclaredField("windowConfiguration"); // 触发异常的来源 ``` - 确认调用堆栈中涉及的具体类名(如`android.view.WindowManager`或WebView相关类) #### **2. 适配厂商系统** - **条件判断绕过**:针对小米设备禁用相关反射逻辑 ```java if (!"xiaomi".equalsIgnoreCase(Build.MANUFACTURER)) { // 执行反射操作 } ``` - **字段存在性检查**:通过`try-catch`或`Class.getDeclaredFields()`动态判断字段是否存在 ```java try { Field field = clazz.getDeclaredField("windowConfiguration"); // 处理字段 } catch (NoSuchFieldException e) { Log.e("TAG", "Field not found, skip reflection"); } ``` #### **3. 避免反射调用非公开API** - **使用官方API替代**:若需获取窗口配置信息,改用`Activity.getWindow().getAttributes()`或`Configuration`类 - **依赖注入框架**:使用`ViewModel`或`WindowInfoRepository`管理窗口状态,避免直接操作底层字段 #### **4. 线程合规性检查** - 确保所有WebView操作在主线程执行: ```java runOnUiThread(() -> { webView.loadUrl("https://example.com"); }); ``` #### **5. 更新依赖库** - 若异常来自第三方库(如Chromium内核适配库),升级到最新版本或提交Issue给维护者 --- ### **兼容性验证** 1. **多设备测试**:在小米、华为、Pixel等设备上复现问题,确认是否为小米专属问题 2. **API版本适配**:通过`Build.VERSION.SDK_INT`区分不同系统版本的行为 ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 使用高版本API } else { // 降级实现 } ``` --- ### **引用关联** - 反射调用字段需严格匹配类结构,否则会触发`NoSuchFieldException`[^2] - WebView线程调用违规会导致`RuntimeException` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值