Skip to content

Commit 80de131

Browse files
committed
fixes #927 Avoid wrapper object being created for each element when adding an array to CacheKey.
1 parent ed2cc17 commit 80de131

File tree

3 files changed

+270
-25
lines changed

3 files changed

+270
-25
lines changed

src/main/java/org/apache/ibatis/cache/CacheKey.java

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2016 the original author or authors.
2+
* Copyright 2009-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,10 +16,11 @@
1616
package org.apache.ibatis.cache;
1717

1818
import java.io.Serializable;
19-
import java.lang.reflect.Array;
2019
import java.util.ArrayList;
2120
import java.util.List;
2221

22+
import org.apache.ibatis.reflection.ArrayUtil;
23+
2324
/**
2425
* @author Clinton Begin
2526
*/
@@ -55,19 +56,7 @@ public int getUpdateCount() {
5556
}
5657

5758
public void update(Object object) {
58-
if (object != null && object.getClass().isArray()) {
59-
int length = Array.getLength(object);
60-
for (int i = 0; i < length; i++) {
61-
Object element = Array.get(object, i);
62-
doUpdate(element);
63-
}
64-
} else {
65-
doUpdate(object);
66-
}
67-
}
68-
69-
private void doUpdate(Object object) {
70-
int baseHashCode = object == null ? 1 : object.hashCode();
59+
int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);
7160

