IDEABKL-6771 Add optional parameter 'exceptionMessage' to @NotNull annotation

This commit is contained in:
VISTALL
2013-04-17 14:11:10 +03:00
parent 33f3792dc3
commit 6eef63fadc
5 changed files with 70 additions and 4 deletions
@@ -34,6 +34,8 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode
private static final String CONSTRUCTOR_NAME = "<init>";
private static final String EXCEPTION_INIT_SIGNATURE = "(L" + STRING_CLASS_NAME + ";)V";
private static final String ANNOTATION_DEFAULT_METHOD = "value";
private static final String NULL_ARG_MESSAGE = "Argument %d for @NotNull parameter of %s.%s must not be null";
private static final String NULL_RESULT_MESSAGE = "@NotNull method %s.%s must not return null";
@@ -65,6 +67,7 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode
private final List<Integer> myNotNullParams = new ArrayList<Integer>();
private int mySyntheticCount = 0;
private boolean myIsNotNull = false;
private String myMessage = null;
private Label myStartGeneratedCodeLabel;
public AnnotationVisitor visitParameterAnnotation(final int parameter, final String anno, final boolean visible) {
@@ -76,7 +79,19 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode
// see http://forge.ow2.org/tracker/?aid=307392&group_id=23&atid=100023&func=detail
mySyntheticCount++;
}
return av;
return new AnnotationVisitor(Opcodes.ASM4, av) {
@Override
public void visit(String methodName, Object o) {
if(ANNOTATION_DEFAULT_METHOD.equals(methodName)) {
String message = (String) o;
if(!message.isEmpty()) {
myMessage = message;
}
}
super.visit(methodName, o);
}
};
}
@Override
@@ -86,7 +101,18 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode
myIsNotNull = true;
}
return av;
return new AnnotationVisitor(Opcodes.ASM4, av) {
@Override
public void visit(String methodName, Object o) {
if(ANNOTATION_DEFAULT_METHOD.equals(methodName)) {
String message = (String) o;
if(!message.isEmpty()) {
myMessage = message;
}
}
super.visit(methodName, o);
}
};
}
@Override
@@ -105,7 +131,7 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode
Label end = new Label();
mv.visitJumpInsn(IFNONNULL, end);
generateThrow(IAE_CLASS_NAME, String.format(NULL_ARG_MESSAGE, param - mySyntheticCount, myClassName, name), end);
generateThrow(IAE_CLASS_NAME, myMessage == null ? String.format(NULL_ARG_MESSAGE, param - mySyntheticCount, myClassName, name) : myMessage, end);
}
}
@@ -124,7 +150,7 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode
mv.visitInsn(DUP);
final Label skipLabel = new Label();
mv.visitJumpInsn(IFNONNULL, skipLabel);
generateThrow(ISE_CLASS_NAME, String.format(NULL_RESULT_MESSAGE, myClassName, name), skipLabel);
generateThrow(ISE_CLASS_NAME, myMessage == null ? String.format(NULL_RESULT_MESSAGE, myClassName, name) : myMessage, skipLabel);
}
}
@@ -0,0 +1,6 @@
import org.jetbrains.annotations.NotNull;
public class ConstructorParamWithMessage {
public ConstructorParamWithMessage(@NotNull("ConstructorParam.ConstructorParam.o cant be null") Object o) {
}
}
@@ -0,0 +1,6 @@
import org.jetbrains.annotations.NotNull;
public class SimpleParamWithMessage {
public void test(@NotNull("SimpleParamWithMessage.test(o) cant be null") Object o) {
}
}
@@ -0,0 +1,8 @@
import org.jetbrains.annotations.NotNull;
public class SimpleReturnWithMessage {
@NotNull("This method cannot return null")
public Object test() {
return null;
}
}
@@ -70,6 +70,13 @@ public class NotNullVerifyingInstrumenterTest extends UsefulTestCase {
verifyCallThrowsException("@NotNull method SimpleReturn.test must not return null", instance, method);
}
public void testSimpleReturnWithMessage() throws Exception {
Class testClass = prepareTest();
Object instance = testClass.newInstance();
Method method = testClass.getMethod("test");
verifyCallThrowsException("This method cannot return null", instance, method);
}
public void testMultipleReturns() throws Exception {
Class testClass = prepareTest();
Object instance = testClass.newInstance();
@@ -84,12 +91,25 @@ public class NotNullVerifyingInstrumenterTest extends UsefulTestCase {
verifyCallThrowsException("Argument 0 for @NotNull parameter of SimpleParam.test must not be null", instance, method, (Object)null);
}
public void testSimpleParamWithMessage() throws Exception {
Class testClass = prepareTest();
Object instance = testClass.newInstance();
Method method = testClass.getMethod("test", Object.class);
verifyCallThrowsException("SimpleParamWithMessage.test(o) cant be null", instance, method, (Object)null);
}
public void testConstructorParam() throws Exception {
Class testClass = prepareTest();
Constructor method = testClass.getConstructor(Object.class);
verifyCallThrowsException("Argument 0 for @NotNull parameter of ConstructorParam.<init> must not be null", null, method, (Object)null);
}
public void testConstructorParamWithMessage() throws Exception {
Class testClass = prepareTest();
Constructor method = testClass.getConstructor(Object.class);
verifyCallThrowsException("ConstructorParam.ConstructorParam.o cant be null", null, method, (Object)null);
}
public void testEnumConstructor() throws Exception {
Class testClass = prepareTest();
Object field = testClass.getField("Value");