No compilation warning with #Deprecated annotation? - java

According to Java tutorial on Oracle, if deprecated method marked with #Deprecated annotation is used, compiler should be giving warning on compilation. But with following code sample, I am not getting any warning in the console.
Java version used: 1.8.0_112
Please let me know what could be missing here.
Thanks.
public class PreDefinedAnnotationTypesTest {
/**
* This method is deprecated.
* #deprecated
*/
#Deprecated
public void m1(){
}
public static void main(String[] args) {
PreDefinedAnnotationTypesTest obj = new PreDefinedAnnotationTypesTest();
obj.m1();
}
}

From docs
The compiler suppresses deprecation warnings if a deprecated item is
used within an entity which itself is deprecated or is used within the same outermost class or is used in an entity that is annotated to
suppress the warning.
so your function is being used within the same class in which it is declared simply try to use in some other class.
In the below image the wontShowWarning function will not generate any warning although show() funtion will, which is from another class.
The API design can have different rules for itself because it is presumed that the outermost classes will be modified according to new design so this is just a indication to other classes

For Compiling and running your Java program using Command Prompt:
javac -Xlint className.java

Related

Create a custom annotation for springboot beans [duplicate]

Can anyone explain in a clear way the practical differences between the java.lang.annotation.RetentionPolicy constants SOURCE, CLASS, and RUNTIME?
I'm also not exactly sure what the phrase "retaining annotation" means.
RetentionPolicy.SOURCE: Discard during
the compile. These annotations don't
make any sense after the compile has
completed, so they aren't written to
the bytecode.
Example: #Override, #SuppressWarnings
RetentionPolicy.CLASS: Discard during
class load. Useful when doing
bytecode-level post-processing.
Somewhat surprisingly, this is the
default.
RetentionPolicy.RUNTIME: Do not
discard. The annotation should be
available for reflection at runtime.
Example: #Deprecated
Source:
The old URL is dead now
hunter_meta and replaced with hunter-meta-2-098036. In case even this goes down, I am uploading the image of the page.
Image (Right Click and Select 'Open Image in New Tab/Window')
According to your comments about class decompilation, here is how I think it should work:
RetentionPolicy.SOURCE: Won't appear in the decompiled class
RetentionPolicy.CLASS: Appear in the decompiled class, but can't be inspected at run-time with reflection with getAnnotations()
RetentionPolicy.RUNTIME: Appear in the decompiled class, and can be inspected at run-time with reflection with getAnnotations()
Minimal runnable example
Language level:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.SOURCE)
#interface RetentionSource {}
#Retention(RetentionPolicy.CLASS)
#interface RetentionClass {}
#Retention(RetentionPolicy.RUNTIME)
#interface RetentionRuntime {}
public static void main(String[] args) {
#RetentionSource
class B {}
assert B.class.getAnnotations().length == 0;
#RetentionClass
class C {}
assert C.class.getAnnotations().length == 0;
#RetentionRuntime
class D {}
assert D.class.getAnnotations().length == 1;
}
Bytecode level: using javap we observe that the Retention.CLASS annotated class gets a RuntimeInvisible class attribute:
#14 = Utf8 LRetentionClass;
[...]
RuntimeInvisibleAnnotations:
0: #14()
while Retention.RUNTIME annotation gets a RuntimeVisible class attribute:
#14 = Utf8 LRetentionRuntime;
[...]
RuntimeVisibleAnnotations:
0: #14()
and the Runtime.SOURCE annotated .class does not get any annotation.
Examples on GitHub for you to play with.
Retention Policy: A retention policy determines at what point an annotation is discarded. It is s specified using Java's built-in annotations: #Retention[About]
1.SOURCE: annotation retained only in the source file and is discarded
during compilation.
2.CLASS: annotation stored in the .class file during compilation,
not available in the run time.
3.RUNTIME: annotation stored in the .class file and available in the run time.
CLASS
:Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time.
RUNTIME
:Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.
SOURCE
:Annotations are to be discarded by the compiler.
Oracle Doc

#com.sun.istack.internal.NotNull annotation