7261
count++;
7362
checksum += baseHashCode;
@@ -108,14 +97,8 @@ public boolean equals(Object object) {
10897
for (int i = 0; i < updateList.size(); i++) {
10998
Object thisObject = updateList.get(i);
11099
Object thatObject = cacheKey.updateList.get(i);
111-
if (thisObject == null) {
112-
if (thatObject != null) {
113-
return false;
114-
}
115-
} else {
116-
if (!thisObject.equals(thatObject)) {
117-
return false;
118-
}
100+
if (!ArrayUtil.equals(thisObject, thatObject)) {
101+
return false;
119102
}
120103
}
121104
return true;
@@ -130,9 +113,8 @@ public int hashCode() {
130113
public String toString() {
131114
StringBuilder returnValue = new StringBuilder().append(hashcode).append(':').append(checksum);
132115
for (Object object : updateList) {
133-
returnValue.append(':').append(object);
116+
returnValue.append(':').append(ArrayUtil.toString(object));
134117
}
135-
136118
return returnValue.toString();
137119
}
138120

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/**
2+
* Copyright 2009-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.apache.ibatis.reflection;
18+
19+
import java.util.Arrays;
20+
21+
/**
22+
* Provides hashCode, equals and toString methods that can handle array.
23+
*/
24+
public class ArrayUtil {
25+
26+
/**
27+
* Returns a hash code for {@code obj}.
28+
*
29+
* @param obj
30+
* The object to get a hash code for. May be an array or <code>null</code>.
31+
* @return A hash code of {@code obj} or 0 if {@code obj} is <code>null</code>
32+
*/
33+
public static int hashCode(Object obj) {
34+
if (obj == null) {
35+
// for consistency with Arrays#hashCode() and Objects#hashCode()
36+
return 0;
37+
}
38+
final Class<?> clazz = obj.getClass();
39+
if (!clazz.isArray()) {
40+
return obj.hashCode();
41+
}
42+
final Class<?> componentType = clazz.getComponentType();
43+
if (long.class.equals(componentType)) {
44+
return Arrays.hashCode((long[]) obj);
45+
} else if (int.class.equals(componentType)) {
46+
return Arrays.hashCode((int[]) obj);
47+
} else if (short.class.equals(componentType)) {
48+
return Arrays.hashCode((short[]) obj);
49+
} else if (char.class.equals(componentType)) {
50+
return Arrays.hashCode((char[]) obj);
51+
} else if (byte.class.equals(componentType)) {
52+
return Arrays.hashCode((byte[]) obj);
53+
} else if (boolean.class.equals(componentType)) {
54+
return Arrays.hashCode((boolean[]) obj);
55+
} else if (float.class.equals(componentType)) {
56+
return Arrays.hashCode((float[]) obj);
57+
} else if (double.class.equals(componentType)) {
58+
return Arrays.hashCode((double[]) obj);
59+
} else {
60+
return Arrays.hashCode((Object[]) obj);
61+
}
62+
}
63+
64+
/**
65+
* Compares two objects. Returns <code>true</code> if
66+
* <ul>
67+
* <li>{@code thisObj} and {@code thatObj} are both <code>null</code></li>
68+
* <li>{@code thisObj} and {@code thatObj} are instances of the same type and
69+
* {@link Object#equals(Object)} returns <code>true</code></li>
70+
* <li>{@code thisObj} and {@code thatObj} are arrays with the same component type and
71+
* equals() method of {@link Arrays} returns <code>true</code> (not deepEquals())</li>
72+
* </ul>
73+
*
74+
* @param thisObj
75+
* The left hand object to compare. May be an array or <code>null</code>
76+
* @param thatObj
77+
* The right hand object to compare. May be an array or <code>null</code>
78+
* @return <code>true</code> if two objects are equal; <code>false</code> otherwise.
79+
*/
80+
public static boolean equals(Object thisObj, Object thatObj) {
81+
if (thisObj == null) {
82+
return thatObj == null;
83+
} else if (thatObj == null) {
84+
return false;
85+
}
86+
final Class<?> clazz = thisObj.getClass();
87+
if (!clazz.equals(thatObj.getClass())) {
88+
return false;
89+
}
90+
if (!clazz.isArray()) {
91+
return thisObj.equals(thatObj);
92+
}
93+
final Class<?> componentType = clazz.getComponentType();
94+
if (long.class.equals(componentType)) {
95+
return Arrays.equals((long[]) thisObj, (long[]) thatObj);
96+
} else if (int.class.equals(componentType)) {
97+
return Arrays.equals((int[]) thisObj, (int[]) thatObj);
98+
} else if (short.class.equals(componentType)) {
99+
return Arrays.equals((short[]) thisObj, (short[]) thatObj);
100+
} else if (char.class.equals(componentType)) {
101+
return Arrays.equals((char[]) thisObj, (char[]) thatObj);
102+
} else if (byte.class.equals(componentType)) {
103+
return Arrays.equals((byte[]) thisObj, (byte[]) thatObj);
104+
} else if (boolean.class.equals(componentType)) {
105+
return Arrays.equals((boolean[]) thisObj, (boolean[]) thatObj);
106+
} else if (float.class.equals(componentType)) {
107+
return Arrays.equals((float[]) thisObj, (float[]) thatObj);
108+
} else if (double.class.equals(componentType)) {
109+
return Arrays.equals((double[]) thisObj, (double[]) thatObj);
110+
} else {
111+
return Arrays.equals((Object[]) thisObj, (Object[]) thatObj);
112+
}
113+
}
114+
115+
/**
116+
* If the {@code obj} is an array, toString() method of {@link Arrays} is called. Otherwise
117+
* {@link Object#toString()} is called. Returns "null" if {@code obj} is <code>null</code>.
118+
*
119+
* @param obj
120+
* An object. May be an array or <code>null</code>.
121+
* @return String representation of the {@code obj}.
122+
*/
123+
public static String toString(Object obj) {
124+
if (obj == null) {
125+
return "null";
126+
}
127+
final Class<?> clazz = obj.getClass();
128+
if (!clazz.isArray()) {
129+
return obj.toString();
130+
}
131+
final Class<?> componentType = obj.getClass().getComponentType();
132+
if (long.class.equals(componentType)) {
133+
return Arrays.toString((long[]) obj);
134+
} else if (int.class.equals(componentType)) {
135+
return Arrays.toString((int[]) obj);
136+
} else if (short.class.equals(componentType)) {
137+
return Arrays.toString((short[]) obj);
138+
} else if (char.class.equals(componentType)) {
139+
return Arrays.toString((char[]) obj);
140+
} else if (byte.class.equals(componentType)) {
141+
return Arrays.toString((byte[]) obj);
142+
} else if (boolean.class.equals(componentType)) {
143+
return Arrays.toString((boolean[]) obj);
144+
} else if (float.class.equals(componentType)) {
145+
return Arrays.toString((float[]) obj);
146+
} else if (double.class.equals(componentType)) {
147+
return Arrays.toString((double[]) obj);
148+
} else {
149+
return Arrays.toString((Object[]) obj);
150+
}
151+
}
152+
153+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* Copyright 2009-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.apache.ibatis.reflection;
18+
19+
import static org.junit.Assert.*;
20+
21+
import java.util.Arrays;
22+
23+
import org.junit.Test;
24+
25+
public class ArrayUtilTest extends ArrayUtil {
26+
27+
@Test
28+
public void testHashCode() throws Exception {
29+
Object arr;
30+
arr = new long[] { 1 };
31+
assertEquals(Arrays.hashCode((long[]) arr), ArrayUtil.hashCode(arr));
32+
arr = new int[] { 1 };
33+
assertEquals(Arrays.hashCode((int[]) arr), ArrayUtil.hashCode(arr));
34+
arr = new short[] { 1 };
35+
assertEquals(Arrays.hashCode((short[]) arr), ArrayUtil.hashCode(arr));
36+
arr = new char[] { 1 };
37+
assertEquals(Arrays.hashCode((char[]) arr), ArrayUtil.hashCode(arr));
38+
arr = new byte[] { 1 };
39+
assertEquals(Arrays.hashCode((byte[]) arr), ArrayUtil.hashCode(arr));
40+
arr = new boolean[] { true };
41+
assertEquals(Arrays.hashCode((boolean[]) arr), ArrayUtil.hashCode(arr));
42+
arr = new float[] { 1f };
43+
assertEquals(Arrays.hashCode((float[]) arr), ArrayUtil.hashCode(arr));
44+
arr = new double[] { 1d };
45+
assertEquals(Arrays.hashCode((double[]) arr), ArrayUtil.hashCode(arr));
46+
arr = new Object[] { "str" };
47+
assertEquals(Arrays.hashCode((Object[]) arr), ArrayUtil.hashCode(arr));
48+
49+
assertEquals(0, ArrayUtil.hashCode(null));
50+
assertEquals("str".hashCode(), ArrayUtil.hashCode("str"));
51+
assertEquals(Integer.valueOf(1).hashCode(), ArrayUtil.hashCode(1));
52+
}
53+
54+
@Test
55+
public void testequals() throws Exception {
56+
assertTrue(ArrayUtil.equals(new long[] { 1 }, new long[] { 1 }));
57+
assertTrue(ArrayUtil.equals(new int[] { 1 }, new int[] { 1 }));
58+
assertTrue(ArrayUtil.equals(new short[] { 1 }, new short[] { 1 }));
59+
assertTrue(ArrayUtil.equals(new char[] { 1 }, new char[] { 1 }));
60+
assertTrue(ArrayUtil.equals(new byte[] { 1 }, new byte[] { 1 }));
61+
assertTrue(ArrayUtil.equals(new boolean[] { true }, new boolean[] { true }));
62+
assertTrue(ArrayUtil.equals(new float[] { 1f }, new float[] { 1f }));
63+
assertTrue(ArrayUtil.equals(new double[] { 1d }, new double[] { 1d }));
64+
assertTrue(ArrayUtil.equals(new Object[] { "str" }, new Object[] { "str" }));
65+
66+
assertFalse(ArrayUtil.equals(new long[] { 1 }, new long[] { 2 }));
67+
assertFalse(ArrayUtil.equals(new int[] { 1 }, new int[] { 2 }));
68+
assertFalse(ArrayUtil.equals(new short[] { 1 }, new short[] { 2 }));
69+
assertFalse(ArrayUtil.equals(new char[] { 1 }, new char[] { 2 }));
70+
assertFalse(ArrayUtil.equals(new byte[] { 1 }, new byte[] { 2 }));
71+
assertFalse(ArrayUtil.equals(new boolean[] { true }, new boolean[] { false }));
72+
assertFalse(ArrayUtil.equals(new float[] { 1f }, new float[] { 2f }));
73+
assertFalse(ArrayUtil.equals(new double[] { 1d }, new double[] { 2d }));
74+
assertFalse(ArrayUtil.equals(new Object[] { "str" }, new Object[] { "rts" }));
75+
76+
assertTrue(ArrayUtil.equals(null, null));
77+
assertFalse(ArrayUtil.equals(new long[] { 1 }, null));
78+
assertFalse(ArrayUtil.equals(null, new long[] { 1 }));
79+
80+
assertTrue(ArrayUtil.equals(1, 1));
81+
assertTrue(ArrayUtil.equals("str", "str"));
82+
}
83+
84+
@Test
85+
public void testToString() throws Exception {
86+
Object arr;
87+
arr = new long[] { 1 };
88+
assertEquals(Arrays.toString((long[]) arr), ArrayUtil.toString(arr));
89+
arr = new int[] { 1 };
90+
assertEquals(Arrays.toString((int[]) arr), ArrayUtil.toString(arr));
91+
arr = new short[] { 1 };
92+
assertEquals(Arrays.toString((short[]) arr), ArrayUtil.toString(arr));
93+
arr = new char[] { 1 };
94+
assertEquals(Arrays.toString((char[]) arr), ArrayUtil.toString(arr));
95+
arr = new byte[] { 1 };
96+
assertEquals(Arrays.toString((byte[]) arr), ArrayUtil.toString(arr));
97+
arr = new boolean[] { true };
98+
assertEquals(Arrays.toString((boolean[]) arr), ArrayUtil.toString(arr));
99+
arr = new float[] { 1f };
100+
assertEquals(Arrays.toString((float[]) arr), ArrayUtil.toString(arr));
101+
arr = new double[] { 1d };
102+
assertEquals(Arrays.toString((double[]) arr), ArrayUtil.toString(arr));
103+
arr = new Object[] { "str" };
104+
assertEquals(Arrays.toString((Object[]) arr), ArrayUtil.toString(arr));
105+
106+
assertEquals(Integer.valueOf(1).toString(), ArrayUtil.toString(1));
107+
assertEquals("null", ArrayUtil.toString(null));
108+
}
109+
110+
}

0 commit comments

Comments
 (0)