Proxy for abstract class without changing the usage - java

I have an abstract class (database mapping) implementing an interface where default implementations are injected at runtime (this is part of another library and cannot be changed).
I want to override one of the default implementation via a proxy (as that seems like the way to override this).
public abstract class Table1 implements Storable<Table1>
{
#Sequence("ID_SEQUENCE")
#Alias("ID")
public abstract String getID();
public abstract void setID(String ID);
#Alias("NAME")
public abstract String getAvailabilityZone();
public abstract void setAvailabilityZone(String value);
}
public interface Storable<S extends Storable<S>> {
//a bunch of method definition.
boolean tryLoad() throws Exception;
}
Let's say I want to override tryLoad() method to do my own things instead of what the generated code provides. Given the nature of the library, it is not something I can achieve by simple #Override.
The simple way this is currently used is as following:
public void method() {
Table1 t = Repository.storageFor(Table1.class).prepare();
t.setName( "temp" );
if (!t.tryLoad())
t.tryInsert();
}
I want to proxy tryLoad() without making changes in all the methods across the whole codebase - that would be to get proxied instance instead of actual one and perform the operation on that.
Is there any recommended way to achieve this?
Thanks!

I woke up last night and felt bored, so despite your lack of feedback I created a little Carbonado showcase project and shared it on GitHub. I made three commits:
Initial commit with Maven project already prepared for AspectJ and a JUnit test for me to find out how Carbonado actually works, because I had never used it before.
Add failing unit test for behaviour of tryLoad() expected to be provided by aspect.
Add aspect to make unit test pass. Aspect hooks into tryLoad() and auto-creates non-existent record. I do not know if I guessed right what you actually wanted to achieve, but if it was a different thing, just change the aspect implementation.
Sample code
Carbonado storable:
package de.scrum_master.app;
import com.amazon.carbonado.Nullable;
import com.amazon.carbonado.PrimaryKey;
import com.amazon.carbonado.Storable;
#PrimaryKey("ID")
public interface StoredMessage extends Storable<StoredMessage> {
long getID();
void setID(long id);
#Nullable String getMessage();
void setMessage(String message);
}
Aspect:
package de.scrum_master.aspect;
import com.amazon.carbonado.Storable;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class CarbonadoAspect {
#Around("call(boolean tryLoad()) && target(storable)")
public boolean tryInsertIfNotFound(ProceedingJoinPoint thisJoinPoint, Storable storable) throws Throwable {
System.out.println(thisJoinPoint);
if ((boolean) thisJoinPoint.proceed())
return true;
System.out.println("Not found: " + storable + " -> inserting");
return storable.tryInsert();
}
}
JUnit test:
package de.scrum_master.app;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.amazon.carbonado.FetchException;
import com.amazon.carbonado.PersistException;
import com.amazon.carbonado.Repository;
import com.amazon.carbonado.RepositoryException;
import com.amazon.carbonado.Storage;
import com.amazon.carbonado.SupportException;
import com.amazon.carbonado.repo.map.MapRepositoryBuilder;
import de.scrum_master.app.StoredMessage;
public class CarbonadoTest {
private Repository repo;
private Storage<StoredMessage> storage;
StoredMessage message;
#Before
public void setUp() throws Exception {
repo = MapRepositoryBuilder.newRepository();
storage = repo.storageFor(StoredMessage.class);
message = storage.prepare();
}
#After
public void tearDown() throws Exception {
repo.close();
repo = null;
storage = null;
message = null;
}
// (...)
#Test
public void aspectCreatesNonExistentRecord() throws SupportException, RepositoryException {
message.setID(1);
// Without the aspect this would be false
assertTrue(message.tryLoad());
assertEquals(message.getID(), 1);
assertEquals(message.getMessage(), null);
}
}
Enjoy!

Related

org.powermock.api.mockito.ClassNotPreparedException in Static class mocking