I try to use the #NotNull annotation from package com.sun.istack.internal.
I am using IDE Intellij IDEA Community Edition.
when I build a program using IDE no problem. When I try to compile a file from the command line using javac, I get an error "cannot find symbol".
package ibkr;
import com.sun.istack.internal.NotNull;
public class Main {
public static void main(String[] args) {
test("Test");
}
public static void test(#NotNull String text) {
System.out.println(text);
}
}
I don't understand why i can't compile this code using javac and how Intellij IDEA make compilation and run it.
The annotation is an internal class, it's not for public use. The closest alternative is Jetbrains' stuff:
https://www.jetbrains.com/help/idea/nullable-and-notnull-annotations.html
Even if the class is in the classpath, it doesn't necessarily mean that you can safely refer to that class. The compiler can have some limitations upon accessing some classes/packages.
In most cases, as here, it's obvious whether the package is internal or not: com.sun.istack.internal. Oracle discourages developers from using classes from such packages.
Ok i know this question is a bit old, but if my info is correct, the reason for this is the fact that intellij uses full rt.jar for compilation while javac uses incomplete version, because of ct.sym
This is an annotation used to identify non-nullable values, also this will let static analyzer have their checks in place. In case you are using IntelliJ you can use its annotation but it would make it very tool-specific, same is the case for eclipse
One can also you
https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl
This provides the same non-null annotation but you need to add an extra dependency there.

How to implement something similar to the #Override java annotation?

With this jdk code in ../java/lang/Override.java,
package java.lang;
import java.lang.annotation.*;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.SOURCE)
public #interface Override {
}
having just annotation declaration, java compiler is intelligent enough to detect error(compile time):
The method toString123() of type Example must override or implement a supertype method
in the below problem code.
package annotationtype;
public class Example {
#Override public String toString() {
return "Override the toString() of the superclass";
}
#Override public String toString123() {
return "Override the toString123() of the superclass";
}
public static void main(String[] args) {
}
}
Annotation declaration for Override just gets compiled to,
interface java.lang.Override extends java.lang.annotation.Annotation{
}
which is nothing more than an interface.
So,
How does interface java.lang.Override syntax help java compiler to detect above error at compile time?
The implementation that triggers the compile error doesn't lie in the annotation, it lies in the Java compiler.
If you want to write your own similar annotation processor, you would use the annotation processor API: http://docs.oracle.com/javase/7/docs/api/javax/annotation/processing/Processor.html
which is nothing more than an interface.
So,
How does interface java.lang.Override syntax help java compiler to
detect above error at compile time?
That's right. Override is nothing more than an interface. The actual work is done by the java compiler. How the compiler does this is not specified.
Here are some links that explain how to work with an AnnotationProcessor to implement something similar to #Override :
Processor Java doc
Java annotation processing tool
Code generation using AnnotationProcessor
Annotation Processor, generating a compiler error
Source code analysis using Java 6 API
Playing with Java annotation processing

How to suppress warnings for API marked as depreceated. #SuppressWarnings("deprecation") does not seems suppressing it

I tried to suppres warnings using #SuppressWarnings("deprecation") for depreceated APIs. Tried to build using make. Still getting compiler warnings.
Deprecated methods should be replaced as soon as possible. You can check the javadoc to see what you should replace it with.
One way to "suppress" the warnings is to compile your code with an older compiler where the methods you're using aren't deprecated yet.
Another would be to compile your code using -Xlint:deprecation
javac -Xlint:deprecation Application.java
#SuppressWarnings("deprecation") does not work on imports. In that case - if you have the liberty to do that - remove the import and address the class with the complete name in your code. That way, #SuppressWarnings("deprecation") will work on it successfully.
Warnings:
import net.example.fancy.DeprecatedClass;
public class FooBar {
#SuppressWarnings("deprecation")
private DeprecatedClass depr;
}
No more warnings:
public class FooBar {
#SuppressWarnings("deprecation")
private net.example.fancy.DeprecatedClass depr;
}

Overloaded package-private method causes compilation failure - Is this a JLS oddity or javac bug?

