Java annotation not working on Callable - java

I have writen an annotation (in a spring boot application) and try to apply it to the call() method of Callable, but it doesn't work, yet on the other hand, when applied to a normal method (please see code below), it works, this keeps bothering me, could you please give me some clues? Thank you very much.
Here are my code,
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface LogExecutionTime {
}
#Aspect
#Component
public class LogExecutionTimeAspect {
private static final Logger logger = LoggerFactory.getLogger(LogExecutionTimeAspect.class);
#Around("#annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
final long start = System.currentTimeMillis();
final Object proceed = joinPoint.proceed();
final long executionTime = System.currentTimeMillis() - start;
logger.info(joinPoint.getSignature() + " executed in " + executionTime + "ms");
return proceed;
}
}
public class DummyCallable implements Callable<Integer> {
private Integer start, count;
DummyCallable() {}
DummyCallable(Integer start, Integer count) {
this.start = start;
this.count = count;
}
#LogExecutionTime // not working...
#Override
public Integer call() throws Exception {
Thread.sleep(start * 1000);
Integer sum = 0;
for (Integer i = start; i <= start + count; i++) {
sum += i;
}
return sum;
}
}
#LogExecutionTime // This will work...
public List<Integer> getAllUserScores() {
Callable c1 = new DummyCallable(1, 100000);
Callable c2 = new DummyCallable(2, 100000);
Callable c3 = new DummyCallable(3, 100000);
// .... run them ...
return result;
}

Inspired by #sbjavateam, I realize that three things,
spring aop work only with object that are managed by spring container. To apply aspect for your class it should be a bean or component and instantiated by spring context. (All right, this is copied from #sbjavateam's answer.)
Based on the former statement, Callable c1 = new DummyCallable(1, 100000); is wrong by nature, since we must create the DummyCallable from the spring context (so that bean will be properly injected with it's dependencies), calling new is not capable.
The DummyCallable class needs to have a scope of prototype so that it is not a singleton. The singleton scope is the default scope for a Spring bean. As a result, this class must have this annotation: #Scope("prototype").
Below is my fix,
#Component
#Scope("prototype")
public class DummyCallable implements Callable<Integer> {}
private DummyCallable createDummyCallable(Integer start, Integer end) {
return context.getBean(DummyCallable.class, start, end);
}
Besides, you might want this configuration as well,
spring.aop.proxy-target-class=true
Last but not least, thank you very much, #sbjavateam.

Related

Testing an abstract class with Mockito does not give the expected result

I have a class structure similar to the following
public abstract class AbstractStep {
private final Range RANGE;
AbstractStep(AbstractStepBuilder builder) {
RANGE = builder.range;
}
public abstract static class AbstractStepBuilder {
Range range;
public AbstractStepBuilder setRange(int start, end end) {
this.range = new Range(start, end);
return self();
}
abstract AbstractStepBuilder self();
}
public static class Range() {
private final int START;
private final int END;
private Range(int start, int end) {
if(start < 0 || end < 0 || start >= end)
throw new IllegalArgumentException();
START = start;
END = end;
}
}
}
I want to test setRange(int, int) in AbstractStepBuilder to see if the an IllegalArgumentException is thrown. I use TestNG and Mockito, and I have attempted the following using with the help of this.
final class RangeTest {
AbstractStepBuilder builder;
#BeforeSuite
void setup() {
builder = Mockito.mock(AbstractStepBuilder.class);
Mockito.when(builder.self()).thenReturn(null);
}
#Test(expectedExceptions = IllegalArgumentException.class)
final void testCreatingRangeWithNegativeStart() {
builder.setRange(-1, 2);
}
}
This test fails. I have also tried replacing Mockito.mock(AbstractStepBuilder.class) with Mockito.mock(AbstractStepBuilder.class, Mockito.CALLS_REAL_METHODS) as in the top answer of this question.
Note that if I make CodeRange as its own outer class, this test passes, so I do not believe it could be the test itself.
Why is this test failing, and is it possible to fix it without having to use a concrete class in the test instead?
You're calling a method on a mock, that will never throw an Exception until you tell it to. You never mock a class you want to test.
If you want to test the actual class, you'll need to create a subclass of the step builder, create an instance and test that.
I think you can also create a spy (by Mockito.spy(AbstractStepBuilder.class)) to avoid creating a subclass just for the test.

Writing a JUnit Rule: Description doesn't contain my annotation

I'm trying to write a simple JUnit Rule implementation which reruns a test case a given amount of times if not successful.
It works fine as such, but I'd like to make it configurable per method with a custom annotation I attach to the method.
Here's my rule implementation:
public class Retry implements TestRule {
private int retryCount = 10;
#Override
public Statement apply(Statement base, Description description) {
return new Statement() {
public void evaluate() throws Throwable {
RetryCount annotation = description.getAnnotation(RetryCount.class);
// Problem is here, the annotation is always null!
int retries = (annotation != null) ? annotation.retries() : retryCount;
// keep track of the last failure to include it in our failure later
AssertionError lastFailure = null;
for (int i = 0; i < retries; i++) {
try {
// call wrapped statement and return if successful
base.evaluate();
return;
} catch (AssertionError err) {
lastFailure = err;
}
}
// give meaningful message and include last failure for the
// error trace
throw new AssertionError("Gave up after " + retries + " tries", lastFailure);
}
};
}
// the annotation for method-based retries
public static #interface RetryCount {
public int retries() default 1;
}
}
In the line I commented, I don't get the annotation I attach to the method:
public class UnreliableServiceUnitTest {
private UnreliableService sut = new UnreliableService();
#Rule
public Retry retry = new Retry();
#Test
#RetryCount(retries=5) // here it is
public void worksSometimes() {
boolean worked = sut.workSometimes();
assertThat(worked, is(true));
}
}
If I debug into the Rule, the Description annotation list contains the #Test annotation but not the #RetryCount. I also tried adding a #Deprecated which will also get added.
Any idea why?
For completeness, this is the sample SUT:
public class UnreliableService {
private static Random RANDOM = new Random();
// needs at least two calls
private static int COUNTER = RANDOM.nextInt(8) + 2;
public boolean workSometimes() {
if (--COUNTER == 0) {
COUNTER = RANDOM.nextInt(8) + 2;
return true;
}
return false;
}
}
The #Test annotation is a Runtime annotation. Your RetryCount is not defined like that. It should be so you can access it during runtime. Change your code to this:
// the annotation for method-based retries
#Retention(value=RUNTIME)
public static #interface RetryCount {
public int retries() default 1;
}
Using RetentionPolicy Runtime allows you to read the annotations reflectively. See here the Javadoc

