GCC supports declaring methods with the attribute warn_unused_result so that any caller who does not save the return value of the method gets a warning.
Does Java have any comparable feature?
No, Java doesn't have such a feature.
This could be accomplished by static code analysis tools like FindBugs, based on an annotation on the method, but I don't think such a rule exists. You could create one, though: FindBugs is free software.
FindBugs does a similar check already for specific API calls like File.delete() (it throws a warning if the result of the method is ignored. See http://findbugs.sourceforge.net/bugDescriptions.html#RV_RETURN_VALUE_IGNORED_BAD_PRACTICE). So you could take this rule as an example.
As far as I know there is no such a thing, but some IDEs such as IntelliJ IDEA warn you so about some known methods (for example methods on a String which return another String).
Related
I'm programming a Config class that reads a file and provides config parameters as a Map.
Parameters can be accessed by conf.get("LogLevel") or conf.getLogLevel().
The first function just reads from the map and returns the value (that can be null or invalid) while the second function converts the value to a LogLevel and returns a default value when no valid value is given.
Therefore I want to discourage Programmers from using the genereral get(), but there are special cases where this method is useful so I cant just make it protected.
Right now I use #Deprecated but I dont think this is a good solution because it is only ment for methods that will be removed in the future. (Correct me if I'm wrong there, thats what SonarLint told me about the #Deprecated annotation)
/**
* #Deprecated When possible, use the key-specific getter instead
*/
public String get(String key) {
return values.get(key);
}
public int getLogLevel() {
return Log.getLogLevel(values.get(LOG_LEVEL), Log.getLogLevel(defaultValues.get(LOG_LEVEL)));
}
Well, if #Deprecated is not the solution, you are left with only one option. Put message that notes that the usage is "discouraged" (except for the special cases) into the javadocs ... and hope that people are going to read the javadocs.
Defining your own custom annotation will not help because you can't get your users to use an annotation processor that will recognize it.
Likewise, you can't do it via custom rules for FindBugs, PMD, Sonar and so forth because that requires your users to customize their installations of those products.
(Though ... if this is an in-house product and all of your users use a common CI server ... you could possibly do the checks in the CI server. It depends if you can define custom rules that can reliably distinguish the general "discouraged" use-cases from the special cases. This will also entail convincing your co-workers that this is a good idea.)
In my opinion, the #Deprecated tag would be better than all of the above. For the special cases, encourage people to judiciously add #SuppressWarning("deprecation") in the cases where the usage is necessary.
I don't think this is a good solution because it is only meant for methods that will be removed in the future.
This is incorrect. Possible future removal is only one of the example reasons for deprecation listed in the #Deprecated javadoc (Java 11 version). Other reasons listed there are:
"the tagged element's usage is likely to lead to errors",
"it may be changed incompatibly [...] in a future version",
"it has been superseded by a newer, usually preferable alternative", or
"it is obsolete".
Note that these are listed as example reasons ... which means that you could deprecate for other reasons.
This is also consistent with the older "when to deprecate" guidance here.
IMO, your "discouraged" scenario is covered by that.
If you arrived here and looking for android solution there's #Discouraged annotation in androidx
There is a lot of confusion about the getCompletions method in the javax.annotation.processing package. What is the completion function returned by this method? Can you give me an example of specific use. Thank you。
Iterable<? extends Completion> getCompletions(Element element,
AnnotationMirror annotation,
ExecutableElement member,
String userText);
There is a lot of confusion about the getCompletions method in the javax.annotation.processing package.
By who?
What is the completion function returned by this method?
it's a nice-to-have, optional feature. What it is for, is to help IDEs specifically.
When you compile code with javac or some other command line compiler, this method isn't invoked at all. It's there solely for IDEs. When you open up your eclipse or intellij or whatnot, type "Hello". and wait 500msec or hit CTRL+SPACE or whatever the IDE uses for shortcut for 'auto-complete', you get a menu of sorts that shows all the various methods that strings have. And possibly some templates and other features as well; IDEs are free to add whatever they want to this, there is no actual java specification for 'auto completers in IDEs'.
Nevertheless, that's what this method is for.
Specifically, it's for having the IDE help you out when you type: #YourAnn(someAnnotationParamName=...) - anywhere in the ... part, that's where this feature is relevant.
How to help yourself next time
Docs are good... if they are there. But in this case, they were there. The docs on this feature can be found where-ever you find your javadoc (google, your IDE, and so many other places): The javadoc of Processor.getCompletions explains stuff, including a great example.
Given that this example is quite nice, I dispute your characterization that 'there is a lot of confusion about the getCompletions method' :)
getCompletions is intended for use by IDEs. It helps users to know what arguments may be supplied to an annotation.
It is well described by its Javadoc documentation.
The example used there is: Suppose there is an annotation defined as
#MersennePrime {
int value(); // must be a prime of the form 2^n-1, e.g., 3, 7, 31, 127, 8191, ...
}
The implementation of getComletions could be
return Arrays.asList(of("3"),
of("7"),
of("31"),
of("127"),
of("8191"),
of("131071"),
of("524287"),
of("2147483647"));
If a user has written #MersennePrime, the IDE can suggest the arguments returned by getCompletions. If a user has written #MersennePrime(1, then getCompletions is passed "1" as its userText command-line argument and should return a list containing just 127 and 131071.
Can I make Findbugs, or any other code analyser, check if a method that can return null is annotated as #Nullable?
That't the case I would like to check:
// Third party library
class Foo
{
// Static test should fail because it's not annotated as #Nullable
String get()
{
return null;
}
}
I believe the current tooling cannot do that out of the box, including IntelliJ. You will have to write a custom FindBugs check. FindBugs has some logic to support nullness analysis.
The reason for that is that you are trying to reverse-engineer the contract of the method. Nullness annotations are part of the contract, so they cannot, and should not be inferred from the code. There is no way, not even in theory, to tell if the programmer wanted the method to return null values or if that is a programming mistake. Depending on that, you would have to fix the code by either adding the #Nullable annotation, or by changing the method body so that it cannot return null (and probably adding #Nonnull).
FindBugs features some annotations that you can use to specify nullness defaults on a package level. It will then check that all methods of classes in that package conform to your default. If you didn't do that, FindBugs assumes that you set #Nullable; so maybe your case is already solved.
Yes, you can. IntelliJ Idea has static code analysis tool. You can find instructions here.
EDIT: You can also run all inspections for your code in Idea (look here), or in offline mode with command line tools (look here).
I understand that annotations serve a purpose to modify code without actually BEING code, such as:
#Author(
name = "Benjamin Franklin",
date = "3/27/2003"
)
But I don't understand how using the annotation is any better/ clearer/ more concise than just saying name = "Benjamin Franklin" ? How does the addition of annotations strengthen the code?
EDIT: Sorry for another questoin, but I know that #Override can help prevent/ track spelling mistakes when calling methods or classes, but how does it do that? Does it help the actual program at all?
Annotations are just metadata. On their own they serve little to no purpose. There must be an annotation processor, either at the compiler or run time level that uses them for something.
With an annotation like
#Author(
name = "Benjamin Franklin",
date = "3/27/2003"
)
for example, some annotation processor might read it with reflection at run time and create some log file that this author wrote whatever it's annotating on that date.
Annotations are metadata.
#Override annotation is used to make sure that you are overriding method of a superclass and not just making a method with the same name. Common mistakes here consist of:
spelling the method's name wrong
equal(Object o) instead of equals(Object o)
putting different set of arguments
MyString extends String { public boolean equals(MyString str) {} }
equals(MyString str) is not overriding the method equals(Object o) and therefore will not be used by standard Java comparators (which is used in some standard functions, such as List.contains() and this is prone to error situation).
This annotation helps compiler to ensure that you code everything correctly and in this way it helps program.
#Deprecated annotation doesn't make program not to compile but it makes developers think about using the code that can and/or will be removed in a future releases. So they (developers) would think about moving onto another (updated) set of functions. And if you compile your program with the flag -Xlint compilation process will return with an error unless you remove all usages of deprecated code or explicitly mark them with annotation #SuppressWarnings("deprecation").
#SuppressWarnings is used to suppress warnings (yes, I know it's Captain Obvious style :)). There is a deprecation suppression with #SuppressWarnings("deprecation"), unsafe type casting with #SuppressWarnings("unchecked") and some others. This is helpfull when your project compiler have a compilation flag -Xlint and you cannot (or don't want to) change that.
There are also annotation processors that you integrate into your program build process to ensure that program code meets some sort of criteria. For example with IntelliJ Idea IDE annotation processor you can use #Nullable and #NotNull annotations. They show other programmers when they use your code so that can transfer null as a certain parameter to a method or not. If they transfer null it will cause exception during compilation or before executing a single line method's code.
So annotations are quite helpful if you use them to their full potential.
Annotations are most likely used by other programs. Examples include:
#Override
IDE (compiler?) ensures that the signatures match
#Deprecated
IDE marks occurences, compiler warning
#FXML
JavaFX can use these annotations initialize variables in a controller class when an .fxml File is inflated (see http://docs.oracle.com/javafx/2/get_started/fxml_tutorial.htm). They are also used by JavaFX Scene Builder.
Annotations works as a way to marking up the code. Several frameworks uses it, and some others make a great use of it producing your own.
Besides, is important to understand that annotations are the equivalent to meta-data, but is much more than that, since it works as a tag language for the code.
Java #Annotation
#Annotation(from Java 5) adds a metadata which are used for instruction in compile, deployment and run time. It is defined by RetentionPolicy
RetentionPolicy defines a lifetime
RetentionPolicy.SOURCE: It is visible only in compile time(#Override, #SuppressWarnings, #StringDef). For example it can be used by apt to generate some code
RetentionPolicy.CLASS: It is visible in compile and deployment time(.class). For example it can be used by ASM or Java AOP paradigm like AspectJ
RetentionPolicy.RUNTIME: It is visible in deployment and run time. For example it can be used java reflection using getAnnotations(). Dagger 2 uses #Scope annotation
Create a custom Annotation
#Retention(<retention_policy>) //optional
#Target(<element_type>) //optional to specify Java element like, field, method...
#Inherited // optional will be visible by subclass
#Documented // optional will be visible by JavaDoc
#interface MyAnnotation {
//attributes:
String someName();
}
using
#MyAnnotation(someName = "Alex")
public class SomeClass {
}
I found that there seem to be 2 general solutions:
don't obfuscate what is referred to through the reflection API [Retroguard, Jobfuscate]
replace Strings in reflection API invocations with the obfuscated name.
Those solutions work only for calls within the same project - client code (in another project) may not use the reflection API to access non-public API methods.
In the case of 2 it also only works when the Reflection API is used with Strings known at compile-time (private methods testing?). In those cases dp4j also offers a solution injecting the reflection code after obfuscation.
Reading Proguard FAQ I wondered if 2 otherwise always worked when it says:
ProGuard automatically handles
constructs like
Class.forName("SomeClass") and
SomeClass.class. The referenced
classes are preserved in the shrinking
phase, and the string arguments are
properly replaced in the obfuscation
phase.
With variable string arguments, it's generally not possible to determine
their possible values.
Q: what does the statement in bold mean? Any examples?
With variable string arguments, it's generally not possible to determine their possible values.
public Class loadIt(String clsName) throws ClassNotFoundException {
return Class.forName(clsName);
}
basically if you pass a non-constant string to Class.forName, there's generally no way for proguard or any obfuscation tool to figure out what class you are talking about, and thus can't automatically adjust the code for you.
The Zelix KlassMaster Java obfuscator can automatically handle all Reflection API calls. It has a function called AutoReflection which uses an "encrypted old name" to "obfuscated name" lookup table.
However, it again can only work for calls within the same obfuscated project.
See http://www.zelix.com/klassmaster/docs/tutorials/autoReflectionTutorial.html.
It means that this:
String className;
if (Math.random() <= 0.5) className = "ca.simpatico.Foo";
else className = "ca.simpatico.Bar";
Class cl = Class.forName(className);
Won't work after obfuscation. ProGuard doesn't do a deep enough dataflow analysis to see that the class name which gets loaded came from those two string literals.
Really, your only plausible option is to decide which classes, interfaces, and methods should be accessible through reflection, and then not obfuscate those. You're effectively defining a strange kind of API to clients - one which will only be accessed reflectively.