This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new f51299ced LANG-1677 : Add
ReflectionDiffBuilder.setExcludeFieldNames(...) and DiffExclude a… (#838)
f51299ced is described below
commit f51299ced4fd40b44a3f6eca9ae528e818558205
Author: Baerten Dennis <[email protected]>
AuthorDate: Sun Jun 4 20:30:40 2023 +0200
LANG-1677 : Add ReflectionDiffBuilder.setExcludeFieldNames(...) and
DiffExclude a… (#838)
* LANG-1677 : Make it possible to exclude fields in ReflectionDiffBuilder
* Fix Javadoc typo
* Javadoc
* Javadoc
---------
Co-authored-by: Gary Gregory <[email protected]>
---
.../apache/commons/lang3/builder/DiffExclude.java | 35 +++++++++++++
.../lang3/builder/ReflectionDiffBuilder.java | 47 +++++++++++++++++-
.../lang3/builder/ReflectionDiffBuilderTest.java | 58 +++++++++++++++++++++-
3 files changed, 138 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/apache/commons/lang3/builder/DiffExclude.java
b/src/main/java/org/apache/commons/lang3/builder/DiffExclude.java
new file mode 100755
index 000000000..2f69b5776
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/builder/DiffExclude.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.commons.lang3.builder;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excludes a field from being used by
+ * the {@link ReflectionDiffBuilder}.
+ *
+ * @since 3.13.0
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface DiffExclude {
+ // empty
+}
diff --git
a/src/main/java/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java
b/src/main/java/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java
index ddae64874..1337e93c1 100644
--- a/src/main/java/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java
+++ b/src/main/java/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java
@@ -18,7 +18,10 @@ package org.apache.commons.lang3.builder;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import org.apache.commons.lang3.ArraySorter;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
@@ -70,6 +73,12 @@ public class ReflectionDiffBuilder<T> implements
Builder<DiffResult<T>> {
private final Object right;
private final DiffBuilder<T> diffBuilder;
+ /**
+ * Which field names to exclude from output. Intended for fields like
{@code "password"} or {@code "lastModificationDate"}.
+ * @since 3.13.0
+ */
+ private String[] excludeFieldNames;
+
/**
* Constructs a builder for the specified objects with the specified style.
*
@@ -94,6 +103,34 @@ public class ReflectionDiffBuilder<T> implements
Builder<DiffResult<T>> {
diffBuilder = new DiffBuilder<>(lhs, rhs, style);
}
+ /**
+ * Gets the field names that should be excluded from the diff
+ * @return Returns the excludeFieldNames.
+ * @since 3.13.0
+ */
+ public String[] getExcludeFieldNames() {
+ return this.excludeFieldNames.clone();
+ }
+
+
+ /**
+ * Sets the field names to exclude.
+ *
+ * @param excludeFieldNamesParam
+ * The field names to exclude from the diff or {@code null}.
+ * @return {@code this}
+ * @since 3.13.0
+ */
+ public ReflectionDiffBuilder setExcludeFieldNames(final String...
excludeFieldNamesParam) {
+ if (excludeFieldNamesParam == null) {
+ this.excludeFieldNames = ArrayUtils.EMPTY_STRING_ARRAY;
+ } else {
+ // clone and remove nulls
+ this.excludeFieldNames =
ArraySorter.sort(ReflectionToStringBuilder.toNoNullStringArray(excludeFieldNamesParam));
+ }
+ return this;
+ }
+
@Override
public DiffResult<T> build() {
if (left.equals(right)) {
@@ -126,7 +163,15 @@ public class ReflectionDiffBuilder<T> implements
Builder<DiffResult<T>> {
if (Modifier.isTransient(field.getModifiers())) {
return false;
}
- return !Modifier.isStatic(field.getModifiers());
+ if (Modifier.isStatic(field.getModifiers())) {
+ return false;
+ }
+ if (this.excludeFieldNames != null
+ && Arrays.binarySearch(this.excludeFieldNames,
field.getName()) >= 0) {
+ // Reject fields from the getExcludeFieldNames list.
+ return false;
+ }
+ return !field.isAnnotationPresent(DiffExclude.class);
}
}
diff --git
a/src/test/java/org/apache/commons/lang3/builder/ReflectionDiffBuilderTest.java
b/src/test/java/org/apache/commons/lang3/builder/ReflectionDiffBuilderTest.java
index 8fc3a1d43..a1fdce249 100644
---
a/src/test/java/org/apache/commons/lang3/builder/ReflectionDiffBuilderTest.java
+++
b/src/test/java/org/apache/commons/lang3/builder/ReflectionDiffBuilderTest.java
@@ -17,6 +17,7 @@
package org.apache.commons.lang3.builder;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.apache.commons.lang3.AbstractLangTest;
import org.junit.jupiter.api.Test;
@@ -48,10 +49,14 @@ public class ReflectionDiffBuilderTest extends
AbstractLangTest {
private final Object[] objectArrayField = {null};
private static int staticField;
private transient String transientField;
+ @DiffExclude
+ private String annotatedField = "a";
+ private String excludedField = "a";
+
@Override
public DiffResult diff(final TypeTestClass obj) {
- return new ReflectionDiffBuilder(this, obj, style).build();
+ return new ReflectionDiffBuilder(this, obj,
style).setExcludeFieldNames("excludedField").build();
}
@Override
@@ -128,4 +133,55 @@ public class ReflectionDiffBuilderTest extends
AbstractLangTest {
final DiffResult list = firstObject.diff(secondObject);
assertEquals(1, list.getNumberOfDiffs());
}
+
+ @Test
+ public void test_no_differences_excluded_field() {
+ final TypeTestClass firstObject = new TypeTestClass();
+ firstObject.excludedField = "b";
+ final TypeTestClass secondObject = new TypeTestClass();
+
+ final DiffResult list = firstObject.diff(secondObject);
+ assertEquals(0, list.getNumberOfDiffs());
+ }
+
+ @Test
+ public void test_no_differences_diff_exclude_annotated_field() {
+ final TypeTestClass firstObject = new TypeTestClass();
+ firstObject.annotatedField = "b";
+ final TypeTestClass secondObject = new TypeTestClass();
+
+ final DiffResult list = firstObject.diff(secondObject);
+ assertEquals(0, list.getNumberOfDiffs());
+ }
+
+ @Test
+ public void
test_no_differences_diff_exluded_field_and_exclude_annotated_field() {
+ final TypeTestClass firstObject = new TypeTestClass();
+ firstObject.excludedField = "b";
+ firstObject.annotatedField = "b";
+ final TypeTestClass secondObject = new TypeTestClass();
+
+ final DiffResult list = firstObject.diff(secondObject);
+ assertEquals(0, list.getNumberOfDiffs());
+ }
+
+ @Test
+ public void testGetExcludeFieldNamesWithNullExcludedFieldNames() {
+ final ReflectionDiffBuilder<TypeTestClass> reflectionDiffBuilder = new
ReflectionDiffBuilder<>(new TypeTestClass(), new TypeTestChildClass(),
SHORT_STYLE);
+ reflectionDiffBuilder.setExcludeFieldNames(null);
+ final String[] excludeFieldNames =
reflectionDiffBuilder.getExcludeFieldNames();
+ assertNotNull(excludeFieldNames);
+ assertEquals(0, excludeFieldNames.length);
+ }
+
+ @Test
+ public void testGetExcludeFieldNamesWithNullValuesInExcludedFieldNames() {
+ final ReflectionDiffBuilder<TypeTestClass> reflectionDiffBuilder = new
ReflectionDiffBuilder<>(new TypeTestClass(), new TypeTestChildClass(),
SHORT_STYLE);
+ reflectionDiffBuilder.setExcludeFieldNames("charField", null);
+ final String[] excludeFieldNames =
reflectionDiffBuilder.getExcludeFieldNames();
+ assertNotNull(excludeFieldNames);
+ assertEquals(1, excludeFieldNames.length);
+ assertEquals("charField", excludeFieldNames[0]);
+ }
+
}