Is there an unsupported operation annotation in Java? - java

Are there any annotations in java which mark a method as unsupported? E.g. Let's say I'm writing a new class which implements the java.util.List interface. The add() methods in this interface are optional and I don't need them in my implementation and so I to do the following:
public void add(Object obj) {
throw new UnsupportedOperationException("This impl doesn't support add");
}
Unfortunately, with this, it's not until runtime that one might discover that, in fact, this operation is unsupported.
Ideally, this would have been caught at compile time and such an annotation (e.g. maybe #UnsupportedOperation) would nudge the IDE to say to any users of this method, "Hey, you're using an unsupported operation" in the way that using #Deprecated flags Eclipse to highlight any uses of the deprecated item.

Although on the surface this sounds useful, in reality it would not help much. How do you usually use a list? I generally do something like this:
List<String> list = new XXXList<String>();
There's already one indirection there, so if I call list.add("Hi"), how should the compiler know that this specific implementation of list doesn't support that?
How about this:
void populate(List<String> list) {
list.add("1");
list.add("2");
}
Now it's even harder: The compiler would need to verify that all calls to that function used lists that support the add() operation.
So no, there is no way to do what you are asking, sorry.

You can do it using AspectJ if you are familiar with it. You must first create a point-cut, then give an advice or declare error/warning joint points matching this point cut. Of course you need your own #UnsupportedOperation annotation interface. I gave a simple code fragment about this.
// This the point-cut matching calls to methods annotated with your
// #UnsupportedOperation annotation.
pointcut unsupportedMethodCalls() : call(#UnsupportedOperation * *.*(..));
// Declare an error for such calls. This causes a compilation error
// if the point-cut matches any unsupported calls.
declare error: unsupportedMethodCalls() : "This call is not supported."
// Or you can just throw an exception just before this call executed at runtime
// instead of a compile-time error.
before() : unsupportedMethodCalls() {
throw new UnsupportedOperationException(thisJoinPoint.getSignature()
.getName());
}

(2018) While it may not be possible to detect it at compile time, there could be an alternative. i.e. The IDE (or other tools) could use the annotation to warn the user that such a method is being used.
There actually is a ticket for this: JDK-6447051
From a technical point of view, it shouldn't be much harder to implement than inspections that detect an illegal use of an #NotNull or a #Nullable accessor.

try this annotation #DoNotCall
https://errorprone.info/api/latest/com/google/errorprone/annotations/DoNotCall.html

Related

Using 'diamond' notation for methods in java

I'm currently working on a component-based architecture management system in java. My current implementation of the retrieval of a component attached to an object works like this:
// ...
private final HashMap<Class<? extends EntityComponent>, EntityComponent> components;
// ...
public <T extends EntityComponent> T getComponent(Class<T> component)
{
// ... some sanity checks
if (!this.hasComponent(component))
{
// ... some exception handling stuff
}
return component.cast(this.components.get(component));
}
// ...
Now, this works fine, but it somewhat bugs me to have to write
object.getComponent(SomeComponent.class)
everytime I need to access a component.
Would it be possible to utilize generics in a way to shift the syntax to something more along the lines of
object.getComponent<SomeComponent>()
, utilizing the diamond operator to specify the class, instead of passing the class of the component as a parameter to the method?
I know it's not really a big thing, but making the syntax of often used code as pretty / compact as possible goes a long way I guess.
Unfortunately not, since type-parameters are "erased" in Java. That means that they are only available at compile-time (where the compiler is using them to type-check the code), but not at run-time.
So when your code is running, the <SomeComponent> type-parameter no longer exists, and your code therefore can't do any operations (if/else, etc) based on its value.
In other words:
At compile time, your method call looks like this: object.getComponent<SomeComponent>()
But after compilation your method call just looks like this object.getComponent(). There is no type-parameter any more.
So, yes, unfortunately you still need to pass a Class object along, or something similar (see "Super Type Tokens" for example), if you need to do something that depends on the type parameter at run-time.
The reason the Class workaround works is that it loosely speaking represents the type-parameter, since the type-checker makes sure that its instance fits with the type-parameter, but is an object and thus available at run-time too - unlike the type-parameter.
Note: The Class-trick doesn't work for type-parameters within type-parameters, such as Class<List<Something>>, since at run-time List<Something> and List<OtherThing> is the same class, namely List. So you can't make a Class token to differentiate between those two types. As far as i remember "Super Type Tokens" can be used instead to fix this (they exploit the fact that there is an exception to erasure: For subclasses of generic classes, the type-parameters used when "extending" the superclass are actually available at run-time through reflection. (there are also more exceptions: https://stackoverflow.com/a/2320725/1743225)).
(Related google terms: "Erasure", "Reification", "Reified generics")

Why would I use Lombok-Annotation #NonNull?

Lombok offers the annotation #NonNull which executes the nullcheck and throws a NPE (if not configured differently).
I do not understand why I would use that annotation as described in the example of that documentation:
private String name;
public NonNullExample(#NonNull Person person) {
super("Hello");
if (person == null) {
throw new NullPointerException("person is marked #NonNull but is null");
}
this.name = person.getName();
}
The NPE would be thrown anyway. The only reason here to use the annotation imo is if you would want the exception to be different from a NPE.
EDIT: I do know that the Exception would be thrown explicitly and thus 'controlled', but at least the text of the error message should be editable, shouldn't it?
Writing a type annotation such as #NonNull serves several purposes.
It is documentation: it communicates the method's contract to clients, in a more concise and precise way than Javadoc text.
It enables run-time checking -- that is, it guarantees that your program crashes with a useful error message (rather than doing something worse) if a buggy client mis-uses your method. Lombok does this for you, without forcing the programmer to write the run-time check. The referenced example shows the two ways to do this: with a single #NonNull annotation or with an explicit programmer-written check. The "Vanilla Java" version either has a typo (a stray #NonNull) or shows the code after Lombok processes it.
It enables compile-time checking. A tool such as the Checker Framework gives a guarantee that the code will not crash at run time. Tools such as NullAway, Error Prone, and FindBugs are heuristic bug-finders that will warn you about some mis-uses of null but do not give you a guarantee.
IMHO, you've understood that documentation page wrongly.
That documentation page doesn't imply that you are recommended to use both Lombok #NonNull annotations and explicit if (smth == null) throw …-like checks as the same time (in the same method).
It just says that a code like this one (let's call it code A):
import lombok.NonNull;
public class NonNullExample extends Something {
private String name;
public NonNullExample(#NonNull Person person) {
super("Hello");
this.name = person.getName();
}
}
will be automatically (internally) translated by Lombok into a code like the one quoted the question (let's call it code B).
But that documentation page doesn't say that it would make sense for you to explicitly write the code B (though you are allowed; and Lombok will even try to prevent double check in this case). It just says that with Lombok you are now able to write the code A (and how it will work — it will be implicitly converted into the code B).
Note, that the code B is a “vanilla Java” code. It isn't expected to be processed by the Lombok for the second time. So #NonNull in the code B is just a plain annotation, which has no influence on the behavior (at least, not by Lombok means).
It's a separate question why Lombok works in that way — why it doesn't remove #NonNull from the generated code. Initially I even thought that it might be a bug in that documentation page. But, as Lombok author explains in his comment, #NonNulls are intentionally kept for the purposes of documentation and possible processing by other tools.
The idea of the annotation is to avoid the if (person == null) in your code and keep your code cleaner.
I love lombok but in this case (personally) I prefer to use the #Nonnull annotation from javax.annotation with the Objects.requireNonNull from java.util.Objects.
Using lombok in this way make the code cleaner but even less clear and readable:
public Builder platform(#NonNull String platform) {
this.platform = platform;
return this;
}
This method raises a NullPointerException (no evidence of it) and in addiction
passing a null argument, in a method call, is not reported by my IDE (IntelliJ Ultimate 2020.1 EAP - latest version - with lombok plugin)
So I prefer using the #Nonnull annotation from javax.annotation in this way:
public Builder platform(#Nonnull String platform) {
this.platform = Objects.requireNonNull(platform);
return this;
}
The code is a little bit verbose but clearer and my IDE is capable to warning me if I pass a null argument on method call!
It serves similar purpose to
java.util.Objects requireNonNull()
or Guava’s PreConditions. This just makes the code more compact and fail-fast.

This method has two signatures -- so why the error? [duplicate]

I'm sure you all know the behaviour I mean - code such as:
Thread thread = new Thread();
int activeCount = thread.activeCount();
provokes a compiler warning. Why isn't it an error?
EDIT:
To be clear: question has nothing to do with Threads. I realise Thread examples are often given when discussing this because of the potential to really mess things up with them. But really the problem is that such usage is always nonsense and you can't (competently) write such a call and mean it. Any example of this type of method call would be barmy. Here's another:
String hello = "hello";
String number123AsString = hello.valueOf(123);
Which makes it look as if each String instance comes with a "String valueOf(int i)" method.
Basically I believe the Java designers made a mistake when they designed the language, and it's too late to fix it due to the compatibility issues involved. Yes, it can lead to very misleading code. Yes, you should avoid it. Yes, you should make sure your IDE is configured to treat it as an error, IMO. Should you ever design a language yourself, bear it in mind as an example of the kind of thing to avoid :)
Just to respond to DJClayworth's point, here's what's allowed in C#:
public class Foo
{
public static void Bar()
{
}
}
public class Abc
{
public void Test()
{
// Static methods in the same class and base classes
// (and outer classes) are available, with no
// qualification
Def();
// Static methods in other classes are available via
// the class name
Foo.Bar();
Abc abc = new Abc();
// This would *not* be legal. It being legal has no benefit,
// and just allows misleading code
// abc.Def();
}
public static void Def()
{
}
}
Why do I think it's misleading? Because if I look at code someVariable.SomeMethod() I expect it to use the value of someVariable. If SomeMethod() is a static method, that expectation is invalid; the code is tricking me. How can that possibly be a good thing?
Bizarrely enough, Java won't let you use a potentially uninitialized variable to call a static method, despite the fact that the only information it's going to use is the declared type of the variable. It's an inconsistent and unhelpful mess. Why allow it?
EDIT: This edit is a response to Clayton's answer, which claims it allows inheritance for static methods. It doesn't. Static methods just aren't polymorphic. Here's a short but complete program to demonstrate that:
class Base
{
static void foo()
{
System.out.println("Base.foo()");
}
}
class Derived extends Base
{
static void foo()
{
System.out.println("Derived.foo()");
}
}
public class Test
{
public static void main(String[] args)
{
Base b = new Derived();
b.foo(); // Prints "Base.foo()"
b = null;
b.foo(); // Still prints "Base.foo()"
}
}
As you can see, the execution-time value of b is completely ignored.
Why should it be an error? The instance has access to all the static methods. The static methods can't change the state of the instance (trying to is a compile error).
The problem with the well-known example that you give is very specific to threads, not static method calls. It looks as though you're getting the activeCount() for the thread referred to by thread, but you're really getting the count for the calling thread. This is a logical error that you as a programmer are making. Issuing a warning is the appropriate thing for the compiler to do in this case. It's up to you to heed the warning and fix your code.
EDIT: I realize that the syntax of the language is what's allowing you to write misleading code, but remember that the compiler and its warnings are part of the language too. The language allows you to do something that the compiler considers dubious, but it gives you the warning to make sure you're aware that it could cause problems.
They cannot make it an error anymore, because of all the code that is already out there.
I am with you on that it should be an error.
Maybe there should be an option/profile for the compiler to upgrade some warnings to errors.
Update: When they introduced the assert keyword in 1.4, which has similar potential compatibility issues with old code, they made it available only if you explicitly set the source mode to "1.4". I suppose one could make a it an error in a new source mode "java 7". But I doubt they would do it, considering that all the hassle it would cause. As others have pointed out, it is not strictly necessary to prevent you from writing confusing code. And language changes to Java should be limited to the strictly necessary at this point.
Short answer - the language allows it, so its not an error.
The really important thing, from the compiler's perspective, is that it be able to resolve symbols. In the case of a static method, it needs to know what class to look in for it -- since it's not associated with any particular object. Java's designers obviously decided that since they could determine the class of an object, they could also resolve the class of any static method for that object from any instance of the object. They choose to allow this -- swayed, perhaps, by #TofuBeer's observation -- to give the programmer some convenience. Other language designers have made different choices. I probably would have fallen into the latter camp, but it's not that big of a deal to me. I probably would allow the usage that #TofuBeer mentions, but having allowed it my position on not allowing access from an instance variable is less tenable.
Likely for the same logical that makes this not an error:
public class X
{
public static void foo()
{
}
public void bar()
{
foo(); // no need to do X.foo();
}
}
It isn't an error because it's part of the spec, but you're obviously asking about the rationale, which we can all guess at.
My guess is that the source of this is actually to allow a method in a class to invoke a static method in the same class without the hassle. Since calling x() is legal (even without the self class name), calling this.x() should be legal as well, and therefore calling via any object was made legal as well.
This also helps encourage users to turn private functions into static if they don't change the state.
Besides, compilers generally try to avoid declaring errors when there is no way that this could lead to a direct error. Since a static method does not change the state or care about the invoking object, it does not cause an actual error (just confusion) to allow this. A warning suffices.
The purpose of the instance variable reference is only to supply the type which encloses the static. If you look at the byte code invoking a static via instance.staticMethod or EnclosingClass.staticMethod produces the same invoke static method bytecode. No reference to the instance appears.
The answer as too why it's in there, well it just is. As long as you use the class. and not via an instance you will help avoid confusion in the future.
Probably you can change it in your IDE (in Eclipse Preferences -> Java -> Compiler -> Errors/Warnings)
There's not option for it. In java (like many other lang.) you can have access to all static members of a class through its class name or instance object of that class. That would be up to you and your case and software solution which one you should use that gives you more readability.
It's pretty old topic but still up-to-date and surprisingly bringing higher impact nowadays. As Jon mentioned, it might be just a mistake Java's designers made at the very beginning. But I wouldn't imagine before it can have impact on security.
Many coders know Apache Velocity, flexible and powerful template engine. It's so powerful that it allows to feed template with a set of named objects - stricly considered as objects from programming language (Java originally). Those objects can be accessed from within template like in programming language so for example Java's String instance can be used with all its public fields, properties and methods
$input.isEmpty()
where input is a String, runs directly through JVM and returns true or false to Velocity parser's output). So far so good.
But in Java all objects inherit from Object so our end-users can also put this to the template
$input.getClass()
to get an instance of String Class.
And with this reference they can also call a static method forName(String) on this
$input.getClass().forName("java.io.FileDescriptor")
use any class name and use it to whatever web server's account can do (deface, steal DB content, inspect config files, ...)
This exploit is somehow (in specific context) described here: https://github.com/veracode-research/solr-injection#7-cve-2019-17558-rce-via-velocity-template-by-_s00py
It wouldn't be possible if calling static methods from reference to the instance of class was prohibited.
I'm not saying that a particular programming framework is better than the other one or so but I just want to put a comparison. There's a port of Apache Velocity for .NET. In C# it's not possible to call static methods just from instance's reference what makes exploit like this useless:
$input.GetType().GetType("System.IO.FileStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
I just consider this:
instanceVar.staticMethod();
to be shorthand for this:
instanceVar.getClass().staticMethod();
If you always had to do this:
SomeClass.staticMethod();
then you wouldn't be able to leverage inheritance for static methods.
That is, by calling the static method via the instance you don't need to know what concrete class the instance is at compile time, only that it implements staticMethod() somewhere along the inheritance chain.
EDIT: This answer is wrong. See comments for details.

Compiletime validation of enum parameters

There is a constructor with three parameters of type enum:
public SomeClass(EnumType1 enum1,EnumType2 enum2, EnumType3 enum3)
{...}
The three parameters of type enum are not allowd to be combined with all possible values:
Example:
EnumType1.VALUE_ONE, EnumType2.VALUE_SIX, EnumType3.VALUE_TWENTY is a valid combination.
But the following combination is not valid:
EnumType1.VALUE_TWO, EnumType2.VALUE_SIX, EnumType3.VALUE_FIFTEEN
Each of the EnumTypes knows with which values it is allowed to be combined:
EnumType1 and the two others implement a isAllowedWith() method to check that as follows:
public enum EnumType1 {
VALUE_ONE,VALUE_TWO,...;
public boolean isAllowedWith(final EnumType2 type) {
switch (this) {
case VALUE_ONE:
return type.equals(Type.VALUE_THREE);
case VALUE_TWO:
return true;
case VALUE_THREE:
return type.equals(Type.VALUE_EIGHT);
...
}
}
I need to run that check at compile time because it is of extreme importance in my project that the combinations are ALWAYS correct at runtime.
I wonder if there is a possibility to run that check with user defined annotations?
Every idea is appreciated :)
The posts above don't bring a solution for compile-time check, here's mine:
Why not use concept of nested Enum.
You would have EnumType1 containing its own values + a nested EnumType2 and this one a nested EnumType3.
You could organize the whole with your useful combination.
You could end up with 3 classes (EnumType1,2 and 3) and each one of each concerned value containing the others with the allowed associated values.
And your call would look like that (with assuming you want EnumType1.VALUE_ONE associated with EnumType2.VALUE_FIFTEEN) :
EnumType1.VALUE_ONE.VALUE_FIFTEEN //second value corresponding to EnumType2
Thus, you could have also: EnumType3.VALUE_SIX.VALUE_ONE (where SIX is known by type3 and ONE by type1).
Your call would be change to something like:
public SomeClass(EnumType1 enumType)
=> sample:
SomeClass(EnumType1.VALUE_ONE.VALUE_SIX.VALUE_TWENTY) //being a valid combination as said
To better clarify it, check at this post: Using nested enum types in Java
So the simplest way to do this is to 1) Define the documentation to explain valid combinations and
2) add the checks in the constructor
If a constructor throws an Exception than that is the responsibility of the invoker. Basically you would do something like this:
public MyClass(enum foo, enum bar, enum baz)
{
if(!validateCombination(foo,bar,baz))
{
throw new IllegalStateException("Contract violated");
}
}
private boolean validateCombination(enum foo, enum bar, enum baz)
{
//validation logic
}
Now this part is absolutely critical. Mark the class a final, it is possible that a partially constructed object can be recovered and abused to break your application. With a class marked as final a malicious program cannot extend the partially constructed object and wreak havoc.
One alternative idea is to write some automated tests to catch this, and hook them into your build process as a compulsory step before packaging/deploying your app.
If you think about what you're trying to catch here, it's code which is legal but wrong. While you could catch that during the compilation phase, this is exactly what tests are meant for.
This would fit your requirement of not being able to build any code with an illegal combination, because the build would still fail. And arguably it would be easier for other developers to understand than writing your own annotation processor...
The only way I know is to work with annotations.
Here is what I do I mean.
Now your constructor accepts 3 parameters:
public SomeClass(EnumType1 enum1,EnumType2 enum2, EnumType3 enum3){}
so you are calling it as following:
SomeClass obj = new SomeClass(EnumTupe1.VALUE1, EnumTupe2.VALUE2, EnumTupe1.VALUE3)
Change the constructor to be private. Create public constructor that accept 1 parameter of any type you want. It may be just a fake parameter.
public SomeClass(Placeholder p)
Now you have to require to call this constructor while each argument is annotated with special annotation. Let's call it TypeAnnotation:
SomeClass obj = new SomeClass(TypeAnnotation(
type1=EnumType1.VALUE1,
type2=EnumTupe2.VALUE2,
type3=EnumTupe1.VALUE3)
p3);
The call is more verbose but this is what we have to pay for compile time validation.
Now, how to define the annotation?
#Documented
#Retention({RetentionPolicy.RUNTIME, RetentionPolicy.SOURCE})
#Target(PARAMETER)
#interface TypeAnnotation {
EnumType1 type1();
EnumType2 type3();
EnumType3 type3();
}
Please pay attention that target is PARAMETER and retention values are RUNTIME and SOURCE.
RUNTIME allows reading this annotation at runtime, while SOURCE allows creating annotation processor that can validate the parameters at runtime.
Now the public constructor will call the 3-parameters private construcor:
public SomeClass(Placeholder p) {
this(readAnnotation(EnumType1.class), readAnnotation(EnumType2.class), readAnnotation(EnumType3.class), )
}
I am not implementing readAnnotation() here: it should be static method that takes stack trace, goes 3 elements back (to caller of the public costructor) and parses annotation TypeAnnotation.
Now is the most interesting part. You have to implement annotation processor.
Take a look here for instructions and here for an example of annotation processor.
You will have to add usage of this annotation processor to your build script and (optionally) to your IDE. In this case you will get real compilation error when your compatibility rules are violated.
I believe that this solution looks too complicated but if you really need this you can do this. It may take a day or so. Good luck.
Well, I am not aware of a compile time check but I do not think it is possible because how can the compiler know which value will be passed to the constructor (In case the value of your enum variable is calculated in runtime (e.g. by an If clause) ?
This can only be validated on runtime by using a validator method as you implemented for the enum types.
Example :
If in your code you have something like this :
EnumType1 enumVal;
if (<some condition>) {
enumVal = EnumType2.VALUE_SIX;
} else {
enumVal = EnumType2.VALUE_ONE;
}
There is no way the compiler can know which of the values will be assigned to enumVal so it won't be able to verify what is passed to the constructor until the if block is evaluated (which can be done only in runtime)

Java Function Annotation Help, use #Deprecated?

Scenario:
Java 1.6
class Animal {
private String name;
...
public String getName() { return name; }
...
}
class CatDog extends Animal {
private String dogName;
private String catName;
...
public String getDogName() { return dogName; }
public String getCatName() { return catName; }
public String[] getNames() { return new String[]{ catName, dogName }; }
...
public String getName() { return "ERROR! DO NOT USE ME"; }
}
Problem:
getName doesn't make sense and shouldn't be used in this example. I'm reading about #Deprecated annotation. Is there a more appropriate annotation method?
Questions:
A) Is it possible to force an error when this function is used (before runtime)?
B) Is there a way to display a customized warning/error message for the annotation method I will use? Ideally when the user is hovering over deprecated/error function.
Generally, you use #Deprecated for methods that have been made obsolete by a newer version of your software, but which you're keeping around for API compatibility with code that depends on the old version. I'm not sure if it's exactly the best tag to use in this scenario, because getName is still being actively used by other subclasses of Animal, but it will certainly alert users of the CatDog class that they shouldn't call that method.
If you want to cause an error at compile time when that function is used, you can change your compiler options to consider use of #Deprecated methods to be an error instead of a warning. Of course, you can't guarantee that everyone who uses your library will set this option, and there's no way I know of to force a compile error just based on the language specification. Removing the method from CatDog will still allow clients to call it, since the client will just be invoking the default implementation from the superclass Animal (which presumably you still want to include that method).
It is certainly possible, however, to display a custom message when the user hovers over the deprecated method. The Javadoc #deprecated tag allows you to specify an explanation of why a method was deprecated, and it will pop up instead of the usual description of the method when the user hovers over the method in an IDE like Eclipse. It would look like this:
/**
*
* #deprecated Do not use this method!
*/
#Deprecated
public String getName() {
throw new UnsupportedOperationException();
}
(Note that you can make your implementation of the method throw an exception to guarantee that if the user didn't notice the #Deprecated tag at compile time, they'll definitely notice it at runtime).
Deprecation means the method shouldn't be used any longer and that it may be removed in future releases. Basically exactly what you want.
Yes there's a trivially easy way to get a compile error when someone tries to use the method: Remove the method - that'll cause errors at linktime for any code that tries to use it, generally not to be recommended for obvious reasons, but if there's a really good reason to break backwards compatibility, that's the easiest way to achieve it. You could also make the method signature incompatible (always possible), but really the simplest solution that works is generally the best.
If you want a custom message when someone hovers over the method, use the javadoc for it, that's exactly what it's there for:
/**
* #deprecated
* explanation of why function was deprecated, if possible include what
* should be used.
*/
After refactoring our User class, we could not remove userGuid property, because it was used by mobile apps. Therefore, I have marked it as deprecated. The good thing is dev tools such as IntellijIdea recognize it and shows the message.
public User {
...
/**
* #Deprecated userGuid equals to guid but SLB mobile app is using user_guid.
* This is going to be removed in the future.
*/
#Deprecated
public String getUserGuid() {
return guid;
}
}
Deprecated is the way to go ... you can also configure the compiler to flag certain things as an error as opposed to a warning, but as Edward pointed out, you generally deprecate a method so that you don't have to completely clean up all references to it at this point in time.
In Eclipse, to configure Errors and Warnings, go to Window -> Preferences. Under Java -> Compiler -> Errors/Warnings, you'll see a section for Deprecated APIs. You may choose to instruct the compiler to ignore, warn, or error when a method is deprecated. Of course, if you're working with other developers, they would have to configure their compiler the same way .

Categories