What is the best way to approximate class.getSimpleName() without loading class? - java

Given a fully qualified class name that can be loaded with Class.forName(), is there a way to transform the name into what would be the result of loading the class and invoking getSimpleName() without actually attempting to load the class?
I need this capability for reflection purposes.

I'm going to say that you can't do it simply based on the name.
You can try to split on . and $, but this example code demonstrates that it is not always obvious where the simple name begins:
class Ideone
{
private static class Bar {};
public static void main (String[] args) throws java.lang.Exception
{
class Foo$o {
class Bar$bar {}
};
class Foo$o$Bar {
class Bar$bar {}
};
class Foo$o$Bar$Bar$bar {}
print(Ideone.class);
print(Bar.class);
print(Foo$o.class);
print(Foo$o.Bar$bar.class);
print(Foo$o$Bar.Bar$bar.class);
print(Foo$o$Bar$Bar$bar.class);
}
private static void print(Class<?> clazz) {
System.out.printf("fqn=%s, sn=%s%n", clazz.getName(), clazz.getSimpleName());
}
}
Output:
fqn=Ideone, sn=Ideone
fqn=Ideone$Bar, sn=Bar
fqn=Ideone$1Foo$o, sn=Foo$o
fqn=Ideone$1Foo$o$Bar$bar, sn=Bar$bar
fqn=Ideone$1Foo$o$Bar$Bar$bar, sn=Bar$bar
fqn=Ideone$2Foo$o$Bar$Bar$bar, sn=Foo$o$Bar$Bar$bar
Ideone demo
i.e. if you were to say "the bit of the name after the final $ or .", you'd be wrong.
The only conclusive way to do this is to load the class, potentially without initializing it:
Class<?> clazz = Class.forName(className, false, someClassLoadeR);

