How to generate JavaDoc documentation for classes without source? - java

I would like to generate some basic html interface documentation (without comments of course) of the class files within a jar to which I do not have source. How can I go about doing this?
The old tool of classdoc [Class Doc][1]http://classdoc.sourceforge.net/ which was available for java 1.3 used to provide this service. It seems to me that this can be done via the use of reflection.
Any ideas or examples using javadoc or another utility on how to perform this seemingly simple task on 1.6 or 1.7 classes?

There are maybe automated solutions but I do not know any. My best bet would be to write manually some code which will generate dummy java files with javadoc inside. You'll have to browse the jar file using something like this:
ArrayList<Class> classes = new ArrayList<Class>();
JarFile jfile = new JarFile("your jar file name");
String pkgpath = pckgname.replace(".", "/");
for (Enumeration<JarEntry> entries = jfile.entries(); entries.hasMoreElements();) {
JarEntry element = entries.nextElement();
if(element.getName().startsWith(pkgpath)
&& element.getName().endsWith(".class")){
String fileName = element.getName().substring(pckgname.length() + 1);
classes.add(Class.forName(pckgname + "." + fileName .split("\\.")[0]));
}
}
Then for each class you'll have to browse their methods to finally write down the dummy classes which look like the original ones in the jar file. While the code write the dummy methods to file, make it also write javadoc comments based on what the parameters and the return type are.
Once this is done use javadoc to generate the documentation from your dummy classes.
This might be a bit long to do but that's my guess for this one...

You can use jar tvf yourjar.jar for listing the classes, and javap for disassembling the classes, it yields a very legible documentation.

Related

Identify extension of a file based on its stem name

I have a simple problem that I am quite struggling with. I have several files in a directory and I am reading them and passing processing them based on their type (extension). However, as an input, I receive a path to the file without extension so I have to identify the type myself.
example (files):
files/file1.txt
files/file1.txt
files/pic1.jpg
----------------
String path = "files/file1";
String ext = FilenameUtils.getExtension(path); // this returns null
Is there a way to identify the type of file when the extension is not included in the path?
Your best bet here is to "do it yourself" by implementing instances of FileTypeDetectors.
When you have this, you can then just use Files.probeContentType() to have a string returned which describes the file contents as a MIME type.
The JDK does provide a default implementation but it relies on file extensions, basically; if you have a PNG image named foo.txt, the default implementation will return text/plain where the file is really an image/png.
Which is of course wrong.
Final note: if all you really have is only part of the file name, then use Files.newDirectoryStream() and provide it with the appropriate DirectoryStream.Filter<Path>. Not sure yet why you only have part of it though.
Since you're only given part of the file name, you'll need to search for files that start with that prefix. Note that there could be multiple matches.
Using java.nio.file
Path prefix = Paths.get(path);
Path directory = prefix.getParent();
try (Stream<Path> stream = Files.list(directory)) {
stream.filter(p -> p.getFileName().startsWith(prefix.getFileName() + "."))
.forEach(p -> System.out.printf("Found %s%n", p));
}
Using java.io
File prefix = new File(path);
File directory = prefix.getParentFile();
List<File> matches = directory.listFiles((dir, name) ->
name.startsWith(prefix.getName() + "."));
for (File match: matches) {
System.out.printf("Found %s%n", match);
}
Files.probeContentType(Path) implements a basic MIME type inquiry you can use (or extend), the internal details of which are platform specific. You can also make a little utility method that walks a Set of extensions. A combination of the two approaches may be necessary, depending on your application.
The MIME type checker will give different results on different releases implementations of the JRE. So, always have a fail-over solution.
See: http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType%28java.nio.file.Path
[EDIT]
This actually does not answer the question posited, as this method needs a full, legal Path object to work on. If you are given just the stem name, and the extension is missing, then you neither have an extension to work with nor a valid Path name for Files to work with [and probeContentType() may, in some implementations, just use the extension anyway.]
I'm not sure how you can do this without Path that refers to a real on-disk file that the JRE can access, or by hand if you don't have an extension. If you don't have a File of some sort, you can't even open it up yourself to attempt file type "magic".

Internal JAR uses files on the file system

