Java - static initializers in imported projects - java

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.

Related

Invoke some code when VM load interface

In normal Java class, when VM load a class, it will invoke clinit method, so I wonder know when VM load a interface, can it invoke some code?
for example, class B implements A, new B(), VM invoke clinit of B, what will VM do with A, in A can I insert some code like System.out.println("hello")
Directly not, Java interfaces are not supposed to contain any code, even if you can now have default method. Following code will not compile:
interface Foo {
init {
System.out.println("Loading Foo...");
}
}
However, interfaces can contain static fields:
interface Foo {
static class FooLoader {
private static Object init() {
System.out.printf("Initializing %s%n", Foo.class);
}
}
Object NULL = FooLoader.init();
}
Again, it may work BUT:
through Reflection, it's still possible to invoke init() method, so it can be called twice
code isn't really called at load time but at init time. To understand, what I mean check this simple main:
System.out.println("START");
System.out.println(Foo.class);
System.out.println("END");
As long as you don't access static members, Java interfaces are not initialized (See §5.5 of JVM Specification)
So, to truely catch load time, you can use a custom class loader, or instrumentation API.
Having static {} block in interfaces isn't possible. But if you are really certain that you need to invoke some code when loading interface you can use custom classloader which will hook your interface loading and perform some action on that
Here is an example:
static class MyClassLoader extends ClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("test.Test1")) {
... do whatewer you need on loading class/interface...
}
return getParent().loadClass(name);
}
}
}
How to replace classes in a running application in java ?
Also there is very usefull tutorial: https://zeroturnaround.com/rebellabs/reloading-objects-classes-classloaders/
As mentioned in another answers, you cannot have static section in interfaces. However you can have static methods and static final fields. You can combine both for debugging purposes.
interface TestInterface {
int dummy = init();
static int init() {
System.out.println("Loaded TestInterface");
return 1;
}
}

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 does Java find already loaded classes?

I know that Java uses the ClassLoader hierarchy for loading the classes.
For example a program:
public void test(){
A a = new A(); // Line 1 The class is accessed first time here so it should be loaded and defined
A ab = new A(); //Line 2 How can the second line be represented?
}
The first line of the code is similar to
Thread.currentThread().getContextClassLoader().loadClass("A");
So the class is loaded and defined to create instance of Class.
Now the question is when the second line is executed the Class A is referred again, will Java not lookup for the class again and return the same loaded instance of the Class?
As the Java classloader document says that every class loader should maintain the instances of loaded classes and return the same instances for the next call.
Where does Java keep the loaded classes? ClassLoader class has a Vector of classes which is called by VM to add the loaded classes.
Maybe the question is a bit confusing, basically I am trying to figure out from which method are the already loaded classes returned. I tried to keep a debug point in the loadClass() method but it is not called for the Line 2.
The loadClass() method of ClassLoader has findLoadedClass method but that too is not called.
If you want to "translate" the mention of A to any method call, then the closest you could get is not loadClass() but Class.forName().
This method call queries the classloader for the class, which may or may not trigger class loading (and the caller doesn't even care). It will simply return a fully loaded (and initialized, if you don't use the three-argument version) class back to the caller.
And once the class has been loaded, the class loader no longer get's invoked when the class is used (as the name suggests, it's job is done, once it loaded the class).
package java_language;
public class NewClass {
Java_language j;
public NewClass() throws ClassNotFoundException {
j=new Java_language();
if (Class.forName("java_language.Java_language", true, Thread.currentThread().getContextClassLoader()).equals(j.getClass())) {
System.out.println("CLass has been loaded");
}
}
public static void main(String[] args) throws ClassNotFoundException {
new NewClass();
}
}
package java_language;
public class Java_language {
static Java_language java_language = null;
public Java_language() {
System.out.println("Stack Overflow");
}
}
Ans is:
enter image description here

Accessing public methods of a Private Inner Class, from outside the Enclosing class