I've come across an oddity of the JLS, or a JavaC bug (not sure which). Please read the following and provide an explanation, citing JLS passage or Sun Bug ID, as appropriate.
Suppose I have a contrived project with code in three "modules" -
API - defines the framework API - think Servlet API
Impl - defines the API implementation - think Tomcat Servlet container
App - the application I wrote
Here are the classes in each module:
API - MessagePrinter.java
package api;
public class MessagePrinter {
public void print(String message) {
System.out.println("MESSAGE: " + message);
}
}
API - MessageHolder.java (yes, it references an "impl" class - more on this later)
package api;
import impl.MessagePrinterInternal;
public class MessageHolder {
private final String message;
public MessageHolder(String message) {
this.message = message;
}
public void print(MessagePrinter printer) {
printer.print(message);
}
/**
* NOTE: Package-Private visibility.
*/
void print(MessagePrinterInternal printer) {
printer.print(message);
}
}
Impl - MessagePrinterInternal.java - This class depends on an API class. As the name suggests, it is intended for "internal" use elsewhere in my little framework.
package impl;
import api.MessagePrinter;
/**
* An "internal" class, not meant to be added to your
* application classpath. Think the Tomcat Servlet API implementation classes.
*/
public class MessagePrinterInternal extends MessagePrinter {
public void print(String message) {
System.out.println("INTERNAL: " + message);
}
}
Finally, the sole class in the App module...MyApp.java
import api.MessageHolder;
import api.MessagePrinter;
public class MyApp {
public static void main(String[] args) {
MessageHolder holder = new MessageHolder("Hope this compiles");
holder.print(new MessagePrinter());
}
}
So, now I attempt to compile my little application, MyApp.java. Suppose my API jars are exported via a jar, say api.jar, and being a good citizen I only referencd that jar in my classpath - not the Impl class shiped in impl.jar.
Now, obviously there is a flaw in my framework design in that the API classes shouldn't have any dependency on "internal" implementation classes. However, what came as a surprise is that MyApp.java didn't compile at all.
javac -cp api.jar src\MyApp.java
src\MyApp.java:11: cannot access impl.MessagePrinterInternal class file for impl.MessagePrinterInternal not found
holder.print(new MessagePrinter());
^
1 error
The problem is that the compiler is trying to resolve the version print() to use, due to method overloading. However, the compilation error is somewhat unexpected, as one of the methods is package-private, and therefore not visible to MyApp.
So, is this a javac bug, or some oddity of the JLS?
Compiler: Sun javac 1.6.0_14
There is is nothing wrong with JLS or javac. Of course this doesn't compile, because your class MessageHolder references MessagePrinterInternal which is not on the compile classpath if I understand your explanation right. You have to break this reference into the implementation, for example with an interface in your API.
EDIT 1: For clarification: This has nothing to do with the package-visible method as you seem to think. The problem is that the type MessagePrinterInternal is needed for compilation, but you don't have it on the classpath. You cannot expect javac to compile source code when it doesn't have access to referenced classes.
EDIT 2: I reread the code again and this is what seems to be happening: When MyApp is compiled, it tries to load class MessageHolder. Class MessageHolder references MessagePrinterInternal, so it tries to load that also and fails. I am not sure that is specified in the JLS, it might also depend on the JVM. In my experience with the Sun JVM, you need to have at least all statically referenced classes available when a class is loaded; that includes the types of fields, anything in the method signatures, extended classses and implemented interfaces. You could argue that this is counter-intuitive, but I would respond that in general there is very little you do with a class where such information is missing: you cannot instantiate objects, you cannot use the metadata (the Class object) etc. With that background knowledge, I would say the behavior you see is expected.
First off I would expect the things in the api package to be interfaces rather than classes (based on the name). Once you do this the problem will go away since you cannot have package access in interfaces.
The next thing is that, AFAIK, this is a Java oddity (in that it doesn't do what you would want). If you get rid of the public method and make the package on private you will get the same thing.
Changing everything in the api package to be interfaces will fix your problem and give you a cleaner separation in your code.
I guess you can always argue that javac can be a little bit smarter, but it has to stop somewhere. it's not human, human can always be smarter than a compiler, you can always find examples that make perfect sense for a human but dumbfound a compiler.
I don't know the exact spec on this matter, and I doubt javac authors made any mistake here. but who cares? why not put all dependencies in the classpath, even if some of them are superficial? doing that consistently makes our lives a lot easier.

Categories

Resources