ReadThroughMultiCacheAdvice extends MultiCacheAdvice { @Around("getMulti()") @SuppressWarnings("unchecked") public Object cacheMulti(final ProceedingJoinPoint pjp) throws Throwable { if (isDisabled()) { getLogger().info("Cache disabled"); return pjp.proceed(); } final ReadThroughMultiCache annotation; final MultiCacheCoordinator coord; final AnnotationData data; final SerializationType serializationType; Object[] args = pjp.getArgs(); try { final Method methodToCache = getCacheBase().getMethodToCache(pjp, ReadThroughMultiCache.class); getCacheBase().verifyReturnTypeIsList(methodToCache, ReadThroughMultiCache.class); annotation = methodToCache.getAnnotation(ReadThroughMultiCache.class); serializationType = getCacheBase().getSerializationType(methodToCache); data = AnnotationDataBuilder.buildAnnotationData(annotation, ReadThroughMultiCache.class, methodToCache); coord = new MultiCacheCoordinator(methodToCache, data); setMultiCacheOptions(coord, annotation.option()); coord.setHolder(createObjectIdCacheKeyMapping(data, args, coord.getMethod())); List<Object> listKeyObjects = (List<Object>) Utils.getMethodArg(data.getListIndexInMethodArgs(), args, coord.getMethod() .toString()); coord.setListKeyObjects(listKeyObjects); coord.setInitialKey2Result(getCacheBase().getCache(data).getBulk(coord.getKey2Obj().keySet(), serializationType)); if (coord.getMissedObjects().isEmpty()) { return coord.generateResultList(); } args = coord.createModifiedArgumentList(args); } catch (Exception ex) { warn(ex, "Caching on %s aborted due to an error.", pjp.toShortString()); return pjp.proceed(); } final List<Object> results = (List<Object>) pjp.proceed(args); try { if (results == null || results.isEmpty()) { if (coord.isAddNullsToCache()) { addNullValues(coord.getMissedObjects(), coord, serializationType); } return coord.generatePartialResultList(); } if (coord.isGenerateKeysFromResult()) { return generateByKeysFromResult(results, coord, serializationType); } else { return generateByKeysProviders(results, coord, serializationType); } } catch (Exception ex) { warn(ex, "Caching on %s aborted due to an error. The underlying method will be called twice.", pjp.toShortString()); return pjp.proceed(pjp.getArgs()); } }  @Pointcut("@annotation(com.google.code.ssm.api.ReadThroughMultiCache)") void getMulti(); @Around("getMulti()") @SuppressWarnings("unchecked") Object cacheMulti(final ProceedingJoinPoint pjp);  }
@Test public void validCacheAllMiss() throws Throwable { Assume.assumeTrue(isValid); when(pjp.proceed(params)).thenReturn(expectedValue); assertEquals(expectedValue, advice.cacheMulti(pjp)); verify(cache).getBulk(eq(new HashSet<String>(Arrays.asList(cacheKeys))), any(SerializationType.class)); for (int i = 0; i < cacheKeys.length; i++) { verify(cache).setSilently(eq(cacheKeys[i]), eq(EXPIRATION), eq(expectedValue.get(i)), any(SerializationType.class)); } verify(pjp).proceed(params); }
@Test public void validCacheHit() throws Throwable { Assume.assumeTrue(isValid); Map<String, Object> map = new HashMap<String, Object>(); for (int i = 0; i < cacheKeys.length; i++) { map.put(cacheKeys[i], expectedValue.get(i)); } when(cache.getBulk(eq(new HashSet<String>(Arrays.asList(cacheKeys))), any(SerializationType.class))).thenReturn(map); assertEquals(expectedValue, advice.cacheMulti(pjp)); verify(cache).getBulk(eq(new HashSet<String>(Arrays.asList(cacheKeys))), any(SerializationType.class)); verify(cache, never()).setSilently(anyString(), anyInt(), any(), any(SerializationType.class)); verify(pjp, never()).proceed(params); }
@Test @SuppressWarnings("unchecked") public void invalid() throws Throwable { Assume.assumeThat(isValid, CoreMatchers.is(false)); when(pjp.proceed()).thenReturn(expectedValue); assertEquals(expectedValue, advice.cacheMulti(pjp)); verify(cache, never()).getBulk(any(Collection.class), any(SerializationType.class)); verify(cache, never()).set(anyString(), anyInt(), any(), any(SerializationType.class)); verify(pjp).proceed(); }