Drop the commons-lang and dnsjava dependencies

Both were pulled in for a single call each: commons-lang for
ConstructorUtils.invokeConstructor when building a packet handler, and
dnsjava for the _ts3._udp SRV lookup. Together they added over a
megabyte to a shaded jar (and dnsjava drops jnamed/update classes into
the jar root). Plain reflection and JNDI's dns: provider cover both.

Also drop the BouncyCastleProvider registration: every digest here is
requested by a name the SUN provider already answers, so the only thing
it accomplished was keeping the whole JCE provider, the post-quantum
suite and the X.509 stack reachable for a shaded-jar tree-shaker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 23:46:56 +00:00
co-authored by Claude Opus 5
parent db57d60c98
commit dce4e68150
4 changed files with 58 additions and 36 deletions
-12
View File
@@ -40,18 +40,6 @@
<version>1.67</version> <version>1.67</version>
</dependency> </dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>dnsjava</groupId>
<artifactId>dnsjava</artifactId>
<version>2.1.8</version>
</dependency>
<dependency> <dependency>
<groupId>org.ini4j</groupId> <groupId>org.ini4j</groupId>
<artifactId>ini4j</artifactId> <artifactId>ini4j</artifactId>
@@ -1,13 +1,13 @@
package com.github.manevolent.ts3j.protocol; package com.github.manevolent.ts3j.protocol;
import org.xbill.DNS.*; import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
public class TS3DNS { public class TS3DNS {
private static final int TS3_VOICE_DEFAULT_PORT = 9987; private static final int TS3_VOICE_DEFAULT_PORT = 9987;
@@ -18,23 +18,56 @@ public class TS3DNS {
private static final String DNS_PREFIX_TCP = "_tsdns._tcp."; private static final String DNS_PREFIX_TCP = "_tsdns._tcp.";
private static final String DNS_PREFIX_UDP = "_ts3._udp."; private static final String DNS_PREFIX_UDP = "_ts3._udp.";
/**
* SRV record, as returned by JNDI: "priority weight port target."
*/
private static final class SrvRecord {
private final int priority, weight, port;
private final String target;
private SrvRecord(String record) {
String[] parts = record.trim().split("\\s+");
if (parts.length < 4) throw new IllegalArgumentException("malformed SRV record: " + record);
this.priority = Integer.parseInt(parts[0]);
this.weight = Integer.parseInt(parts[1]);
this.port = Integer.parseInt(parts[2]);
// Trim the trailing dot of the fully-qualified target name.
String target = parts[3];
this.target = target.endsWith(".") ? target.substring(0, target.length() - 1) : target;
}
}
private static List<InetSocketAddress> lookupSRV(String domain) throws IOException { private static List<InetSocketAddress> lookupSRV(String domain) throws IOException {
org.xbill.DNS.Record[] records = new Lookup(domain, Type.SRV).run(); Attribute attribute;
if (records == null || records.length <= 0) throw new UnknownHostException("Host not found"); try {
Attributes attributes = new InitialDirContext().getAttributes("dns:/" + domain, new String[] { "SRV" });
attribute = attributes.get("SRV");
} catch (NamingException e) {
throw new UnknownHostException("Host not found: " + domain);
}
return Arrays.stream(records) if (attribute == null || attribute.size() <= 0) throw new UnknownHostException("Host not found");
.filter(Objects::nonNull)
.map(x -> (SRVRecord) x) List<SrvRecord> records = new ArrayList<>(attribute.size());
.filter(x -> x.getTarget() != null)
.sorted((a, b) -> { try {
// Loose sorting for (int i = 0; i < attribute.size(); i++)
int prioComp = Integer.compare(a.getPriority(), b.getPriority()); records.add(new SrvRecord((String) attribute.get(i)));
if (prioComp != 0) return prioComp; } catch (NamingException e) {
else return Integer.compare(a.getWeight(), b.getWeight()); throw new IOException(e);
}) }
.map(x -> new InetSocketAddress(x.getTarget().toString(), x.getPort()))
.collect(Collectors.toList()); // Loose sorting
records.sort(Comparator.comparingInt((SrvRecord x) -> x.priority).thenComparingInt(x -> x.weight));
List<InetSocketAddress> addresses = new ArrayList<>(records.size());
for (SrvRecord record : records)
addresses.add(new InetSocketAddress(record.target, record.port));
return addresses;
} }
public static List<InetSocketAddress> lookup(String domain) throws IOException { public static List<InetSocketAddress> lookup(String domain) throws IOException {
@@ -24,7 +24,6 @@ import com.github.manevolent.ts3j.util.QuickLZ;
import com.github.manevolent.ts3j.util.Ts3Crypt; import com.github.manevolent.ts3j.util.Ts3Crypt;
import com.github.manevolent.ts3j.util.Ts3Debugging; import com.github.manevolent.ts3j.util.Ts3Debugging;
import com.github.manevolent.ts3j.util.Pair; import com.github.manevolent.ts3j.util.Pair;
import org.apache.commons.lang.reflect.ConstructorUtils;
import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.InvalidCipherTextException;
import java.io.EOFException; import java.io.EOFException;
@@ -1466,6 +1465,12 @@ public abstract class AbstractTeamspeakClientSocket
} }
private PacketHandler createHandler(Class<? extends PacketHandler> clazz) throws ReflectiveOperationException { private PacketHandler createHandler(Class<? extends PacketHandler> clazz) throws ReflectiveOperationException {
return (PacketHandler) ConstructorUtils.invokeConstructor(clazz, this); for (java.lang.reflect.Constructor<?> constructor : clazz.getConstructors()) {
Class<?>[] parameters = constructor.getParameterTypes();
if (parameters.length == 1 && parameters[0].isInstance(this))
return (PacketHandler) constructor.newInstance(this);
}
throw new NoSuchMethodException(clazz.getName() + " has no constructor accepting " + getClass().getName());
} }
} }
@@ -28,10 +28,6 @@ import java.security.*;
import java.util.*; import java.util.*;
public final class Ts3Crypt { public final class Ts3Crypt {
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
public static byte[] hash128(byte[] data, int offs, int len) { public static byte[] hash128(byte[] data, int offs, int len) {
try { try {
MessageDigest digest = MessageDigest.getInstance("SHA1"); MessageDigest digest = MessageDigest.getInstance("SHA1");