diff --git a/src/main/java/org/apache/ibatis/annotations/CacheNamespaceRef.java b/src/main/java/org/apache/ibatis/annotations/CacheNamespaceRef.java index 28667f39b54..649219f5f4d 100644 --- a/src/main/java/org/apache/ibatis/annotations/CacheNamespaceRef.java +++ b/src/main/java/org/apache/ibatis/annotations/CacheNamespaceRef.java @@ -22,11 +22,24 @@ import java.lang.annotation.Target; /** + * The annotation that reference a cache. + *

+ * If you use this annotation, should be specified either {@link #value()} and {@link #name()} attribute. + *

* @author Clinton Begin + * @author Kazuki Shimizu */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface CacheNamespaceRef { - Class value(); + /** + * A namespace type to reference a cache (the namespace name become a FQCN of specified type) + */ + Class value() default void.class; + /** + * A namespace name to reference a cache + * @since 3.4.2 + */ + String name() default ""; } diff --git a/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java b/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java index 216612c3e1c..2c90fced31a 100644 --- a/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java +++ b/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java @@ -200,7 +200,16 @@ private Properties convertToProperties(Property[] properties) { private void parseCacheRef() { CacheNamespaceRef cacheDomainRef = type.getAnnotation(CacheNamespaceRef.class); if (cacheDomainRef != null) { - assistant.useCacheRef(cacheDomainRef.value().getName()); + Class refType = cacheDomainRef.value(); + String refName = cacheDomainRef.name(); + if (refType == void.class && refName.isEmpty()) { + throw new BuilderException("Should be specified either value() or name() attribute in the @CacheNamespaceRef"); + } + if (refType != void.class && !refName.isEmpty()) { + throw new BuilderException("Cannot use both value() and name() attribute in the @CacheNamespaceRef"); + } + String namespace = (refType != void.class) ? refType.getName() : refName; + assistant.useCacheRef(namespace); } } diff --git a/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java b/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java index 709e14bd69a..50310f37721 100644 --- a/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java +++ b/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java @@ -23,6 +23,8 @@ import org.apache.ibatis.annotations.Property; import org.apache.ibatis.cache.Cache; import org.apache.ibatis.cache.CacheException; +import org.apache.ibatis.annotations.CacheNamespaceRef; +import org.apache.ibatis.builder.BuilderException; import org.apache.ibatis.io.Resources; import org.apache.ibatis.jdbc.ScriptRunner; import org.apache.ibatis.session.SqlSession; @@ -59,7 +61,7 @@ public void setUp() throws Exception { reader.close(); session.close(); } - + /* * Test Plan: * 1) SqlSession 1 executes "select * from A". @@ -76,23 +78,21 @@ public void testplan1() { try { PersonMapper pm = sqlSession1.getMapper(PersonMapper.class); Assert.assertEquals(2, pm.findAll().size()); - } - finally { + } finally { sqlSession1.close(); } - + SqlSession sqlSession2 = sqlSessionFactory.openSession(false); try { PersonMapper pm = sqlSession2.getMapper(PersonMapper.class); pm.delete(1); Assert.assertEquals(1, pm.findAll().size()); - } - finally { + } finally { sqlSession2.commit(); sqlSession2.close(); } } - + /* * Test Plan: * 1) SqlSession 1 executes "select * from A". @@ -111,31 +111,28 @@ public void testplan2() { try { PersonMapper pm = sqlSession1.getMapper(PersonMapper.class); Assert.assertEquals(2, pm.findAll().size()); - } - finally { + } finally { sqlSession1.close(); } - + SqlSession sqlSession2 = sqlSessionFactory.openSession(false); try { PersonMapper pm = sqlSession2.getMapper(PersonMapper.class); pm.delete(1); - } - finally { + } finally { sqlSession2.rollback(); sqlSession2.close(); } - + SqlSession sqlSession3 = sqlSessionFactory.openSession(false); try { PersonMapper pm = sqlSession3.getMapper(PersonMapper.class); Assert.assertEquals(2, pm.findAll().size()); - } - finally { + } finally { sqlSession3.close(); } } - + /* * Test Plan with Autocommit on: * 1) SqlSession 1 executes "select * from A". @@ -154,26 +151,23 @@ public void testplan3() { try { PersonMapper pm = sqlSession1.getMapper(PersonMapper.class); Assert.assertEquals(2, pm.findAll().size()); - } - finally { + } finally { sqlSession1.close(); } - + SqlSession sqlSession2 = sqlSessionFactory.openSession(true); try { PersonMapper pm = sqlSession2.getMapper(PersonMapper.class); pm.delete(1); - } - finally { + } finally { sqlSession2.close(); } - + SqlSession sqlSession3 = sqlSessionFactory.openSession(true); try { PersonMapper pm = sqlSession3.getMapper(PersonMapper.class); Assert.assertEquals(1, pm.findAll().size()); - } - finally { + } finally { sqlSession3.close(); } } @@ -307,6 +301,26 @@ public void shouldApplyCacheNamespaceRef() { try { PersonMapper pm = sqlSession.getMapper(PersonMapper.class); Assert.assertEquals(3, pm.findAll().size()); + Person p = new Person(4, "foo", "bar"); + pm.createWithoutFlushCache(p); + } finally { + sqlSession.close(); + } + } + { + SqlSession sqlSession = sqlSessionFactory.openSession(true); + try { + SpecialPersonMapper pm = sqlSession.getMapper(SpecialPersonMapper.class); + Assert.assertEquals(4, pm.findWithFlushCache().size()); + } finally { + sqlSession.close(); + } + } + { + SqlSession sqlSession = sqlSessionFactory.openSession(true); + try { + PersonMapper pm = sqlSession.getMapper(PersonMapper.class); + Assert.assertEquals(4, pm.findAll().size()); } finally { sqlSession.close(); } @@ -341,6 +355,24 @@ public void shouldErrorUnsupportedProperties() { sqlSessionFactory.getConfiguration().addMapper(CustomCacheUnsupportedPropertyMapper.class); } + @Test + public void shouldErrorInvalidCacheNamespaceRefAttributesSpecifyBoth() { + expectedException.expect(BuilderException.class); + expectedException.expectMessage("Cannot use both value() and name() attribute in the @CacheNamespaceRef"); + + sqlSessionFactory.getConfiguration().getMapperRegistry() + .addMapper(InvalidCacheNamespaceRefBothMapper.class); + } + + @Test + public void shouldErrorInvalidCacheNamespaceRefAttributesIsEmpty() { + expectedException.expect(BuilderException.class); + expectedException.expectMessage("Should be specified either value() or name() attribute in the @CacheNamespaceRef"); + + sqlSessionFactory.getConfiguration().getMapperRegistry() + .addMapper(InvalidCacheNamespaceRefEmptyMapper.class); + } + private CustomCache unwrap(Cache cache){ Field field; try { @@ -364,4 +396,12 @@ private CustomCache unwrap(Cache cache){ private interface CustomCacheUnsupportedPropertyMapper { } + @CacheNamespaceRef(value = PersonMapper.class, name = "org.apache.ibatis.submitted.cache.PersonMapper") + private interface InvalidCacheNamespaceRefBothMapper { + } + + @CacheNamespaceRef + private interface InvalidCacheNamespaceRefEmptyMapper { + } + } diff --git a/src/test/java/org/apache/ibatis/submitted/cache/ImportantPersonMapper.java b/src/test/java/org/apache/ibatis/submitted/cache/ImportantPersonMapper.java index 58caa617290..6914334d17b 100644 --- a/src/test/java/org/apache/ibatis/submitted/cache/ImportantPersonMapper.java +++ b/src/test/java/org/apache/ibatis/submitted/cache/ImportantPersonMapper.java @@ -22,7 +22,7 @@ import java.util.List; -@CacheNamespaceRef(PersonMapper.class) +@CacheNamespaceRef(PersonMapper.class) // by type public interface ImportantPersonMapper { @Select("select id, firstname, lastname from person") diff --git a/src/test/java/org/apache/ibatis/submitted/cache/SpecialPersonMapper.java b/src/test/java/org/apache/ibatis/submitted/cache/SpecialPersonMapper.java new file mode 100644 index 00000000000..e76435a3756 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/cache/SpecialPersonMapper.java @@ -0,0 +1,32 @@ +/** + * Copyright 2009-2016 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.submitted.cache; + +import org.apache.ibatis.annotations.CacheNamespaceRef; +import org.apache.ibatis.annotations.Options; +import org.apache.ibatis.annotations.Options.FlushCachePolicy; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@CacheNamespaceRef(name = "org.apache.ibatis.submitted.cache.PersonMapper") // by name +public interface SpecialPersonMapper { + + @Select("select id, firstname, lastname from person") + @Options(flushCache = FlushCachePolicy.TRUE) + List findWithFlushCache(); + +} diff --git a/src/test/java/org/apache/ibatis/submitted/cache/mybatis-config.xml b/src/test/java/org/apache/ibatis/submitted/cache/mybatis-config.xml index dfaa66f3653..d5a94a65bca 100644 --- a/src/test/java/org/apache/ibatis/submitted/cache/mybatis-config.xml +++ b/src/test/java/org/apache/ibatis/submitted/cache/mybatis-config.xml @@ -45,5 +45,6 @@ + \ No newline at end of file