I am writing a unit test to mock a static method in the verticle but getting ClassNotPreparedException always. I think that its only possible to mock this way if only the class is static, but i have non static class. What am i missing?
I have tried various solutions like using #rule or #PowerMockIgnore
//myVerticleTest.java
package com.blabla.me.verticles;
import static com.google.common.truth.Truth.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import io.vertx.core.Vertx;
import io.vertx.junit5.VertxTestContext;
import io.vulpx.VulpxTestBase;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.junit.runner.RunWith;
import com.blabla.me.verticles.AdditionalInformationCardVerticle;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.junit.Rule;
import com.blabla.me.verticles.st;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ st.class })
#PowerMockIgnore({"org.mockito.*"})
public class myVerticleTest extends VulpxTestBase {
#Rule public PowerMockRule rule = new PowerMockRule();
private Vertx vertx;
private AdditionalInformationCardVerticle dummy;
#BeforeEach
#PrepareForTest({ st.class })
public void setUp(VertxTestContext testContext) throws Exception {
vertx = Vertx.vertx();
try {
PowerMockito.mockStatic(st.class);
PowerMockito.when(st.createClient()).thenReturn("kk");
//deploying verticle
dummy = new AdditionalInformationCardVerticle();
vertx.deployVerticle(dummy, testContext.completing());
} catch (Exception e) {
System.out.println("heyyy eroorrr : " + e);
}
}
#Test
#PrepareForTest({ st.class })
public void justnormaltest() {
cla ownclass = new cla();
String k = ownclass.createfromclass();
assertThat("kk").isEqualTo(k);
}
}
// st.java
public class st {
public static String createClient() {
return "kk";
}
}
// cla.java
public class cla {
public String createfromclass() {
return st.createClient();
}
}
I expect it to run the assertion but i always get below excpetion:
"org.powermock.api.mockito.ClassNotPreparedException:
The class com.sap.me.verticles.st not prepared for test.
To prepare this class, add class to the '#PrepareForTest' annotation.
In case if you don't use this annotation, add the annotation on class or method level. "
Here:
#PrepareForTest({ st.class })
That one goes to exactly one place: in front of your test class public class myVerticleTest.
And hint: instead of adding more and more "things" to not working code: pick any good documentation, and try to follow that to the last ; in the example code (instead of assuming that adding more and more things here or there would help).
One good starting point: the official documentation on static mocking.
And of course, the usual caveat: consider not learning about PowerMock in the first place. Instead focus on writing "easy to test" code. Far too often, people think PowerMock(ito) is the answer to their problem. When their problem in reality is their inability to write "easy to test" production code.

how to use System.getenv in Junit PowerMockito

I'm able to mock the System.getenv value from Junit but when I execute the test case - in my service class System.getevn value coming as null. Not sure what I'm doing wrong here. Please find my test service class and junit class.
Can some please help me to fix this issue - why the value is not setting in my actual service class?
TestService.java
public class TestService {
public TestService() throws Exception {
loadTestMethod();
}
private void loadTestMethod() {
System.out.println("Environment vairlable : " + System.getenv("my_key_name"));
System.setProperty("app.key", System.getenv("my_key_name"));
}
}
TestServiceTest.java
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(value = { System.class })
#PowerMockIgnore("javax.management.*")
public class TestServiceTest {
#Mock
TestService testService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("my_key_name")).thenReturn("Testing");
System.out.println("Junit Environment vairlable : " + System.getenv("my_key_name"));
testService = new TestService();
}
#Test
public void myServiceTest() {
}
}
Just because PowerMockito allows us to mock static does not mean that we should.
Your classes are dependent on static implementation concerns that make unit testing in isolation, in most cases, difficult.
Consider following the Explicit Dependency Principle
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
Create an abstraction of the desired functionality
public interface SystemWrapper {
//The "standard" output stream
PrintStream out;
//Gets the value of the specified environment variable
string getenv(string name);
//Sets the system property indicated by the specified key.
string setProperty(String key, String value);
}
The implementation will encapsulate the actual calls to the static system class
public class SystemWrapperImplementation implements SystemWrapper {
//The "standard" output stream
public final PrintStream out = System.out;
//Gets the value of the specified environment variable
public string getenv(string name) {
return System.getenv(name);
}
//Sets the system property indicated by the specified key.
public string setProperty(String key, String value) {
return System.setProperty(key, value);
}
}
Your dependent class will then need to be refactored to include the abstraction
public class TestService {
private SystemWrapper system;
public TestService(SystemWrapper system) throws Exception {
this.system = system;
string key = "app.key";
string name = "my_key_name";
loadTestMethod(key, name);
}
private void loadTestMethod(string key, string name) {
string environmentVariable = system.getenv(name);
system.out.println("Environment variable : " + environmentVariable);
system.setProperty(key, environmentVariable);
}
}
Now for testing you can mock the necessary dependencies as needed without any adverse effects. The implementation will then be used in production when invoking actual code.
Finally I would suggest not having your constructors throwing exceptions. Constructors should mainly be used for assignments of variables.

