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..83ed7ab97 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
@@ -15,6 +15,8 @@
*/
package org.jvnet.jaxb.plugin.commons_lang;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.xml.sax.ErrorHandler;
import com.sun.codemodel.JCodeModel;
@@ -30,9 +32,12 @@
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.Outline;
+import static com.sun.codemodel.JExpr._null;
+import static com.sun.codemodel.JExpr.lit;
+
/**
* 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.
@@ -50,11 +55,11 @@
* Example 2:
*
* -Xcommons-lang
- * -Xcommons-lang:ToStringStyle=my.CustomToStringStyle
+ * -Xcommons-lang:ToStringStyle=my.CustomToStringStyleClass
*
* to specify the use of
*
- * my.CustomToStringStyle, which must be a subclass of
+ * my.CustomToStringStyleClass, which must be a subclass of
*
* org.apache.commons.lang3.builder.ToStringStyle, and contains a public no-arg constructor.
*
@@ -62,17 +67,53 @@
*
* The default ToStringStyle adopted by this plugin is MULTI_LINE_STYLE.
*
+ * Equals options:
+ *
+ * -Xcommons-lang:equalsTestTransients=TRUE|FALSE (default: FALSE)
+ * -Xcommons-lang:equalsTestRecursive=TRUE|FALSE (default: FALSE)
+ *
+ * NOTE:
+ * When enabled equals passing when sub objects where last object POJO returns by ref check only but contents is equals
+ *
+ * Performance Cost: Deep reflection is significantly slower than standard equality checks.
+ *
+ *
+ * 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=";
+ private static final String EQUALS_TEST_TRANSIENTS_PARAM = "-Xcommons-lang:equalsTestTransients=";
+ private static final String EQUALS_TEST_RECURSIVE_PARAM = "-Xcommons-lang:equalsTestRecursive=";
+
+ //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;
+
+ protected Log logger = LogFactory.getLog(getClass());
+
+ private String toStringStyle = "MULTI_LINE_STYLE"; //Default Style
+ private String toStringClass = null;
+
+ private boolean toStringEnabled = true;
+ private boolean equalsEnabled = true;
+ private boolean hashCodeEnabled = true;
+ private boolean equalsTestTransients = false;
+ private boolean equalsTestRecursive = false;
@Override
public String getOptionName()
@@ -83,13 +124,30 @@ public String getOptionName()
@Override
public String getUsage()
{
- return " -Xcommons-lang : generate toString(), hashCode() and equals() for generated code using Jakarta's common-lang\n"
- + " [-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"
+ return " -Xcommons-lang : generate toString(), hashCode() and equals() for generated code using Jakarta's common-lang "
+ + "[\n"
+ + "\t -Xcommons-lang:ToStringStyle=MULTI_LINE_STYLE\n"
+ + "\t| -Xcommons-lang:ToStringStyle=DEFAULT_STYLE\n"
+ + "\t| -Xcommons-lang:ToStringStyle=NO_FIELD_NAMES_STYLE\n"
+ + "\t| -Xcommons-lang:ToStringStyle=SHORT_PREFIX_STYLE\n"
+ + "\t| -Xcommons-lang:ToStringStyle=SIMPLE_STYLE\n"
+ + "\t| -Xcommons-lang:ToStringStyle=NO_CLASS_NAME_STYLE\n"
+ + "\t| -Xcommons-lang:ToStringStyle=JSON_STYLE\n"
+ + "\t| -Xcommons-lang:ToStringStyle=$\n"
+ + "\t| -Xcommons-lang:ToStringStyle=\n"
+ + "]\n"
+ + " Note: custom ToStringStyle class is needed if you wish to turn off setUseIdentityHashCode on top of MULTI_LINE_STYLE"
+ + "\n"
+ + " Equals options:\n"
+ + " -Xcommons-lang:equalsTestTransients=TRUE|FALSE (default: FALSE)\n"
+ + " -Xcommons-lang:equalsTestRecursive=TRUE|FALSE (default: FALSE)\n"
+ + " NOTE: \n"
+ + " Performance Cost: When equalsTestRecursive is TRUE, due to Deep reflection is significantly slower than standard equality checks.\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"
;
}
@@ -108,51 +166,76 @@ public boolean run(Outline outline,
return true;
}
- private void createToStringMethod(JDefinedClass implClass)
- {
+ private void createToStringMethod(JDefinedClass implClass) {
+ if (!toStringEnabled) {
+ return;
+ }
JCodeModel codeModel = implClass.owner();
JMethod toStringMethod =
implClass.method(JMod.PUBLIC, codeModel.ref(String.class), "toString");
// Annotate with @Override
toStringMethod.annotate(Override.class);
- final JExpression toStringStyleExpr =
- customToStringStyle == null
- ? codeModel.ref(TOSTRINGSTYLE_CLASSNAME)
- .staticRef(toStringStyle)
- : JExpr._new(
- codeModel.ref(customToStringStyle))
- ;
+
+ //Build body of method
+ final JExpression toStringStyleExpr;
+ if (toStringClass == null) {
+ // Call Static Reference i.e. ToStringStyle.JSON_STYLE;
+ toStringStyleExpr = codeModel.ref(TOSTRINGSTYLE_CLASSNAME).staticRef(toStringStyle);
+ } else {
+ //Direct class passed and calls new on it;
+ toStringStyleExpr = JExpr._new(codeModel.ref(toStringClass));
+ }
+
// Invoke ToStringBuilder.reflectionToString(Object,StringStyle)
toStringMethod.body()
- ._return(
- codeModel.ref(TOSTRINGBUILDER_CLASSNAME)
- .staticInvoke("reflectionToString")
- .arg(JExpr._this())
- .arg(toStringStyleExpr)
- );
- return;
+ ._return(
+ codeModel.ref(TOSTRINGBUILDER_CLASSNAME)
+ .staticInvoke("reflectionToString")
+ .arg(JExpr._this())
+ .arg(toStringStyleExpr)
+ );
}
private void createEqualsMethod(JDefinedClass implClass)
{
+ if (!equalsEnabled) {
+ return;
+ }
JCodeModel codeModel = implClass.owner();
JMethod toStringMethod =
implClass.method(JMod.PUBLIC, codeModel.BOOLEAN, "equals");
JVar that = toStringMethod.param(Object.class, "that");
// Annotate with @Override
toStringMethod.annotate(Override.class);
- // Invoke EqualsBuilder.reflectionEquals(Object,Object);
- toStringMethod.body()._return(
- codeModel.ref(EQUALSBUILDER_CLASSNAME)
- .staticInvoke("reflectionEquals")
- .arg(JExpr._this())
- .arg(that)
- );
- return;
+ if (equalsTestTransients || equalsTestRecursive) {
+ //Since: 3.6
+ toStringMethod.body()._return(
+ codeModel.ref(EQUALSBUILDER_CLASSNAME)
+ .staticInvoke("reflectionEquals") // public static boolean reflectionEquals(
+ .arg(JExpr._this()) //final Object lhs,
+ .arg(that) // final Object rhs,
+ .arg(lit(equalsTestTransients)) // final boolean testTransients,
+ .arg(_null()) // final Class> reflectUpToClass,
+ .arg(lit(equalsTestRecursive)) // final boolean testRecursive,
+ .arg(_null()) // final String... excludeFields) {
+ );
+ } else {
+ // Invoke EqualsBuilder.reflectionEquals(Object,Object);
+ toStringMethod.body()._return(
+ codeModel.ref(EQUALSBUILDER_CLASSNAME)
+ .staticInvoke("reflectionEquals")
+ .arg(JExpr._this())
+ .arg(that)
+
+ );
+ }
}
private void createHashCodeMethod(JDefinedClass implClass)
{
+ if (!hashCodeEnabled) {
+ return;
+ }
JCodeModel codeModel = implClass.owner();
JMethod toStringMethod =
implClass.method(JMod.PUBLIC, codeModel.INT, "hashCode");
@@ -171,26 +254,75 @@ private void createHashCodeMethod(JDefinedClass implClass)
public int parseArgument(Options opt, String[] args, int i)
throws BadCommandLineException
{
- // eg. -Xcommons-lang ToStringStyle=SIMPLE_STYLE
+ // eg.
+ // -Xcommons-lang:ToStringStyle=SIMPLE_STYLE
+ // or
+ // -Xcommons-lang:ToStringStyle=
String arg = args[i].trim();
if (arg.startsWith(TOSTRING_STYLE_PARAM))
{
- toStringStyle = arg.substring(TOSTRING_STYLE_PARAM.length());
- try {
- Class.forName(TOSTRINGSTYLE_CLASSNAME).getField(toStringStyle);
+ String value = arg.substring(TOSTRING_STYLE_PARAM.length());
+
+ if (value.matches("^[A-Z0-9_]+$")) {
+ try {
+ Class.forName(TOSTRINGSTYLE_CLASSNAME).getField(value);
+ } catch (NoSuchFieldException | ClassNotFoundException | SecurityException e) {
+ logger.error("Could not verify : '" + TOSTRINGSTYLE_CLASSNAME + "." + value + "'. Assume it's not visible to generator.", e);
+ }
+ toStringStyle = value;
return 1;
- } catch (ClassNotFoundException | SecurityException e) {
- throw new BadCommandLineException(e.getMessage());
- } catch (NoSuchFieldException ignore) {
}
+
try {
- customToStringStyle = Class.forName(toStringStyle);
+ Class.forName(value);
} catch (ClassNotFoundException e) {
- throw new BadCommandLineException(e.getMessage());
+ logger.warn("Could not find class: '" + value + "'. Assume it's not visible to generator.");
}
+ toStringClass = value;
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;
+ }
+
+ // eg. -Xcommons-lang:equalsTestTransients=TRUE
+ if (arg.startsWith(EQUALS_TEST_TRANSIENTS_PARAM))
+ {
+ String toStringBoolean = arg.substring(EQUALS_TEST_TRANSIENTS_PARAM.length());
+ equalsTestTransients = Boolean.parseBoolean(toStringBoolean);
+ return 1;
+ }
+
+ // eg. -Xcommons-lang:equalsTestRecursive=TRUE
+ if (arg.startsWith(EQUALS_TEST_RECURSIVE_PARAM))
+ {
+ String toStringBoolean = arg.substring(EQUALS_TEST_RECURSIVE_PARAM.length());
+ equalsTestRecursive = 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..7c5457031
--- /dev/null
+++ b/jaxb-plugins-parent/jaxb-plugins/src/test/java/org/jvnet/jaxb/plugin/commons_lang/XjcCommonsLangPluginTest.java
@@ -0,0 +1,315 @@
+/*
+ * 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 [\n" +
+ "\t -Xcommons-lang:ToStringStyle=MULTI_LINE_STYLE\n" +
+ "\t| -Xcommons-lang:ToStringStyle=DEFAULT_STYLE\n" +
+ "\t| -Xcommons-lang:ToStringStyle=NO_FIELD_NAMES_STYLE\n" +
+ "\t| -Xcommons-lang:ToStringStyle=SHORT_PREFIX_STYLE\n" +
+ "\t| -Xcommons-lang:ToStringStyle=SIMPLE_STYLE\n" +
+ "\t| -Xcommons-lang:ToStringStyle=NO_CLASS_NAME_STYLE\n" +
+ "\t| -Xcommons-lang:ToStringStyle=JSON_STYLE\n" +
+ "\t| -Xcommons-lang:ToStringStyle=$\n" +
+ "\t| -Xcommons-lang:ToStringStyle=\n" +
+ "]\n" +
+ " Note: custom ToStringStyle class is needed if you wish to turn off setUseIdentityHashCode on top of MULTI_LINE_STYLE\n" +
+ " Equals options:\n" +
+ " -Xcommons-lang:equalsTestTransients=TRUE|FALSE (default: FALSE)\n" +
+ " -Xcommons-lang:equalsTestRecursive=TRUE|FALSE (default: FALSE)\n" +
+ " NOTE: \n" +
+ " Performance Cost: When equalsTestRecursive is TRUE, due to Deep reflection is significantly slower than standard equality checks.\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));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:equalsTestTransients=TRUE"}, 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));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:equalsTestRecursive=TRUE"}, 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));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:equalsTestTransients=TRUE"}, 0));
+ assertEquals(1, plugin.parseArgument(options, new String[]{"-Xcommons-lang:equalsTestRecursive=TRUE"}, 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 testParseArgumentToStringStyleToClassGeneratorCantSeet() throws BadCommandLineException {
+ String arg = "-Xcommons-lang:ToStringStyle=com.non.existent.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 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 testParseArgumentToStringStyleInvalidClassError() throws BadCommandLineException {
+ String arg = "-Xcommons-lang:ToStringStyle=NO_FINAL_STATIC_EXISTS_FOR_THIS";
+ assertEquals(1, plugin.parseArgument(options, new String[]{arg}, 0));
+
+ plugin.run(outline, options, errorHandler);
+
+ assertTrue(hasMethod(implClass, "toString"), "toString() 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;
+ }
+ }
+}
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_class/pom.xml b/jaxb-plugins-parent/tests/commons_lang_custom_class/pom.xml
new file mode 100644
index 000000000..d03d063be
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_class/pom.xml
@@ -0,0 +1,47 @@
+
+ 4.0.0
+
+ org.jvnet.jaxb
+ jaxb-plugins-tests
+ 4.1.0-SNAPSHOT
+ ../pom.xml
+
+ jaxb-plugins-test-commons_lang_custom_class
+ jar
+ JAXB Tools :: JAXB Plugins :: Test [commons_lang_custom_class]
+
+
+ org.jvnet.jaxb
+ jaxb-maven-plugin-testing
+ test
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ test
+
+
+ org.jvnet.jaxb
+ jaxb-maven-plugin
+
+ true
+
+ -Xcommons-lang
+ -Xcommons-lang:ToStringStyle=com.example.CustomToStringStyle
+
+
+
+ org.jvnet.jaxb
+ jaxb-plugins
+
+
+
+
+
+
+
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_class/src/main/java/com/example/CustomToStringStyle.java b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/main/java/com/example/CustomToStringStyle.java
new file mode 100644
index 000000000..cd04dd3b7
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/main/java/com/example/CustomToStringStyle.java
@@ -0,0 +1,33 @@
+package com.example;
+
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+public class CustomToStringStyle extends ToStringStyle {
+
+ public static final ToStringStyle CUSTOM_TO_STRING_STYLE = new CustomToStringStyle();
+
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a new instance.
+ *
+ * Use the static constant rather than instantiating.
+ */
+ public CustomToStringStyle() {
+ setUseIdentityHashCode(false);
+ setContentStart("[");
+ setFieldSeparator(System.lineSeparator() + " ");
+ setFieldSeparatorAtStart(true);
+ setContentEnd(System.lineSeparator() + "]");
+ }
+
+ /**
+ * Ensure Singleton after serialization.
+ * @return the singleton
+ */
+ private Object readResolve() {
+ return CUSTOM_TO_STRING_STYLE;
+ }
+
+}
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_class/src/main/resources/Person.xsd b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/main/resources/Person.xsd
new file mode 100644
index 000000000..1ee143788
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/main/resources/Person.xsd
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_class/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/AddressTest.java b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/AddressTest.java
new file mode 100644
index 000000000..3fa2776af
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/AddressTest.java
@@ -0,0 +1,22 @@
+package org.jvnet.jaxb2_commons.tests.commons_lang;
+
+import com.example.CustomToStringStyle;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+import generated.Address;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class AddressTest {
+
+ @Test
+ public void testAddress() {
+ Address a = new Address();
+ // No plugin default-value present, checking everything is null or default java value
+ Assertions.assertEquals(0, a.getNumber());
+ Assertions.assertNull(a.getCareOf());
+ Assertions.assertNull(a.getStreet());
+
+ Assertions.assertEquals(ToStringBuilder.reflectionToString(a, new CustomToStringStyle()), a.toString());
+ }
+}
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_class/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/PersonTest.java b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/PersonTest.java
new file mode 100644
index 000000000..be06f8bd9
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/PersonTest.java
@@ -0,0 +1,21 @@
+package org.jvnet.jaxb2_commons.tests.commons_lang;
+
+import com.example.CustomToStringStyle;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import generated.Person;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class PersonTest {
+
+ @Test
+ public void testPerson() {
+ Person p = new Person();
+ // No plugin default-value present, checking everything is null or default java value
+ Assertions.assertEquals(false, p.isMailingAddressIdentical());
+
+ Assertions.assertEquals(ToStringBuilder.reflectionToString(p, new CustomToStringStyle()), p.toString());
+ }
+}
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_class/src/test/resources/log4j.properties b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/test/resources/log4j.properties
new file mode 100644
index 000000000..ca4ee5e2c
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_class/src/test/resources/log4j.properties
@@ -0,0 +1,5 @@
+log4j.rootCategory=DEBUG, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.target=system.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_equals/pom.xml b/jaxb-plugins-parent/tests/commons_lang_custom_equals/pom.xml
new file mode 100644
index 000000000..1c1fca8f9
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_equals/pom.xml
@@ -0,0 +1,51 @@
+
+ 4.0.0
+
+ org.jvnet.jaxb
+ jaxb-plugins-tests
+ 4.1.0-SNAPSHOT
+ ../pom.xml
+
+ jaxb-plugins-test-commons_lang_custom_equals
+ jar
+ JAXB Tools :: JAXB Plugins :: Test [commons_lang_custom_equals]
+
+
+ org.jvnet.jaxb
+ jaxb-maven-plugin-testing
+ test
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ test
+
+
+ org.jvnet.jaxb
+ jaxb-maven-plugin
+
+ true
+
+ -Xcommons-lang
+ -Xcommons-lang:addToStringMethod=FALSE
+ -Xcommons-lang:addHashCodeMethod=FALSE
+ -Xcommons-lang:addEqualsMethod=TRUE
+ -Xcommons-lang:equalsTestTransients=FALSE
+ -Xcommons-lang:equalsTestRecursive=TRUE
+
+
+
+ org.jvnet.jaxb
+ jaxb-plugins
+
+
+
+
+
+
+
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/main/java/com/example/CustomToStringStyle.java b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/main/java/com/example/CustomToStringStyle.java
new file mode 100644
index 000000000..cd04dd3b7
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/main/java/com/example/CustomToStringStyle.java
@@ -0,0 +1,33 @@
+package com.example;
+
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+public class CustomToStringStyle extends ToStringStyle {
+
+ public static final ToStringStyle CUSTOM_TO_STRING_STYLE = new CustomToStringStyle();
+
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a new instance.
+ *
+ * Use the static constant rather than instantiating.
+ */
+ public CustomToStringStyle() {
+ setUseIdentityHashCode(false);
+ setContentStart("[");
+ setFieldSeparator(System.lineSeparator() + " ");
+ setFieldSeparatorAtStart(true);
+ setContentEnd(System.lineSeparator() + "]");
+ }
+
+ /**
+ * Ensure Singleton after serialization.
+ * @return the singleton
+ */
+ private Object readResolve() {
+ return CUSTOM_TO_STRING_STYLE;
+ }
+
+}
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/main/resources/Person.xsd b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/main/resources/Person.xsd
new file mode 100644
index 000000000..1ee143788
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/main/resources/Person.xsd
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/AddressTest.java b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/AddressTest.java
new file mode 100644
index 000000000..489d4f6f6
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/AddressTest.java
@@ -0,0 +1,22 @@
+package org.jvnet.jaxb2_commons.tests.commons_lang;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import generated.Address;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class AddressTest {
+
+ @Test
+ public void testAddress() {
+ Address a = new Address();
+ // No plugin default-value present, checking everything is null or default java value
+ Assertions.assertEquals(0, a.getNumber());
+ Assertions.assertNull(a.getCareOf());
+ Assertions.assertNull(a.getStreet());
+
+ Assertions.assertEquals(a, a);
+ }
+}
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/PersonTest.java b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/PersonTest.java
new file mode 100644
index 000000000..f0a4bf952
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/test/java/org/jvnet/jaxb2_commons/tests/commons_lang/PersonTest.java
@@ -0,0 +1,21 @@
+package org.jvnet.jaxb2_commons.tests.commons_lang;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import generated.Person;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class PersonTest {
+
+ @Test
+ public void testPerson() {
+ Person p = new Person();
+ Person p2 = new Person();
+ // No plugin default-value present, checking everything is null or default java value
+ Assertions.assertEquals(false, p.isMailingAddressIdentical());
+ Assertions.assertEquals(p, p2);
+
+ }
+}
diff --git a/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/test/resources/log4j.properties b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/test/resources/log4j.properties
new file mode 100644
index 000000000..ca4ee5e2c
--- /dev/null
+++ b/jaxb-plugins-parent/tests/commons_lang_custom_equals/src/test/resources/log4j.properties
@@ -0,0 +1,5 @@
+log4j.rootCategory=DEBUG, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.target=system.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
diff --git a/jaxb-plugins-parent/tests/pom.xml b/jaxb-plugins-parent/tests/pom.xml
index 41b95f7cf..0871afbd2 100644
--- a/jaxb-plugins-parent/tests/pom.xml
+++ b/jaxb-plugins-parent/tests/pom.xml
@@ -19,6 +19,8 @@
camelcase
commons_lang
commons_lang_custom
+ commons_lang_custom_class
+ commons_lang_custom_equals
copyable
defaultvalue
elementwrapper
diff --git a/pom.xml b/pom.xml
index 2420b96b5..22624c0ae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,6 +77,7 @@
3.0
4.1.1.Final
5.11.0
+ 5.23.0
1.7.36
1.8.3
1.2.0
@@ -387,6 +388,11 @@
hamcrest
${hamcrest.version}
+
+ org.mockito
+ mockito-core
+ ${mockito-core.version}
+
org.slf4j