Merge branch 'LANG-1031'
LANG-1031: Add annotations to exclude fields from ReflectionEqualsBuilder, ReflectionToStringBuilder and ReflectionHashCodeBuilder. Thanks to Felipe Adorno. This closes #29, #77.
This commit is contained in:
commit
8548b12d8f
3
pom.xml
3
pom.xml
|
@ -478,6 +478,9 @@
|
||||||
<contributor>
|
<contributor>
|
||||||
<name>Michał Kordas</name>
|
<name>Michał Kordas</name>
|
||||||
</contributor>
|
</contributor>
|
||||||
|
<contributor>
|
||||||
|
<name>Felipe Adorno</name>
|
||||||
|
</contributor>
|
||||||
</contributors>
|
</contributors>
|
||||||
|
|
||||||
<!-- Lang should depend on very little -->
|
<!-- Lang should depend on very little -->
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<release version="3.5" date="tba" description="tba">
|
<release version="3.5" date="tba" description="tba">
|
||||||
|
<action issue="LANG-1031" type="add" dev="britter" due-to="Felipe Adorno">Add annotations to exclude fields from ReflectionEqualsBuilder, ReflectionToStringBuilder and ReflectionHashCodeBuilder</action>
|
||||||
<action issue="LANG-1127" type="add" dev="chas">Unit test helpers which set and reset default Locale and TimeZone</action>
|
<action issue="LANG-1127" type="add" dev="chas">Unit test helpers which set and reset default Locale and TimeZone</action>
|
||||||
<action issue="LANG-1128" type="fix" dev="britter" due-to="jacktan1991">JsonToStringStyle doesn't handle chars and objects correctly</action>
|
<action issue="LANG-1128" type="fix" dev="britter" due-to="jacktan1991">JsonToStringStyle doesn't handle chars and objects correctly</action>
|
||||||
<action issue="LANG-456" type="fix" dev="britter" due-to="Bob Fields, Woosan Ko, Bruno P. Kinoshita">HashCodeBuilder throws StackOverflowError in bidirectional navigable association</action>
|
<action issue="LANG-456" type="fix" dev="britter" due-to="Bob Fields, Woosan Ko, Bruno P. Kinoshita">HashCodeBuilder throws StackOverflowError in bidirectional navigable association</action>
|
||||||
|
|
|
@ -411,7 +411,8 @@ public class EqualsBuilder implements Builder<Boolean> {
|
||||||
if (!ArrayUtils.contains(excludeFields, f.getName())
|
if (!ArrayUtils.contains(excludeFields, f.getName())
|
||||||
&& !f.getName().contains("$")
|
&& !f.getName().contains("$")
|
||||||
&& (useTransients || !Modifier.isTransient(f.getModifiers()))
|
&& (useTransients || !Modifier.isTransient(f.getModifiers()))
|
||||||
&& !Modifier.isStatic(f.getModifiers())) {
|
&& (!Modifier.isStatic(f.getModifiers()))
|
||||||
|
&& (!f.isAnnotationPresent(EqualsExclude.class))) {
|
||||||
try {
|
try {
|
||||||
builder.append(f.get(lhs), f.get(rhs));
|
builder.append(f.get(lhs), f.get(rhs));
|
||||||
} catch (final IllegalAccessException e) {
|
} catch (final IllegalAccessException e) {
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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.Target;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this annotation to builds a equals excluding the annotated field.
|
||||||
|
*/
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
public @interface EqualsExclude {
|
||||||
|
|
||||||
|
}
|
|
@ -192,7 +192,8 @@ public class HashCodeBuilder implements Builder<Integer> {
|
||||||
if (!ArrayUtils.contains(excludeFields, field.getName())
|
if (!ArrayUtils.contains(excludeFields, field.getName())
|
||||||
&& !field.getName().contains("$")
|
&& !field.getName().contains("$")
|
||||||
&& (useTransients || !Modifier.isTransient(field.getModifiers()))
|
&& (useTransients || !Modifier.isTransient(field.getModifiers()))
|
||||||
&& !Modifier.isStatic(field.getModifiers())) {
|
&& (!Modifier.isStatic(field.getModifiers()))
|
||||||
|
&& (!field.isAnnotationPresent(HashCodeExclude.class))) {
|
||||||
try {
|
try {
|
||||||
final Object fieldValue = field.get(object);
|
final Object fieldValue = field.get(object);
|
||||||
builder.append(fieldValue);
|
builder.append(fieldValue);
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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.Target;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this annotation to builds a hash code excluding the annotated field.
|
||||||
|
*/
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
public @interface HashCodeExclude {
|
||||||
|
|
||||||
|
}
|
|
@ -494,6 +494,9 @@ public class ReflectionToStringBuilder extends ToStringBuilder {
|
||||||
// Reject fields from the getExcludeFieldNames list.
|
// Reject fields from the getExcludeFieldNames list.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if(field.isAnnotationPresent(ToStringExclude.class)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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.Target;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this annotation to builds a String excluding the annotated field.
|
||||||
|
*/
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
public @interface ToStringExclude {
|
||||||
|
|
||||||
|
}
|
|
@ -1150,5 +1150,37 @@ public class EqualsBuilderTest {
|
||||||
assertTrue(EqualsBuilder.reflectionEquals(d1, d3));
|
assertTrue(EqualsBuilder.reflectionEquals(d1, d3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class TestObjectEqualsExclude {
|
||||||
|
@EqualsExclude
|
||||||
|
private int a;
|
||||||
|
private int b;
|
||||||
|
|
||||||
|
public TestObjectEqualsExclude(int a, int b) {
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToEqualsExclude() {
|
||||||
|
TestObjectEqualsExclude one = new TestObjectEqualsExclude(1, 2);
|
||||||
|
TestObjectEqualsExclude two = new TestObjectEqualsExclude(1, 3);
|
||||||
|
|
||||||
|
assertFalse(EqualsBuilder.reflectionEquals(one, two));
|
||||||
|
|
||||||
|
one = new TestObjectEqualsExclude(1, 2);
|
||||||
|
two = new TestObjectEqualsExclude(2, 2);
|
||||||
|
|
||||||
|
assertTrue(EqualsBuilder.reflectionEquals(one, two));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -622,4 +622,51 @@ public class HashCodeBuilderTest {
|
||||||
hcb.toHashCode(), hcb.hashCode());
|
hcb.toHashCode(), hcb.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class TestObjectHashCodeExclude {
|
||||||
|
@HashCodeExclude
|
||||||
|
private int a;
|
||||||
|
private int b;
|
||||||
|
|
||||||
|
public TestObjectHashCodeExclude(int a, int b) {
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TestObjectHashCodeExclude2 {
|
||||||
|
@HashCodeExclude
|
||||||
|
private int a;
|
||||||
|
@HashCodeExclude
|
||||||
|
private int b;
|
||||||
|
|
||||||
|
public TestObjectHashCodeExclude2(int a, int b) {
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToHashCodeExclude() {
|
||||||
|
TestObjectHashCodeExclude one = new TestObjectHashCodeExclude(1, 2);
|
||||||
|
TestObjectHashCodeExclude2 two = new TestObjectHashCodeExclude2(1, 2);
|
||||||
|
assertEquals(17 * 37 + 2, HashCodeBuilder.reflectionHashCode(one));
|
||||||
|
assertEquals(17, HashCodeBuilder.reflectionHashCode(two));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* 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 org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for ToStringExclude annotation
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class ReflectionToStringBuilderExcludeWithAnnotationTest {
|
||||||
|
|
||||||
|
class TestFixture {
|
||||||
|
@ToStringExclude
|
||||||
|
private final String secretField = SECRET_VALUE;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String showField = NOT_SECRET_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String NOT_SECRET_FIELD = "showField";
|
||||||
|
|
||||||
|
private static final String NOT_SECRET_VALUE = "Hello World!";
|
||||||
|
|
||||||
|
private static final String SECRET_FIELD = "secretField";
|
||||||
|
|
||||||
|
private static final String SECRET_VALUE = "secret value";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_toStringExclude() {
|
||||||
|
final String toString = ReflectionToStringBuilder.toString(new TestFixture());
|
||||||
|
this.validateSecretFieldAbsent(toString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateNonSecretField(final String toString) {
|
||||||
|
Assert.assertTrue(toString.indexOf(NOT_SECRET_FIELD) > ArrayUtils.INDEX_NOT_FOUND);
|
||||||
|
Assert.assertTrue(toString.indexOf(NOT_SECRET_VALUE) > ArrayUtils.INDEX_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSecretFieldAbsent(final String toString) {
|
||||||
|
Assert.assertEquals(ArrayUtils.INDEX_NOT_FOUND, toString.indexOf(SECRET_FIELD));
|
||||||
|
Assert.assertEquals(ArrayUtils.INDEX_NOT_FOUND, toString.indexOf(SECRET_VALUE));
|
||||||
|
this.validateNonSecretField(toString);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue