I use eclipse and in some of my heavily used libraries (lets stick to slf4j in this example) there is a large amount of methods I will NEVER use.
Its up to the point that if I use those methods its most likely a bug.
(or a bad practice, missing debug info (checkNotNull(Object)), or dangerous to use)
For example there are 10 methods for "debug" alone. I need 3-4 at best.
How can I hide those other 5x 6-7 methods that clogs my code completion?
I know there is a feature in eclipse that hides classes and packages, however I haven't found such a feature for methods yet.
As an alternative I thought about using a "lite" library jar that only provides the methods I need and replace it with the original during the packaging. (I would use maven for this: lite = compile + optional/provided ; original = runtime scope)
However this alternative is tedious to maintain and may cause binary or license incompatibilities.
How can I hide "unwanted" methods from libraries in eclipse.
Related
I'm developing a library that needs to access layout items of the app implementing it. The only way I know how to do it is with reflection. In other words, if I create a constructor to my Library API like this:
public MyLibraryAPI(String packageName) {
Class appR = Class.forName(String.format("%s.R", packageName));
...
}
And the developer would instantiate the library with his package name as the parameter in the constructor.
What I ultimately need is to let my inner classes know the Android Views used in the developers layout (.xml files) - both the id and the type. Is there a way to achieve this without reflection and escape the performance overhead? I'm certain it cannot be done, but asking in case there's an expert that sees what I fail to notice.
EDIT: Additionally, proguard, by default, obfuscates the code for protection but, as a consequence, fails to provide JVM with means to achieve reflection at runtime, so if I use reflection I would have to ask the developer to turn off proguard obfuscation for his or her R class which is a bummer.
Reflection on Android is extremely costly. Some well-meaning and popular libraries like Roboguice have fallen over partly because of the performance cost of reflection.
I suspect some kind of code generation is the correct solution here. Dagger 2, Butter Knife and the Data Binding Library are successful examples of Android libraries that employ code generation. Since the data binding library performs inspections on the XML, it must be available to code generation libraries at that stage in the build and you may be able to base your implementation on that: here's a link to the source jars at Maven Central.
Apart from that, yes it seems there will be some compromise between ease of use and difficulty-to-implement. If you force your consumers to annotate their classes with your annotations, it becomes harder to use but probably much easier for you to implement. If you restrict yourself to inspecting XML and the generated R file and generating code from just that then I think your job will be a lot more difficult. On the other hand, using annotations has become rather commonplace and it may not be such an issue with your users.
Good luck!
Most of the time, I don't like Javascript and would prefer strict and compiled languages like Scala, Java, Haskell...
However, one thing that can be nice with Javascript is to be able to easily change code of external dependencies. For exemple, if you have a bug and you think it's one of your dependency library you can easily hack around and swap a library method by your own override and check if it's better. You can even add methods to Array ou String prototypes and things like that... One could even go to node_modules and alter the library code here temporarily if he wants to.
In the JVM world this seems to me like an heavy process to just get started:
Clone the dependency sources
Hack it
Compile it
Publish it to some local maven/ivy repository
Integrate the fixed version in your project
This is a pain, I just don't want to do that more than once in a year
Today I was trying to fix a bug in my app, and the lib did not provide me enough information. I would have loved to just be able to put a Logger on one line of that lib to have better insight of what was happening but instead I tried to hack with the debugger with no success (the bug was not reproductible on my computer anyway...)
Isn't there any simple alternative for rapidly altering the code of a dependency?
I would be interested in any solution for Scala, Java, Clojure or any other JVM language.
I'm not looking for a production-deployable solution, just a quick solution to use locally and eventually deployable on a test env.
Edit: I'm talking about library internals that are not intended to be modified by the library author. Please assume that the class to change is final, not replaceable by library configuration, and not injectable by any way into the library.
In Clojure you can re-bind vars, also from other namespaces, by using intern. So as long as the code you want to alter is Clojure code, that's a possible way to monkeypatch.
(intern 'user 'inc dec)
(inc 1)
=> 0
This is not something to do lightly though, since it can and will lead to problems with other code not expecting this behavior. It can be handy to use during development to temporarily fix edge cases or bugs in other libraries, but don't use it in published libraries or production code.
Best to simply fork and fix these libraries, and send a pull request to have it fixed in the original library.
When you're writing a library yourself that you expect people need to extend or overload, implement it in Clojure protocols, where these changes can be restricted to the extending/overloading namespaces only.
I disagree that AspectJ is difficult to use, it, or another bytecode manipulation library is your only realistic alternative.
Load-time weaving is a definite way around this issue. Depending on how you're using the class in question you might even be able to use a mocking library to achieve the same results, but something like AspectJ, which is specifically designed for augmentation and manipulation, would likely be the easiest.
I am developing/maintaining a Java library, and would like to keep track of backwards-incompatible changes between releases. This list could contain changes in class declarations, method signatures etc.
For example, if I (accidentally) changed a constructor by adding a parameter, then I would like to have it included in the list and be warned about the change.
// before
public MyCar(String name) { ... }
// after (some accidental change)
public MyCar(String name, long mileage) { ... }
// an application using my library depending on this constructor would be broken
// when it updates to the new version
Is there an automated way to generate this list? It feels like something that IntelliJ or Gradle should be able to do.
My team has tried reviewing pull requests and maintaining a CHANGELOG manually (which seems to be a common approach), but that's prone to human errors. I seek an automated way that can ideally be part of the build system.
I've always maintained the compatibility list manually but sometimes I forget something.
A quick look around shows several open source libraries but they haven't had new versions released in nearly 10 years. So I don't know if they would work with new Java 7 or 8 features.
Note: I've never used any of these!
CLIRR - apache project used by some other apache projects to show what has changed (example output from apache commons-lang here. last updated in 2005 doesn't even build with Maven 2 (or 3)
JDiff javadoc doclet comparator. Might support Java 5. Last updated in 2008
Japitools - apparently was used by the GNU Classpath project to compare their APIs for signature compatibility with different versions of the Sun Java class libraries. Doesn't look like it's been updated since 2006
There's a better way to do it.
Preserve backwards compatibility for a time by annotating your methods with #Deprecated, and indicate when they'll be unsupported. Then add the #deprecated piece to your Javadoc and that will automatically generate a list of deprecated features that the end user needs to care about.
This has the added benefit of allowing you to introduce when a feature was introduced (#since), and when a feature will be removed, without having to fuss too much with a lot of other tools.
Since you've added a more concrete code example, I'll add one more note: those sorts of changes...are the result of a conscious design decision, and it brings to the forefront two issues:
Regression testing (as in, a test should have caught this)
Ease of transition into the newer API (as in, if I need to suddenly give a new parameter to this to gain functionality, isn't it a new thing rather than it being attached to the old, legacy thing?)
Those issues can't be teased away with any conventional tools; that requires an earnest conversation about the amount of time it takes to transition from one API to another. If you find that you need to introduce new functionality to the core, then you had better make darn certain that hasn't broken the legacy case.
This is what it means to have an API - you have to have the older version lurking around for a while.
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.
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!