Java, unit test mocking mxbean

I want to sort all the Java threads on CPU time. I use the ThreadMXBean to get the CPU time of the threads by thread ID. The comparator is used for sortinging the Thread ID's.
public class ThreadStats{
private static ThreadMXBean mxbean = ManagementFactory.getThreadMXBean();
class ThreadCPUCompare implements Comparator<Long>{
#Override
public int compare(Long threadId1, Long threadId2) {
return Long.compare(mxbean.getThreadCpuTime(threadId2), mxbean.getThreadCpuTime(threadId1));
}
}
}
And I've made the following unit test:
#RunWith(MockitoJUnitRunner.class)
public class ThreadStatsTest {
#InjectMocks ThreadCPUCompare comperator = new ThreadStats().new ThreadCPUCompare();
#Mock ThreadMXBean mxbean;
#Test
public void threadCPUSortTest() {
Mockito.when(mxbean.getThreadCpuTime(1L)).thenReturn(3L);
Mockito.when(mxbean.getThreadCpuTime(2L)).thenReturn(2L);
Mockito.when(mxbean.getThreadCpuTime(3L)).thenReturn(4L);
Mockito.when(mxbean.getThreadCpuTime(4L)).thenReturn(1L);
List<Long>expectedList = new ArrayList<Long>();
expectedList.add(3L);
expectedList.add(1L);
expectedList.add(2L);
expectedList.add(4L);
List<Long>actualList = new ArrayList<Long>();
actualList.add(4L);
actualList.add(2L);
actualList.add(3L);
actualList.add(1L);
//Sorting of the actual list
Collections.sort(actualList, comperator);
assertEquals(expectedList, actualList);
}
}
But I cant get the test to work. I think because the mocking doesn't work. Could someone show me how to fix the unit test please?
Your test is failing because the mock is not being injected. Mockito will not inject into static fields, nor will it inject into an outer class (such as the ThreadStats class in your case).
You need to write the code as something like this:
class ThreadCPUCompare implements Comparator<Long>
{
private ThreadMXBean mxbean;
#Override
public int compare(Long threadId1, Long threadId2) {
return Long.compare(mxbean.getThreadCpuTime(threadId2), mxbean.getThreadCpuTime(threadId1));
}
}
#RunWith(MockitoJUnitRunner.class)
public class ThreadStatsTest
{
#Mock ThreadMXBean mxbean;
#InjectMocks Comparator comperator = new ThreadCPUCompare();
#Test
public void threadCPUSortTest() {
// do your tests exactly as before
}
}
You will then have the challenge of wiring it into the production code, but that is a different exercise, where I would recommend some sort of dependency injection (guice, spring, manual etc depending on context and preferences).
One simple way to write the test is as follows, no mocking involved:
public class ThreadStatsTest {
Comparator<Long> comparator = new ThreadStats().new ThreadCPUCompare();
#Test
public void orderThreadIdsFromLongestToShortestCPUTime() {
long longLivedThread = Thread.currentThread().getId(); // > 0 cpu time
long shortLivedThread = new Thread().getId(); // 0 cpu time
int longTimeFirst = comparator.compare(longLivedThread, shortLivedThread);
int sameTimes = comparator.compare(longLivedThread, longLivedThread);
int longTimeSecond = comparator.compare(shortLivedThread, longLivedThread);
assertEquals(-1, longTimeFirst);
assertEquals( 0, sameTimes);
assertEquals( 1, longTimeSecond);
}
}

Spring Cacheable vs CachePut?