I have a use case where I need to export this specific piece of code as a java library (which will be a JAR eventually) but the problem is that it needs to use some piece of information stored in physical files on the file system.
I have 2 questions here:
1) Where should I put these files on the filesystem (One option that I could think of was in the resources directory of the Java module containing the library: Have a doubt though that the resources directory also gets compiled into the jar?)
2) When I am using this library from an external Java application, how would the library be able to locate the files? Would they still be in the classpath?
You have two options, first one is to place the files inside the package structure, so that they will be packed inside the jar. You would get them from the code like this:
getClass().getResourceAsStream("/path/to/your/resource/resource.ext");
If you would call it from a static method of class named A then you should write like this:
A.class.getResourceAsStream("/path/to/your/resource/resource.ext");
The "/path" part of the path is the topmost package, and the resource.ext is your file name.
The other option is to put them outside the jar package, but then the jar needs to know their location:
provide it as an argument to the program (java -jar program.jar system/path/to/file)
hardcode the location from which you would read the file with paths
The way I undestood your queastion and answered it, it has nothing to do with classpath:
The CLASSPATH variable is one way to tell applications, including the JDK tools, where to look for user classes. (Classes that are part of the JRE, JDK platform, and extensions should be defined through other means, such as the bootstrap class path or the extensions directory.)
EDIT:
but you can nevertheless, put it there and get it from code like this:
System.getProperty("java.class.path");
It would however require some logic to parse it out.
You can pass the location of the files in a property file or some technique like this.
Where should I put these files on the filesystem
That is up to you to decide, though it would be a good idea to make this configurable. It would also be a good idea to try to fit into the conventions of the host operating system / distro, though these vary ... and depend on the nature of your application.
When I am using this library from an external Java application, how would the library be able to locate the files?
You would typically use a configuration property or initialization parameter to hold/pass the location. If you were writing an application rather that a library, you could use the Java Preferences APIs, though this probably a poor choice for a library.
Would they still be in the classpath?
Only if you put the location on the classpath ... and that is going to make configuration more tricky. Given that these files are required to be stored in the file system, I'd recommend using FileInputStream or similar.
Using Eclipse, I always create a package 'resources' where I put the files the jar needs. I access the files (from pretty much anywhere) through
this.getClass().getClassLoader().getResources("/resources/file.ext");
With export->runnable jar all those files are included in the .jar. I'm not sure this is the correct way of doing it though. Also, I'm not 100% sure about the "/" before resources, maybe it should be omitted.
I found a relevant answer as a part of another question : How to load a folder from a .jar?
I am able to successfully retrieve the files using the following code:
/**
* List directory contents for a resource folder. Not recursive.
* This is basically a brute-force implementation.
* Works for regular files and also JARs.
*
* #author Greg Briggs
* #param clazz Any java class that lives in the same place as the resources you want.
* #param path Should end with "/", but not start with one.
* #return Just the name of each member item, not the full paths.
* #throws URISyntaxException
* #throws IOException
*/
String[] getResourceListing(Class clazz, String path) throws URISyntaxException, IOException {
URL dirURL = clazz.getClassLoader().getResource(path);
if (dirURL != null && dirURL.getProtocol().equals("file")) {
/* A file path: easy enough */
return new File(dirURL.toURI()).list();
}
if (dirURL == null) {
/*
* In case of a jar file, we can't actually find a directory.
* Have to assume the same jar as clazz.
*/
String me = clazz.getName().replace(".", "/")+".class";
dirURL = clazz.getClassLoader().getResource(me);
}
if (dirURL.getProtocol().equals("jar")) {
/* A JAR path */
String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf("!")); //strip out only the JAR file
JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
Set<String> result = new HashSet<String>(); //avoid duplicates in case it is a subdirectory
while(entries.hasMoreElements()) {
String name = entries.nextElement().getName();
if (name.startsWith(path)) { //filter according to the path
String entry = name.substring(path.length());
int checkSubdir = entry.indexOf("/");
if (checkSubdir >= 0) {
// if it is a subdirectory, we just return the directory name
entry = entry.substring(0, checkSubdir);
}
result.add(entry);
}
}
return result.toArray(new String[result.size()]);
}
throw new UnsupportedOperationException("Cannot list files for URL "+dirURL);
}

How to replace default properties in library

I am making the library that has the default properties in the file default.properties.
private static String defPropertyPath = "/database.properties";
I want to ask if this file can be replaced by the program that use my library. So the program will define the properties with the same name default.properties that will replace the properties from library. I created the default.properties in the program where i use the library, but the library is still loading the properties from their package.
edit:
I read the properties file via input stream:
InputStream ins = DbProperties.class.getResourceAsStream(defPropertyPath);
if (ins == null) {
logger.error("Can't find properties:" + pathToProperties);
return;
}
Edit: File structure:
DbLibrary.jar
/
/database.properties
/src
MyApplication.jar
/
/database.properties
/src
/lib/DbLibrary.jar
My application use the DbLibrary.jar and wants to force this library to use database.properties from MyApplication and not from the DbLibrary.
May be much clearer if your library exports some API that allows the user of your library to invoke an init method at any time.
public static void init(Properties p) { ... }
I'm not sure there is enough information to answer your question, but I'm going to guess that perhaps you included the "database.properties" file in the jar with your application. If you did that, the application will always read the file from the jar, and not from the file system.
You only have to override the properties file in these projects which include your library.

