From 3abbf7ac734a3a04365197c0168e2f8215d2dc9d Mon Sep 17 00:00:00 2001 From: Matteo Merli Date: Tue, 12 May 2026 13:27:02 -0700 Subject: [PATCH] Drop jibx-tools dependency to remove transitive log4j 1.x jibx-tools was only used in Util.plural / Util.singular to derive accessor names for `repeated` fields (addItem / getItemsCount / etc.). It transitively pulled in log4j 1.2.17 (multiple CVEs) and ~10 ancient Eclipse JDT jars. The relevant pluralize/depluralize logic from JiBX NameUtilities is ~40 lines of rule-based suffix manipulation with no irregular-plural handling, so vendor it directly into Util (BSD 3-clause, attribution in comment). Generated output is byte-identical; all 262 existing tests pass unchanged. Add UtilTest covering every branch of plural / singular, including the case-sensitivity quirk in jibx where "ANY" pluralizes to "ANYs". --- code-generator/pom.xml | 11 ++- .../lightproto/generator/Util.java | 38 ++++++-- .../lightproto/generator/UtilTest.java | 92 +++++++++++++++++++ pom.xml | 7 -- 4 files changed, 127 insertions(+), 21 deletions(-) create mode 100644 code-generator/src/test/java/io/streamnative/lightproto/generator/UtilTest.java diff --git a/code-generator/pom.xml b/code-generator/pom.xml index f317bb0..ad623f1 100644 --- a/code-generator/pom.xml +++ b/code-generator/pom.xml @@ -46,11 +46,6 @@ guava - - org.jibx - jibx-tools - - org.jboss.forge.roaster roaster-api @@ -60,6 +55,12 @@ roaster-jdt runtime + + + org.junit.jupiter + junit-jupiter + test + diff --git a/code-generator/src/main/java/io/streamnative/lightproto/generator/Util.java b/code-generator/src/main/java/io/streamnative/lightproto/generator/Util.java index d5151ce..1c407cf 100644 --- a/code-generator/src/main/java/io/streamnative/lightproto/generator/Util.java +++ b/code-generator/src/main/java/io/streamnative/lightproto/generator/Util.java @@ -17,9 +17,6 @@ import java.io.PrintWriter; -import org.jibx.schema.codegen.extend.DefaultNameConverter; -import org.jibx.schema.codegen.extend.NameConverter; - import static com.google.common.base.CaseFormat.LOWER_CAMEL; import static com.google.common.base.CaseFormat.LOWER_UNDERSCORE; @@ -66,14 +63,37 @@ public static String upperCase(String... parts) { return sb.toString().toUpperCase(); } - private static final NameConverter nameTools = new DefaultNameConverter(); - - public static String plural(String s) { - return nameTools.pluralize(s); + // pluralize/singular rules vendored from JiBX NameUtilities + // (Copyright (c) 2008-2010, Dennis M. Sosnoski, BSD 3-clause license). + public static String plural(String name) { + if (name.endsWith("List") || (name.endsWith("s") && !name.endsWith("ss"))) { + return name; + } + if (name.endsWith("y") && !name.endsWith("ay") && !name.endsWith("ey") && !name.endsWith("iy") + && !name.endsWith("oy") && !name.endsWith("uy")) { + if (name.equalsIgnoreCase("any")) { + return name; + } + return name.substring(0, name.length() - 1) + "ies"; + } else if (name.endsWith("ss")) { + return name + "es"; + } else { + return name + 's'; + } } - public static String singular(String s) { - return nameTools.depluralize(s); + public static String singular(String name) { + if (name.endsWith("ies")) { + return name.substring(0, name.length() - 3) + 'y'; + } else if (name.endsWith("sses")) { + return name.substring(0, name.length() - 2); + } else if (name.endsWith("s") && !name.endsWith("ss")) { + return name.substring(0, name.length() - 1); + } else if (name.endsWith("List")) { + return name.substring(0, name.length() - 4); + } else { + return name; + } } public static void writeJavadoc(PrintWriter w, String doc, String indent) { diff --git a/code-generator/src/test/java/io/streamnative/lightproto/generator/UtilTest.java b/code-generator/src/test/java/io/streamnative/lightproto/generator/UtilTest.java new file mode 100644 index 0000000..f63fbaa --- /dev/null +++ b/code-generator/src/test/java/io/streamnative/lightproto/generator/UtilTest.java @@ -0,0 +1,92 @@ +/** + * Copyright 2026 StreamNative + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.streamnative.lightproto.generator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/** + * Locks the pluralize/singular behavior inherited from JiBX NameUtilities. + * These functions feed into generated public API names (e.g. {@code addItem}, + * {@code getItemsCount}), so changing their output is an ABI break. + */ +class UtilTest { + + @ParameterizedTest + @CsvSource({ + // default case: append 's' + "item, items", + "book, books", + "Message, Messages", + // ends with 'ss': append 'es' + "address, addresses", + "class, classes", + // ends with consonant+'y': replace with 'ies' + "city, cities", + "category, categories", + "company, companies", + // ends with vowel+'y': default rule, append 's' + "day, days", + "key, keys", + "boy, boys", + "guy, guys", + "way, ways", + // 'any' is a hardcoded exception (case-insensitive match), but + // only reached when endsWith("y") matches, which is case-sensitive. + // So "ANY" slips through to the default rule. + "any, any", + "Any, Any", + "ANY, ANYs", + // already plural ('s' but not 'ss'): unchanged + "items, items", + "books, books", + // ends with 'List': treated as already plural + "itemList, itemList", + "userList, userList", + }) + void pluralizes(String input, String expected) { + assertEquals(expected, Util.plural(input)); + } + + @ParameterizedTest + @CsvSource({ + // ends with 'ies': replace with 'y' + "cities, city", + "categories, category", + "companies, company", + // ends with 'sses': strip 'es' + "addresses, address", + "classes, class", + // ends with 's' (not 'ss'): strip 's' + "items, item", + "books, book", + "days, day", + // ends with 'List': strip suffix + "itemList, item", + "userList, user", + // ends with 'ss': unchanged (not a plural) + "address, address", + "class, class", + // no recognized plural marker: unchanged + "item, item", + "any, any", + }) + void singularizes(String input, String expected) { + assertEquals(expected, Util.singular(input)); + } +} diff --git a/pom.xml b/pom.xml index bee3e9f..ce61a10 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,6 @@ 5.7.0 32.0.0-jre 4.1.131.Final - 1.3.3 2.22.2.Final 1.68.0 @@ -177,12 +176,6 @@ ${protobuf.version} - - org.jibx - jibx-tools - ${jibx.version} - - org.openjdk.jmh jmh-core