I am attempting to wrap a service in a proxy to simulate lag during tests. The following class is meant to wrap an object and sleep the thread for 100ms for any invoked method.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class SleepyProxy<T> implements InvocationHandler {
private T wrapped;
private SleepyProxy(T toWrap) {
this.wrapped = toWrap;
}
#SuppressWarnings({"unchecked", "rawtypes"})
public static <T> T createProxy(T toWrap) {
Object proxy = Proxy.newProxyInstance(
toWrap.getClass().getClassLoader(),
toWrap.getClass().getInterfaces(),
new SleepyProxy(toWrap));
return (T) proxy;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(wrapped, args);
nap();
return result;
}
private void nap() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
From my test class:
private MyService service = SleepyProxy.createProxy(ServiceProvider.getMyService());
Produces the following error:
java.lang.ClassCastException: com.sun.proxy.$Proxy33 cannot be cast to com.example.service.MyService;
Please Note:
I am using Spring Framework and JUnit4
Test class annotated with #RunWith(SpringJUnit4ClassRunner.class)
I'm learning Spring; I'm unsure if I need to be using a Spring InvocationHandler / Proxy service
Why am I having issues casting to MyService? All object values seem to line up when debugging. Is there a better way I can go about simulating lag on my services? (Aside from making a 'test service' for each).
Thanks for your help!
Problem is that MyService is a class, and Proxy.newProxyInstance creates object that implements interface you provide in second argument. To have it working MyService needs to implement interface so:
class MyService implements ServiceInterface
And later use your proxy like this:
ServiceInterface service = SleepyProxy.createProxy(ServiceProvider.getMyService());
Proxy.newProxyInstance has nothing to do with MyService class, it will only create object that will run InvocationHandler.invoke when you will call method on it.
Related
I'm quite new to spring (switching from PHP to Java).
In my code I have a java.lang.reflect.Method objects and I need to instantiate it's class with all it's dependencies.
Normally I'd use #Autowired annotation in my code, but it's not possible because my code gets different Method objects, not specific classes.
Question is - how to get a class instance from dependency container without using annotations and having just class name?
In php i used libraries which gave me access to container and I could just get DI services by it's class name just like:
$this->container->get('My\Class\Name');
In spring I tried:
#Autowired
private ApplicationContext context;
void myMethod(Method method){
this.context.getBean(method.getClass());
and
this.context.getBean(method.getClass().getName());
and that was resulting in NullPointerException.
EDIT
Thanks for quick replys,
I tried using
context.getBean(method.getDeclaringClass());
and
context.getBean(method.getDeclaringClass().getSimpleName());
And it both resulted in NullPointerException as well.
Actually it's okay for my needs to get that class by class or by name. I'm trying to write my own command bus for CQRS.
Let me show you some code:
Handler:
public class SimpleCommandBus implements CommandBus {
#Autowired
private ApplicationContext context;
private Map<Class, Method> registry = new HashMap<>();
#Override
public void register(Class c, Method o) {
registry.put(c, o);
}
#Override
public void dispatch(Object command) {
if (!registry.containsKey(command.getClass())) {
throw new CommandDispatchException(String.format("Handler for command %s was not defined.", command));
}
Method method = registry.get(command.getClass());
Object handler = context.getBean(method.getDeclaringClass().getSimpleName());//line causing exception
Service class:
#Service
public class TestHandler {
public void handle(TestCommand command){
System.err.println(command.getId());
}
}
Calling command bus:
Method method = TestHandler.class.getMethod("handle", TestCommand.class);
TestCommand command = new TestCommand("Test command");
commandBus.register(TestCommand.class, method);
commandBus.dispatch(command);
Use java.lang.reflect.Method.getDeclaringClass() to find in which class the given method is declared. method.getClass() will return the type of method object which is java.lang.reflect.Method.
#Autowired
AplicationContext ctx;
...
Object bean = ctx.getBean(method.getDeclaringClass());
In Spring the default name is the simple name.
Plus as in Karols answer you must use getDeclaringClass() to get the class of the class with the method.
So you must call
this.context.getBean(method.getDeclaringClass().getSimpleName());
I am not so experienced in EJBs, especially EJB 3.0 and thus, I faced out with a question I would like to resolve. A similar issue I have found here, but the suggested solution did not help.
I have a remote stateless EJB with its business methods declared in interface and the bean which implements those methods has also other methods which are not declared in interface.
As an example here is the business interface:
public interface BusinessLogic {
Object create();
void delete(Object x);
}
A BusinessLogicBean which implements the business logic:
#Stateless
#Remote(BusinessLogic.class)
public class BusinessLogicBean implements BusinessLogic {
/** implemented method */
public Object create() {
Object x = new SomeDBMappedObject();
// create an object in DB and return wrapper class
...
return x;
}
/** implemented method */
public void delete(Object x) {
// deleting object from DB
...
}
/** The method that performs some extra logic */
public void aMethod() {
// do extra logic
}
}
I need to write unit tests for that EJB using Arquillian framework including for the bean methods which are not declared in the business interface.
Example:
#RunWith(Arquillian.class)
public class BusinessLogicTest {
/** will be injected during the test run */
#EJB
private BusinessLogic businessLogic;
#Deployment
public static Archive createDeployment() {
WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war")
// add needed libraries and classes
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
return war;
}
#Test
public void aMethodTest() {
businessLogic.aMethod();
// Write appropriate assertions
}
}
My questions are:
how can I call aMethod() in my test?
I cannot call it like businessLogic.aMethod();, since it will result in a compilation error.
I cannot call it like ((BusinessLogicBean) businessLogic).aMethod();, as it will result in a ClassCastException since the actual object is a com.sun.proxy.$ProxyXXX type.
or
Is there a way to inject BusinessLogicBean object directly instead of BusinessLogic?
You can annotate BusinessLogicBean with #javax.ejb.LocalBean
#Stateless
#LocalBean
#Remote(BusinessLogic.class)
public class BusinessLogicBean implements BusinessLogic {
...
}
and inject it by its class name:
#EJB BusinessLogicBean businessLogicBean;
See also:
Docs
A useful related question
Here is my custom annotation AnnoLogExecTime and class AOP:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface AnnoLogExecTime {
}
#Aspect
#Service
public class AOP {
Logger logger = LoggerFactory.getLogger(AOP.class);
#Around("execution(#com.judking.general.aop.AnnoLogExecTime * *(..))")
public Object calExecTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
long t1 = System.currentTimeMillis();
Object obj = proceedingJoinPoint.proceed();
long t2 = System.currentTimeMillis();
logger.info("method `"+method.getName()+"` takes "+(t2-t1)+"ms");
return obj;
}
}
And the test case is as below:
#Service
class A {
public void go() {
B b = new B() { //Anonymous class B
#Override
public void exec() {
aopMethod();
}
};
b.exec();
}
#AnnoLogExecTime
public void aopMethod() {
System.out.println("aopMethod");
}
}
#Service
class B {
public void exec() {
System.out.println("exec");
}
}
When I call a.aopMethod(), the AOP.calExecTime is hooked up to a.aopMethod().
But if I call a.go(), which is using anonymous class B instance to call a.aopMethod(), then the AOP.calExecTime is NOT hooked up to a.aopMethod().
Could anyone give me an explanation to this phenomenon? And please give me a way to resolve this problem in the case of anonymous class. Thanks a lot!
This is not exactly because it is an anonymous inner class. What you are experiencing is a limitation of AOP proxies.
When you have
A a = ...; // get proxy
The proxy itself wraps the actual instance in a wrapper instance. When you interact with this wrapper instance by calling
a.aopMethod();
the proxy interceptor intercepts the call and can execute the advice.
This would apply to you calling
a.go()
if there was a joinpoint. Instead nothing intercepts that call, and the call to go() goes through the interceptor and the method is called on the actual instance
actualA.go();
When you create the anonymous inner class and have
#Override
public void exec() {
aopMethod();
}
it's implicitly doing
#Override
public void exec() {
A.this.aopMethod();
}
which goes around the proxy because you are calling it on the actual instance, not the wrapper.
You might not be using Spring to generate your proxies, but their documentation explains this pretty well.
For an integration test, I need to mock a specific method in a java service client without destroying the rest of the information in it. It has no self-constructor, so a solution like this is out of the question:
private DBClient mockClient = new DBClient(alreadyExistingClient){
#Override
void deleteItem(Item i){
//my stuff goes here
}
};
Is there a way to mock the deleteItem method such that the credentials, endpoints, etc... are preserved in an existing DBClient object?
edit: mockito is not available for use in this case
You can use a Dynamic Proxy to intercept any method invocation you want, so you can decide between invoking the real method or do whatever you want instead.
This is an example of how to intercept the method Set.add(), you can do exactly the same for deleteItem()
package example.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Set;
public class SetProxyFactory {
public static Set<?> getSetProxy(final Set<?> s) {
final ClassLoader classLoader = s.getClass().getClassLoader();
final Class<?>[] interfaces = new Class[] {Set.class};
final InvocationHandler invocationHandler = new InvocationHandler() {
#Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
if (method.getName().equals("add")) {
System.out.println("add() intercepted");
// do/return whatever you want
}
// or invoke the real method
return method.invoke(s, args);
}
};
final Object proxy = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return (Set<?>) proxy;
}
}
You could go lo-fi and create a sub-class of the DBClient class. To this subclass, pass the instance of DBClient you want to mock.
Use composition inside the sub-class, and delegate all method calls to the original DBClient, all except the one you want to mock. Add your mock implementation to the method you want.
This is not as reusable as a mocking framework, but should work.
DBClient mockDbClient = new DBClient() {
private DBClient dbClientDelegate;
public void setDelegate(DBClient dbClient) {
dbClientDelegate = dbClient;
}
//override all methods.
//delegate to the corresponding method of the dbClientDelegate instance
//overide the method you want to mock, add asserts for method arguments
//return mock data as appropriate
}
mockDbClient.setDelegate(preinstantiatedDbClient);
//inject mockDbClient to test class
//call test class / method
Hope this helps.
In Mockito 2+ you can use spy feature for this purpose:
PrintStream realSystemOut = System.out;
realSystemOut.println("XXX");
PrintStream mockedSystemOut = Mockito.spy(realSystemOut);
Mockito.doNothing().when(mockedSystemOut).println(Mockito.anyString());
mockedSystemOut.println("YYY");
Output:
XXX
I have a class with a constructor, e.g.:
#Inject
public ClassTest(ITestInterface testInterface, Class<?> clazz){
...
}
The problem is how do I bind a class to an implementation which can be injected in this constructor and will the ClassTest binding pick the right class?
I want to inject different classes at different point of time. When I attempted to solve it Guice gives an error that it cannot find any suitable constructor on java.lang.Class.
I think you have to use assisted inject extension of Guice.
Basically, you define your ClassTest as it is, but mark 'varying' dependencies as #Assisted:
#Inject
public ClassTest(ITestInterface testInterface, #Assisted Class<?> clazz){
...
}
Then you create a factory interface for ClassTest objects which will accept Class argument and return ClassTests:
public interface ClassTestFactory {
ClassTest create(Class<?> clazz);
}
Then you install special kind of module which will create factories for you:
// Inside your module
install(new FactoryModuleBuilder().build(ClassTestFactory.class));
Then wherever you need ClassTest instances you should inject ClassTestFactory interface instead:
#Inject
YourLogicClass(ClassTestFactory ctFactory) {
this.ctFactory = ctFactory;
}
And finally you use it to create ClassTests for every class object you want:
ClassTest ct1 = ctFactory.create(SomeClass.class);
ClassTest ct2 = ctFactory.create(AnotherClass.class);
But if I were you, I would really reconsider the whole class architecture to avoid the need in such things.
This can be solved even without assisted inject, simply by using a TypeLiteral when creating the binding:
import javax.inject.Inject;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
public class ClassTest
{
static interface ITestInterface {}
#Inject
public ClassTest(ITestInterface testInterface, Class<?> clazz)
{
System.err.println("testInterface=" + testInterface);
System.err.println("clazz=" + clazz);
}
public static void main(String... argument)
{
ITestInterface testObject = new ITestInterface() {};
Module module = new AbstractModule()
{
#Override
protected void configure()
{
binder().bind(ITestInterface.class).toInstance(testObject);
binder().bind(new TypeLiteral<Class<?>>() {}).toInstance(testObject.getClass());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
};
Injector injector = Guice.createInjector(module);
injector.getInstance(ClassTest.class);
}
}
The output when running this code is something like:
testInterface=ClassTest$1#3d921e20
clazz=class ClassTest$1
I have to agree with #VladimirMatveev though, that this is a somewhat unusual use case, and that the need for injection of java.lang.Class objects might be indicative of a design flaw. The only seemingly valid case of this type of injection that I've come across is for type checking, where an injected class needs the Class object to check the type of some other object (via Class.isInstance(...)) but it is not desirable to inject an instance (!) of that class (e.g., because it is not a singleton and might spawn all sorts of other undesired object creations). Still, even that scenario is somewhat hokey and might be solvable in a better way.
At the very least, I would use a more specific type argument, like Class<? extends ITestInterface> (which, I suspect, is what's intended by the OP).
To change injected value over time you could use the Provider bindings. And then it could look like this:
The module configuration:
public class SomeModule extends AbstractModule{
#Override
protected void configure() {
bind(Class.class).toProvider(SomeProvider.class);
}
}
The provider(not very elegant but may be for a start...):
public class SomeProvider implements Provider<Class<?>>{
private static Class<?> myClazz;
public static void setClass(Class<?> clazz){
myClazz = clazz;
}
#Override
public Class<?> get() {
return myClazz;
}
}
Some different classes:
public class SomeClass{
public int itWorks;
}
public class SomeOtherClass{
public int itWorksGreat;
}
Example client code:
public static void main(String[] args){
SomeProvider.setClass(SomeClass.class);
Injector injector = Guice.createInjector(new SomeModule());
printFields(injector.getInstance(Class.class));
SomeProvider.setClass(SomeOtherClass.class);
printFields(injector.getInstance(Class.class));
}
private static void printFields(Class clazz) {
Field[] declaredFields = clazz.getDeclaredFields();
for(Field field : declaredFields){
System.out.println(field.getName());
}
}
And finally the result:
itWorks
itWorksGreat