As demonstrated by the answer of #AndyTurner you cannot derive the simple name from the qualified class string in all cases.
But if the constraint without actually attempting to load the class does not forbid to read the contents of the class file, you could do the following (for the edge cases):
Get a InputStream for the class file contents via Class.getResourceAsStream()
Parse the beginning of the class file and read the super class name from the constant pool.
(as commented by #shmosel) Implement the logic of Class.getSimpleName(). The super class name allows you to replace Class.getSimpleBinaryString() which relies on an already loaded class.

Related

Java - static initializers in imported projects

So I have two projects A and B, and project B is imported in project A, and in project B I want to initialize some objects which have static initializers.
The problem is, they aren't getting called (already tested with final keyword, does not help).
So I actually want to have a small system and it should go this way (every class decribed here are in project B):
class A is a main class in which you can call a method addClassToLoad()* to add other classes (which will be "loaded" when method start() in class A will be called);
classes B, C and D call method addClassToLoad() from its static initializer;
when some class from project A calls a method start(), class A lists all classes it has gotten and calls a method onLoad() (explained in *).
And every method is static, so it's meant to be only one (no "instancing").
Saddly, static initializers aren't getting called.
And the question is: do I do something wrong (or maybe it is not possible at all) or maybe there is another way to do this small system? (I just don't really want to write in class A about every class, which must be loaded at start() method)
*addClassToLoad() takes an interface which has one method onLoad(), so it is getting called when method start() is called in class A
In code version:
class A:
public class A {
private static ArrayList<ClassToLoad> classesToLoad;
public static void addClassToLoad(ClassToLoad c) {
if (classesToLoad == null)
classesToLoad = new ArrayList<ClassToLoad>();
classesToLoad.add(c);
}
public static void start() {
for (ClassToLoad c : classesToLoad) {
c.onLoad();
}
}
}
class B (and others (C, D etc.) like this one):
public class B {
static {
A.addClassToLoad(new ClassToLoad() {
public void onLoad() {
load();
}
});
}
private static void load() {
// do something here on load ...
}
}
class ClassToLoad:
public interface ClassToLoad {
public void onLoad();
}
This is the same question when you add a new JDBC driver, why you have to call Class.forName() to register a JDBC driver. Every JDBC driver class has a static initializer to register itself with DriverManager. Why? A class loader does not by default load all the classes in jar files. A class is loaded only when it is referenced during execution, which is smart as the class loader never has to load those unused classes into memory. So to resolve your issue, you have to manage to load those classes, like by Class.forName() before you call start(). If you use spring, you can create a list of all those classes in your configure. Spring also provides an util to scan packages for certain types of classes, then you can just specify a package name to scan.
Static fields will be set, and static initializers (static blocks) when ClassLoader will load class for the first time. Rembemer that this will happen when given class will be used for the first time as ClassLoader loads classes in lazy fashion (when needed)
So it seems it's not possible for me to execute those static blocks, so I added every class, which I need to load, into class A, and that way they're actually loading without any problems (in project B). And in project A I need to add other classes, which I need to load, in the main class, obviously.
So I made those classes as Singletons, so they're actually loaded and are ready for "main" loading, launching and disposing. So the adding class looks like this:
A.addClassToLoad(B.getInstance());
I used class ClassToLoad as a generic class to load (sounds funny), though I renamed it to SystemCycle.
So the code as an example of class B now looks like this:
public class B implements SystemCycle {
private static B instance = new B();
private B() {}
public static void getInstance() {
return instance;
}
public void onLoad() { /* some code here */ }
public void onLaunch() { /* some code here */ }
public void onDispose() { /* some code here */ }
}
And SystemCycle class looks now like this:
public interface SystemCycle {
public void onLoad();
public void onLaunch();
public void onDispose();
}
Well, that was obvious, because of example of class B.
And I even made small checking system, so if the user tries to call one of these methods, it will be ignored, as the class implementing SystemCycle checks whether the class A is actually loading, launching or disposing at that moment. But if not, it just can do return. (though if the usermade class doesn't check that, it can be abused by other usermade class).
P.S. addClassToLoad in my project is actually called addSystemToLoad, so I made it here this way to make an example easier to understand.
Small edit: I even tried something to do with annotations first, but even that thing didn't help me.

Inner classes with the same name as an outer class?

Constraints:
I have a maven source code generator that I wrote that is creating POJO classes
from some data files that have nested namespaces. I want each namespace to
be nested as an inner class. In some cases out of my control I end up
with inner classes that are the same simple name as the outermost
class.
All the classes must be public scope as this is for a type safe
wrapper over something like a properties file, but hierarchical..
I can't change the names otherwise I am changing the names meaning and the namespace
that is enclosing data.
Given than I have the following code:
public class A
{
public class B
{
public class A
{
}
}
}
Inner classes should append the name of the outer class to form a unique namespace such as A$B$A.class, I haven't found a valid reason for this not to compile.
Is there any trick to get this to compile?
No. From the JLS section on class declarations:
It is a compile-time error if a class has the same simple name as any of its enclosing classes or interfaces.
Note: I somehow managed to miss this on my first pass through looking for an explicit rule. Check the edit history if you want the tortuous way I got here.
You asked: Is there any trick to get this to compile?.
The answer is: Well, maybe....
Create a class like the following:
public class A
{
public class B
{
public class X
{
}
}
}
And a class where this class is going to be used
public class AUse
{
public static void main(String[] args)
{
A.B.X aba = new A().new B().new X();
System.out.println("Created "+aba+" of class "+aba.getClass());
}
}
Then, download the Apache Byte Code Engineering Library (BCEL), and create and run the following class:
import java.io.FileOutputStream;
import org.apache.bcel.Repository;
import org.apache.bcel.util.BCELifier;
public class CreateCreators
{
public static void main(String[] args) throws Exception
{
new BCELifier(
Repository.lookupClass("A"),
new FileOutputStream("ACreator.java")).start();
new BCELifier(
Repository.lookupClass("A$B"),
new FileOutputStream("A$BCreator.java")).start();
new BCELifier(
Repository.lookupClass("A$B$X"),
new FileOutputStream("A$B$XCreator.java")).start();
new BCELifier(
Repository.lookupClass("AUse"),
new FileOutputStream("AUseCreator.java")).start();
}
}
This uses the BCELifier class from the BCEL. This is a class that takes a .class file, and creates a .java file that can be compiled to a .class file, that, when it is executed, creates the .class file that it was originally fed with. (Side note: I love this library).
So the A$B$XCreator.java file that is created there contains the BCEL code that is necessary to create the A$B$X.class file. This consists of statements like the generation of the constant pool and the instructions:
...
_cg = new ClassGen("A$B$X", "java.lang.Object", "A.java",
ACC_PUBLIC | ACC_SUPER, new String[] { });
...
il.append(_factory.createFieldAccess("A$B$X", "this$1",
new ObjectType("A$B"), Constants.PUTFIELD));
Similarly, the AUseCreator.java contains the BCEL code that creates the AUse.class. For example, the instruction of the constructor invocation of `A$B$X':
...
il.append(_factory.createInvoke("A$B$X", "<init>", Type.VOID,
new Type[] { new ObjectType("A$B") }, Constants.INVOKESPECIAL));
Now you can simply replace the String occurrences of "A$B$X" with "A$B$A" in the A$B$XCreator.java and AUseCreator.java, and then compile and run these classes.
The result will be a A$B$A.class file, and a AUse.class file that uses the A$B$A.class. Executing the AUse will print
Created A$B$A#15f5897 of class class A$B$A
I'm not sure whether this is considered as a "trick", or whether it still can be called "compiling" at all, but there is a way, at least. The key point is here, of course, that the fact that it did not compile is solely due to a limitation of the language, but there is no reason why this should not be representable in form of class files, regardless of how they are created.
You can't get it to compile, but more importantly, why would you need to?
What's wrong with:
public class A
{
public class B
{
public class InnerA
{
}
}
}
This seems like a design problem that you need to fix. If you can't rename it, consider anonymous inner classes. Or take some of those classes outside. Or just don't even use them.
It's a bit of a hack, but this compiles at my machine:
class A
{
public class B
{
public class Α
{
}
}
}
Try it. Literally: copy-past this thing ;)
SPOILER:
The name of the inner class is a capital letter alpha of the Greek alphabet. It's a Unicode character.
Depending on what you're after, the following might work for you:
public class A {
class B extends C {
}
public static void main(String[] args) {
new A().new B().new A();
}
}
class C {
class A {
{
System.out.println(getClass());
}
}
}

How to give a programmatic support to a class with a main

I'm sorry for the title but I can't really find another way to express it. I need to create a class with a double function, if you give to it a file as input from the console or terminal it gives back a print of it's calculations, but the class can be also used as subroutine and give a file to another class for further calculation.
To implement the first task I must define a main to accept input from console like this
java MyClass myfile.file
But then I can not simply get an instance the class inside something else like this
MyClass myClass = new MyClass(file);
cause I will always get an error from the main(IndexOutOfBound since args it's just an empty array).
How can I fix this? I must use the same class to do so, I can not build another class for the subroutine function.
Something like:
public class MyClass {
public MyClass(String nameOfFile) {
...
}
public void doSomething() {
}
public static void main(String[] args) {
MyClass myClass = new MyClass(args[0]);
myClass.doSomething();
}
}
So your main method simply interprets the incoming arguments (as file names or similar), then instantiates and executes your class as another library might.

how to load a java class along with static initializations before they are used?

I need to load some classes along with their respective static initializations, for example, in a factory method implementation.
If I just make reference to the class using the below syntax, the JVM does not run the static initialization part. Actually, does the JVM even load the classes?
Class<Shape> shapeClass = Shape.class;
or
Shape s = null;
But with class.forname() it does execute static initializations.
Class.forname("Shape");
The question is if this is the only way to do load a java class along with static initializations? Or are there other ways? Any significant performance penalties for using class.forname()?
From Class.forName(String className) API: Invoking this method is equivalent to: Class.forName(className, true, currentLoader).
The second argument = true means initialize class, and initialize class means run static initializers
This is a test to check
package test;
class Test2 {
static {
System.out.println("static init");
}
}
public class Test1 {
public static void main(String[] args) throws Exception {
Class.forName("test.Test2");
}
}
output
static init
but if you load Test2 with
Class.forName("test.Test2", false, ClassLoader.getSystemClassLoader());
there will be no output. You can also use this test to see that Test.class.getName() does not load the class either.
The simplest way to make it load is to add an empty static method and call it:
class Test2 {
public static void load() {
}
...
Test2.load();
When you load/resolve a class, the static initializers are executed in the order they are defined. It shouldn't matter how you load them, reflection or not. That is, unless you're meaning some other sort of initialization?

How can a class access its own classname?

I use an java application which generates a class dynamically. Via an ant script the source code will be produced for a give classname and a class template.
In the template for the class I need to know the name of even this class, to call a static method of the class.
Example. The class will be named "VersionInfo". Then in static main() of it I want to call the static method: VersionInfo.getId().
But I don't know the class-name.
Is there an equivalent to "this" for static contexts or some Utility-Class for such a purpose?
If you are creating the class via Ant then why not just generate a static method getClassName that returns the name of the class?
If your main method resides in the same class you just can call getId() in the main method.
So you're saying that it should generate this?
public class VersionInfo{ // VersionInfo class name changes, per problem description
public static void main(){
System.out.println(getId());
// but in the main within the class,we don't need the classname to call a static method
}
public static string getId(){
return "what's the problem?";
}
}
Is there something missing from the description, that you're calling some OTHER class' static method by an unknown-to-the-template name?
There's a nasty workaround:
public static final Class THIS_CLASS = new Object() {
public Class getParentClass() {
return getClass().getEnclosingClass();
}
}.getParentClass();
I'm not sure I understand. If you generate the class VersionInfo yourself, why can't you get the class name from the code that generates the class?
Try this:
package uk.co.farwell.stack_overflow;
public class Test_847708 {
private final static String getId() {
return "string";
}
public static void main(String args[]) {
System.out.println("getId=" + getId());
}
}
You cannot use the key "this" in a static context.
Instead, if you want to call dynamically a static function, you can use java reflection.
I cannot help you further for java reflection because I never use it, but I already use it in .Net and it's a powerful tools.
The cleanest answer to the question might be to make a third class with a static, known, name that is generated by the ANT script which references the dynamic class name, and then have your main method reference that known class.
If for some reason that isn't enough, then combine Joachim Sauer and Melursus answer, and get the class name, and then get the method via reflection:
Method m = THIS_CLASS.getDeclaredMethod("getId", null);
Object result = m.invoke(null, null);

Categories

Resources