Skip to content

Commit f3ee69e

Browse files
committed
Bug 37079769 - [37070164->25.03] Fix UniversalExtractor canonical name generation for property name having JavaBean accessor prefixes (main->ce-main)
Remote remote.full on coherence-ce/main success, changes 111470, synced @111470, job.9.20240919150042.32266 [git-p4: depot-paths = "//dev/coherence-ce/main/": change = 111472]
1 parent 41a65f3 commit f3ee69e

File tree

3 files changed

+72
-23
lines changed

3 files changed

+72
-23
lines changed

prj/coherence-core/src/main/java/com/oracle/coherence/common/internal/util/CanonicalNames.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/*
2-
* Copyright (c) 2000, 2022, Oracle and/or its affiliates.
2+
* Copyright (c) 2000, 2024, Oracle and/or its affiliates.
33
*
44
* Licensed under the Universal Permissive License v 1.0 as shown at
5-
* http://oss.oracle.com/licenses/upl.
5+
* https://oss.oracle.com/licenses/upl.
66
*/
77
package com.oracle.coherence.common.internal.util;
88

@@ -21,8 +21,8 @@ public class CanonicalNames
2121
* are provided. If <code>sName</code> does not end in {@link #VALUE_EXTRACTOR_METHOD_SUFFIX},
2222
* <code>"()"</code>, the canonical name is <code>sName</code> and represents a property.
2323
* If <code>sName</code> is prefixed with one of the {@link #VALUE_EXTRACTOR_BEAN_ACCESSOR_PREFIXES}
24-
* and ends in {@link #VALUE_EXTRACTOR_METHOD_SUFFIX},
25-
* the canonical name is <code>sName</code> with prefix and suffix removed.
24+
* and optionally ends in {@link #VALUE_EXTRACTOR_METHOD_SUFFIX},"()",
25+
* the canonical name is <code>sName</code> with prefix and optional suffix removed.
2626
* This canonical name represents a property.
2727
* If the <code>sName</code> just ends in {#link #VALUE_EXTRACTOR_METHOD_SUFFIX},
2828
* the canonical name is same as <code>sName</code>. This canonical name
@@ -41,29 +41,27 @@ public static String computeValueExtractorCanonicalName(String sName, Object[] a
4141
{
4242
return null;
4343
}
44-
else if (sName.endsWith(VALUE_EXTRACTOR_METHOD_SUFFIX))
44+
else
4545
{
46-
// check for JavaBean accessor and convert to property if found.
4746
String sNameCanonical = sName;
4847
int nNameLength = sName.length();
4948
for (String sPrefix : VALUE_EXTRACTOR_BEAN_ACCESSOR_PREFIXES)
5049
{
5150
int nPrefixLength = sPrefix.length();
5251
if (nNameLength > nPrefixLength && sName.startsWith(sPrefix))
5352
{
54-
// detected a JavaBean accessor; convert method to a property. remove prefix and suffix.
53+
// detected a JavaBean accessor; remove prefix and optional suffix when present.
54+
int nSuffixLength = sName.endsWith(VALUE_EXTRACTOR_METHOD_SUFFIX)
55+
? nMethodSuffixLength
56+
: 0;
57+
5558
sNameCanonical = Character.toLowerCase(sName.charAt(nPrefixLength)) +
56-
sName.substring(nPrefixLength + 1, nNameLength - nMethodSuffixLength);
59+
sName.substring(nPrefixLength + 1, nNameLength - nSuffixLength);
5760
break;
5861
}
5962
}
6063
return sNameCanonical;
6164
}
62-
else
63-
{
64-
// is a property
65-
return sName;
66-
}
6765
}
6866

6967
/**

prj/coherence-core/src/main/java/com/tangosol/util/extractor/UniversalExtractor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public UniversalExtractor()
7878
* <p>
7979
* If <code>sName</code> does not end in {@link #METHOD_SUFFIX},
8080
* <code>"()"</code>, this extractor is a property extractor. If <code>sName</code> is prefixed with
81-
* one of the {@link #BEAN_ACCESSOR_PREFIXES} and ends in the {@link #METHOD_SUFFIX},
81+
* one of the {@link #BEAN_ACCESSOR_PREFIXES} and optionally ends in the {@link #METHOD_SUFFIX},
8282
* this extractor is a property extractor. Otherwise,
8383
* if the <code>sName</code> just ends in {#link #METHOD_SUFFIX},
8484
* this extractor is considered a method extractor.
@@ -97,7 +97,7 @@ public UniversalExtractor(String sName)
9797
* If <code>sName</code> does not end in {@link #METHOD_SUFFIX}, <code>"()"</code>,
9898
* and has no <code>aoParams</code>,this extractor is a property extractor.
9999
* If <code>sName</code> is prefixed with
100-
* one of the {@link #BEAN_ACCESSOR_PREFIXES}, ends in {@link #METHOD_SUFFIX}
100+
* one of the {@link #BEAN_ACCESSOR_PREFIXES}, optionally ends in {@link #METHOD_SUFFIX}
101101
* and has no <code>aoParams</code>,this extractor is a property extractor.
102102
* Otherwise, if the <code>sName</code>just ends in {#link #METHOD_SUFFIX},
103103
* this extractor is considered a method extractor.
@@ -120,7 +120,7 @@ public UniversalExtractor(String sName, Object[] aoParam)
120120
* <p>
121121
* If <code>sName</code> does not end in {@link #METHOD_SUFFIX}, <code>"()"</code>,
122122
* this extractor is a property extractor. If <code>sName</code> is prefixed with
123-
* one of the {@link #BEAN_ACCESSOR_PREFIXES} and ends in {@link #METHOD_SUFFIX},
123+
* one of the {@link #BEAN_ACCESSOR_PREFIXES} and optionally ends in {@link #METHOD_SUFFIX},
124124
* this extractor is a property extractor. If the <code>sName</code>
125125
* just ends in {@link #METHOD_SUFFIX}, this extractor is considered a method
126126
* extractor.

prj/test/unit/coherence-tests/src/test/java/com/tangosol/util/extractor/UniversalExtractorTest.java

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@
4141
import static org.junit.Assert.assertNotEquals;
4242
import static org.junit.Assert.assertNotNull;
4343
import static org.junit.Assert.assertNull;
44+
import static org.junit.Assert.assertThat;
4445
import static org.junit.Assert.assertTrue;
4546
import static org.junit.Assert.fail;
47+
import static org.hamcrest.CoreMatchers.is;
4648

4749
/**
4850
* Unit test of the {@link UniversalExtractor}.
@@ -86,13 +88,34 @@ public void testExtractorEquality()
8688
{
8789
UniversalExtractor extractorUniversal1 = new UniversalExtractor("getFoo()");
8890
UniversalExtractor extractorUniversal2 = new UniversalExtractor("foo");
91+
UniversalExtractor extractorUniversal3 = new UniversalExtractor("getFoo");
8992
ReflectionExtractor extractorReflection1 = new ReflectionExtractor("getFoo");
9093

9194
assertTrue("u1=" + extractorUniversal1 + " u2=" + extractorUniversal2, extractorUniversal1.equals(extractorUniversal2));
95+
assertTrue("u1=" + extractorUniversal1 + " u3=" + extractorUniversal3, extractorUniversal1.equals(extractorUniversal3));
96+
assertTrue("u2=" + extractorUniversal1 + " u3=" + extractorUniversal3, extractorUniversal1.equals(extractorUniversal3));
9297
assertTrue("u1=" + extractorUniversal1 + " r1=" + extractorReflection1, extractorUniversal1.equals(extractorReflection1));
9398
assertTrue("u1=" + extractorUniversal1 + " r1=" + extractorReflection1, extractorReflection1.equals(extractorUniversal1));
9499
assertTrue("u2=" + extractorUniversal2 + " r1=" + extractorReflection1, extractorUniversal2.equals(extractorReflection1));
95100
assertTrue("u2=" + extractorUniversal2 + " r1=" + extractorReflection1, extractorReflection1.equals(extractorUniversal2));
101+
assertTrue("u3=" + extractorUniversal3 + " r1=" + extractorReflection1, extractorReflection1.equals(extractorUniversal3));
102+
}
103+
104+
@Test
105+
public void testMethodExtractorEqualityHashCode()
106+
{
107+
UniversalExtractor ueMethod = new UniversalExtractor("aMethod()");
108+
UniversalExtractor ueProperty = new UniversalExtractor("aMethod"); // this is a property, validating not a reflective method extractor
109+
ReflectionExtractor re1 = new ReflectionExtractor("aMethod");
110+
111+
assertTrue(ueMethod.isMethodExtractor());
112+
assertTrue(ueProperty.isPropertyExtractor());
113+
assertEquals(ueMethod, re1);
114+
assertNotEquals(ueMethod, ueProperty);
115+
assertNotEquals(ueProperty, re1);
116+
assertThat(ueMethod.hashCode(), is(re1.hashCode()));
117+
assertNotEquals(re1, ueProperty);
118+
assertNotEquals(ueProperty.hashCode(), re1.hashCode());
96119
}
97120

98121
@Test
@@ -119,22 +142,35 @@ public void testOptionalParameters()
119142
@Test
120143
public void testEqualsHashCodeCanonicalName()
121144
{
122-
UniversalExtractor extractor1 = new UniversalExtractor("foo");
123-
UniversalExtractor extractor2 = new UniversalExtractor("foo()");
124-
UniversalExtractor extractor3 = new UniversalExtractor("getFoo()");
125-
UniversalExtractor extractor5 = new UniversalExtractor("isFoo()");
126-
127-
assertFalse(extractor1.equals(extractor2));
128-
assertFalse(extractor2.equals(extractor1));
145+
UniversalExtractor extractor1 = new UniversalExtractor("foo");
146+
UniversalExtractor extractor2 = new UniversalExtractor("foo()");
147+
UniversalExtractor extractor3 = new UniversalExtractor("getFoo()");
148+
UniversalExtractor extractor6 = new UniversalExtractor("getFoo");
149+
UniversalExtractor extractor5 = new UniversalExtractor("isFoo()");
150+
ReflectionExtractor extractor7 = new ReflectionExtractor("getFoo");
151+
ReflectionExtractor extractor8 = new ReflectionExtractor("foo");
152+
153+
assertFalse("comparing a method extractor with a property extractor, expected false", extractor1.equals(extractor2));
154+
assertFalse("comparing a method extractor with a property extractor, expected false", extractor2.equals(extractor1));
129155
assertNotEquals(extractor1.hashCode(), extractor2.hashCode());
130156

157+
assertTrue("compare RE foo with UE foo(), expect true", extractor2.equals(extractor8));
158+
assertEquals(extractor2.getCanonicalName(), extractor8.getCanonicalName());
159+
131160
assertTrue(extractor1.equals(extractor3));
132161
assertTrue(extractor3.equals(extractor1));
162+
assertTrue(extractor7.equals(extractor6));
163+
assertTrue(extractor7.equals(extractor1));
133164
assertEquals(extractor1.hashCode(), extractor3.hashCode());
134165

135166
assertTrue(extractor1.equals(extractor5));
136167
assertTrue(extractor5.equals(extractor1));
168+
assertTrue(extractor3.equals(extractor6));
169+
assertTrue(extractor1.equals(extractor6));
137170
assertEquals(extractor1.hashCode(), extractor5.hashCode());
171+
assertEquals(extractor1.hashCode(), extractor7.hashCode());
172+
assertEquals(extractor6.hashCode(), extractor3.hashCode());
173+
assertEquals(extractor6.hashCode(), extractor7.hashCode());
138174

139175
// single arg method invocation
140176
UniversalExtractor extractor4 = new UniversalExtractor("foo()", new Integer[]{ 42 });
@@ -143,7 +179,9 @@ public void testEqualsHashCodeCanonicalName()
143179

144180
assertEquals("foo", extractor1.getCanonicalName());
145181
assertEquals("foo()", extractor2.getCanonicalName());
182+
assertEquals("foo()", extractor8.getCanonicalName());
146183
assertEquals("foo", extractor3.getCanonicalName());
184+
assertEquals("foo", extractor6.getCanonicalName());
147185
assertEquals(null, extractor4.getCanonicalName());
148186
}
149187

@@ -377,6 +415,19 @@ public void testJavaBean()
377415
UniversalExtractor extractor = new UniversalExtractor("foo");
378416
assertEquals(extractor.extract(bean), "value");
379417

418+
// Ensure that these are identified as java bean property and work same as above.
419+
UniversalExtractor ue1 = new UniversalExtractor("getFoo()");
420+
UniversalExtractor ue2 = new UniversalExtractor("getFoo");
421+
ValueExtractor<TestJavaBean, String> ve = TestJavaBean::getFoo;
422+
423+
assertEquals(ue1.extract(bean), "value");
424+
assertEquals(ue2.extract(bean), "value");
425+
assertEquals(ve.extract(bean), "value");
426+
assertEquals(ue1, ue2);
427+
assertEquals(extractor, ue1);
428+
assertEquals(extractor, ue2);
429+
assertEquals(ve.getCanonicalName(), ue1.getCanonicalName());
430+
380431
// ensure cached method approach works also
381432
assertEquals(extractor.extract(bean), "value");
382433

0 commit comments

Comments
 (0)