How to get value of {#docroot} in a com.sun.javadoc.Taglet?

I'm writing a custom taglet for inclusion of a mathML file in a javadoc html file. I would like to store all my *.mml files in the same folder, possibly in the
{#docroot}/doc-files
folder. My question is : how can I know the value of the #docRoot string within a Taglet object (more specifically, within the toString(com.sun.javadoc.Tag tag) method ?
Many thanks!
I also needed to display MathML in my javadoc. I wrote a blog post about how I solved it here: http://chadretz.wordpress.com/2010/12/19/mathml-inside-javadoc-using-mathjax-and-a-custom-taglet/
More specifically to your problem though, if you look at the Taglet source code I posted there (collapsed by default), you can see where I get the top level ClassDoc of the Tag.holder() to obtain the directory depth I am at so I can traverse up. This helps if you need the relative HTML root. If you need to know the location of your MML's while the Taglet is running, I suggest you put them on the classpath and access them as resources.
Starting with the getPackageDoc function from #ChadRetz's blog, I've created a utility class that contains a function that does what you wish: Given a com.sun.javadoc.Tag, it returns the relative url from its enclosing file (the file containing that tag), to the JavaDoc root directory--this is the equivalent of {#docRoot}.
The class is called ComSunJavaDocUtil, and the function name is getRelativeUrlToDocRoot.
An example taglet's toString() function:
public String toString(Tag tag) {
return "Relative url to DOC ROOT for this tag's enclosing file is \"" +
ComSunJavaDocUtil.getRelativeUrlToDocRoot(tag) + "\"";
}
This utility class is part of Codelet. Installation instructions are here. If this utility class is all you're going to use, then the only jars you need on your classpath are codelet and xbnjava...and, of course, com.sun.javadoc.

How to walk through Java class resources?

I know we can do something like this:
Class.class.getResourceAsStream("/com/youcompany/yourapp/module/someresource.conf")
to read the files that are packaged within our jar file.
I have googled it a lot and I am surely not using the proper terms; what I want to do is to list the available resources, something like this:
Class.class.listResources("/com/yourcompany/yourapp")
That should return a list of resources that are inside the package com.yourcompany.yourapp.*
Is that possible? Any ideas on how to do it in case it can't be done as easily as I showed?
Note: I know it is possible to know where your jar is and then open it and inspect its contents to achieve it. But, I can't do it in the environment I am working in now.
For resources in a JAR file, something like this works:
URL url = MyClass.class.getResource("MyClass.class");
String scheme = url.getProtocol();
if (!"jar".equals(scheme))
throw new IllegalArgumentException("Unsupported scheme: " + scheme);
JarURLConnection con = (JarURLConnection) url.openConnection();
JarFile archive = con.getJarFile();
/* Search for the entries you care about. */
Enumeration<JarEntry> entries = archive.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().startsWith("com/y/app/")) {
...
}
}
You can do the same thing with resources "exploded" on the file system, or in many other repositories, but it's not quite as easy. You need specific code for each URL scheme you want to support.
In general can't get a list of resources like this. Some classloaders may not even be able to support this - imagine a classloader which can fetch individual files from a web server, but the web server doesn't have to support listing the contents of a directory.
For a jar file you can load the contents of the jar file explicitly, of course.
(This question is similar, btw.)
The most robust mechanism for listing all resources in the classpath is currently to use this pattern with ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author of ClassGraph.)
List<String> resourceNames;
try (ScanResult scanResult = new ClassGraph()
.whitelistPaths("com/yourcompany/yourapp")
.scan()) {
resourceNames = scanResult.getAllResources().getNames();
}
I've been looking for a way to list the contents of a jar file using the classloaders, but unfortunately this seems to be impossible. Instead what you can do is open the jar as a zip file and get the contents this way. You can use standard (here) ways to read the contents of a jar file and then use the classloader to read the contents.
I usually use
getClass().getClassLoader().getResourceAsStream(...)
but I doubt you can list the entries from the classpath, without knowing them a priori.

Categories

Resources