NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString

简介: 笔记

一、问题描述


在Android项目中使用到了org.apache.commons.codec.jar包下的DigestUtils.md5Hex()获取文件的md5值,结果编译通过,运行时总是报java.lang.NoSuchMethodError:org.apache.commons.codec.binary.Hex.encodeHexString([B)Ljava/lang/String;错误

我在APP中使用的是common-codec-1.9.jar

调用代码如下:

//直接传入文件输入流就可以得到文件的标准md5值
String cacheDirMd5Hex = DigestUtils.md5Hex(new FileInputStream(file));
String assetMd5Hex = DigestUtils.md5Hex(FileUtils.getBytes(context.getAssets().open(SkinConfig.SKIN_DIR_NAME + File.separator + fileName)));
DDLog.i(getClass(), "assetMd5Hex=" + assetMd5Hex + ",cacheDirMd5Hex=" +cacheDirMd5Hex);
if (!TextUtils.equals(assetMd5Hex, cacheDirMd5Hex)){    //如果缓存路径中与assets中的文件不相同
    DDLog.i(getClass(), "skin资源文件校验错误");
    file.delete();
    SkinFileUtils.copySkinAssetsToDir(context, fileName, SkinFileUtils.getSkinDir(context));
}

栈信息如下 :

System.err: java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString
System.err:     at org.apache.commons.codec.digest.DigestUtils.md5Hex(DigestUtils.java:310)
System.err:     at com.skin.loader.SkinManager.setUpSkinFile(SkinManager.java:106)
System.err:     at com.skin.loader.SkinManager.access$100(SkinManager.java:38)
System.err:     at com.skin.loader.SkinManager$1.run(SkinManager.java:73)

二、先上解决办法


既然找不到该方法,那么让它找到这个方法或者使用其它方法就可以解决此问题。

思路一是:保证AndroidStudio中调用的API与系统中的API版本一致,这样就不会导致方法找不到的问题。

思路二是:去掉系统中的相关API,这样就应用就会只调用我们自己APP中的API,但是这样未免代价太大,而且系统中其它地方可能对这些API有依赖,不推荐。


方法一、依据思路一:在AndroidStudio中使用1.3或者更低版本的API

另寻途径,改用其它方法。高版本的API使用起来是更方便快捷的,更换到低版本后就需要自己手动做一些工作了

1.3版本的DigestUtils.md5Hex(byte[] data)只能传入字节数组,所以需要自己把文件读出转换成字节数组才行

String cacheDirMd5Hex = DigestUtils.md5Hex(FileUtils.getBytes(file));
String assetMd5Hex = DigestUtils.md5Hex(FileUtils.getBytes(context.getAssets().open(SkinConfig.SKIN_DIR_NAME + File.separator + fileName)));
DDLog.i(getClass(), "assetMd5Hex=" + assetMd5Hex + ",cacheDirMd5Hex=" +cacheDirMd5Hex);
if (!TextUtils.equals(assetMd5Hex, cacheDirMd5Hex)){    //如果缓存路径中与assets中的文件不相同
    DDLog.i(getClass(), "skin资源文件校验错误");
    file.delete();
    SkinFileUtils.copySkinAssetsToDir(context, fileName, SkinFileUtils.getSkinDir(context));
}

//没办法,自己写个工具类吧
public class FileUtils {
    /**
     * 将文件转换成字节数组
     *
     * @param filePath
     * @return
     */
    public static byte[] getBytes(String filePath) {
        FileInputStream fis = null;
        ByteArrayOutputStream baos = null;
        try {
            fis = new FileInputStream(filePath);
            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int read = 0;
            while ((read = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, read);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return new byte[0];
    }
    /**
     * 将文件转换成字节数组
     *
     * @param file
     * @return
     */
    public static byte[] getBytes(File file) {
        FileInputStream fis = null;
        ByteArrayOutputStream baos = null;
        try {
            fis = new FileInputStream(file);
            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int read = 0;
            while ((read = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, read);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return new byte[0];
    }
    /**
     * 将文件转换成字节数组
     *
     * @param is
     * @return
     */
    public static byte[] getBytes(InputStream is) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int read = 0;
            while ((read = is.read(buffer)) != -1) {
                baos.write(buffer, 0, read);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return new byte[0];
    }
}

方法二、依据思路一:在更新系统中的common-codec库版本为1.4以上

因为common库会兼容低版本,所以不会引入更多问题,而且是一种更值得做的方法,开历史倒车总是不好的。当然该方法仅限于你是做系统开发的,可以修改系统源码,否则只有依据方法一。

需要懂一些Android Build相关知识。

//TODO 有空再更

三、问题原因


通过网络查找相关文章,发现根本原因如下:

其根本原因在于android内置了一个Codec库,但是版本过老,如果使用了外部引入的新版本的codec.jar中的DigestUtils执行方法的时候,DigestUtils优先调用的是系统自带的老版本的codec库中相应的方法,当老版本的安卓自带codec.jar中不包含新版本DigestUtil需要的方法时,就产生了异常!

由于我使用的是Android4.4版本,于是在代码中搜索了一番,发现在源码编译后的out目录下:

out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes/org/apache/commons/codec/

编译了系统使用的common-codec库,其对应的源码中的jar包为common.jar,于是我打开了common-codec-1.9.jar,common-codec-1.4.jar,common-codec-1.3.jar和common.jar,对比发现在common.jar和common-codec-1.3.jar中的Hex类中没有对应的方法Hex.encodeHexString,如下图:

1.4版本:

1.png

1.9版本:

2.png

1.3版本:

3.png

Android4.4系统中使用的版本(我的测试机)

4.png

通过对比得出结论:common-codec.jar在1.4及之后的版本中才有Hex.encodeHexString方法,在AndroidStudio中编译的时候使用的是我引入的1.9版本的jar包,不会出现编译错误,但是一旦安装到Android4.4系统中,会首先寻找系统中是否有相同的API,结果找到了系统中低版本(1.3或者更低)的Hex类,然后就找不到encodeHexString方法了。




目录
相关文章
|
消息中间件 Java Kafka
实时计算 Flink版操作报错合集之从hudi读数据,报错NoSuchMethodError:org.apache.hudi.format.cow.vector.reader.PaequetColumnarRowSplit.getRecord(),该怎么办
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
354 0
|
9月前
|
人工智能 数据处理 API
阿里云、Ververica、Confluent 与 LinkedIn 携手推进流式创新,共筑基于 Apache Flink Agents 的智能体 AI 未来
Apache Flink Agents 是由阿里云、Ververica、Confluent 与 LinkedIn 联合推出的开源子项目,旨在基于 Flink 构建可扩展、事件驱动的生产级 AI 智能体框架,实现数据与智能的实时融合。
1486 6
阿里云、Ververica、Confluent 与 LinkedIn 携手推进流式创新,共筑基于 Apache Flink Agents 的智能体 AI 未来
|
存储 Cloud Native 数据处理
从嵌入式状态管理到云原生架构:Apache Flink 的演进与下一代增量计算范式
本文整理自阿里云资深技术专家、Apache Flink PMC 成员梅源在 Flink Forward Asia 新加坡 2025上的分享,深入解析 Flink 状态管理系统的发展历程,从核心设计到 Flink 2.0 存算分离架构,并展望未来基于流批一体的通用增量计算方向。
672 0
从嵌入式状态管理到云原生架构:Apache Flink 的演进与下一代增量计算范式
|
11月前
|
SQL 人工智能 数据挖掘
Apache Flink:从实时数据分析到实时AI
Apache Flink 是实时数据处理领域的核心技术,历经十年发展,已从学术项目成长为实时计算的事实标准。它在现代数据架构中发挥着关键作用,支持实时数据分析、湖仓集成及实时 AI 应用。随着 Flink 2.0 的发布,其在流式湖仓、AI 驱动决策等方面展现出强大潜力,正推动企业迈向智能化、实时化的新阶段。
1210 9
Apache Flink:从实时数据分析到实时AI
|
11月前
|
SQL 人工智能 API
Apache Flink 2.1.0: 面向实时 Data + AI 全面升级,开启智能流处理新纪元
Apache Flink 2.1.0 正式发布,标志着实时数据处理引擎向统一 Data + AI 平台迈进。新版本强化了实时 AI 能力,支持通过 Flink SQL 和 Table API 创建及调用 AI 模型,新增 Model DDL、ML_PREDICT 表值函数等功能,实现端到端的实时 AI 工作流。同时增强了 Flink SQL 的流处理能力,引入 Process Table Functions(PTFs)、Variant 数据类型,优化流式 Join 及状态管理,显著提升作业稳定性与资源利用率。
943 0
|
10月前
|
人工智能 运维 Java
Flink Agents:基于Apache Flink的事件驱动AI智能体框架
本文基于Apache Flink PMC成员宋辛童在Community Over Code Asia 2025的演讲,深入解析Flink Agents项目的技术背景、架构设计与应用场景。该项目聚焦事件驱动型AI智能体,结合Flink的实时处理能力,推动AI在工业场景中的工程化落地,涵盖智能运维、直播分析等典型应用,展现其在AI发展第四层次——智能体AI中的重要意义。
3255 27
Flink Agents:基于Apache Flink的事件驱动AI智能体框架
|
存储 人工智能 大数据
The Past, Present and Future of Apache Flink
本文整理自阿里云开源大数据负责人王峰(莫问)在 Flink Forward Asia 2024 上海站主论坛开场的分享,今年正值 Flink 开源项目诞生的第 10 周年,借此时机,王峰回顾了 Flink 在过去 10 年的发展历程以及 Flink社区当前最新的技术成果,最后展望下一个十年 Flink 路向何方。
1298 33
The Past, Present and Future of Apache Flink
|
SQL Java API
Apache Flink 2.0-preview released
Apache Flink 社区正积极筹备 Flink 2.0 的发布,这是自 Flink 1.0 发布以来的首个重大更新。Flink 2.0 将引入多项激动人心的功能和改进,包括存算分离状态管理、物化表、批作业自适应执行等,同时也包含了一些不兼容的变更。目前提供的预览版旨在让用户提前尝试新功能并收集反馈,但不建议在生产环境中使用。
1882 13
Apache Flink 2.0-preview released
|
11月前
|
存储 人工智能 数据处理
对话王峰:Apache Flink 在 AI 时代的“剑锋”所向
Flink 2.0 架构升级实现存算分离,迈向彻底云原生化,支持更大规模状态管理、提升资源效率、增强容灾能力。通过流批一体与 AI 场景融合,推动实时计算向智能化演进。生态项目如 Paimon、Fluss 和 Flink CDC 构建湖流一体架构,实现分钟级时效性与低成本平衡。未来,Flink 将深化 AI Agents 框架,引领事件驱动的智能数据处理新方向。
1069 6
|
11月前
|
消息中间件 存储 Kafka
Apache Flink错误处理实战手册:2年生产环境调试经验总结
本文由 Ververica 客户成功经理 Naci Simsek 撰写,基于其在多个行业 Flink 项目中的实战经验,总结了 Apache Flink 生产环境中常见的三大典型问题及其解决方案。内容涵盖 Kafka 连接器迁移导致的状态管理问题、任务槽负载不均问题以及 Kryo 序列化引发的性能陷阱,旨在帮助企业开发者避免常见误区,提升实时流处理系统的稳定性与性能。
839 0
Apache Flink错误处理实战手册:2年生产环境调试经验总结

推荐镜像

更多