I'm writing a lib and I need to create proxies for some objects. Since some classes don't implement any interfaces then I decided to use CGLIB to create proxies instead of JDK proxy. But I faced with situation when some classes don't have default constructor and CGLIB fails to create proxies for those types, i.e. CGLIB throws exception with message: Superclass has no null constructors but no arguments were given. How I can solve this problem, is there some way to add default constructor in runtime using cglib/asm or some another instrument? Thanks.
Use http://objenesis.org/. One of its typical use cases exactly addresses your problem:
Proxies, AOP Libraries and Mock Objects - Classes can be subclassed
without needing to worry about the super() constructor.
I'll just copy and paste the solution from the blog post provided in the comments to another answer to preserve it. It combines Objenesis and CGLIB and it really works.
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.objenesis.ObjenesisHelper;
public class ProxyPlayground {
public static void main(final String[] args) {
final MethodInterceptor hashCodeAlwaysNull = new MethodInterceptor() {
#Override
public Object intercept(final Object object, final Method method,
final Object[] args, final MethodProxy methodProxy)
throws Throwable {
if ("hashCode".equals(method.getName())) {
return 0;
}
return methodProxy.invokeSuper(object, args);
}
};
final Foo proxy = createProxy(Foo.class, hashCodeAlwaysNull);
System.out.println(proxy.hashCode()); // prints 0
}
#SuppressWarnings("unchecked")
private static <T> T createProxy(final Class<Foo> classToMock,
final MethodInterceptor interceptor) {
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(classToMock);
enhancer.setCallbackType(interceptor.getClass());
final Class<?> proxyClass = enhancer.createClass();
Enhancer.registerCallbacks(proxyClass, new Callback[] { interceptor });
return (T) ObjenesisHelper.newInstance(proxyClass);
}
}
It's possible, below code reference from objenesis.
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
Constructor<?> constructor = reflectionFactory.newConstructorForSerialization(YourObject.class, Object.class.getConstructor((Class[]) null));
Object instance = constructor.newInstance();
What you assume to be express as byte code, cannot be done as it would be rejected by the JVM' verifier. As pointed out by the other answer, you should consider using a library such as Objenesis. However, note that Objenesis makes use of JVM-internal APIs what will not longer be possible using Java 9 when project Jigsaw is introduced.
For this reason, you might rather approach the matter differently. Cglib merely copies all constructors of the super class. You want to call any constructor of which you know it is side effect free. Simply pass null values or 0 values for primitives. As long as you intercept all methods, the object state does not matter anyways as none of the real methods are ever invoked.
Related
I know that an instance of a class with a private constructor can be created using reflection but is there any way to make sure that the instance of the class can only be created within the same class using its own private constructor?
Let's take an example of a class Test, with a private constructor.
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Test
{
private Test() //private constructor
{
}
}
public class Sample{
public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
{
Class c=Class.forName("Test"); //specify class name in quotes
//----Accessing private constructor
Constructor con=c.getDeclaredConstructor();
con.setAccessible(true);
Object obj=con.newInstance();
}
}
My question is - is there any way to ensure that the instance of the class can only be created within the same class and not from outside using reflection or any other method?
There are several ways to prevent the creation - but it is hard to tell which one is appropriate for your use-case:
Throw an exception in the constructor
You can either unconditionally throw an exception - making it (near) impossible to instantiate an instance - or only throw under certain conditions.
Some conditions can be:
Inspecting the caller - using StackWalker for example.
Passing a "secret" passphrase to the constructor. JMH does this for example.
Use Java Modules.
As other modules can't deeply reflect into other named modules, Constructor.setAccessible will not work on your class outside of your own module.
Of course this restriction doesn't apply to your own module - but you should be able to control your own module ;).
Install a SecurityManager.
Prevents Constructor.setAccessible from returning successfully.
But the security manager is deprecated for removal, so I can't recommend it's use.
Note: Most of those solutions can be circumvented in some way. And it is sometimes possible to add additional defenses against that. But at the end, it'll become a game of cat and mouse.
One way you already mentioned in comments by using Exception & another way to do this is using Thread.currentThread()
package app.test;
public class Test19 {
..
private Test19() {
if (Thread.currentThread().getStackTrace()[1].getClassName() == "app.test.Test19") {
// initialize member fields etc.
} else {
throw new IllegalAccessException();
}
}
}
I need to write a test for this class. I need to verify that when the size of the list is exactly 2 then the modelService.save is called. Is it also possible to get to the object productModel?
I don't know where to start.
public class SoldMaterialPrepareInterceptor implements PrepareInterceptor<SoldMaterialModel> {
#Resource
private ModelService modelService;
#Override
public void onPrepare(SoldMaterialModel soldMaterialModel, InterceptorContext interceptorContext) throws InterceptorException {
setSAPSubstance(soldMaterialModel);
}
private void setSAPSubstance(SoldMaterialModel soldMaterialModel) {
ProductModel productModel = soldMaterialModel.getBaseProduct();
Set superCatagoriesList = [....]// gets the list somehow
if (superCatagoriesList.size() == 2) {
productModel.setSupercategories(superCatagoriesList);
modelService.save(productModel);
}
}
}
It is not a problem that the modelService field is private, it is a class field for which private access modifier is usually expected. You need to check the invocation of its save() method, which in turn cannot be private, otherwise it would not be possible to call it from the interceptor class.
As for the test, assuming the superCatagoriesList (which is actually a Set and not a List and also should be generic) gets its content directly or indirectly (e.g. through productModel) from the soldMaterialModel parameter, your task is to write a test, which populates soldMaterialModel with such values so that superCatagoriesList.size() will be 2, and then you can verify that the modelService.save() method was called exactly once with e.g. something like
Mockito.verify(modelService).save(any(ProductModel.class));
I found that when it is difficult to test a method most often there is a design problem of the code I am testing. I suggest a minor to refactoring first: move setSAPSubstance to SoldMaterialModel class and make it public. That is where that method needs to be (see feature envy). Of course modelService.save(productModel); will stay in the interceptor and it will be called only if needed.
Then you will only have to test the two public methods
Is that the whole class? Then I think I see the issue. There are no non-private ways to set the ModelService. When the whole app runs, the dependency injection framework uses reflection to set the ModelService. When you run the test, you don't have anyway to inject a mock. You have a few options.
You can add a constructor to SoldMaterialPrepareInterceptor which takes the ModelService as a parameter. Then you can use that in your test. You would probably also have to add a no-argument constructor because that's how your dependency injection framework creates it. Better yet, you could figure out how to configure the framework to use the new constructor that takes the ModelService.
public class SoldMaterialPrepareInterceptor {
// Public constructor if needed for dependency injection
public SoldMaterialPrepareInterceptor () { }
// If just used for test use protected or package private
// If used with dependency injection, use public.
protected SoldMaterialPrepareInterceptor(ModelService modelService){
this.modelService = modelService
}
The test class is usually in the same package as the actual class, so package private or protected scope is enough. Then the test looks something like this (Assuming Mockito and Junit. Logically, Spock and other frameworks would be similar):
ModelService modelService = Mockito.mock(ModelService.class);
SoldMaterialPrepareInterceptor interceptor = new SoldMaterialPrepareInterceptor(modelService);
// setup SoldMaterialModel and InterceptorContext
interceptor.onPrepare(soldMaterialModel, interceptorContext);
Mockito.verify(modelService, Mockito.times(0)).save(soldMaterialModel);
I made a Dynamic Proxy to be the middle man when handling specific methods in a class. I'm doing this to avoid having to override every single method in each of the interfaces that I need to take control of.
Waffley bit that nobody will understand or care about (but may add more context to the question):
In the example I am going to give, I've tried to make it generic so you can compile it to test and run yourself, but in the real situation, I have something like this:
interface CommandSender
interface ConsoleCommandSender extends CommandSender
interface Player extends CommandSender
If I were to make a proxy of a ConsoleCommandSender instance, the resulting proxy SHOULD be castable to a CommandSender. In reality, ConsoleCommandSender doesn't list all of its interfaces with getInterfaces() and this happens:
java.lang.ClassCastException: $Proxy18 cannot be cast to org.bukkit.command.CommandSender
The Player class does not have this issue, and is always castable to CommandSender.
The real question:
So, using the following code as a starting point, how can one successfully cast the proxy denoted by myProxy to the format desired without having to worry about the ClassCastException?
The following code will successfully compile and run, but hopefully you understand what I'm getting at by casting to a List rather than an ArrayList.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
public class ProxyClass implements InvocationHandler {
private Object classProxy;
public static void main(String[] args) {
// Example declaration
// (I know the proxy should really be cast as an ArrayList
// but this is my point, it SHOULD work anyway)
ArrayList methodObject = new ArrayList<String>();
List<String> myProxy = (List<String>)ProxyClass.newInstance(methodObject, false);
// Example usage
myProxy.add("Hello World!");
System.out.println(myProxy.get(0));
}
public static Object newInstance(Object proxy, boolean silent) {
return Proxy.newProxyInstance(
proxy.getClass().getClassLoader(),
proxy.getClass().getInterfaces(),
new ProxyClass(proxy));
}
private ProxyClass(Object proxy) {
this.classProxy = proxy;
}
// Is called whenever a method is invoked
public Object invoke(Object p, Method m, Object[] args) throws Throwable {
return m.invoke(classProxy, args);
}
}
On another thread I made about the preliminary part of this issue, one guy commented saying I could use the <T> variable to add another valid interface to the list. I didn't really understand how to implement this though, but it seemed like a good start.
I am not 100% sure I admit I understood your question -
You want to be able to "directly" cast to ArrayList? I mean -
ArrayList<String> myProxy = (ArrayList<String>)ProxyClass.newInstance(methodObject, false);
This just won't work for you. The reason is that the generated object is not an instant of ArrayList. In a sense the behavior resembles decorator.
Is decorator an instance of the object it decorates? No, they conform to the same interface.
What you should do is consider using CGLIB.
CGLIB let's you create proxies (intercepted objects) for classes.
a Proxied object by CGBLib is indeed an instance of the proxied object.
If I remember correctly, Hibernate uses CGLib and ASM in order to proxy the entity objects,
You can see here a link to some experiments I did with CGLIB.
My factory class has a collection of classes, I don't want that dependency, when I add a subclass of SuperClass I need the factory file to stay unchanged
edit:
My factory class has to return all Superclass's subclasses instances, but I can't have a collections of them (or their names) because that's means I will have to change the Factory file whenever I add a new subclass!
package reflection;
public final class Factory {
private final SuperClass[] subclasses_collection
= {new SubClass1(), new SubClass2() /* ...SubClassN */};
public final SuperClass[] getAllSubClasses() {
return subclasses_collection;
}
}
instead of
new SubClass1()
do something like this
Class clazz = Class.forName("SubClass1");
Object subclass1 = clazz.newInstance();
if you want to pass arguments to the constructor, consult this article, section Creating New Objects
http://java.sun.com/developer/technicalArticles/ALT/Reflection/
To find all the subclasses of a given class, I would check out this java world site. It goes through a package, loads the classes, and tests them to see if there are any subclasses.
If you want to search for all subclasses of a class, you can use reflection, as Jeffrey says. However, rather than writing the code to do that yourself, or copy-and-pasting it from some random article, i would use ResolverUtil from the Stripes web framework, which does exactly what you want (and more!).
An alternative to classpath scanning would be to build up a registry at runtime. You could create a base class like this:
public abstract class SuperClass {
private static final Set<Class<? extends SuperClass>> SUB_CLASSES = new HashSet<Class<? extends SuperClass>>();
/* instance initializer */ {
SUB_CLASSES.put(getClass());
}
}
Every subclass of that which is instantiated will add itself to the set of subclasses. Your factory can then use that set. All you have to do is ensure that all the subclasses are instantiated at some point - perhaps using a configuration file, or through startup actions of other parts of your system.
I have class with a forwarding method foo:
void foo( Concrete c, String s ) { c.bar( s ); }
I wish to test whether foo does, in fact, forward. Unfortunately for me, Concrete is a class in a third-party library, and is a concrete type, not an interface. Thus I must use ClassImposteriser in JMock to mock Concrete, so in my test case, I do this:
#Test
public final void testFoo() {
Mockery context = new JUnit4Mockery() {{
setImposteriser(ClassImposteriser.INSTANCE);
}};
final Concrete c = context.mock(Concrete.class);
final String s = "xxx" ;
// expectations
context.checking(new Expectations() {{
oneOf (c).bar(s); // exception gets thrown from here
}});
new ClassUnderTest.foo( c, s );
context.assertIsSatisfied();
}
Unfortunately, Concrete.bar in turn calls a method that throws. That method is final, so I can't override it. Further, even if I comment out the line new ClassUnderTest.foo( c, s );, the exception is thrown when JMock sets up exceptions, not when foo is called.
So how can I test that method ClassUnderTest.foo does forward to Concrete.bar?
Edit:
Yes, bar is final.
My solution, which is not a general one, was to use a "Tester" class in the third-party library to correctly set up Concrete.
It's not clear from the question text if Concrete.bar() is final or if Concrete.somethingElse() is final and called from Concrete.bar().
If Concrete.bar() is not final, create a hand-written stub for Concrete like this:
public class ConcreteStub extends Concrete
{
public int numCallsToBar = 0;
#Override
public void bar(String s) { numCallsToBar++; }
}
and in your test code:
ConcreteStub c = new ConcreteStub();
foo(c,"abc");
assertEquals(1,c.numCallsToBar);
If Concrete.bar() is final, it is more complicated and the answer depends on the complexity of Concrete and your project's use of the Concrete class. If your use of Concrete is simple enough, I would consider wrapping Concrete in an interface (Adapter Pattern) that you can then mock out easier.
Benefits to the Adapter Pattern solution: Possibly clarify behavior by naming interface after your project's use of Concrete. Easier to test.
Drawbacks to the Adapter Pattern solution: Introduces more classes with possibly little benefit to production code. I don't know what Concrete does and it may not be practical to wrap Concrete in an interface.
See http://www.jmock.org/mocking-classes.html for info about mocking classes and how to bypass final limitations.
If a method is final then we can't do much about it. If this is a third-party library, then we would consider wrapping it in a veneer layer and mocking that, then doing integration tests to test against the library. There are other frameworks that will mock locked-down code, but we don't support it because we don't think it's a great idea.
Use a more capable mocking tool, such as JMockit. Your test could then be written as:
#Test
public void testFoo(final Concrete c)
{
final String s = "xxx";
new Expectations() {{
c.bar(s);
}};
new ClassUnderTest().foo(c, s);
}
For JMockit, it makes no difference if Concrete is an interface, a final class, an abstract class, or whatever. Also, there is no need to use #RunWith, extend a base test class, or call any method like assertIsSatisfied(); it's all done automatically, in a transparent way.