I have the following code class Agent.java :
public class Agent {
Helper helper ;
private class SpecificBehaviour extends Behaviour{
private Apple a;
public SpecificBehaviour(Apple a){
setApple(a);
}
public void setApple(Apple a){
this.a=a;
}
public Apple getApple(){
return a;
}
}
public void someMethod(){
helper = new Helper(this);
}
}
In the Helper.java ( another class within the same package) I would like to access the getApple() method. did some search and found this link
I am wondering if there is a better/ easier way of doing this ?
There are at least two issues here:
Helper doesn't know of the existence of SpecificBehaviour, because it's a private class. It could potentially know about the Behaviour class, which you haven't given any details of. If getApple() is declared in Behaviour, and if Behaviour is visible to Helper, then the visibility part needn't be a problem.
Helper will need a reference to an instance of SpecificBehaviour, which means you'll need to instantiate SpecificBehaviour. For that, you'll also need an instance of Agent, because SpecificBehaviour is an inner class. It's not clear whether you have such an instance.
Basically I think the presence of a private inner class is adding confusion here. If you're reasonably new to Java, I'd strongly recommend sticking to top-level classes for the moment. They have a few subtleties around them, and it's best to try to learn one thing at a time.
If this doesn't help, please give more context - your question is quite vague at the moment. Where do you want to use getApple within Helper? Should part of the state of Helper be a reference to an instance of SpecificBehaviour, or should it be a method parameter? Have you created an instance of Agent? What does Behaviour look like? You may find that in the course of answering these questions one at a time, you're better able to figure out the problem for yourself.
- Use Composition principle to get the access to the getApple() method.
Eg:
public class Agent {
Apple a = new Apple(); // Agent class has a reference of type Apple.
.....
.....
}
- Second way would be to make the getApple() method static in Apple class, and then access it from Agent class using the Class name with . (dot) operator.
Eg:
public class Agent {
public void go(){
Apple.getApple();
}
.....
.....
}
You need to ask the Agent object you are passing to the Helper for the instance of the private class SpecificBehaviour. This is the way it works. Encapsulation remember.
Jon Skeet stated that and I completely agree on it:
Helper will need a reference to an instance of SpecificBehaviour,
which means you'll need to instantiate SpecificBehaviour. For that,
you'll also need an instance of Agent, because SpecificBehaviour is an
inner class. It's not clear whether you have such an instance.
Actually, you can understand how weird your try is by testing the sample code below:
Agent.java
public class Agent
{
private class SpecificBehaviour
{
public String toString()
{
return "specific behaviour";
}
}
public Class getInner()
{
return SpecificBehaviour.class;
}
}
Helper.java
public class Helper
{
public static void main(String[] args)
{
try
{
Agent agent = new Agent();
System.out.println(agent.getInner().newInstance().toString());
}
catch (InstantiationException e) { e.printStackTrace(); }
catch (IllegalAccessException e) { e.printStackTrace(); }
}
}
The code above just compiles fine. And let's see what the output is:
java.lang.InstantiationException: Agent$SpecificBehaviour
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at Helper.main(Helper.java:5)

How to create a method in a Java class that is accesible from only one other class

I was wondering if anyone had a pattern that would help me achieve the following:
We have a JPA entity called Employee and on it there is a setLineManager method. We also have a separate updateLineStructureService, which is a Spring-managed service bean. We want to try and ensure that this setLineManager method can only be called from updateLineStructureService and not directly from any other class.
Is there a way to allow the service access to this method without exposing it to any other classes? I am aware that I could give the method package level access and put the service in the same package as Employee, but that will not fit our package structure so I would prefer not to do that. I am also aware that I could make the method private and just access it through reflection in this one place, but I do not like that solution at all.
Any ideas?
You can inspect the stacktrace (using Throwable#getStackTrace()) and see if it contains the allowed method on specified position.
In the following code snippet, System.PrivateEmployee is not visible outside the System class. Thus effectively privateMethod is private and can only be called from within the System class. Since System.PrivateEmployee extends System.PublicEmployee it can be used outside the System class as System.PublicEmployee
public class System
{
public static interface PublicEmployee { void publicMethod ( ) ; }
private static interface PrivateEmployee extends PublicEmployee { void privateMethod ( ) ; }
}
Use an inner class only available to the other service class:
public class Employee
{
static {
LineStructureService.registerEmployeeHelper(new EmployeeHelper() {
#Override
public void setLineManager(Employee emp, Object foo) {
emp.setLineManager(foo);
}
});
}
public static void init() {}
private void setLineManager(Object foo) { }
}
public class LineStructureService
{
private static volatile EmployeeHelper _helper;
static {
// ensure that Employee class is loaded and helper registered
Employee.init();
}
public static synchronized void registerEmployeeHelper(EmployeeHelper helper) {
_helper = helper;
}
public void doSomething(Employee emp)
{
// now this class can call setLineManager on Employee
_helper.setLineManager(emp, blah);
}
public interface EmployeeHelper {
public void setLineManager(Employee emp, Object foo);
}
}
The only way that a class can access private methods of other classes is with inner classes. If that is not an option, this can't be done.
One approach is to make two forms of Employee.
"BasicEmployee" has all the methods except setLineManager(). "ExtendedEmployee" extends BasicEmployee and adds a public void setLineManager(). (I'm assuming these are classes, but they could also be interfaces instead) Underneath the hood, everything is really a FullEmployee (for clarity, you could make BasicEmployee abstract). But, in the code, in all the classes except UpdateLineStructureService, you declare it as a BasicEmployee. Only in UpdateLineStructureService is it declared as a FullEmployee. So, only UpdateLineStructureService has easy access to setLineManager()
Now, a rogue coder could always cast their BasicEmployee to an ExtendedEmployee to access setLineManager(), so this isn't totally secure. But it's a reasonable pattern to limit access.
You could use AOP (e.g. AspectJ or CDI) to intercept the call to setLineManager(); if the caller is updateLineStructureService() call the method; if not do nothing, or raise an exception or whatever.

Categories

Resources