AOP - accessing a protected/private attribute from the intercepted class

I am working on a project that is basically a lot of processes that run periodically. Each process is a different class that extends an abstract class RunnableProcess we created, which contains a private attribute Map<String, String> result and the abstract method run with the signature below:
public abstract void run(Map processContext) throws IOException;
To improve modularization on the project, I'm starting to use Aspect Oriented Programming (AOP) to intercept the run calls from every RunnableProcess. I am still learning AOP, and I have the following code until now:
import static org.slf4j.LoggerFactory.getLogger;
import org.slf4j.Logger;
import process.RunnableProcess;
import java.util.Map;
public aspect ProcessRunInterceptor {
private Logger logger;
pointcut runProcess() : call(void RunnableProcess.run(Map));
after(): runProcess() {
logger = getLogger(thisJoinPoint.getClass());
logger.info("process run successfully");
}
}
It is working, but I want to log more information than just "process run successfully". I have this information inside the intercepted class, in the result attribute mentioned above. Is it possible to access it in the advice without changing the implementation of RunnableProcess?
I can (prefer not to, but if it would be the only choice...) change the attribute from private to protected, but I wouldn't change it to public. I also would not like to create a get method for it.
Building upon my answer to your other question, I will explain to you what you can do. A few hints:
Instead of before() and after() you could just use around().
You should not use a private member for the process instance in a singleton aspect because if you have asynchronous processes in multiple threads, the member could be overwritten. Thus, your approach is not thread-safe and you should use a local variable instead.
You should not print "process run successfully" in an after() advice because after() also runs after an exception. So you cannot safely assume that the process ran successfully, only that it ran at all. You should rather write "finished process" or similar. BTW, if you want to differentiate between successful processes and such ending with an exception, you might want to look into pointcut types after() returning and after() throwing().
It does not make sense to use an abstract base class and not define the member result there directly. Why add it as a private member in each subclass if you can have it as a protected member in the parent? We are still doing OOP here (beside AOP, of course), right? The advantage is that you can access the member directly from the aspect using the base class like you already do in your pointcut.
Here is an MCVE for you:
Process classes:
package de.scrum_master.app;
import java.io.IOException;
import java.util.Map;
public abstract class RunnableProcess {
protected String result = "foo";
public abstract void run(Map processContext) throws IOException;
}
package de.scrum_master.app;
import java.io.IOException;
import java.util.Map;
public class FirstRunnableProcess extends RunnableProcess {
#Override
public void run(Map processContext) throws IOException {
System.out.println("I am #1");
result = "first";
}
}
package de.scrum_master.app;
import java.io.IOException;
import java.util.Map;
public class SecondRunnableProcess extends RunnableProcess {
#Override
public void run(Map processContext) throws IOException {
System.out.println("I am #2");
result = "second";
}
}
Driver application:
package de.scrum_master.app;
import java.io.IOException;
public class Application {
public static void main(String[] args) throws IOException {
new FirstRunnableProcess().run(null);
new SecondRunnableProcess().run(null);
}
}
Aspect:
Here you just bind the target() object to a parameter in the pointcut and use it in both advices.
package de.scrum_master.aspect;
import static org.slf4j.LoggerFactory.getLogger;
import org.slf4j.Logger;
import de.scrum_master.app.RunnableProcess;
import java.util.Map;
public privileged aspect ProcessRunInterceptorProtocol {
pointcut runProcess(RunnableProcess process) :
call(void RunnableProcess.run(Map)) && target(process);
before(RunnableProcess process): runProcess(process) {
Logger logger = getLogger(process.getClass());
logger.info("logger = " + logger);
logger.info("running process = " + thisJoinPoint);
}
after(RunnableProcess process): runProcess(process) {
Logger logger = getLogger(process.getClass());
logger.info("finished process = " + thisJoinPoint);
logger.info("result = " + process.result);
}
}
Console log with JDK logging (some noise removed):
INFORMATION: logger = org.slf4j.impl.JDK14LoggerAdapter(de.scrum_master.app.FirstRunnableProcess)
INFORMATION: running process = call(void de.scrum_master.app.FirstRunnableProcess.run(Map))
I am #1
INFORMATION: finished process = call(void de.scrum_master.app.FirstRunnableProcess.run(Map))
INFORMATION: result = first
INFORMATION: logger = org.slf4j.impl.JDK14LoggerAdapter(de.scrum_master.app.SecondRunnableProcess)
INFORMATION: running process = call(void de.scrum_master.app.SecondRunnableProcess.run(Map))
I am #2
INFORMATION: finished process = call(void de.scrum_master.app.SecondRunnableProcess.run(Map))
INFORMATION: result = second

