Cleaning up stale .class files using Apache Ant - java

How do I clean up stale .class files out of ${workdir} given set of existing .java files in ${srcdir}? By stale I mean .class files that were generated from now removed .java files. I have tried coming up with something using Ant mappers and filesets etc. but I failed. Removing all .class files older than their respective source .java files would be acceptable, too.

I'm pretty sure there's an ant task to kill .classes older than the .java...
Depend sounds close, and may actually do what you want, but this isn't its intended purpose. Given developmentalinsanity's answer however, this may be the only thing that will Actually Work.

The problem is determining whether a class file without an obviously corresponding source file is really stale.
Try this in a single file (A.java)
public class A{}
class B{}
This will result in both A.class and B.class. So, B.class would seem stale because of the missing java file. You'd probably get similar issues with any inner classes.
Safest bet if you want to make sure there's no old class files lying around would be just to delete them all.

As it’s just not possible to detect what’s stale and what’s not, most builds have a clean target (that’s also part of cleanbuild). The clean target, just removes all files from you’re build directory. This directory normally is unversioned (svn:ignore).
Not all files in you’re build will be the result of the compiler, for example .property files, these files can be stored in an alternative directory that will be copies in to the build directory. For example in a web application build you can store those files in /web/WEB-INF/classes and let Ant copy them into the build directory.

Related

What are "BIN" files on github?

I wanted to upload some .java files on github, I don't remember if I uploaded the right files. I have been told that the files I should've submitted were missing. I checked the last commit, and the files I should've submitted were marked with "BIN" and were of type "classname".class instead of "classname".java, underneath each one of them it says "Binary file not shown" instead of the code. I would like to know what happened so that I can avoid this in the future. I have never experienced this before on github. What did I upload? I don't think I had any .class files regarding this project.
From what you say seems like you added files to your commit that shouldn't be added.
Well, to fix this, just remove those files, commit and push the changes. Done.
To avoid this scenario in the future and not only for you but for your team, you can create a .gitignore file at the root of the repository. This file contains patterns of paths (files and folders) so git will ignore those files when showing the state of the branch. If there's no such .gitignore file then create one and add the following:
*.class
bin/
Also, you can add more entries in this file to support omitting other files generated by IDE, for example. There are curated lists you can find like https://gist.github.com/chhh/4961200 or https://www.gitignore.io/api/eclipse
/bin is usually a folder that contains binary files or compiled stuff in general. You should never put it in a repo.
It's not dangerous, but it wastes space and it's something that has to be compiled in each one's computer anyway, so it's pointless to put them in the repo :)

How to make Eclipse package ONLY required libraries?

After developing a java app in Eclipse, I would like to deploy it by packaging it into a runnable .jar with only the minimum necessary by the main method and its dependencies.
I have several packages in my workspace I work with too, but do not need to be in the resulting .jar file.
When I try to export, it clearly says that the required libs will be there, but also the other independent packages are inside too. (With the Export option happen exactly the same)
I choose to export only the Main class of the com.project... package, but also the test.project... has been packaged.
In the project I have both com... and test... packages obviously.
How could I force it to truly package only the required ones?
Thanks in advance.
TEMPORARY ANSWER (2019-07-03):
Seems that, for now, there is no way to achieve this automatically, thus the answer from #arnonuem seems a good workaround.
If better news, please feel free to improve this thread.
Thank you all.
I would create an ANT file for this specific task. There you can freely customize which packages should be compiled into the jar and which not.
Please inspire yourself reading this example.
For a general overview what i am talking about you could take a quick look into this.
https://howtodoinjava.com/ant/ant-build-jar-file-example/
Please focus on
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="classpath"
includes="src/path/to/TheClassToBeIncluded.java" />
For more detailed information on how to include or exclude files or packages you should refer to the documentation over here:
https://ant.apache.org/manual/Tasks/javac.html
At the bottom of this page there is a list with valid build parameters.
First of all, we have to distinguish build and export.
Build transfers .java source code into .class byte code and mostly copies other resources. While doing that it usually merges all source folders into a single bin folder.
Export runs a build (or relies on Build Automatically) and then modifies the resulting .class files and other resources. Usually it packages them into one or more .jar files.
Therefore, our solution includes two steps:
build everything that is unwanted for export into a separate folder (or more)
export from a specific folder (or more)
For step 1, refer to this answer on Stack Overflow.
In a nutshell: Go to Project Properties > Java Build Path > Source tab > Allow output folder for source folders. This enables you to configure a specific output folder for each source folder in the centered viewer.
For step 2, we need to understand that eclipse's Runnable Jar File Export relies on a Launch Configuration.
So before exporting, go to Run > Run Configurations..., select the Classpath tab, remove the default User Entries and hit Advanced.... Now you can Add Folders containing your built classes.
You might want to use separate Run Configurations for internal testing and exporting.
I have struggled with this problem on and off for years, supposing it was just me who was failing to find the right solution. Possible solutions always seem to involve detailed manual configuration e.g. configuration of the build path, or selection of the folders from which classes are exported into a jar, or learning ant, but which still requires manual configuration. The problem is that the inter-dependencies between classes (and packages) are complex - imagine drawing a network diagram from import statements. Manual configuration is time-consuming, error-prone and, I think, infeasible except in simple cases. I am a bit stunned. If there is no automatic solution for selecting necessary classes, I suppose people are regularly exporting their entire code base and that the world is full of bloated jars ... (and, incidentally, without obfuscation, the entire source code base is thereby made available through reverse engineering).

