4

Does java offer a simple way to do this?

I know how to get this using Foo.class.getName())

But how would I be able to do this for any object I may be passing in through some method? Say

public String getClass(File file){
          // Get file class
}

Where file is some java file with a .java extension. I know it works if I directly hard code the name of the java class into Foo.class.getName(), but my approach at this includes java files not found in the current directory or package. Anyone guide me in the right direction? Thanks in advance.

Ceelos
  • 1,116
  • 2
  • 14
  • 35
  • 2
    So you're not asking about finding the class of an object, you're asking about the `public class` declared by the file. – 2rs2ts Apr 11 '14 at 16:11
  • Is this a `.java` file - i.e. Java source code that you want to extract the class name from; or a `.class` file - i.e. a compiled Java class that you want to load? – Boris the Spider Apr 11 '14 at 16:14
  • 2
    To clear it lets say Filename is HelloWorld.java. The file object is instance of java.io.File with content from HelloWorld.java. What OP wants to know is how to retrieve HelloWorld by this file object – Sikorski Apr 11 '14 at 16:14
  • 1
    Please, next time post your real problem instead of a part of it. This way, you can get better and more exact help. – Luiggi Mendoza Apr 11 '14 at 16:26
  • @LuiggiMendoza Hey, sorry about that. I've got the method counting part done, the only issue I had was with doing it for any file outside package – Ceelos Apr 11 '14 at 16:27
  • @Ceelos what do you exactly mean by *any file outside package*? – Luiggi Mendoza Apr 11 '14 at 16:28
  • @LuiggiMendoza my terminology might be incorrect here. Files outside the project package or the directory where my main class is. – Ceelos Apr 11 '14 at 16:29
  • So you already parsed the file but couldn't get the name of the file? – Luiggi Mendoza Apr 11 '14 at 16:32

4 Answers4

4

Well .java files need to have the same name as the class or enum within, so we could just use the file name:

public String getClass(File file){
  return removeExtension(file.getName());
}

removeExtension has many different ways of achieving, here is just one:

public static String removeExtension(String file){
  return file.replaceFirst("[.][^.]+$", "");
}

More here: How to get the filename without the extension in Java?

...the reason behind me wanting to do is is so that I can count the methods within the class.

OK, well this is not the way to do it, you should look into reflection: What is reflection and why is it useful?

Community
  • 1
  • 1
weston
  • 54,145
  • 21
  • 145
  • 203
  • In order to use reflection on a class, it must be loaded first. Using reflection may not work in this case if you're evaluating classes outside the packages and you may get problems when trying to load them. The best scenario would be parsing the Java file and get the desired info. – Luiggi Mendoza Apr 11 '14 at 16:20
  • 1
    Not exactly same as `Class.getName()` which also gives you the package name. This will probably require reading the package declaration too. – Bhesh Gurung Apr 11 '14 at 16:21
  • @LuiggiMendoza good point, but as OP is struggling to get the class name from the file, they're going to have a hell of a time parsing the rest of the file, so I hope they are not attempting that. – weston Apr 11 '14 at 16:23
  • @BheshGurung good point, should be an easy task to open up the file and regex the package name out from it if they need to. – weston Apr 11 '14 at 16:26
  • @LuiggiMendoza I wouldn't say the real problem was counting the methods inside the class. That's done, all I had a problem with was obtaining the class itself. – Ceelos Apr 11 '14 at 16:28
  • @Ceelos which I found really strange how you do this without loading the class. Otherwise, `Foo.class.getName()` would work **always** and this question would have never arose... – Luiggi Mendoza Apr 11 '14 at 16:30
  • @LuiggiMendoza Foo.class.getName() we both know how that works. I've already looked up questions on how to count methods. That's why I didn't want to write that last part of counting methods into the question. That wasn't the focus of my question. – Ceelos Apr 11 '14 at 16:33
  • @Ceelos: If you really talking about the `.java` files (also meaning that there are no corresponding class files) then I don't how you can count methods without parsing the source file. But if you are talking about some classes in the classpath then you shouldn't have to deal with the source (`.java`) files at all. – Bhesh Gurung Apr 11 '14 at 16:34
  • @LuiggiMendoza Easy pal. I'm still learning. Haven't been coding for too long. Thanks for your input though. – Ceelos Apr 11 '14 at 16:40
3

Here is example code that gets classname from source with help of JavaParser.

This also works for wrongly named source files.

import com.github.javaparser.*;
import com.github.javaparser.ast.*;
import com.github.javaparser.ast.body.*;
import java.io.*;
import java.util.*;

public class ClassnameLister {

    private static String parseClassname(File filename) throws Exception {
        try (FileInputStream fin = new FileInputStream(filename)) {
            CompilationUnit cu = JavaParser.parse(fin);
            String packagePrefix = cu.getPackage().getName().toString();
            if (!packagePrefix.isEmpty()) packagePrefix += ".";
            for (TypeDeclaration type : cu.getTypes())
                if (type instanceOf ClassOrInterfaceDeclaration 
                        && ModifierSet.isPublic(type.getModifiers()))
                    return packagePrefix + type.getName();
        }
        return null;
    }

    public static void main(final String[] args) throws Exception {
        System.out.println(parseClassname(new File(args[0])));
    }
}
Vadzim
  • 24,954
  • 11
  • 143
  • 151
2

You can just take advantage of the name of the file. No need to use getClass(). What you want to do is get the filename of the File with getName(), then you need to strip off the extension.

There was a solution, to the second part, in that SO question that used Apache's FilenameUtils. For you it would be something like this:

import org.apache.commons.io.FilenameUtils;

public String getClass(File file) {
    return FilenameUtils.removeExtension(file.getName());
}

Of course, if you've already created a File you should already have its name. I just made this fit into your stub function.

If you are always going to deal with a .java file, then you can just split() the extension off:

    return file.getName().split(".java")[0];
Community
  • 1
  • 1
2rs2ts
  • 10,662
  • 10
  • 51
  • 95
  • I'm so close to upvoting this as well as weston's answer, the thing that's stopping me is the requirement for the third party library when it can be done via regex instead... – JonK Apr 11 '14 at 16:20
  • 1
    @JonK Hence why I added a note about whether OP can know about the extension. He says he knows it will be a `.java` file, but I shouldn't assume. – 2rs2ts Apr 11 '14 at 16:21
  • Well your edit adds a way of doing it that doesn't rely on the library, so here's your +1 – JonK Apr 11 '14 at 16:22
  • @JonK apache commons libraries are all open source. If you don't want/need to add the library, just copy the code and add it into an utility class/method in your project. – Luiggi Mendoza Apr 11 '14 at 16:27
  • @LuiggiMendoza True enough, though I personally wouldn't do that. Then again, that's just me! – JonK Apr 11 '14 at 16:30
1

You have to parse the file by yourself.

  1. Package Search for the line, that starts with \\s*package. If you do not find a matching line no package was declaired.

  2. Class name The outer class definition contains class but can start and lead one with more key words. Best approach would be to take the first appearance of class, and check for final key.

Add you package and class name with a dot, and you are done.

Hannes
  • 2,018
  • 25
  • 32