diff --git a/src/main/java/org/apache/ibatis/cache/CacheKey.java b/src/main/java/org/apache/ibatis/cache/CacheKey.java index 67459d53973..92198e20286 100644 --- a/src/main/java/org/apache/ibatis/cache/CacheKey.java +++ b/src/main/java/org/apache/ibatis/cache/CacheKey.java @@ -1,5 +1,5 @@ /** - * Copyright 2009-2016 the original author or authors. + * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,11 +56,7 @@ public int getUpdateCount() { public void update(Object object) { if (object != null && object.getClass().isArray()) { - int length = Array.getLength(object); - for (int i = 0; i < length; i++) { - Object element = Array.get(object, i); - doUpdate(element); - } + doUpdate(CacheKeyArrayWrapper.wrap(object)); } else { doUpdate(object); } diff --git a/src/main/java/org/apache/ibatis/cache/CacheKeyArrayWrapper.java b/src/main/java/org/apache/ibatis/cache/CacheKeyArrayWrapper.java new file mode 100644 index 00000000000..3174d3a8b86 --- /dev/null +++ b/src/main/java/org/apache/ibatis/cache/CacheKeyArrayWrapper.java @@ -0,0 +1,265 @@ +/** + * Copyright 2009-2017 the original author or authors. + * + * Licensed 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.ibatis.cache; + +import java.util.Arrays; + +class CacheKeyArrayWrapper { + + static CacheKeyArrayWrapper wrap(Object unwrapped) { + if (unwrapped == null || !unwrapped.getClass().isArray()) { + throw new IllegalArgumentException("Expected object of array type, but got " + unwrapped); + } + + Class componentType = unwrapped.getClass().getComponentType(); + + if (componentType == Boolean.TYPE) { + return new WrapBooleanArray((boolean[]) unwrapped); + } else if (componentType == Byte.TYPE) { + return new WrapByteArray((byte[]) unwrapped); + } else if (componentType == Character.TYPE) { + return new WrapCharacterArray((char[]) unwrapped); + } else if (componentType == Short.TYPE) { + return new WrapShortArray((short[]) unwrapped); + } else if (componentType == Integer.TYPE) { + return new WrapIntegerArray((int[]) unwrapped); + } else if (componentType == Long.TYPE) { + return new WrapLongArray((long[]) unwrapped); + } else if (componentType == Float.TYPE) { + return new WrapFloatArray((float[]) unwrapped); + } else if (componentType == Double.TYPE) { + return new WrapDoubleArray((double[]) unwrapped); + } else { + return new WrapObjectArray((Object[]) unwrapped); + } + } + + private static final class WrapObjectArray extends CacheKeyArrayWrapper { + private final Object[] source; + + WrapObjectArray(Object[] source) { + this.source = source; + } + + @Override + public boolean equals(Object other) { + return (other instanceof WrapObjectArray) && + Arrays.equals(source, ((WrapObjectArray) other).source); + } + + @Override + public int hashCode() { + return Arrays.hashCode(source); + } + + @Override + public String toString() { + return Arrays.toString(source); + } + } + + private static final class WrapBooleanArray extends CacheKeyArrayWrapper { + private final boolean[] source; + + WrapBooleanArray(boolean[] source) { + this.source = source; + } + + @Override + public boolean equals(Object other) { + return (other instanceof WrapBooleanArray) && + Arrays.equals(source, ((WrapBooleanArray) other).source); + } + + @Override + public int hashCode() { + return Arrays.hashCode(source); + } + + @Override + public String toString() { + return Arrays.toString(source); + } + } + + private static final class WrapByteArray extends CacheKeyArrayWrapper { + private final byte[] source; + + WrapByteArray(byte[] source) { + this.source = source; + } + + @Override + public boolean equals(Object other) { + return (other instanceof WrapByteArray) && + Arrays.equals(source, ((WrapByteArray) other).source); + } + + @Override + public int hashCode() { + return Arrays.hashCode(source); + } + + @Override + public String toString() { + return Arrays.toString(source); + } + } + + private static final class WrapCharacterArray extends CacheKeyArrayWrapper { + private final char[] source; + + WrapCharacterArray(char[] source) { + this.source = source; + } + + @Override + public boolean equals(Object other) { + return (other instanceof WrapCharacterArray) && + Arrays.equals(source, ((WrapCharacterArray) other).source); + } + + @Override + public int hashCode() { + return Arrays.hashCode(source); + } + + @Override + public String toString() { + return Arrays.toString(source); + } + } + + private static final class WrapShortArray extends CacheKeyArrayWrapper { + private final short[] source; + + WrapShortArray(short[] source) { + this.source = source; + } + + @Override + public boolean equals(Object other) { + return (other instanceof WrapShortArray) && + Arrays.equals(source, ((WrapShortArray) other).source); + } + + @Override + public int hashCode() { + return Arrays.hashCode(source); + } + + @Override + public String toString() { + return Arrays.toString(source); + } + } + + private static final class WrapIntegerArray extends CacheKeyArrayWrapper { + private final int[] source; + + WrapIntegerArray(int[] source) { + this.source = source; + } + + @Override + public boolean equals(Object other) { + return (other instanceof WrapIntegerArray) && + Arrays.equals(source, ((WrapIntegerArray) other).source); + } + + @Override + public int hashCode() { + return Arrays.hashCode(source); + } + + @Override + public String toString() { + return Arrays.toString(source); + } + } + + private static final class WrapLongArray extends CacheKeyArrayWrapper { + private final long[] source; + + WrapLongArray(long[] source) { + this.source = source; + } + + @Override + public boolean equals(Object other) { + return (other instanceof WrapLongArray) && + Arrays.equals(source, ((WrapLongArray) other).source); + } + + @Override + public int hashCode() { + return Arrays.hashCode(source); + } + + @Override + public String toString() { + return Arrays.toString(source); + } + } + + private static final class WrapFloatArray extends CacheKeyArrayWrapper { + private final float[] source; + + WrapFloatArray(float[] source) { + this.source = source; + } + + @Override + public boolean equals(Object other) { + return (other instanceof WrapFloatArray) && + Arrays.equals(source, ((WrapFloatArray) other).source); + } + + @Override + public int hashCode() { + return Arrays.hashCode(source); + } + + @Override + public String toString() { + return Arrays.toString(source); + } + } + + private static final class WrapDoubleArray extends CacheKeyArrayWrapper { + private final double[] source; + + WrapDoubleArray(double[] source) { + this.source = source; + } + + @Override + public boolean equals(Object other) { + return (other instanceof WrapDoubleArray) && + Arrays.equals(source, ((WrapDoubleArray) other).source); + } + + @Override + public int hashCode() { + return Arrays.hashCode(source); + } + + @Override + public String toString() { + return Arrays.toString(source); + } + } +} diff --git a/src/test/java/org/apache/ibatis/cache/CacheKeyArrayWrapperTest.java b/src/test/java/org/apache/ibatis/cache/CacheKeyArrayWrapperTest.java new file mode 100644 index 00000000000..7510bdbcac7 --- /dev/null +++ b/src/test/java/org/apache/ibatis/cache/CacheKeyArrayWrapperTest.java @@ -0,0 +1,72 @@ +/** + * Copyright 2009-2017 the original author or authors. + * + * Licensed 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.ibatis.cache; + +import static org.junit.Assert.*; +import org.junit.Test; + +import static org.apache.ibatis.cache.CacheKeyArrayWrapper.wrap; + +public class CacheKeyArrayWrapperTest { + + @Test + public void shouldBeEqualWithSameContent() { + checkSame(wrap(new boolean[] {true}), wrap(new boolean[] {true})); + checkSame(wrap(new byte[] {1}), wrap(new byte[] {1})); + checkSame(wrap(new char[] {'a'}), wrap(new char[] {'a'})); + checkSame(wrap(new short[] {1}), wrap(new short[] {1})); + checkSame(wrap(new int[] {1}), wrap(new int[] {1})); + checkSame(wrap(new long[] {1L}), wrap(new long[] {1L})); + checkSame(wrap(new float[] {1.0f}), wrap(new float[] {1.0f})); + checkSame(wrap(new double[] {1.0}), wrap(new double[] {1.0})); + Object obj = new Object(); + checkSame(wrap(new Object[] {obj}), wrap(new Object[] {obj})); + } + + @Test + public void shouldNotBeEqualWithDifferentContent() { + assertNotEquals(wrap(new boolean[] {true}), wrap(new boolean[] {false})); + assertNotEquals(wrap(new byte[] {1}), wrap(new byte[] {2})); + assertNotEquals(wrap(new char[] {'a'}), wrap(new char[] {'b'})); + assertNotEquals(wrap(new short[] {1}), wrap(new short[] {2})); + assertNotEquals(wrap(new int[] {1}), wrap(new int[] {2})); + assertNotEquals(wrap(new long[] {1L}), wrap(new long[] {2L})); + assertNotEquals(wrap(new float[] {1.0f}), wrap(new float[] {2.0f})); + assertNotEquals(wrap(new double[] {1.0}), wrap(new double[] {2.0})); + Object obj1 = new Object(); + Object obj2 = new Object(); + assertNotEquals(wrap(new Object[] {obj1}), wrap(new Object[] {obj2})); + } + + + @Test + public void shouldNotBeEqualWithBoxedContent() { + assertNotEquals(wrap(new boolean[] {true}), wrap(new Boolean[] {true})); + assertNotEquals(wrap(new byte[] {1}), wrap(new Byte[] {1})); + assertNotEquals(wrap(new char[] {'a'}), wrap(new Character[] {'a'})); + assertNotEquals(wrap(new short[] {1}), wrap(new Short[] {1})); + assertNotEquals(wrap(new int[] {1}), wrap(new Integer[] {1})); + assertNotEquals(wrap(new long[] {1L}), wrap(new Long[] {1L})); + assertNotEquals(wrap(new float[] {1.0f}), wrap(new Float[] {1.0f})); + assertNotEquals(wrap(new double[] {1.0}), wrap(new Double[] {1.0})); + } + + private void checkSame(Object a, Object b) { + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + assertEquals(a.toString(), b.toString()); + } +} diff --git a/src/test/java/org/apache/ibatis/cache/CacheKeyTest.java b/src/test/java/org/apache/ibatis/cache/CacheKeyTest.java index 0f2071d6255..983b00d4c94 100644 --- a/src/test/java/org/apache/ibatis/cache/CacheKeyTest.java +++ b/src/test/java/org/apache/ibatis/cache/CacheKeyTest.java @@ -1,5 +1,5 @@ /** - * Copyright 2009-2015 the original author or authors. + * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ public void shouldTestCacheKeysEqual() { } @Test - public void shouldTestCacheKeysNotEqualDueToDateDifference() throws Exception { - CacheKey key1 = new CacheKey(new Object[] { 1, "hello", null, new Date() }); - Thread.sleep(1000); - CacheKey key2 = new CacheKey(new Object[] { 1, "hello", null, new Date() }); + public void shouldTestCacheKeysNotEqualDueToDateDifference() { + long time = new Date().getTime(); + CacheKey key1 = new CacheKey(new Object[] { 1, "hello", null, new Date(time) }); + CacheKey key2 = new CacheKey(new Object[] { 1, "hello", null, new Date(time + 1L) }); assertFalse(key1.equals(key2)); assertFalse(key2.equals(key1)); assertFalse(key1.hashCode() == key2.hashCode()); @@ -45,9 +45,8 @@ public void shouldTestCacheKeysNotEqualDueToDateDifference() throws Exception { } @Test - public void shouldTestCacheKeysNotEqualDueToOrder() throws Exception { + public void shouldTestCacheKeysNotEqualDueToOrder() { CacheKey key1 = new CacheKey(new Object[] { 1, "hello", null }); - Thread.sleep(1000); CacheKey key2 = new CacheKey(new Object[] { 1, null, "hello" }); assertFalse(key1.equals(key2)); assertFalse(key2.equals(key1));