How can I test if my jar file has any unresolved dependencies?

I'm writing a custom tool to build jar files from our build tree. We like to build "minimal" jar files that contain only the .class files actually referenced from the "root" class (where main() lives) -- and so on, recursively following dependencies.
Historically we have done this by getting javac to follow source dependencies, but that means recompiling common files many many times. (We build 60 or 70 distinct application jars from a single source tree.) I'm writing a new build system that compiles each source file only once, but that means we need to follow dependencies by parsing .class files.
The good news is, I've got working code that does what I want. But I need to be absolutely sure I didn't screw it up, i.e. I want to ensure that I'm building internally consistent jar files, where "consistent" means that all unresolved references can be resolved with one of our known third-party jars.
So ideally I want a MagicTool that I can run like
MagicTool \
--classpath commons-lang.jar:commons-collections.jar:[...etc...] \
myapp.jar
that will examine every unresolved reference inside myapp.jar and make sure that it can be resolved by one of the third-party jars passed to --classpath. If not, barf.
Better hope nothing in that path includes any sort of reflection, forName, etc.
I use depfind (if I'm not using my own Java spelunking tools) which may or may not provide output in a way that's helpful for you. jdepend is another option, although I've never used it for anything other than package-level dependencies.
Other tools like ProGuard will strip out unused classes (amongst other things), with the same reflective caveats.
I'm very wary of trying too hard to create minimal jar files; there's a point of diminishing returns/increased risk.
I am pretty sure that ProGuard is your magic tool, even if I don't now the exact call syntax.
At one stage some years ago, trying to index a JAR file with jar -i made it throw an exception if there were unresolved dependencies. I can't quickly test the current state of things.

overwrite java class in jar

I have class called org.jbpm.task.Comment in my jbpm.jar.
However, this it's a CR1 version and there is a bug in the class that I would like my application to overwrite.
Is it fine just to have a class in my project under com.jbpm.task called Comment and everywhere even in other jars it will refer to mine?
JAR files are just ZIP files. Use a tool like WinZip to extract all the files from the JAR, replace the .class file with yours, recreate the ZIP file using e.g. WinZip, rename it to .jar, overwrite the original JAR file.
If you don't have the original source to the .class file you need to correct, then use a Java decompiler to produce .java source for the class. It will lack comments etc present in the original, but it will be sufficient to correct errors (e.g. incorrect null checking, as I had a few times in some products.)
I would suggest using a Zip utility like 7zip to open the jar file and replace the class in the jar file the the latest one.
Well the behavior is not guaranteed. Sometime back I had a bad experience because of that. Check out the below SO thread. If you are targeting differnt JVM implementation then it could be a problem.
Xerces behaving differently on SUN JRE v1.5 and IBM J9 v1.5
You would have to make sure that your jar is loaded before bpm.jar. In some JREs jars are in the same location are loaded in alphabetic order.

Problems importing WAR files in Eclipse?

I was unfortunately forced to result to uploading a WAR file as my backup for a web application I am working on.
Luckily I have the most recent WAR file available. I am using Eclipse IDE and am using the Web Tools plugin for all the J2EE work that I am doing with the Dynamic Web Application Project.
When I imported my WAR file, and ran it on a local server, everything works fine. The problem I a ran into is that in the Java Resources/src folder that all my packages and .java files were now only consists of all the same packages, but they are empty.
I checked to see if I could find the files and I found the .class files in an "Imported files" folder that is not accessible in the Eclipse Project Explorer. I believe that I need to do some type of build or something so that my .java files are available for me, but unfortunately this is one area where I lack.
One thing I would also like to know is, one way or the other, am I able to obtain the .java source code files if I have access to the .class files?
Also, I would like to configure this environment as it was before where my Java Resources:src folder contaiend the packages and .java files.
One thing I would also like to know is, one way or the other, am I able to obtain the .java source code files if I have access to the .class files?
The short answer is No. There is no way to regenerate original source files from bytecode files.
If you were really, really desperate you could try to use a Java bytecode decompiler on your bytecode files, but the result will be be nothing like your original source code.
All comments and javadocs will be gone.
All original code layout will be gone.
Original local variable and parameter names may be gone, depending on your original compiler switches.
Constant expressions may have been pre-evaluated, and loops, string concatenations and other constructs may have been transformed unrecognizably.
Depending on the maturity of the decompiler, the Java code might not be semantically equivalent to the original code, and might not even be compilable.
I hope you haven't spent too long developing this application because the best answer may be to start again.

Categories