#CachePut or #Cacheable(value = "CustomerCache", key = "#id")
public Customer updateCustomer(Customer customer) {
sysout("i am inside updateCustomer");
....
return customer;
}
I found below documentation under CachePut source code
CachePut annotation does not cause the target method to be skipped -
rather it always causes the method to be invoked and its result to be
placed into the cache.
Does it mean if I use #Cacheable , updateCustomer method will be executed only once and result will be updated in cache. Subsequent calls to
updateCustomer will not execute updateCustomer , it will just update the cache.
While in case of #CachePut, updateCustomer method will be executed on each call and result will be updated in cache.
Is my understanding correct?
Yes.
I even made a test to be sure:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = CacheableTest.CacheConfigurations.class)
public class CacheableTest {
public static class Customer {
final private String id;
final private String name;
public Customer(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
final public static AtomicInteger cacheableCalled = new AtomicInteger(0);
final public static AtomicInteger cachePutCalled = new AtomicInteger(0);
public static class CustomerCachedService {
#Cacheable("CustomerCache")
public Customer cacheable(String v) {
cacheableCalled.incrementAndGet();
return new Customer(v, "Cacheable " + v);
}
#CachePut("CustomerCache")
public Customer cachePut(String b) {
cachePutCalled.incrementAndGet();
return new Customer(b, "Cache put " + b);
}
}
#Configuration
#EnableCaching()
public static class CacheConfigurations {
#Bean
public CustomerCachedService customerCachedService() {
return new CustomerCachedService();
}
#Bean
public CacheManager cacheManager() {
return new GuavaCacheManager("CustomerCache");
}
}
#Autowired
public CustomerCachedService cachedService;
#Test
public void testCacheable() {
for(int i = 0; i < 1000; i++) {
cachedService.cacheable("A");
}
Assert.assertEquals(cacheableCalled.get(), 1);
}
#Test
public void testCachePut() {
for(int i = 0; i < 1000; i++) {
cachedService.cachePut("B");
}
Assert.assertEquals(cachePutCalled.get(), 1000);
}
}
#CachePut always lets the method execute. It is generally used if you want your cache to be updated with the result of the method execution.
Example: When you want to update a stale data which is cached, instead of blowing the cache completely.
#Cacheable will be executed only once for the given cachekey and subsequent requests won't execute the method, until the cache expires or gets flushed.
Yes, you are absolutely correct.
#Cacheput and #Cacheable are used in conjunction.
#Cacheable will not update the cache on every call. In order to remove the stale data, there must be a service that uses the #Cacheput that clears the stale data.
Below answer is for the ones who are using guava caching to build cache.
Using guava caching, the time interval that is applied will empty the cache after a certain period of time which is not the case with #Cacheput. #Cacheput will only update the values that are stale and hence it calls the method every time to update the cache.
I hope my answer clears your question.

java bean null pointer exception

This is my first post, so hopefully I live up to the high standards of the community.
I'm trying to learn Enterprise Java beans and I've been thrown into the deep end and asked to debug an EAR file that's throwing a NullPointerException. This is the line that's throwing the Exception:
private CrashMonitorTimer crash;
...
/*THE NEXT LINE THROWS THE NULL POINTER EXCEPTION*/
crash.createTimer(Long.parseLong(sCrashMonitorInterval),"CrashMoniterScheduler");
This is the code for the interface being called:
import javax.ejb.Local;
#Local
public interface CrashMonitorTimer
{
public abstract void createTimer(long l, String s);
public abstract void cancelTimer(String s);
}
And this is the code for the Java bean:
#Stateless(name = "CrashMonitorBean", mappedName = "CrashMonitorBean")
#Local(CrashMonitorTimer.class)
public class CrashMonitorBean
implements CrashMonitorTimer
{
#Resource
SessionContext sessionCtx;
TimerService timerService;
Timer timer;
int iMsgCntBeforeCtxRenew;
int iCtxReusedCount;
Context _context;
CrashMonitorInfoUtil crashMonitorRMIContext[];
public CrashMonitorBean()
{
iMsgCntBeforeCtxRenew = 10;
iCtxReusedCount = 0;
_context = null;
crashMonitorRMIContext = null;
}
#Override
public void createTimer(long lInterval, String sName)
{
//CrashMonitorInfoUtil leaves context open for reuse
System.out.println((new StringBuilder("Creating ")).append(sName).append(" timer").toString());
timerService = sessionCtx.getTimerService();
timer = timerService.createTimer(lInterval, lInterval, sName);
String sPorts = SystemConfigurator.getConfigValue("RMIPorts");
String saPorts[] = sPorts.split(",");
String server = SystemConfigurator.getConfigValue("host");
crashMonitorRMIContext = new CrashMonitorInfoUtil[saPorts.length];
for(int i = 0; i < saPorts.length; i++)
{
crashMonitorRMIContext[i] = new CrashMonitorInfoUtil(server, saPorts[i]);
}
}
...
}
I've poked around at this, but having had zero experience with Java beans or interfaces (or the new annotations) I'm kind of at a loss on what I should even try. Any explanation or direction would be greatly appreciated.
crash variable is null.
If sCrashMonitorInterval were null, then it would have thrown NumberFormatException

Categories

Resources