diff --git a/.github/workflows/maven-build-action.yaml b/.github/workflows/maven-build-action.yaml
index 1bdb386f8..30d86d8d7 100644
--- a/.github/workflows/maven-build-action.yaml
+++ b/.github/workflows/maven-build-action.yaml
@@ -5,6 +5,8 @@ on:
branches: [ master, jaxb-tools-4.0.x, jaxb-tools-3.x, jaxb-tools-2.x, 0.15.x ]
pull_request:
branches: [ master, jaxb-tools-4.0.x, jaxb-tools-3.x, jaxb-tools-2.x, 0.15.x ]
+ workflow_dispatch:
+ ## Allow's manual runs
jobs:
build_and_test:
diff --git a/jaxb-plugins-parent/jaxb-plugins/src/main/java/org/jvnet/jaxb/plugin/commons_lang/XjcCommonsLangPlugin.java b/jaxb-plugins-parent/jaxb-plugins/src/main/java/org/jvnet/jaxb/plugin/commons_lang/XjcCommonsLangPlugin.java
index 1af1ba23d..260b14807 100644
--- a/jaxb-plugins-parent/jaxb-plugins/src/main/java/org/jvnet/jaxb/plugin/commons_lang/XjcCommonsLangPlugin.java
+++ b/jaxb-plugins-parent/jaxb-plugins/src/main/java/org/jvnet/jaxb/plugin/commons_lang/XjcCommonsLangPlugin.java
@@ -32,7 +32,7 @@
/**
* Automatically generates the toString(), hashCode() and equals() methods
- * using Jakarta's commons-lang.
+ * using org.apache.commons:commons-lang3.
*
* Supports the optional ToStringStyle command line parameter to specify
* the style for use within the toString method.
@@ -62,18 +62,38 @@
*
* The default ToStringStyle adopted by this plugin is MULTI_LINE_STYLE.
*
+ *
+ * To disable one of the generated plugins if you wish to use another module use one of the following:
+ *
+ *
+ * -Xcommons-lang:addToStringMethod=TRUE|FALSE (default: TRUE)
+ * -Xcommons-lang:addHashCodeMethod=TRUE|FALSE (default: TRUE)
+ * -Xcommons-lang:addEqualsMethod=TRUE|FALSE (default: TRUE)
+ *
+ *
* @author Hanson Char
+ * @author William Dutton (disable methods)
*/
public class XjcCommonsLangPlugin extends Plugin
{
private static final String TOSTRING_STYLE_PARAM = "-Xcommons-lang:ToStringStyle=";
+ private static final String TOSTRING_DISABLED_PARAM = "-Xcommons-lang:addToStringMethod=";
+ private static final String HASH_CODE_DISABLED_PARAM = "-Xcommons-lang:addHashCodeMethod=";
+ private static final String EQUALS_DISABLED_PARAM = "-Xcommons-lang:addEqualsMethod=";
+
+ //Classes
private static final String TOSTRINGSTYLE_CLASSNAME = "org.apache.commons.lang3.builder.ToStringStyle";
private static final String EQUALSBUILDER_CLASSNAME = "org.apache.commons.lang3.builder.EqualsBuilder";
private static final String HASHCODEBUILDER_CLASSNAME = "org.apache.commons.lang3.builder.HashCodeBuilder";
private static final String TOSTRINGBUILDER_CLASSNAME = "org.apache.commons.lang3.builder.ToStringBuilder";
+
private String toStringStyle = "MULTI_LINE_STYLE";
private Class> customToStringStyle;
+ private boolean toStringEnabled = true;
+ private boolean equalsEnabled = true;
+ private boolean hashCodeEnabled = true;
+
@Override
public String getOptionName()
{
@@ -83,13 +103,18 @@ public String getOptionName()
@Override
public String getUsage()
{
- return " -Xcommons-lang : generate toString(), hashCode() and equals() for generated code using Jakarta's common-lang\n"
+ return " -Xcommons-lang : generate toString(), hashCode() and equals() for generated code using Jakarta's common-lang "
+ " [-Xcommons-lang:ToStringStyle=MULTI_LINE_STYLE\n\t"
+ "| DEFAULT_STYLE\n\t"
+ "| NO_FIELD_NAMES_STYLE\n\t"
+ "| SHORT_PREFIX_STYLE\n\t"
+ "| SIMPLE_STYLE\n\t"
+ "| ]\n"
+ + "\n"
+ + " To disable one of the generated plugins if you wish to use another module use one of the following:\n"
+ + " -Xcommons-lang:addToStringMethod=FALSE\n"
+ + " -Xcommons-lang:addHashCodeMethod=FALSE\n"
+ + " -Xcommons-lang:addEqualsMethod=FALSE\n"
;
}
@@ -110,6 +135,9 @@ public boolean run(Outline outline,
private void createToStringMethod(JDefinedClass implClass)
{
+ if (!toStringEnabled) {
+ return;
+ }
JCodeModel codeModel = implClass.owner();
JMethod toStringMethod =
implClass.method(JMod.PUBLIC, codeModel.ref(String.class), "toString");
@@ -135,6 +163,9 @@ private void createToStringMethod(JDefinedClass implClass)
private void createEqualsMethod(JDefinedClass implClass)
{
+ if (!equalsEnabled) {
+ return;
+ }
JCodeModel codeModel = implClass.owner();
JMethod toStringMethod =
implClass.method(JMod.PUBLIC, codeModel.BOOLEAN, "equals");
@@ -153,6 +184,9 @@ private void createEqualsMethod(JDefinedClass implClass)
private void createHashCodeMethod(JDefinedClass implClass)
{
+ if (!hashCodeEnabled) {
+ return;
+ }
JCodeModel codeModel = implClass.owner();
JMethod toStringMethod =
implClass.method(JMod.PUBLIC, codeModel.INT, "hashCode");
@@ -191,6 +225,30 @@ public int parseArgument(Options opt, String[] args, int i)
}
return 1;
}
+
+ // eg. -Xcommons-lang:addToStringMethod=TRUE
+ if (arg.startsWith(TOSTRING_DISABLED_PARAM))
+ {
+ String toStringBoolean = arg.substring(TOSTRING_DISABLED_PARAM.length());
+ toStringEnabled = Boolean.parseBoolean(toStringBoolean);
+ return 1;
+ }
+
+ // eg. -Xcommons-lang:addEqualsMethod=TRUE
+ if (arg.startsWith(EQUALS_DISABLED_PARAM))
+ {
+ String toStringBoolean = arg.substring(EQUALS_DISABLED_PARAM.length());
+ equalsEnabled = Boolean.parseBoolean(toStringBoolean);
+ return 1;
+ }
+
+ // eg. -Xcommons-lang:addHashCodeMethod=TRUE
+ if (arg.startsWith(HASH_CODE_DISABLED_PARAM))
+ {
+ String toStringBoolean = arg.substring(HASH_CODE_DISABLED_PARAM.length());
+ hashCodeEnabled = Boolean.parseBoolean(toStringBoolean);
+ return 1;
+ }
return 0;
}
}
diff --git a/jaxb-plugins-parent/jaxb-plugins/src/test/java/org/jvnet/jaxb/plugin/commons_lang/XjcCommonsLangPluginTest.java b/jaxb-plugins-parent/jaxb-plugins/src/test/java/org/jvnet/jaxb/plugin/commons_lang/XjcCommonsLangPluginTest.java
new file mode 100644
index 000000000..dc4dd3961
--- /dev/null
+++ b/jaxb-plugins-parent/jaxb-plugins/src/test/java/org/jvnet/jaxb/plugin/commons_lang/XjcCommonsLangPluginTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * 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 org.jvnet.jaxb.plugin.commons_lang;
+
+import com.sun.codemodel.*;
+import com.sun.tools.xjc.BadCommandLineException;
+import com.sun.tools.xjc.Options;
+import com.sun.tools.xjc.model.CClassInfo;
+import com.sun.tools.xjc.outline.ClassOutline;
+import com.sun.tools.xjc.outline.Outline;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xml.sax.ErrorHandler;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.when;
+
+class XjcCommonsLangPluginTest {
+
+ @Mock
+ private Outline outline;
+ @Mock
+ private Options options;
+ @Mock
+ private ErrorHandler errorHandler;
+ @Mock
+ private CClassInfo cClassInfo;
+
+ private JDefinedClass implClass;
+ private XjcCommonsLangPlugin plugin;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ MockitoAnnotations.openMocks(this);
+
+ JCodeModel codeModel = new JCodeModel();
+ implClass = codeModel._class("TestGeneratedClass");
+
+ ClassOutline classOutline = new TestableClassOutline(cClassInfo, implClass);
+ when(outline.getClasses()).thenReturn((Collection) Collections.singletonList(classOutline));
+
+ plugin = new XjcCommonsLangPlugin();
+ }
+
+ @Test
+ void testGetOptionName() {
+ assertEquals("Xcommons-lang", plugin.getOptionName());
+ }
+
+ @Test
+ void testGetUsage() {
+ String usage = plugin.getUsage();
+ assertNotNull(usage);
+ assertEquals(" -Xcommons-lang : generate toString(), hashCode() and equals() for generated code using Jakarta's common-lang "
+ + " [-Xcommons-lang:ToStringStyle=MULTI_LINE_STYLE\n\t"
+ + "| DEFAULT_STYLE\n\t"
+ + "| NO_FIELD_NAMES_STYLE\n\t"
+ + "| SHORT_PREFIX_STYLE\n\t"
+ + "| SIMPLE_STYLE\n\t"
+ + "| ]\n"
+ + "\n"
+ + " To disable one of the generated plugins if you wish to use another module use one of the following:\n"
+ + " -Xcommons-lang:addToStringMethod=FALSE\n"
+ + " -Xcommons-lang:addHashCodeMethod=FALSE\n"
+ + " -Xcommons-lang:addEqualsMethod=FALSE\n", usage);
+ }
+
+ @Test
+ void testRunGeneratesAllMethods() throws Exception {
+ plugin.run(outline, options, errorHandler);
+
+ assertTrue(hasMethod(implClass, "toString"), "toString() should be generated");
+ assertTrue(hasMethod(implClass, "equals"), "equals() should be generated");
+ assertTrue(hasMethod(implClass, "hashCode"), "hashCode() should be generated");
+ }
+
+ @Test
+ void testRunSkipsMethodsWhenDisabled() throws Exception {
+ // Set flags to disable generation
+ plugin.parseArgument(options, new String[]{"-Xcommons-lang:addToStringMethod=FALSE"}, 0);
+ plugin.parseArgument(options, new String[]{"-Xcommons-lang:addEqualsMethod=FALSE"}, 0);
+ plugin.parseArgument(options, new String[]{"-Xcommons-lang:addHashCodeMethod=FALSE"}, 0);
+
+ plugin.run(outline, options, errorHandler);
+
+ // Verify that the methods were NOT added to the real object
+ assertFalse(hasMethod(implClass, "toString"), "toString() should not be generated");
+ assertFalse(hasMethod(implClass, "equals"), "equals() should not be generated");
+ assertFalse(hasMethod(implClass, "hashCode"), "hashCode() should not be generated");
+ }
+
+
+ @Test
+ void testOnlyToStringGenerated() throws Exception {
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addToStringMethod=TRUE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addEqualsMethod=FALSE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addHashCodeMethod=FALSE"}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertTrue(hasMethod(implClass, "toString"), "toString() should be generated");
+ assertFalse(hasMethod(implClass, "equals"), "equals() should be generated");
+ assertFalse(hasMethod(implClass, "hashCode"), "hashCode() should be generated");
+ }
+
+ @Test
+ void testOnlyEqualsGenerated() throws Exception {
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addToStringMethod=FALSE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addEqualsMethod=TRUE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addHashCodeMethod=FALSE"}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertFalse(hasMethod(implClass, "toString"), "toString() should be generated");
+ assertTrue(hasMethod(implClass, "equals"), "equals() should be generated");
+ JMethod method = getMethod(implClass, "equals").get();
+ assertEquals(1, method.listParams().length);
+ assertEquals("that", Arrays.stream(method.listParams()).findFirst().get().name());
+ assertEquals("java.lang.Object", Arrays.stream(method.listParams()).findFirst().get().type().fullName());
+ assertFalse(hasMethod(implClass, "hashCode"), "hashCode() should be generated");
+ }
+
+ @Test
+ void testOnlyEqualsGeneratedWithTestTransients() throws Exception {
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addToStringMethod=FALSE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addEqualsMethod=TRUE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addHashCodeMethod=FALSE"}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertFalse(hasMethod(implClass, "toString"), "toString() should be generated");
+ assertTrue(hasMethod(implClass, "equals"), "equals() should be generated");
+ assertFalse(hasMethod(implClass, "hashCode"), "hashCode() should be generated");
+ }
+
+ @Test
+ void testOnlyEqualsGeneratedWithRecursive() throws Exception {
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addToStringMethod=FALSE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addEqualsMethod=TRUE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addHashCodeMethod=FALSE"}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertFalse(hasMethod(implClass, "toString"), "toString() should be generated");
+ assertTrue(hasMethod(implClass, "equals"), "equals() should be generated");
+ assertFalse(hasMethod(implClass, "hashCode"), "hashCode() should be generated");
+ }
+
+ @Test
+ void testOnlyEqualsGeneratedWithTransiantAndRecursive() throws Exception {
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addToStringMethod=FALSE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addEqualsMethod=TRUE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addHashCodeMethod=FALSE"}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertFalse(hasMethod(implClass, "toString"), "toString() should be generated");
+ assertTrue(hasMethod(implClass, "equals"), "equals() should be generated");
+ JMethod method = getMethod(implClass, "equals").get();
+ assertEquals(1, method.listParams().length);
+ assertEquals("that", Arrays.stream(method.listParams()).findFirst().get().name());
+ assertEquals("java.lang.Object", Arrays.stream(method.listParams()).findFirst().get().type().fullName());
+ //Unsure how to verify args inside since post jdk8 its now in a class that does hides its classes externally.
+ assertFalse(hasMethod(implClass, "hashCode"), "hashCode() should be generated");
+ }
+
+ @Test
+ void testOnlyHashCodeGenerated() throws Exception {
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addToStringMethod=FALSE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addEqualsMethod=FALSE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addHashCodeMethod=TRUE"}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertFalse(hasMethod(implClass, "toString"), "toString() should not be generated");
+ assertFalse(hasMethod(implClass, "equals"), "equals() should not be generated");
+ assertTrue(hasMethod(implClass, "hashCode"), "hashCode() should be generated");
+ }
+
+
+ @Test
+ void testParseArgumentToStringStyleStandard() throws BadCommandLineException {
+ String arg = "-Xcommons-lang:ToStringStyle=SIMPLE_STYLE";
+ assertEquals(1, plugin.parseArgument(options, new String[]{arg}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertTrue(hasMethod(implClass, "toString"), "toString() should be generated");
+ }
+
+ @Test
+ void testParseArgumentToStringStyleCustom() throws BadCommandLineException {
+ String arg = "-Xcommons-lang:ToStringStyle=java.lang.String";
+ assertEquals(1, plugin.parseArgument(options, new String[]{arg}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertTrue(hasMethod(implClass, "toString"), "toString() should be generated");
+ }
+
+ @Test
+ void testParseArgumentDisablingFlags() throws BadCommandLineException {
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addToStringMethod=FALSE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addEqualsMethod=FALSE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:addHashCodeMethod=FALSE"}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertFalse(hasMethod(implClass, "toString"), "toString() should not be generated");
+ assertFalse(hasMethod(implClass, "equals"), "equals() should not be generated");
+ assertFalse(hasMethod(implClass, "hashCode"), "hashCode() should not be generated");
+ }
+
+ @Test
+ void testParseArgumentUnknown() throws BadCommandLineException {
+ assertEquals(0, plugin.parseArgument(options, new String[]{"-Xunknown-param"}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertTrue(hasMethod(implClass, "toString"), "toString() should be generated");
+ assertTrue(hasMethod(implClass, "equals"), "equals() should be generated");
+ assertTrue(hasMethod(implClass, "hashCode"), "hashCode() should be generated");
+ }
+
+
+ @Test
+ void testCreateToStringMethodWithCustomClassBranch() throws Exception {
+ String arg = "-Xcommons-lang:ToStringStyle=java.lang.String";
+ plugin.parseArgument(options, new String[]{arg}, 0);
+
+ assertTrue(plugin.run(outline, options, errorHandler));
+
+ assertTrue(hasMethod(implClass, "toString"), "toString() should be generated using custom class branch");
+ }
+
+ private boolean hasMethod(JDefinedClass clazz, String methodName) {
+ for (JMethod m : clazz.methods()) {
+ if (m.name().equals(methodName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private Optional getMethod(JDefinedClass clazz, String methodName) {
+ return clazz.methods().stream()
+ .filter(anno -> anno.name().equals(methodName))
+ .findFirst();
+ }
+
+ public static class TestableClassOutline extends ClassOutline {
+ public TestableClassOutline(CClassInfo target, JDefinedClass implClass) {
+ super(target, null, null, implClass);
+ }
+
+ @Override
+ public Outline parent() {
+ return null;
+ }
+ }
+}