I have a method where a parameter is marked with the #Nonnull annotation. The code which calls the method has to check whether the value is null. Rather than just a straight x != null check, it is calling a utility method on another class. (In the real code, the utility method also checks whether it is a blank String).
My problem is that Intellij Idea is showing an inspection warning on the Nonnull method call, saying that my variable "might be null". I know it cannot be null because of the utility method check - how can I tell the inspector that?
Since that is a bit abstract, here's a minimal example of what I mean:
package org.ethelred.ideatest;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* tests annotations
*/
public class AnnotationChecker
{
public static void main(String[] args)
{
String x = null;
if(args.length > 0)
{
x = args[0];
}
if(!isNull(x))
{
useObject(x);
}
if(x != null)
{
useObject(x);
}
}
public static boolean isNull(#CheckForNull Object o)
{
return o == null;
}
public static void useObject(#Nonnull Object o)
{
System.out.println(o);
}
}
This uses the JSR 305 annotations.
In this example, in the first call to useObject Intellij puts a warning on the x parameter saying "Argument 'x' might be null". In the second call, there is no warning.
In IDEA 13 very fancy feature was added, called Method Contracts. For example, you could have a method, that throws validation exception if it encounters null:
#Contract("null -> fail")
public static void validateNull(#Nullable final Object object) {
if (object == null) {
throw new ValidationException();
}
}
IDEA will analyze the annotation and won't show up warnings, if you call it before possible NPE:
validateNull(user);
user.setSomething("something"); // no warning
You have full documentation in IDEA's settings (just search for Method Contract). For this to work you need additional dependency on jetbrain's annotations jar:
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>13.0</version>
</dependency>
With IDEA 12 you can configure the NotNull-check methods:
http://youtrack.jetbrains.com/issue/IDEA-35808#tab=Comments
I don't believe there's any way to resolve the warning with the code written as it is. I was hoping to find that IntelliJ supports a value for #SuppressWarnings that you could use on the useObject(x) statement, but according to this source it does not. You may just have to bite the bullet and change your code to something like the following:
if (x != null && !isBlank(x)) {
useObject(x);
}
Notice that I renamed the method isNull to isBlank since it is my understanding that the actual method you're calling that does the check for null checks other conditions as well.
I've dealt with this issue by using a static method to whitelist object calls:
/** Wrapper to mask NullPointerException warnings. */
private static <T> T _(T obj) {
return obj;
}
The method name is intended to not interfere with readability. Thus,
mObject.method();
becomes
_(mObject).method();
Furthermore, if a NullPointerException does occur it will still refer to the same line number.
Related
I'm trying to write an ArchUnit test which tests if a certain unchecked exception when thrown is also declared by that method, and recursively, if any method calling that method also declares it.
The intention is to ensure these exceptions are documented everywhere, and, since I can enforce anything that is declared to be thrown has to be documented (other tools can enforce this), this seemed a good way to go about it.
The scope of these checks can be limited to a certain package; ie. treat runtime exception X when used within package Y as a "checked" exception, and enforce it with a rule.
Passing code:
void someMethod() throws MyRunTimeException {
throws new MyRunTimeException();
}
void anotherMethod() throws MyRunTimeException {
someMethod();
}
Failing code:
void someMethod() { // doesn't declare exception
throws new MyRunTimeException();
}
void anotherMethod() { // should declare exception when someMethod declares it
someMethod();
}
Now I think I can detect methods that do not declare the exception as follows:
noMethods().should().declareThrowableOfType(MyRunTimeException.class)
And I think I can detect calls to create this exception (even better would be when it is actually thrown, but I couldn't find that):
noClasses().should().callConstructorWhere(
target(is(declaredIn(MyRunTimeException.class)))
.and(not(originOwner(is(assignableTo(MyRunTimeException.class)))))
);
... but I see no way how I could combine these two rules.
For some reason however ArchUnit only allows checking calls from classes, but not from methods (which seems to make more sense). In other words, I couldn't find a way to check calls given a method:
noMethods().should().callConstructorWhere( ... )
Or:
noMethods().should().throw(MyRuntimeException.class)
.and(not(declareThrowableOfType(MyRunTimeException.class)))
Any idea how I could go about enforcing such a rule?
You're right that the fluent MethodsShould API (as of ArchUnit 0.23.1) does not seem to support method calls, but as the information is present in the domain objects (see JavaCodeUnit, e.g. getMethodCallsFromSelf, getConstructorCallsFromSelf, or more generally getAccessesFromSelf), you can always implement a custom ArchCondition.
With
import static com.tngtech.archunit.base.DescribedPredicate.doNot;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo;
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.have;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.codeUnits;
import static java.util.stream.Collectors.toSet;
I'd use the following tests:
#ArchTest
ArchRule codeUnits_should_declare_all_RuntimeExceptions_they_throw = codeUnits()
.that(doNot(have(owner(assignableTo(RuntimeException.class)))))
.should(new ArchCondition<JavaCodeUnit>("declare all RuntimeExceptions they throw") {
#Override
public void check(JavaCodeUnit codeUnit, ConditionEvents events) {
// TODO: ArchUnit 0.23.1 might not have an API to get exceptions actually thrown.
// As a first approximation, the following code collects all RuntimeExceptions that are instantiated
// – which has false positives (exceptions that are instantiated, but not thrown),
// as well as false negatives (exceptions that are created via factory methods and thrown).
// Accounting for the false negatives in the same way as here is left as an exercise for the interested reader.
Set<JavaClass> instantiatedRuntimeExceptions = codeUnit.getConstructorCallsFromSelf().stream()
.map(JavaAccess::getTargetOwner)
.filter(targetClass -> targetClass.isAssignableTo(RuntimeException.class))
.collect(toSet());
boolean satisfied = codeUnit.getExceptionTypes().containsAll(instantiatedRuntimeExceptions);
String message = String.format("%s does%s declare all RuntimeExceptions it instantiates in %s",
codeUnit.getDescription(), satisfied ? "" : " not", codeUnit.getSourceCodeLocation());
events.add(new SimpleConditionEvent(codeUnit, satisfied, message));
}
});
#ArchTest
ArchRule codeUnits_should_declare_all_RuntimeExceptions_of_methods_they_call = codeUnits()
.should(new ArchCondition<JavaCodeUnit>("declare all RuntimeExceptions of methods they call") {
#Override
public void check(JavaCodeUnit codeUnit, ConditionEvents events) {
Set<JavaClass> runtimeExceptionsDeclaredByCalledMethods = codeUnit.getMethodCallsFromSelf().stream()
.map(JavaAccess::getTarget)
.map(MethodCallTarget::resolveMember)
.filter(Optional::isPresent)
.map(Optional::get)
.flatMap(method -> method.getExceptionTypes().stream())
.filter(exceptionType -> exceptionType.isAssignableTo(RuntimeException.class))
.collect(toSet());
boolean satisfied = codeUnit.getExceptionTypes().containsAll(runtimeExceptionsDeclaredByCalledMethods);
String message = String.format("%s does%s declare all RuntimeExceptions of methods they call declare in %s",
codeUnit.getDescription(), satisfied ? "" : " not", codeUnit.getSourceCodeLocation());
events.add(new SimpleConditionEvent(codeUnit, satisfied, message));
}
});
I am using this custom annotation for logging execution time, annotation could be present on method or class in which all public methods have it. Everything works fine, except in case of method level "LogExecutionTime logExecutionTime" comes null. This throws an NPE.
#Around("#annotation(logExecutionTime) || #within(logExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
final String name = joinPoint.toShortString();
final StopWatch stopWatch = new StopWatch(name);
stopWatch.start(name);
try {
return joinPoint.proceed();
} finally {
stopWatch.stop();
if (logExecutionTime.value()) {
logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeSeconds());
}
}
}
if I reverse the order-
#Around("#within(logExecutionTime) || #annotation(logExecutionTime)")
the behavior reverses and I get a valid object at method level and null at class level annotated methods.
I have worked around this by having 2 explicit methods and separating the two-
#Around("#within(logExecutionTime)")
public Object logExecutionTimeClassLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
return logExecutionTimeMethodLevel(joinPoint, logExecutionTime);
}
#Around("#annotation(logExecutionTime)")
public Object logExecutionTimeMethodLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
final String name = joinPoint.toShortString();
final StopWatch stopWatch = new StopWatch(name);
stopWatch.start(name);
try {
return joinPoint.proceed();
} finally {
stopWatch.stop();
if (logExecutionTime.value()) {
logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeMillis());
}
}
Was hoping to understand this behavior, when we use OR '||' with two pointcuts.
class level
#LogExecutionTime
#Component
public class CleanUpService implements ICleanUpService { ... }
method level
#Scheduled(fixedDelay = 100)
#LogExecutionTime(false)
public void processMessageQueue() { ... }
I came to run you example, and reproduce the same example as yours, when it come to runtime expression is same weird because when you specify the annotation on class level and you write this expression
#Around(" #within(logExecutionTime) || #annotation(logExecutionTime) ")
The point cut will evaluate to true for you class (event you annotation its available in joinPoint.getTarget().getClass().getAnnotations(), )
Now when it come to binding the variable the compiler check all your expressions that mean binding #within(logExecutionTime) to variable logExecutionTime and #annotation(logExecutionTime) to the same variable , if the method is not annotated it will ge null, => override the initial with, that cause all senarios you mention.
Try to put this expression #within(logExecutionTime) || #annotation(logExecutionTime) || #within(logExecutionTime)
and you'll get you variable not null which prove what i said, last #within(logExecutionTime) override what precedent
The key here is that the logic applied to select the point cut matching not the same when it come context-binding
Now when it come to AOP point-cut you must be careful and follow best practice as the spring team they mention here to avoid weird runtime results
Cheers
This cannot work, it does not even compile with the AspectJ compiler. Maybe in your IDE and with Spring AOP you do not see any warnings or errors, but I see:
ambiguous binding of parameter(s) logExecutionTime across '||' in pointcut
This means that it is not clear which annotation should be selected if e.g. both the class and the method contain an instance of that annotation. It is, as the error message said, ambiguous. But ambiguous parameter bindings across || are not permitted. They can also happen if you try to bind values from different "or" branches to a single parameter in an args() list.
I had the same problem. What you want is exactly same as Spring #Transcriptional behaves (I mean, class level or method level annotation with parameters). I used your solution but to get the class level parameter value (as the annotation object received null), I used reflection. I know it is a dirty solution! But I tried other solutions and couldn't find!
Her is the full code. This will call the advice code either the annotation is used on a class or a method. If the annotation is placed on both (class and method), the method takes the precedence.
#Aspect
#Configurable
#Component
public class DynamicValueAspect {
#Around(" #within(dynamicValueAnnotation) || #annotation(dynamicValueAnnotation))")
public Object process(ProceedingJoinPoint joinPoint, DynamicValue dynamicValueAnnotation) throws Throwable {
String annotationParameter;
if (dynamicValueAnnotation == null) { //class level annotation
annotationParameter = extractClassLevelAnnotationParameterValue(joinPoint);
} else {
annotationParameter = dynamicValueAnnotation.myAnnotationParameter();
}
System.out.println(" " + annotationParameter);//get the annotation parameter value
return joinPoint.proceed();
}
private String extractClassLevelAnnotationParameterValue(ProceedingJoinPoint joinPoint) {
Annotation[] classAnnotations = joinPoint.getTarget().getClass().getAnnotations();
for (Annotation annotation : classAnnotations) {
if (annotation.annotationType() == DynamicValue.class) {
return ((DynamicValue) annotation).myAnnotationParameter();
}
}
throw new RuntimeException("No DynamicValue value annotation was found");
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface DynamicValue {
String myAnnotationParameter();
}
Let's know if you got a cleaner solution!
The problem with your workaround appears when you annotate both a class and a method with the annotation, resulting in triggering both of them.
To prevent it declare the class level advice as:
#Around("!#annotation(LogExecutionTime) && #within(logExecutionTime)")
I'd like to use the #NonNull annotation in Android, but I can't figure out just the right way to do it.
I propose you this example:
public void doStuff(#NonNull String s){
//do work with s...
}
So when i call doStuff(null) the IDE will give me a warning. The problem is that I cannot rely on this annotation since, like this question points out, they don't propagate very far. So I'd like to put a null check on my method, like this:
if(s==null) throw new IllegalAgrumentException();
But the IDE, assuming that s!=null, will warn me that s==null is always false. I'd like to know what is the best way to do this.
I personally think that there should be an annotation like #ShouldntBeNull that only checks and warns that null isn't passed to it, but doesn't complains when the value is null checked.
You can use Objects.requireNonNull for that. It will do the check internally (so the IDE will not show a warning on your function) and raise a NullPointerException when the parameter is null:
public MyMethod(#NonNull Context pContext) {
Objects.requireNonNull(pContext);
...
}
If you want to throw another exception or use API level < 19, then you can just make your own helper-class to implement the same check. e.g.
public class Check {
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new IllegalArgumentException();
return obj;
}
}
and use it like so:
public MyMethod(#NonNull Context pContext) {
Check.requireNonNull(pContext);
...
}
Google examples do it as follows
import static com.google.common.base.Preconditions.checkNotNull;
...
public void doStuff(#NonNull String sParm){
this.sParm= checkNotNull(s, "sParm cannot be null!");
}
You can use the comment-style suppression to disable that specific null check warning, e.g.:
public MyMethod(#NonNull Context pContext) {
//noinspection ConstantConditions
if (pContext == null) {
throw new IllegalArgumentException();
}
...
}
You'll need that //noinspection ConstantConditions every time you do it.
I have a class like this:
import javax.annotation.Nullable;
public class Nullness {
private #Nullable Object someObject;
public void foo() {
if (someObject != null) {
someObject.toString(); //error "Potential null pointer access: The field someObject is specified as #Nullable"
}
}
}
And when enable eclipse null analysis, an error is marked at the statement someObject.toString(); which reads Potential null pointer access: The field someObject is specified as #Nullable.
Eclipse has a quick fix that can change my code to be like this:
public void foo() {
final Object someObject2 = someObject;
if (someObject2 != null) {
someObject2.toString();
}
}
which can wipe out the error, note that, actually, the final modifier is not required to make the error disappear.
I don't understand why Eclipse does not allow me to use field variable directly in null-checking statement if (someObject != null) but force me to create additional local variable someObject2. Is this behavior just a bug or it is intended?
Must apologize the community by posting the question without doing carefully research. This issue is clearly mention in this wiki, which discuss that using field variable directly can cause unexpected effect in several ways.
I have some code which is similar to the following snippet:
public void foo(Order o) {
...
checkInput(o, "some error message");
doSomehing(o.getId());
}
private void checkInput(Object o, String message) {
if (o == null) {
throw new SomeRuntimeException(message);
}
}
And I got Findbugs reporting an 'NP_NULL_ON_SOME_PATH' issue.
Here is the description:
There is a branch of statement that, if executed, guarantees that a null value will be dereferenced, which would generate a NullPointerException when the code is executed. Of course, the problem might be that the branch or statement is infeasible and that the null pointer exception can't ever be executed; deciding that is beyond the ability of FindBugs.
My questions are:
Can I treat it as a false positive in this example?
Is it a good practice to put the null test in a separate method? The actual null check method is a bit longer than the sample method so I don't want to repeat the code everywhere.
Thanks!
It looks like FindBugs is not able to detect this case, at least with 2.0.2 in Eclipse. One workaround is to return the value from checkError and annotate the method with #Nonnull.
public void foo(Order o) {
...
doSomehing(checkInput(o, "some error message").getId());
}
#Nonnull
private Order checkInput(Order o, String message) {
if (o == null) {
throw new SomeRuntimeException(message);
}
...
return o;
}