com.fitbur.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker Maven / Gradle / Ivy
The newest version!
package com.fitbur.mockito.internal.creation.bytebuddy;
import com.fitbur.mockito.exceptions.base.MockitoException;
import com.fitbur.mockito.internal.InternalMockHandler;
import com.fitbur.mockito.internal.configuration.plugins.Plugins;
import com.fitbur.mockito.internal.creation.bytebuddy.MockMethodInterceptor.MockAccess;
import com.fitbur.mockito.internal.creation.instance.Instantiator;
import com.fitbur.mockito.invocation.MockHandler;
import com.fitbur.mockito.mock.MockCreationSettings;
import com.fitbur.mockito.mock.SerializableMode;
import com.fitbur.mockito.plugins.MockMaker;
import java.lang.reflect.Modifier;
import static com.fitbur.mockito.internal.util.StringJoiner.join;
public class ByteBuddyMockMaker implements MockMaker {
private final CachingMockBytecodeGenerator cachingMockBytecodeGenerator;
public ByteBuddyMockMaker() {
cachingMockBytecodeGenerator = new CachingMockBytecodeGenerator();
}
@Override
public T createMock(MockCreationSettings settings, MockHandler handler) {
Class mockedProxyType = createProxyClass(mockWithFeaturesFrom(settings));
Instantiator instantiator = Plugins.getInstantiatorProvider().getInstantiator(settings);
T mockInstance = null;
try {
mockInstance = instantiator.newInstance(mockedProxyType);
MockAccess mockAccess = (MockAccess) mockInstance;
mockAccess.setMockitoInterceptor(new MockMethodInterceptor(asInternalMockHandler(handler), settings));
return ensureMockIsAssignableToMockedType(settings, mockInstance);
} catch (ClassCastException cce) {
throw new MockitoException(join(
"ClassCastException occurred while creating the mockito mock :",
" class to mock : " + describeClass(mockedProxyType),
" created class : " + describeClass(settings.getTypeToMock()),
" proxy instance class : " + describeClass(mockInstance),
" instance creation by : " + instantiator.getClass().getSimpleName(),
"",
"You might experience classloading issues, please ask the mockito mailing-list.",
""
),cce);
} catch (com.fitbur.mockito.internal.creation.instance.InstantiationException e) {
throw new MockitoException("Unable to create mock instance of type '" + mockedProxyType.getSuperclass().getSimpleName() + "'", e);
}
}
Class createProxyClass(MockFeatures mockFeatures) {
return cachingMockBytecodeGenerator.get(mockFeatures);
}
private MockFeatures mockWithFeaturesFrom(MockCreationSettings settings) {
return MockFeatures.withMockFeatures(
settings.getTypeToMock(),
settings.getExtraInterfaces(),
settings.getSerializableMode() == SerializableMode.ACROSS_CLASSLOADERS
);
}
private T ensureMockIsAssignableToMockedType(MockCreationSettings settings, T mock) {
// Force explicit cast to mocked type here, instead of
// relying on the JVM to implicitly cast on the client call site.
// This allows us to catch earlier the ClassCastException earlier
Class typeToMock = settings.getTypeToMock();
return typeToMock.cast(mock);
}
private static String describeClass(Class> type) {
return type == null ? "null" : "'" + type.getCanonicalName() + "', loaded by classloader : '" + type.getClassLoader() + "'";
}
private static String describeClass(Object instance) {
return instance == null ? "null" : describeClass(instance.getClass());
}
@Override
public MockHandler getHandler(Object mock) {
if (!(mock instanceof MockAccess)) {
return null;
}
return ((MockAccess) mock).getMockitoInterceptor().getMockHandler();
}
@Override
public void resetMock(Object mock, MockHandler newHandler, MockCreationSettings settings) {
((MockAccess) mock).setMockitoInterceptor(
new MockMethodInterceptor(asInternalMockHandler(newHandler), settings)
);
}
@Override
public TypeMockability isTypeMockable(final Class> type) {
return new TypeMockability() {
@Override
public boolean mockable() {
return !type.isPrimitive() && !Modifier.isFinal(type.getModifiers());
}
@Override
public String nonMockableReason() {
//TODO SF does not seem to have test coverage. What is the expected value when type mockable
if(type.isPrimitive()) {
return "primitive type";
}
if(Modifier.isFinal(type.getModifiers())) {
return "final or anonymous class";
}
return join("not handled type");
}
};
}
private static InternalMockHandler asInternalMockHandler(MockHandler handler) {
if (!(handler instanceof InternalMockHandler)) {
throw new MockitoException(join(
"At the moment you cannot provide own implementations of MockHandler.",
"Please see the javadocs for the MockMaker interface.",
""
));
}
return (InternalMockHandler) handler;
}
}