When I have to generate javadocs for a new, unfamiliar project, I find that I spend a long time trying to simply write the correct command, specifying all the packages, all the source trees, etc. It's time-consuming and error-prone: I'm probably missing some source.
So let's say I have a directory myproj, and underneath it there are a few packages (and various other resources and stuff), and under those package directories there are eventually some src/ directories, and then lots of my/awesome/java/project/package type structures.
Is there a single command that will always recurse over EVERYTHING and generate ALL javadocs in one output location? I don't care how long it takes. Something brain-dead like javadoc -d doc -sourcepath . -subpackages * would be great. Failing that, what's the easiest way to generate all javadocs, no matter what the directory structure is?
Use find to find all Java source files and then send them to javadoc:
find . -type f -name "*.java" | xargs javadoc -d outputdir
On Windows you can do it like this:
Generate file list:
dir /s /b *.java > file.lst
Generate javadoc:
javadoc -d outputdir #file.lst
Related
I'm trying without any success to create a java makefile that compiles the java source codes to classes which go in a specific folder. So far, I managed to get the classes but I am really having trouble understanding how to create a folder and place the classes in there.
Here's my code so far:
JC = javac
JVM = java
.SUFFIXES: .java .class
.java.class:
$(JC) *.java
default: .java.class
clean:
$(RM) *.class
I followed a lot of tutorials and still can't figure it out. Basically I have my .java files in my folder. When I run make, I would like the classes to go in /bin folder and if it doesn't exist it gets created
You cannot do what you want to do with suffix rules. You'll have to use pattern rules if you want the output to be placed in a different directory than the source. Pattern rules are a feature of GNU make so hopefully you're using that (you don't say).
Plus, the way you're using suffix rules is not right: you don't declare the suffix rule itself as a prerequisite. You declare the actual files you want to build as prerequisites.
Also, make cannot do this by itself: you have to tell your compiler where to put the output. I'm not a Java person so I can't help you with that. Check your manual.
Your recipe builds all the .java files with a single invocation, which is not really how make works: make wants to translate a single source file (plus possibly other header files etc.) into a single output file.
Replace your suffix rule:
.SUFFIXES: .java .class
.java.class:
$(JC) *.java
with a pattern rule:
$(OUT)/%.class : %.java
mkdir -p $(#D)
$(JC) -o $# $<
(I have no idea if -o is right for javac: as I said you'll have to consult your Java manual). You don't need to declare .SUFFIXES when you use pattern rules.
Then, declare your default target to depend on the output files you want to be generated:
classfiles := $(wildcard *.class)
default: $(classfiles:%.class=$(OUT)/%.java)
My makefile always rebuilds the project, even if no changes were made.
How can I fix it?
My project structure follows the usual bin/, src/, Makefile pattern.
Makefile:
# output directory
BIN = bin/
# input directory
SRC = src/
# java compiler
JC = javac
# compile flags
JFLAGS = -d $(BIN) -cp $(SRC)
sourcefiles = $(addprefix $(SRC), \
A.java \
B.java \
C.java)
classfiles = $(sourcefiles:.java=.class)
all: $(classfiles)
%.class: %.java
$(JC) $(JFLAGS) $<
clean:
$(RM) $(BIN)*.class
I made this makefile from examples I found online, but I'm not sure I understand everything being done, so if I could also get an explanation, that would be great :3
In general, make is not a good fit for Java. Make works best with tools that behave similarly to traditional compilers: they take an input file foo.X (and maybe some other input files as well) and they generate a single output file foo.Y. For a C compiler for example X is c and Y is o (foo.c compiles to foo.o).
Make is hard to use in situations where a single invocation of the compiler generates more than one output file, and it's not simple to use when the name of the output file doesn't relate directly to the name of the input file (in this case you have to write all explicit rules, not pattern rules).
For Java compilers a single .java input file can generate multiple different .class files, and the names of the .class files are not necessarily related to the name of the .java file.
In your situation, I'll bet if you look at the output files that javac is generating for your A.java file you'll see it's not generating A.class. Because A.class doesn't exist, make will always try to rebuild it.
Oh. Also. You're putting files in different directories. So even if you DO restrict yourself to situations where the names are identical, you have to write your pattern like this:
# ... Keep the first part as in your example
classfiles = $(patsubst $(SRC)%.java,$(BIN)%.class,$(sourcefiles))
all: $(classfiles)
$(BIN)%.class : $(SRC)%.java
$(JC) $(JFLAGS) $<
# ... Keep the clean rule as in your example
The patterns % must be identical; if you put things in different directories they're not identical.
For a given jar, I want to find out all classes (as far as possible) that are used by this jar. Since I have a lot of jars, I want to automate this process. My best idea so far is to
Decompile the jar (I have no experience with that but there should be command line tools).
Look for imports and parse them.
But I hope that someone else has done something like this before and give me advice on this.
Using a specialised tool is probably the way to do this reliably.
However, one really janky way of doing this would be to grab a list of all the .class files in your JAR, put the JAR on the classpath and use javap to get references to other classes:
#!/usr/bin/env bash
javap -cp $1 -v \
`zipinfo -1 $1 '*.class' | sed 's:/:.:g' | sed 's:\.class$::'` | \
grep ' = Class' | sed 's:.*// ::' | sort | uniq
Running this on guava-19.0.jar gives this:
"[[B"
"[B"
"[[C"
"[C"
com/google/common/annotations/Beta
com/google/common/annotations/GwtCompatible
com/google/common/annotations/GwtIncompatible
com/google/common/annotations/VisibleForTesting
com/google/common/base/Absent
com/google/common/base/AbstractIterator
...............................................................
"[Lcom/google/common/util/concurrent/MoreExecutors$DirectExecutor;"
"[Lcom/google/common/util/concurrent/Service$State;"
"[Lcom/google/thirdparty/publicsuffix/PublicSuffixType;"
"[Ljava/io/File;"
"[[Ljava/lang/annotation/Annotation;"
"[Ljava/lang/annotation/Annotation;"
"[Ljava/lang/Class;"
"[Ljava/lang/Comparable;"
"[Ljava/lang/Enum;"
"[[Ljava/lang/Object;"
"[Ljava/lang/Object;"
"[Ljava/lang/reflect/Field;"
"[Ljava/lang/reflect/Method;"
"[Ljava/lang/reflect/Type;"
"[Ljava/lang/reflect/TypeVariable;"
"[Ljava/lang/StackTraceElement;"
"[Ljava/lang/String;"
"[Ljava/net/URL;"
"[Ljava/util/Iterator;"
"[Ljava/util/Map$Entry;"
"[[S"
"[S"
sun/misc/Unsafe
"[[Z"
"[Z"
You'll need more output formatting, and, as others have pointed out, it won't pick up any use of reflection.
How this works:
zipinfo -1 $1 '*.class' will print out the names of all .class files in $1, which is the argument to the script shown. The seds change /s to .s and remove the .class extension, so that you end up with a list of Java-style class names. You could do this more elegantly, but it should work.
The javap invocation puts the jar on the classpath with -cp, and passes all the classes. -v makes it output a lot of information, including some entries which represent references to names of classes. The grep ensures we're only looking at those, the sed removes some extra information we're not interested in. sort | uniq ensures we're not printing the name of any class more than once. It does need a bit more sedding to standardize an output format.
A simple way is to try to compile your code without adding that jar.
Try to compile and looking at the compiler errors is the fastest way to do that.
But remember that a class can be loaded also a runtime using reflection (for example via spring configuration files) and compiling the code without the jar will not inform you about potential errors at runtime.
Is there an equivalent of the UNIX 'which' command, i.e. for given resource(s), traverse all classpath components and tell me in which component(s) it is found? In particular when there are multiple occurrences on the classpath?
(Context: I just spent the best part of a day chasing a bug which boiled down to a very long classpath having a source directory with stale source preceding (and thus eclipsing) a compiled jar with compiled newer code.)
(Yes I know you can get this with 'java -verbose' but that produces tons of output.
Maybe 'java -verbose ... | grep SpecificResource' is the best way?)
See jwhich, I believe it does exactly what you are looking for. It is not difficult to roll your own but why do that when it is readily available?
I use a shell script for finding classes within a set of JARs. The relevant part is this:
find /my/jars -name \*.jar | while read jar; do
jar -tf "$jar" | fgrep --label="$jar" -l foo/bar/SomeClass.class
done
which lists all JARs in /my/jars containing a file foo/bar/SomeClass.class.
Edit
This one-liner from the comments also works:
grep -rail --include=\*.jar foo/bar/SomeClass.class /my/jars
Your best bet is to take your classpath and search each element for the class(es) in question.
In theory, classes are guaranteed to be loaded in classpath order. If your classpath has a wildcard element, however, it's no longer deterministic. So you'd need to check for those and just dump out the classpath elements that match the resource in question.
A short JRuby/Groovy script should do it if java -verbose doesn't give you all the info you need.
I am joining a competition that requires me to put all my java classes in one single .java file. Does there exist a tool that does this for me (including changing the visibility of classes to be able to do this)?
Addition: thanks for trying to help me to read the site of the competition but I quote:
It is possible to make more than one
class for your program, but you will
have to put the source for all classes
in a single .java file (the compiler
will produce multiple .class files
anyway). When you do this, you should
not declare your classes public, or
the compiler will complain about it.
So, only 1 .java file is allowed (no jar) and in that file I can have multiple non-public classes besides my public main class (and not only static inner classes as suggested).
If you have access to Unix-y shell (for Windows, you can install e.g. Git for a decent Bash implementation, and it gives you a great VC tool):
cat *.java | sed 's/public class/class/g' >AllTehCodez.java
Doesn't have to be more complicated than that (unless you have a lot of strings containing the substring "public class", of course).
Edit: Doesn't work for package and imports. But...
(
egrep -h ^package *.java | head -1
egrep -h ^import *.java | sort -u
egrep -hv '^(import|package)' *.java | sed 's/public class/class/g'
) >AllTehCodez.java
This does of course assume all the classes are in the same package.
If we exclude various "bijou scripting haquettes" along the lines suggested above, I seriously doubt that any serious tool exists for doing this.
Why? Because this kind of nonsense goes against all known Java style rules and conventions!
The people behind that website need to be taught about archive file formats; e.g. TAR, ZIP, JAR.
EDIT
I take that back. They DO understand JAR files. Quoting from one of their documents:
Using your own executable Java jar with Caia
You can also use your own Java jar in
Caia competitions. We have written the
jarwrapper for that. The source of
jarwrapper.c is put in the
caia_install_/jarwrapper/
folder. In the Windows distro this is
put into the src/ folder.
Suppose the name of your class file is
JavaPlayer.class. The only thing you
will have to do is to rename the
executable in the bin/ folder from
jarwrapper to JavaPlayer. The
executable now will perform the
command: java -jar JavaPlayer. The jar
file should contain a manifest which
points to the class with the main
method.
In manager.txt you can use the program
name JavaPlayer which refers to the
executable that starts your Java jar
player.