I would like to mark usage of certain methods provide by the JRE as deprecated. How do I do this?
You can't. Only code within your control can have the #Deprecated annotation added. Any attempt to reverse engineer the bytecode will result in a non-portable JRE. This is contrary to Java's write once, run anywhere methodology.
you can't deprecate JRE methods, but you can add warnings or even compile errors to your build system i.e. using AspectJ or forbid the use of given methods in the IDE.
For example in Eclipse:
Go to Project properties -->Java Compiler --> Errors Warnings, Then enable project specific settings, Expand Deprecated and restrited APIs category
"Forbidden reference (acess rule)"
Obviously you could instrument or override the class adding #Deprecated annotation, but it's not a clean solution.
Add such restrictions to your coding guidelines, and enforce as part of your code review process.
You only can do it, if and only if you are building your own JRE! In that case just add #Deprecated above the corresponding code block! But if you are using Oracle's JRE, you are no where to do so!
In what context? Do you mean you want to be able to easily configure your IDE to inhibit use of certain API? Or are you trying to dictate to the world what APIs you prohibit? Or are you trying to do something at runtime?
If the first case, Eclipse, and I assume other IDEs, allow you to mark any API as forbidden, discouraged, or accessible at the package or class level.
If you mean the second, you can't, of course. That would be silly.
If you are trying to prohibit certain methods from being called at runtime, you can configure a security policy to prevent code loaded from specified locations from being able to call specific methods that check with the SecurityManager, if one is installed.
You can compile your own version of the class and add it to the boot class path or lib/ext directory. http://docs.oracle.com/javase/tutorial/ext/basics/install.html This will change the JDK and the JRE.
In fact you can remove it for compiling and your program won't compile if it is used.
Snihalani: Just so that I get this straight ...
You want to 'deprecate methods in the JRE' in order to 'Making sure people don't use java's implementation and use my implementation from now on.' ?
First of all: you can't change anything in the JRE, neither are you allowed to, it's property of Oracle. Uou might be able to change something locally if you want to go through the trouble, but that 'll just be in your local JRE, not in the ones that can be downloaded from the Oracle webpage.
Next to that, nobody has your implementation, so how would we be able to use it anyway? The implementations provided by Oracle do exactly what they should do, and when a flaw/bug/... is found it'll be corrected or replaced by a new method (at which point the original method becomes deprecated).
But, what mostly worries me, is that you would go and change implementations with something you came up with. Reminds me quite lot of phishing and such techniques, having us run your code, without knowing what it does, without even knowing we are running your code. After all, if you would have access to the original code and "build" the JRE, what's to stop you from altering the code in the original method?
Deprecated is a way for the author to say:
"Yup ... I did this in the past, but it seems that there are problems with the method.
just in order not to change the behaviour of existing applications using this method, I will not change this method, rather mark it as deprecated, and add a method that solves this problem".
You are not the author, so it isn't up to you to decide whether or not the methods work the way they should anyway.
Related
I have three Java classes that implement an Iterable interface. Two of them have the exact same implementation for their iterator() methods, which causes IntelliJ to flag the code as duplicated.
Since I'm using Java 8, I could push the implementation as a "default" at the level of the interface, but that would require also adding private fields on the interface which really gives out more information than is necessary, even if it were possible (I'm new to Java 8 so I'm not sure whether Java 8 also allows you to declare or even initialize fields at the level of the interface). Even if I were to do that, there will be more classes implementing the common interface with different implementations for iterator().
I have found this link towards the IntelliJ documentation that says the following:
To do that, select the check box Ignore duplicated code in sources marked as generated in the inspection settings page:[...]
Unfortunately, despite the fact that this checkbox does indeed appear in my inspection settings page:
The problem still persists after checking that checkbox. I'm not entirely sure what "generated sources" means in the link that I posted above and I'm looking for some assistance.
For what it's worth, I'm running IntelliJ 2017.1 Ultimate Edition.
I used #CrazyCoder's response above and found out and ran a so-called "code analysis", as offered by IntelliJ, and found the following functionality:
Clicking on "disable inspection" does solve the problem at hand, however in general this is undesirable. I would really like it if I could somehow only keep this "weak warning" for same-source file methods. If I duplicate code across public class definitions, it's usually because I know what I'm doing, as in this case.
I am transitioning from Scala to Java and miss having final parameters by default. I explored an experimental version of the Lombok library here (background info here) which had files hinting at this functionality:
"src/core/lombok/experimental/FinalArgs.java", "src/core/lombok/javac/handlers/HandleFinalArgs.java", "src/core/lombok/eclipse/handlers/HandleFinalArgs.java"
I have never done much reflection or annotation writing in Java, so points to anyone who can figure out how to get a working #FinalArgs annotation into my current Java project (not connected to Lombak - my team is not willing to use a modified/custom version of Lombak). First prize to anyone who can also explain what is going on.
You can't get such an annotation without doing what Lombok does (installing plugins in IDE's and possibly installing a vm agent).
However, you can set most IDE's to give you a warning or error if a parameter was re-assigned.
There's no further benefit in making them truly final. The JIT is smart enough to figure that out on its own.
Lombok will not add this feature. You can instruct your IDE or static source analyzer to generate warnings, but since java8, there is no added benefit to make variables and parameters final. If they are effectively final (never reassigned) they can be used inside lambda's and anonymous inner classes as if they were final.
I'm working on a Java library that I would like to be able to use across a couple of different Java compiler versions. Some annotations (specifically #SafeVarargs) only exist on some of these compiler versions and generate errors in others.
Especially for something like #SafeVarargs, which serves mostly as a marker to suppress warnings rather than actually changing the output of the compiler, I would like to be able to use these annotations and simply provide a dummy-implementation if an earlier compiler is missing them.
How would I go about doing this?
I guess you could just create surrogate implementations of those annotations and put them in a Jar that is added to the classpath making sure that the system/compiler provided one take priority when resolved by the corresponding class loader.
For example you can just copy the code of SafeVarargs from here
I have a scenario where I have code written against version 1 of a library but I want to ship version 2 of the library instead. The code has shipped and is therefore not changeable. I'm concerned that it might try to access classes or members of the library that existed in v1 but have been removed in v2.
I figured it would be possible to write a tool to do a simple check to see if the code will link against the newer version of the library. I appreciate that the code may still be very broken even if the code links. I am thinking about this from the other side - if the code won't link then I can be sure there is a problem.
As far as I can see, I need to run through the bytecode checking for references, method calls and field accesses to library classes then use reflection to check whether the class/member exists.
I have three-fold question:
(1) Does such a tool exist already?
(2) I have a niggling feeling it is much more complicated that I imagine and that I have missed something major - is that the case?
(3) Do you know of a handy library that would allow me to inspect the bytecode such that I can find the method calls, references etc.?
Thanks!
I think that Clirr - a binary compatibility checker - can help here:
Clirr is a tool that checks Java libraries for binary and source compatibility with older releases. Basically you give it two sets of jar files and Clirr dumps out a list of changes in the public api. The Clirr Ant task can be configured to break the build if it detects incompatible api changes. In a continuous integration process Clirr can automatically prevent accidental introduction of binary or source compatibility problems.
Changing the library in your IDE will result in all possible compile-time errors.
You don't need anything else, unless your code uses another library, which in turn uses the updated library.
Be especially wary of Spring configuration files. Class names are configured as text and don't show up as missing until runtime.
If you have access to the source code, you could just compile source against the new library. If it doesn't compile, you have definitely a problem. If it compiles you may still have a problem if the program uses reflection, some kind of IoC stuff like Spring etc.
If you have unit tests, then you may have a better change catch any linking errors.
If you have only have a .class file of the program, then I don't know any tools that would help besides decomplining class file to source and compiling source again against the new library, but that doesn't sound too healthy.
The checks you mentioned are done by the JVM/Java class loader, see e.g. Linking of Classes and Interfaces.
So "attempting to link" can be simply achieved by trying to run the application. Of course you could hoist the checks to run them yourself on your collection of .class/.jar files. I guess a bunch of 3rd party byte code manipulators like BCEL will also do similar checks for you.
I notice that you mention reflection in the tags. If you load classes/invoke methods through reflection, there's no way to analyse this in general.
Good luck!
This is for an Android application but I'm broadening the question to Java as I don't know how this is usually implemented.
Assuming you have a project that targets a specific SDK version. A new release of the SDK is backward incompatible and requires changing three lines in one class.
How is this managed in Java without duplicating any code(or by duplicating the least amount)?
I don't want to create two projects for only 3 lines that are different.
What I'm trying to achieve in the end is a single executable that'll work for both versions. In C/C++, you'd have a #define based on the version. How do I achieve the same thing in Java?
Edit: after reading the comments about the #define, I realized there were two issues I was merging into one:
So first issue is, how do I not
duplicate code ? What construct is there that is the equivalent of a
#define in C.
The second one is: is it possible
to bundle everything in the same
executable? (this is less of a
concern as the first one).
It depends heavily on the incompatibility. If it is simply behavior, you can check the java.version system property and branch the code accordingly (for three lines, something as simple as an if statement).
If, however, it is a lack of a class or something similar that will throw an error when the class is loaded or when the code gets closer to execution (not necessarily something you can void reasonably by checking before calling), then the solution gets a lot harder. The notion of having a separate version is the cleanest from a code point of view, but it does mean you have to distribute two versions.
Another solution is reflection. Don't reference the class directly, call it via reflection (test for the methods or classes to determine what environment you are currently running in and execute the methods). This is probably the "official" approach in that reflection exists to deal with classes that you don't have or don't know you will have at compile time. It is just being applied to libraries within the JDK. It gets very ugly very fast, however. For three lines of code, it's ok, but doing anything extensive is going to get bad.
The last thing I can think of is to write common denominator code - that is code that gets the job done in both, finding another way to do it that doesn't trigger the problematic class or method.
I would isolate the code that needs to be different in a separate class (or multiple classes if necessary), and include / exclude them when building the project for the different versions.
So i would have like src/java/org/myproj/Foo.java which is the common stuff, and then oldversion/java/org/myproj/Bar.java and newversion/java/org/myproj/Bar.java which is the different implementations of the class that uses changed api.
Then I either compile "src/java and oldversion/java" or "src/java and newversion/java".
Possibly a similar situation, I had a method which wasn't available in the previous version of the JDK but if it was there I wanted to call it, I didn't want to force people to use the more recent version though. I used reflection to look for the method, if it was there I called it, if it wasn't I didn't.
Pretty hacky but might give you what you want.
Addressing Java in general, I see two primary approaches.
1). Refactor the specific code to its own library. Have different versions of that library. Effectively your app is creating an abstaction above the different SDKs. Heavyweight for 3 lines of code, but perhaps quite reasonable for larger scale problems.
2). Injection using annotation. Write your own annotation processor to manage the appropriate injection. More work, but maybe more fun.
Separate changing code in different classes with the same interface. Place classes in the same jar. Use factory design pattern to instantiate one or another class depending on SDK version.