I'd like a mechanism to throw a compile-time warning manually. I'm using it to flag unfinished code so I can't possibly forget about it later. #Deprecated is close but warns at caller site, not at creation site. I'm using eclipse. Something like #Warning in C#.
Why not just add a flag in the source code like //TODO: or something? And then just search for all occurances of TODO in the file? You could even have some special flag too like FINISHME or something.
If you have hundreds of TODOs in your project from the team, you can filter by a string e.g. your initials in the Task pane's top-right menus.
A lot better than using the deprecated annotation in my humble opinion the suppresswarnings annotation.
#SuppressWarnings("XXX")
can be annotated almost everywhere and as long as XXX is not a valid warning you will get a warning from eclipse about that.
Create an annotation that prints out a warning.
You could try to throw an exception if an unfinished method is called (e.g.)
throw new UnsupportedOperationException()
(Or you could create your own Exception). Obviously this will only help at runtime (unless you do a search or something in your code for it - but Todo would be a better solution for that)
And if you are using eclipse you can mark your unfinished code with // TODO and it will show up on your task list (and the right gutter if you have it configured). Obviously things can get very noisy if you have a lot of Todo tags.
I do this all the time by just putting "*** LEFT OFF HERE ***" or some such. As this is not valid Java or C++ or pretty much any other language syntax, the compiler gives an error message for it.
Of course that gives an error and not a warning. If you want to otherwise successfully compile, I suppose an easy thing to do would be to put a statement that you know will generate a compiler warning with a comment saying "finish this" or whatever.
When I want to warn users about calling a method, I (mis)use the build-in #Deprecated annotation which generates a warning at the caller side. Actually it has a slightly different meaning, but I don't care.
/** [Additional information...]
* It is marked as deprecated to warn callers. */
#Deprecated public void methodForWhichIWantToCreateAWarning();
I'm not sure if there is anything like that in java
but here is something that may help you:
compile the code below like this:
javac -Xprint verbose.java
public class verbose{
public #interface SomeMessage {
String somevalue();
}
#SomeMessage(
somevalue = "WHOOOOHOOOO000000000000000"
)
public static void main(){
System.out.println("Hello");
}
}
Related
I have made a call to the log4j-v2-API like this:
Logger logger = LogManager.getLogger("MyLogger");
/**
* syntactic sugar as part of a facade
*/
private void logAtLevel(String level, Supplier<String> messageSupplier, Throwable thrown){
Level priority = Level.toLevel(level, Level.ALL);
if (null == thrown) {
logger.log(priority, messageSupplier);
} else {
logger.log(priority, messageSupplier, thrown);
}
}
/**
* method calling logger
*/
private void callLogging(Object value){
logAtLevel("Debug", ()->String.format("something or other: %s", value), null);
}
My expectations would have been that the above call creates a log entry "something or other: <object.toString()>" however I got "lambda#1223454" instead.
This suggests to me that the method that was executed is log(level, object) rather than the expected log(level, supplier)
Why are the methods resolved the way they are and how can I prevent this (preferably without casting)?
Your Supplier is not Log4j2's Supplier!
java.util.function.Supplier was introduced in Java 8. At around the same time (version 2.4, cf. LOG4J2-599) Log4j2 introduced org.apache.logging.log4j.util.Supplier so that the library can be used on Java 7.
That is why your code does not call log(Level, Supplier<?>, Throwable) but log(Level, Object, Throwable) and you end up with Supplier#toString() being logged instead of Supplier#get().
This is probably something that should change and I filed a wish list bug about it (cf. #1262).
Remark: Wrapping well established logging APIs like Log4j2 API and SLF4J into custom wrappers is not a good idea (cf. this question). While it is not rocket science to write a good wrapper, there are many details you should consider. For example your wrapper breaks location information.
Doing a level lookup for every call, when your intent is to avoid every nanosecond for levels that don't matter, is probably something you need to reconsider.
At any rate, there is nothing immediately obvious about your snippet that would explain what you observe. Thus, let's get into debugging it, and likely causes.
The code you are running isn't the code you wrote. For example, because you haven't (re)compiled.
logger.log is overloaded, and older versions of slf4j exist that contain only the 'object' variant, which just calls toString(), which would lead to precisely the behaviour you are now witnessing.
You can do some debugging on both of these problems by applying the following trick:
Add System.out.println(TheClassThisCodeIsIn.class.getResource("TheClassThisCodeIsIn.class")); - this will tell you exactly where the class file is at.
Then use javap -v -c path/to/that/file.class and check the actual call to logger.log - is the 'signature' that it links to the Supplier variant or the Object variant?
The different effects and what it means:
The sysout call isn't showing up. Then you aren't running the code you are looking at, and you need to investigate your toolstack. How are you compiling it, because it's not working.
The javap output shows that the 'Object' variant is invoked. In which case the compilation step is using an old version of log4j2 in its classpath. It's not about the slf4j version that exists at runtime, it's what the compiler is using, as that determines which overload is chosen.
Everything looks fine and yet you are still seeing lambda#... - then I would start suspecting that this is the actual output of your lambda code somehow, or something really, really wonky is going on. The only things I can think of that get you here are ridiculously exotic, not worth mentioning.
I'm using Findbugs and javax.annotation.Nonnull on method parameters.
On private methods I usually add an assert line to check for nullness like
private void myMethod(#Nonnull String str) {
assert str != null
....
Latest Netbeans version (7.3rc2) is reporting that the assert check is not necessary (because of the Nonnull annotation). I'm not fully sure this is a Netbeans bug or not.
Can the assert line be removed because I specified the #Nonnull annotation ?
As far as I understand, the annotation is used only during static analysis while assert is, when enabled, active during execution so the twos are not alternative.
The assert is evaluated at runtime, the annotation helps FindBugs catch problems during the analysis before runtime. As both checks are not really conflicting you could keep them both. I would find it annoying if my IDE told me to remove the assert.
Netbeans is right. If you think it can be null: remove the annotation. If you know it can't: remove the assert.
If there's ANY chance that your method could be called with a null value, then #Nonnull annotation shouldn't be there.
Like you said, that annotation doesn't actually do anything at runtime: it is only used by IDEs and static code analysis tools. It doesn't ensure that things aren't null.
Since this is private method, we can ensure that annotated parameter cannot be null. I think you can remove this assertion.
If NetBeans warns to public method, I think it has problem. I recommend you to put assertion.
If you still feel that assertion in private method is necessary, I think you can use bytecode injection.
For instance, here is a maven plugin to inject null check. Sorry this is my personal project, but it works to me. I guess it can suit your need.
https://github.com/KengoTODA/jsr305-maven-plugin
I found a different solution, as I was thinking about my IDE warnings.
Initially, I felt that the IDE was wrong. I'm a paranoid programmer, and want to have the label for documentation & static analysis AND a runtime check in case I ever use it from reflection, or another JVM language or something that isn't statically analyzable, so I thought it was wrong to give me a warning and tell me the assert(x != null) statement wasn't needed.
But then I thought about how asserts can be removed depending on the status of the -ea flag passed to Java at Runtime, and that in some ways assert and #Nonnull are really both development-only checks.
Turns out, there's an actual runtime check that can be inserted (Java 7+) Objects.requireNonNull which will throw a NullPointerException and cannot be removed with an -ea assertion. I think I'm going to prefer this to my assert(x != null); use(x); pattern.
public ConstructorForClass(#Nonnull Type x) {
this.x = Objects.requireNonNull(x);
//...
}
Too often one sees the following pattern in enterprising Java programs
public Something myMethod() throws MyException {
try {
// may throw checked DbException:
Connection c = openDataBase("connectionstring");
// ... other code throwing more checked exceptions ...
} catch(DbException e) {
throw new MyException(e);
}
return something;
}
...or any other mechanism to "cast" one checked exception type that is not declared in the method header to the one that is. Very often this "try-catch-cast"-block must go into every method of such a class.
I wonder, how to implement an annotation, that catches and converts exceptions?
The using code should then look like this:
#ConvertException(MyException, DbException)
public Something myMethod() throws MyException {
// may throw checked DbException:
Connection c = openDataBase("connectionstring");
// ...
return something;
}
Of course, Maybe one has to write MyException.class or "MyException" instead. It should also be possible to chain these annotations, or list multiple exceptions to convert.
My guess is that the annotation would introduce a wrapper function with the catching code block that would call the original function. The annotation would then only have compile-time-retension (and not run-time-retension).
I don't advocate that its wise to do this, it probably isn't because these annotations change the program semantics. It may well be an academical question to "just learn"...
Annotations don't do anything at all by themselves. You need a tool that evaluates them and does some code changing according to them.
In your case, AspectJ seems to be the best match.
My advice would be to read AspectJ in Action (2nd ed) by Ramnivas Laddad.
As you can see from it's Table of Content, it contains a chapter about exception softening, which is almost exactly what you want.
And since you tagged this question dependency-injection, assuming you use Spring, here is Spring's own Exception translation mechanism
Yes, this should be possible by creating an annotation processor that uses the compiler tree api (javac.tree package) to manipulate the source code while it's being compiled.
The problem is of course that this annotation processor now must be present whenever the code is compiled, and many tools that process source code (most prominently IDEs) may not know about it and consider the code invalid.
In C++ if we do not want some statements to compile into code that ships like assert function calls, we control their compilation through #ifndef preprocessor directives.
How do we do this in Java?
I have some System.out.println() statements for debugging which I would like to remove for the final code.
one way is to make them execute conditionally under the affect of a boolean variable. Is there a better way of doing this?
As I have a java swing application I can turn off the System.out.println statements without affecting the output. What is the method of doing this?
Use a logging framework like slf4j. You can print to the console in debugging and omit everything in production without recompiling the application.
Use logging. See log4j or commons logging.
Generally, each log entry has a severity level (like debug, info, warning, error) and you can configure which are printed from the application. You can print all of them for debug, but only some (e.g. info and higher) in production. The configuration is usually done with a single plain text file.
Logging frameworks can do more than that: Add more detail automatically (e.g. timestamp or thread ID), log to console, file and/or database, rotate files, and more.
Use AspectJ for those pieces of code which you want added or removed at compile time and compile without AspectJ when you don't want to use them.
In general (not only for your example), you can create multiple implementations of an interface, and change, which instance is used during execution. This is called polymorphism, the advantage over if/else is: you choose the implementation once, instead of every time it's used.
In Java, polymorphism does not result in performance overhead.
public interface MyInterface {
void trashTheCPU();
}
public class MyRealImpl implements MyInterface {
#Override
public void trashTheCPU() {
// actually trash the CPU with heavy tasks
}
}
public class MyEmptyImpl implements MyInterface {
#Override
public void trashTheCPU() {
// do nothing
}
}
// ... somewhere else:
MyInterface mi = null;
public void initEveryting() {
if(trashTheCPUconditionIsMet) {
mi = new MyRealImpl();
} else {
mi = new MyEmptyImpl();
}
}
For what you're doing, assertions may be the way to go. The assert keyword was added to Java in version 1.4, and is conceptually similar to C++'s assert(), which I see you're familiar with.
assert statements in Java do nothing if they evaluate to true and yell at you otherwise, which is perfect for debugging. They also don't work by default, which means that the compiler will ignore them unless you explicitly tell it not to. The end result is a debugging tool that "evaporates" when you ship your production code.
Here's Sun's tutorial on Java asserts.
Consider a private method which is called from JNI and not used otherwise, generating a compiler warning about an unused method:
private void someMethodCalledOnlyFromJNI() { // WARNING: method is never used
// ....
}
This is some legacy code in Java 1.4 - so no dice on #SuppressWarnings.
What hack would you use to suppress this compiler warning?
Edit: Obviously this is just a warning and it can easily be ignored. But, personally, I hate warnings in my code just as much as I don't want to see errors in it. AFAIC - my code should have 0 warnings, it might be an exaggeration, but I am very pedantic about this.
Just as an example, someone might see this function, not know it is used from JNI, and simply delete it.
Ignore it. It is a warning, after all - best option
use protected (and add a comment for the reason why) - bearable
Make a dummy method just above it and make the two call each other (again with comments) - ugly
configure the IDE not to show this warning at all (in eclipse it is Windows > Preferences > Java > Compiler > Errors/Warnings) - not preferable
As per your update: having 0 warnings is not a goal you should set. The number of warnings depends on the settings, so if you don't all have unified IDEs, this number will vary. And then you can add checkstyle / PMD to report warnings as well - then you'll have even more. The reasonable behaviour is to have a warnings treshold.
If you don't want anyone to delete this method, just add a comment:
// This method is used is used by JNI. (Don't delete)
Somewhere else in the class:
if(Boolean.FALSE.booleanValue())
{ // prevents warning for unused private method which is used from JNI
someMethodCalledOnlyFromJNI();
}
(can't use simple false because that results in dead code warning).
Either just ignore the warning, or declare it as protected instead. If you go for protected and want to prevent subclassing/overriding as well, then declare it final as well.
To start with, its only a warning, thus it should not be an issue for you.
You could either mod the code to remove that function thus removing the problem.
Or just call it from some where at the start/end of your code and ignore any results. As long as it is not going to try to set up any thing that will affect the rest of your program you will be fine.
you can make it public. if it's legacy code I am sure no one will complain :)