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]);
+    }
+
 }

Reply via email to