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 <garydgregory@users.noreply.github.com>
This commit is contained in:
parent
119623760e
commit
f51299ced4
|
@ -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
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue