错误信息
java.lang.NoClassDefFoundError: com/sun/xml/internal/ws/util/ByteArrayBuffer
复现
经多次尝试,项目内运行正常,编译,打包都没问题,只是在运行Jar
包时,出现此错误。
询问ChatGPT
java.lang.NoClassDefFoundError
异常通常表示虚拟机在运行时无法找到类的定义。在你的情况下,异常指出缺少了com.sun.xml.internal.ws.util.ByteArrayBuffer
类的定义,这是一个 JDK 内部类,不应该直接依赖于它。解决这个问题的方法如下:
避免直接依赖 JDK 内部类:尽量避免直接依赖于 JDK 内部类,因为它们不是公共 API 的一部分,可能会导致兼容性问题。
检查项目依赖:检查你的项目依赖关系,看看是否有引入了直接依赖于
com.sun.xml.internal.ws.util.ByteArrayBuffer
类的库。如果有,尝试找到更好的替代方案。升级相关依赖:尝试升级你的项目依赖,特别是涉及到 Web Services 的库。新版本可能已经移除了对这个 JDK 内部类的依赖。
排除相关依赖:如果确定是某个特定依赖引入了对
com.sun.xml.internal.ws.util.ByteArrayBuffer
的依赖,可以尝试在构建工具(如 Maven 或 Gradle)中排除这个依赖,以避免冲突。使用合适的替代方案:尝试寻找替代方案来替代使用
com.sun.xml.internal.ws.util.ByteArrayBuffer
类的功能。可能有其他库或方法可以完成相同的任务。最重要的是要避免直接依赖于 JDK 内部类,因为它们不是为公共使用而设计的,可能会导致类似的问题。通过遵循最佳实践和避免直接依赖 JDK 内部类,可以帮助确保你的应用程序更具可移植性和稳定性。
地毯式搜寻导入ByteArrayBuffer
的类
根据ChatGPT
提供的解决方案:
- 避免直接依赖
JDK
内部类:发现一个功能类直接导入了此类。 - 检查项目依赖:未发现相关依赖
- 升级相关依赖:未发现相关依赖
- 排除相关依赖:未发现相关依赖
- 使用合适的替代方案:开始深入搜寻替代方案!
快速了解 ByteArrayBuffer
类
源文件如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.sun.xml.internal.ws.util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class ByteArrayBuffer extends OutputStream {
protected byte[] buf;
private int count;
private static final int CHUNK_SIZE = 4096;
public ByteArrayBuffer() {
this(32);
}
public ByteArrayBuffer(int size) {
if (size <= 0) {
throw new IllegalArgumentException();
} else {
this.buf = new byte[size];
}
}
public ByteArrayBuffer(byte[] data) {
this(data, data.length);
}
public ByteArrayBuffer(byte[] data, int length) {
this.buf = data;
this.count = length;
}
public final void write(InputStream in) throws IOException {
while(true) {
int cap = this.buf.length - this.count;
int sz = in.read(this.buf, this.count, cap);
if (sz < 0) {
return;
}
this.count += sz;
if (cap == sz) {
this.ensureCapacity(this.buf.length * 2);
}
}
}
public final void write(int b) {
int newcount = this.count + 1;
this.ensureCapacity(newcount);
this.buf[this.count] = (byte)b;
this.count = newcount;
}
public final void write(byte[] b, int off, int len) {
int newcount = this.count + len;
this.ensureCapacity(newcount);
System.arraycopy(b, off, this.buf, this.count, len);
this.count = newcount;
}
private void ensureCapacity(int newcount) {
if (newcount > this.buf.length) {
byte[] newbuf = new byte[Math.max(this.buf.length << 1, newcount)];
System.arraycopy(this.buf, 0, newbuf, 0, this.count);
this.buf = newbuf;
}
}
public final void writeTo(OutputStream out) throws IOException {
int remaining = this.count;
int chunk;
for(int off = 0; remaining > 0; off += chunk) {
chunk = remaining > 4096 ? 4096 : remaining;
out.write(this.buf, off, chunk);
remaining -= chunk;
}
}
public final void reset() {
this.count = 0;
}
/** @deprecated */
public final byte[] toByteArray() {
byte[] newbuf = new byte[this.count];
System.arraycopy(this.buf, 0, newbuf, 0, this.count);
return newbuf;
}
public final int size() {
return this.count;
}
public final byte[] getRawData() {
return this.buf;
}
public void close() throws IOException {
}
public final InputStream newInputStream() {
return new ByteArrayInputStream(this.buf, 0, this.count);
}
public final InputStream newInputStream(int start, int length) {
return new ByteArrayInputStream(this.buf, start, length);
}
public String toString() {
return new String(this.buf, 0, this.count);
}
}
此类是一个单独的实现类,完全可以全选复制代码,自创个工具类粘贴使用,以达成替代方案!
解决方法:使用替代方案
创建工具类ByteArrayBuffer
,添加类注释和@Component
注解以加入Spring IOC
容器。
package com.demo.example.utils;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 日期:2024/3/15
* 该类来源为:com.sun.xml.internal.ws.util.ByteArrayBuffer;
* 声明:导入此包的类为(xx类)
* 导入此Java内部类包会导致成功打jar包后,运行jar包出现如下错误:
* java.lang.NoClassDefFoundError: com/sun/xml/internal/ws/util/ByteArrayBuffer
* 解决方法:采用替代方案
* 为了避免直接使用Java内部类,深入此类了解后,决定把此类单独抽取出来,作为一个工具类。
* 由于此类为官方内部类,所以只写类注释,类内的属性和方法就不再注释处理。
*/
@Component
public class ByteArrayBuffer extends OutputStream {
protected byte[] buf;
private int count;
private static final int CHUNK_SIZE = 4096;
public ByteArrayBuffer() {
this(32);
}
public ByteArrayBuffer(int size) {
if (size <= 0) {
throw new IllegalArgumentException();
} else {
this.buf = new byte[size];
}
}
public ByteArrayBuffer(byte[] data) {
this(data, data.length);
}
public ByteArrayBuffer(byte[] data, int length) {
this.buf = data;
this.count = length;
}
public final void write(InputStream in) throws IOException {
while(true) {
int cap = this.buf.length - this.count;
int sz = in.read(this.buf, this.count, cap);
if (sz < 0) {
return;
}
this.count += sz;
if (cap == sz) {
this.ensureCapacity(this.buf.length * 2);
}
}
}
public final void write(int b) {
int newcount = this.count + 1;
this.ensureCapacity(newcount);
this.buf[this.count] = (byte)b;
this.count = newcount;
}
public final void write(byte[] b, int off, int len) {
int newcount = this.count + len;
this.ensureCapacity(newcount);
System.arraycopy(b, off, this.buf, this.count, len);
this.count = newcount;
}
private void ensureCapacity(int newcount) {
if (newcount > this.buf.length) {
byte[] newbuf = new byte[Math.max(this.buf.length << 1, newcount)];
System.arraycopy(this.buf, 0, newbuf, 0, this.count);
this.buf = newbuf;
}
}
public final void writeTo(OutputStream out) throws IOException {
int remaining = this.count;
int chunk;
for(int off = 0; remaining > 0; off += chunk) {
chunk = remaining > 4096 ? 4096 : remaining;
out.write(this.buf, off, chunk);
remaining -= chunk;
}
}
public final void reset() {
this.count = 0;
}
/** @deprecated */
public final byte[] toByteArray() {
byte[] newbuf = new byte[this.count];
System.arraycopy(this.buf, 0, newbuf, 0, this.count);
return newbuf;
}
public final int size() {
return this.count;
}
public final byte[] getRawData() {
return this.buf;
}
public void close() throws IOException {
}
public final InputStream newInputStream() {
return new ByteArrayInputStream(this.buf, 0, this.count);
}
public final InputStream newInputStream(int start, int length) {
return new ByteArrayInputStream(this.buf, start, length);
}
public String toString() {
return new String(this.buf, 0, this.count);
}
}
原功能类导入信息替换为导入此工具类
相关代码:
// 替换前
import com.sun.xml.internal.ws.util.ByteArrayBuffer;
// 替换后
import com.demo.example.utils.ByteArrayBuffer;
项目测试
测试内容 | 测试结果 |
---|---|
能否成功编译、打包 | 能 |
能否成功运行Jar 包 | 能 |
涉及的原有功能是否可用 | 可用 |
成功解决!
以上为个人实践总结,如有更好的方法或者有需要改进的地方,欢迎评论区指正。
如果觉得有帮助的话,不妨点个赞和收藏,加个关注吧!