How to write AspectJ AOP expression for this method?

I have tried many combinations but I am unable to invoke callback before execution of following method
#SomeAnnotation(...)
#Override
public void someMethod(Serializable id) {
}
I have tried many combinations similar to
#Before("execution(#com.full.name.of.SomeAnnotation * com.full.name.of.Class.someMethod(java.io.Serializable))")
public void beforeMethod() {
System.out.println("I am here.");
}
If I write a more generic expession, it hits the beforeMethod but I am unable to target a single specific method. What am I missing here?
Okay guys, let me prove that the pointcut actually works as written by the original poster Haris Hasan.
Sample annotation:
package com.full.name.of;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface SomeAnnotation {
int id();
String name();
}
Sample class using the annotation:
package com.full.name.of;
import java.io.Serializable;
public class Class {
#SomeAnnotation(id = 1, name = "John Doe")
public void someMethod(Serializable s) {}
public static void main(String[] args) {
new Class().someMethod("x");
}
}
Sample aspect with Haris Hasan's exact pointcut:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class SampleAspect {
#Before("execution(#com.full.name.of.SomeAnnotation * com.full.name.of.Class.someMethod(java.io.Serializable))")
public void yetAnotherPointcut(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
Console output:
execution(void com.full.name.of.Class.someMethod(Serializable))
Copy and paste everything exactly as is, then run it. Quod erat demonstrandum.
The expression below should work:
#Before("com.full.name.of.Class.someMethod(..) && args(java.io.Serializable)")
Correction by kriegaex:
#Before("execution(* com.full.name.of.Class.someMethod(*)) && args(java.io.Serializable)")
A few points worth considering: Is the method being advised public? Are you using cglib proxies or jdk proxies? Does your class implement any interface and is the method being advised declared in the interface contract?
Also do take a look at what spring doc has to say about writing good pointcuts
Hope this helps.
Why do you not just use
#Before("execution(* com.full.name.of.Class.someMethod(java.io.Serializable))")
That specifically targets the method you want, you do not need to put the annotation to specify the target

AspectJ - Multiple #annotation Pointcut

I can't make a pointcut with "||" operator and multiple annotations. I'm trying to create a Pointcut for some JBehave annotations (#Given, #Then, #When).
This works fine:
#Pointcut("#annotation(given)")
public void jBehaveGivenPointcut(Given given) { }
and if I create and advice arount it, it also works.
What would be the syntax for making the Pointcut for the three annotations? Since I had used the logical OR operator in other pointcuts I would assume it is something like:
#Pointcut("#annotation(given) || #annotation(then) || #annotation(when) ")
public void jBehaveGivenPointcut(Given given, Then then, When when) { }
but it doesn't work, I get an inconsist binding exception. I tried other combinations but couldn't find the one that does the trick.
What you want cannot be done this way because, as the error message says, the annotation binding is inconsistent: You cannot bind all three annotations at the same time because they are in (possibly mutually exclusive) OR parts of the pointcut, i.e. usually only of of them can be bound (unless you assign multiple annotations to the same method). Your expectation might be that AspectJ can deal with this inconsistency by just assigning null to the other two if one is bound, but this is not how the compiler works right now.
I can offer a workaround which involves reflection instead of using the #annotation() binding.
Driver application:
package de.scrum_master.app;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;
public class Application {
public static void main(String[] args) {
doGiven("foo");
doSomething("bar");
doWhen(11);
doSomethingElse(22);
doThen();
}
#Given("an input value") public static void doGiven(String string) {}
#When("I do something") public static void doWhen(int i) {}
#Then("I should obtain a result") public static boolean doThen() { return true; }
public static void doSomething(String string) {}
public static void doSomethingElse(int i) {}
}
Aspect:
package de.scrum_master.aspect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
#Aspect
public class JBehaveInterceptor {
#Pointcut("execution(#org.jbehave.core.annotations.* * *(..))")
public void jBehavePointcut() {}
#Before("jBehavePointcut()")
public void jBehaveAdvice(JoinPoint.StaticPart thisJoinPointStaticPart) {
Method method = ((MethodSignature) thisJoinPointStaticPart.getSignature()).getMethod();
for (Annotation jBehaveAnnotation : method.getAnnotations()) {
if (jBehaveAnnotation.annotationType().getPackage().getName().equals("org.jbehave.core.annotations"))
System.out.println(thisJoinPointStaticPart + " -> " + jBehaveAnnotation);
}
}
}
As you can see, the pointcut only intercepts methods annotated by org.jbehave.core.annotations.* which narrows down pointcut matching considerably - to more than just #Given, #When, #Then, but maybe that is even what you want because JBehave offers more annotations than just those.
In the advice we loop over all method annotations because there might be more than just the JBehave ones. If any annotation package name matches the corresponding JBehave package, we do something (in this case print the annotation to standard output).
I hope this solves your problem. I cannot extend the AspectJ language for you, this is the best I can think of. Anyway, this yields the following output:
execution(void de.scrum_master.app.Application.doGiven(String)) -> #org.jbehave.core.annotations.Given(priority=0, value=an input value)
execution(void de.scrum_master.app.Application.doWhen(int)) -> #org.jbehave.core.annotations.When(priority=0, value=I do something)
execution(boolean de.scrum_master.app.Application.doThen()) -> #org.jbehave.core.annotations.Then(priority=0, value=I should obtain a result)
This works:
#Component
#Aspect
#RequiredArgsConstructor
public class PermissionAspect {
#Pointcut("#annotation(org.springframework.web.bind.annotation.GetMapping)")
public void getMapping(){}
#Pointcut("#annotation(org.springframework.web.bind.annotation.PostMapping)")
public void postMapping(){}
#Pointcut("#annotation(org.springframework.web.bind.annotation.PutMapping)")
public void putMapping(){}
#Pointcut("#annotation(org.springframework.web.bind.annotation.DeleteMapping)")
public void deleteMapping(){}
#Around("(execution(* xx.*.controller.*.*(..))) && (getMapping() || postMapping() || putMapping() || deleteMapping())")
Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

Categories