import lombok.NonNull;
@Test
void methodNameWithNullArgumentThrowException() {
try {
instance.getAnyType(null);
fail("Exception not thrown");
} catch (final NullPointerException e) {
assertNotNull(e);
}
}
@TestUnitRepeatOnce
void methodNameWithNullArgumentThrowException() {
assertThrows(NullPointerException.class, () -> instance.getAnyType(null));
}
exception.getCause().getMessage().equals(parameter.getName())
@TestUnitRepeatOnce
@SneakyThrows
void nonNullAnnotationTest() {
assertNonNullAnnotation(YourPerfectClass.class);
}
private List<Method> getPublicMethods(final Class clazz) {
return Arrays.stream(clazz.getDeclaredMethods())
.filter(METHOD_FILTER)
.collect(toList());
}
if (method.getParameterCount() == 0) {
continue;
}
int nonNullAnnotationCount = 0;
int index = 0;
val parameterCurrentMethodArray = method.getParameters();
val notNullAnnotationParameterMap = new HashMap<Integer, Boolean>();
for (val parameter : parameterCurrentMethodArray) {
if (isNull(parameter.getAnnotation(Nullable.class)) && isFalse(parameter.getType().isPrimitive())) {
notNullAnnotationParameterMap.put(index++, true);
nonNullAnnotationCount++;
} else {
notNullAnnotationParameterMap.put(index++, false);
}
}
if (nonNullAnnotationCount == 0) {
continue;
}
if (nonNullAnnotationCount == 0) {
continue;
}
if (ONLY_ONE_PRIVATE_CONSTRUCTOR_FILTER.test(clazz)) {
notNullAnnotationParameterMap.put(currentNullableIndex, false);
method.invoke(clazz, invokeMethodParameterArray);
makeErrorMessage(method);
}
val invokeMethodParameterArray = new Object[parameterCurrentMethodArray.length];
boolean hasNullParameter = false;
int currentNullableIndex = 0;
for (int i = 0; i < invokeMethodParameterArray.length; i++) {
if (notNullAnnotationParameterMap.get(i) && isFalse(hasNullParameter)) {
currentNullableIndex = i;
invokeMethodParameterArray[i] = null;
hasNullParameter = true;
} else {
mappingParameter(parameterCurrentMethodArray[i], invokeMethodParameterArray, i);
}
}
if (INTERFACE_FILTER.test(clazz)) {
notNullAnnotationParameterMap.put(currentNullableIndex, false);
method.invoke(createInstanceByDynamicProxy(clazz, invokeMethodParameterArray), invokeMethodParameterArray);
makeErrorMessage(method);
}
private Object createInstanceByDynamicProxy(final Class clazz, final Object[] invokeMethodParameterArray) {
return newProxyInstance(
currentThread().getContextClassLoader(),
new Class[]{clazz},
(proxy, method1, args) -> {
Constructor<Lookup> constructor = Lookup.class
.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
constructor.newInstance(clazz)
.in(clazz)
.unreflectSpecial(method1, clazz)
.bindTo(proxy)
.invokeWithArguments(invokeMethodParameterArray);
return null;
}
);
}
if (isAbstract(clazz.getModifiers())) {
createInstanceByCGLIB(clazz, method, invokeMethodParameterArray);
makeErrorMessage();
}
private void mappingParameter(final Parameter parameter, final Object[] methodParam, final int index)
throws InstantiationException, IllegalAccessException {
if (isFinal(parameter.getType().getModifiers())) {
if (parameter.getType().isEnum()) {
methodParam[index] = Enum.valueOf(
(Class<Enum>) (parameter.getType()),
parameter.getType().getEnumConstants()[0].toString()
);
} else if (parameter.getType().isPrimitive()) {
mappingPrimitiveName(parameter, methodParam, index);
} else if (parameter.getType().getTypeName().equals("byte[]")) {
methodParam[index] = new byte[0];
} else {
methodParam[index] = parameter.getType().newInstance();
}
} else {
methodParam[index] = mock(parameter.getType());
}
}
val firstFindConstructor = clazz.getConstructors()[0];
val constructorParameterArray = new Object[firstFindConstructor.getParameters().length];
for (int i = 0; i < constructorParameterArray.length; i++) {
mappingParameter(firstFindConstructor.getParameters()[i], constructorParameterArray, i);
}
notNullAnnotationParameterMap.put(currentNullableIndex, false);
createAndInvoke(clazz, method, invokeMethodParameterArray, firstFindConstructor, constructorParameterArray);
makeErrorMessage(method);
method.invoke(spy(clazz.getConstructors()[0].newInstance()), invokeMethodParameterArray);
method.invoke(spy(clazz.getConstructors()[0].newInstance()), invokeMethodParameterArray);
public class TestUtil {
private static final Predicate<Method> METHOD_FILTER = method ->
isPublic(method.getModifiers())
&& isFalse(method.isSynthetic())
&& isFalse(isAbstract(method.getModifiers()))
&& isFalse(method.getName().equals("equals"));
private static final Predicate<Class> ONLY_ONE_PRIVATE_CONSTRUCTOR_FILTER = clazz ->
clazz.getConstructors().length == 0 && isFalse(clazz.isInterface());
private static final Predicate<Class> INTERFACE_FILTER = clazz ->
clazz.getConstructors().length == 0;
private static final BiPredicate<Exception, Parameter> LOMBOK_ERROR_FILTER =
(exception, parameter) -> isNull(exception.getCause().getMessage())
|| isFalse(exception.getCause().getMessage().equals(parameter.getName()));
protected void assertNonNullAnnotation(final Class clazz) throws Throwable {
for (val method : getPublicMethods(clazz)) {
if (method.getParameterCount() == 0) {
continue;
}
int nonNullAnnotationCount = 0;
int index = 0;
val parameterCurrentMethodArray = method.getParameters();
val notNullAnnotationParameterMap = new HashMap<Integer, Boolean>();
for (val parameter : parameterCurrentMethodArray) {
if (isNull(parameter.getAnnotation(Nullable.class)) && isFalse(parameter.getType().isPrimitive())) {
notNullAnnotationParameterMap.put(index++, true);
nonNullAnnotationCount++;
} else {
notNullAnnotationParameterMap.put(index++, false);
}
}
if (nonNullAnnotationCount == 0) {
continue;
}
for (int j = 0; j < nonNullAnnotationCount; j++) {
val invokeMethodParameterArray = new Object[parameterCurrentMethodArray.length];
boolean hasNullParameter = false;
int currentNullableIndex = 0;
for (int i = 0; i < invokeMethodParameterArray.length; i++) {
if (notNullAnnotationParameterMap.get(i) && isFalse(hasNullParameter)) {
currentNullableIndex = i;
invokeMethodParameterArray[i] = null;
hasNullParameter = true;
} else {
mappingParameter(parameterCurrentMethodArray[i], invokeMethodParameterArray, i);
}
}
try {
if (ONLY_ONE_PRIVATE_CONSTRUCTOR_FILTER.test(clazz)) {
notNullAnnotationParameterMap.put(currentNullableIndex, false);
method.invoke(clazz, invokeMethodParameterArray);
makeErrorMessage(method);
}
if (INTERFACE_FILTER.test(clazz)) {
notNullAnnotationParameterMap.put(currentNullableIndex, false);
method.invoke(createInstanceByDynamicProxy(clazz, invokeMethodParameterArray), invokeMethodParameterArray);
makeErrorMessage(method);
}
if (isAbstract(clazz.getModifiers())) {
createInstanceByCGLIB(clazz, method, invokeMethodParameterArray);
makeErrorMessage();
}
val firstFindConstructor = clazz.getConstructors()[0];
val constructorParameterArray = new Object[firstFindConstructor.getParameters().length];
for (int i = 0; i < constructorParameterArray.length; i++) {
mappingParameter(firstFindConstructor.getParameters()[i], constructorParameterArray, i);
}
notNullAnnotationParameterMap.put(currentNullableIndex, false);
createAndInvoke(clazz, method, invokeMethodParameterArray, firstFindConstructor, constructorParameterArray);
makeErrorMessage(method);
} catch (final Exception e) {
if (LOMBOK_ERROR_FILTER.test(e, parameterCurrentMethodArray[currentNullableIndex])) {
makeErrorMessage(method);
}
}
}
}
}
@SneakyThrows
private void createAndInvoke(
final Class clazz,
final Method method,
final Object[] invokeMethodParameterArray,
final Constructor firstFindConstructor,
final Object[] constructorParameterArray
) {
if (firstFindConstructor.getParameters().length == 0) {
method.invoke(spy(clazz.getConstructors()[0].newInstance()), invokeMethodParameterArray);
} else {
method.invoke(spy(clazz.getConstructors()[0].newInstance(constructorParameterArray)), invokeMethodParameterArray);
}
}
@SneakyThrows
private void createInstanceByCGLIB(final Class clazz, final Method method, final Object[] invokeMethodParameterArray) {
MethodInterceptor handler =
(obj, method1, args, proxy) -> proxy.invoke(clazz, args);
if (clazz.getConstructors().length > 0) {
val firstFindConstructor = clazz.getConstructors()[0];
val constructorParam = new Object[firstFindConstructor.getParameters().length];
for (int i = 0; i < constructorParam.length; i++) {
mappingParameter(firstFindConstructor.getParameters()[i], constructorParam, i);
}
for (val constructor : clazz.getConstructors()) {
if (constructor.getParameters().length == 0) {
val proxy = Enhancer.create(clazz, handler);
method.invoke(proxy.getClass().newInstance(), invokeMethodParameterArray);
}
}
}
}
private Object createInstanceByDynamicProxy(final Class clazz, final Object[] invokeMethodParameterArray) {
return newProxyInstance(
currentThread().getContextClassLoader(),
new Class[]{clazz},
(proxy, method1, args) -> {
Constructor<Lookup> constructor = Lookup.class
.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
constructor.newInstance(clazz)
.in(clazz)
.unreflectSpecial(method1, clazz)
.bindTo(proxy)
.invokeWithArguments(invokeMethodParameterArray);
return null;
}
);
}
private void makeErrorMessage() {
fail("Тестирование аннотации @NonNull в Абстрактных классах без DefaultConstructor не поддерживается");
}
private void makeErrorMessage(final Method method) {
fail("Параметр в публичном методе " + method.getName() + " не аннотирован @NonNull");
}
private List<Method> getPublicMethods(final Class clazz) {
return Arrays.stream(clazz.getDeclaredMethods())
.filter(METHOD_FILTER)
.collect(toList());
}
private void mappingParameter(final Parameter parameter, final Object[] methodParam, final int index)
throws InstantiationException, IllegalAccessException {
if (isFinal(parameter.getType().getModifiers())) {
if (parameter.getType().isEnum()) {
methodParam[index] = Enum.valueOf(
(Class<Enum>) (parameter.getType()),
parameter.getType().getEnumConstants()[0].toString()
);
} else if (parameter.getType().isPrimitive()) {
mappingPrimitiveName(parameter, methodParam, index);
} else if (parameter.getType().getTypeName().equals("byte[]")) {
methodParam[index] = new byte[0];
} else {
methodParam[index] = parameter.getType().newInstance();
}
} else {
methodParam[index] = mock(parameter.getType());
}
}
private void mappingPrimitiveName(final Parameter parameter, final Object[] methodParam, final int index) {
val name = parameter.getType().getName();
if ("long".equals(name)) {
methodParam[index] = 0L;
} else if ("int".equals(name)) {
methodParam[index] = 0;
} else if ("byte".equals(name)) {
methodParam[index] = (byte) 0;
} else if ("short".equals(name)) {
methodParam[index] = (short) 0;
} else if ("double".equals(name)) {
methodParam[index] = 0.0d;
} else if ("float".equals(name)) {
methodParam[index] = 0.0f;
} else if ("boolean".equals(name)) {
methodParam[index] = false;
} else if ("char".equals(name)) {
methodParam[index] = 'A';
}
}
}
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${compile.target.source}</source/>
<target>${compile.target.source}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<compilerArgs><arg>-parameters</arg></compilerArgs>
</configuration>
</plugin>
<compilerArgs><arg>-parameters</arg></compilerArgs>
К сожалению, не доступен сервер mySQL