UTM Link Builder — Java source
Build campaign tracking URLs with utm_source, utm_medium and utm_campaign parameters. Bulk mode processes a whole list, presets and import round-trip existing tracking URLs, and a validator flags attribution-breaking values — runs entirely in your browser.
This is the Java implementation — the same logic the interactive tool runs, in a shareable, citable form.
// utm-link-builder — campaign URL builder with canonical utm_* ordering. Java (17+, JDK only). Port of src/lib/utm.ts build(); lint/bulk/preset helpers live in the TypeScript/Go sources. Kept query pairs pass through verbatim; new utm values are form-encoded.
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
public class UtmLinkBuilder {
private static final List<Map.Entry<String, String>> CANONICAL = List.of(
Map.entry("source", "utm_source"), Map.entry("medium", "utm_medium"),
Map.entry("campaign", "utm_campaign"), Map.entry("term", "utm_term"),
Map.entry("content", "utm_content"));
static String build(String baseUrl, Map<String, String> params) {
try {
String text = baseUrl.contains("://") ? baseUrl : "https://" + baseUrl;
URI uri = URI.create(text);
if (uri.getHost() == null) return null; // unparseable / no host
StringBuilder query = new StringBuilder();
if (uri.getRawQuery() != null) { // keep unrelated pairs, drop stale utm_*
for (String pair : uri.getRawQuery().split("&")) {
String key = pair.substring(0, Math.max(pair.indexOf('='), 0));
if (!key.isEmpty() && !key.startsWith("utm_")) {
if (query.length() > 0) query.append('&');
query.append(pair);
}
}
}
for (Map.Entry<String, String> pair : CANONICAL) {
String value = params.get(pair.getKey());
if (value != null && !value.isEmpty()) {
if (query.length() > 0) query.append('&');
query.append(pair.getValue()).append('=')
.append(URLEncoder.encode(value, StandardCharsets.UTF_8));
}
}
StringBuilder out = new StringBuilder(uri.getScheme()).append("://").append(uri.getHost());
if (uri.getPort() != -1) out.append(':').append(uri.getPort());
out.append(uri.getRawPath() == null ? "" : uri.getRawPath());
if (query.length() > 0) out.append('?').append(query);
if (uri.getRawFragment() != null) out.append('#').append(uri.getRawFragment());
return out.toString();
} catch (IllegalArgumentException e) {
return null;
}
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →