There is a base class (or interface) from which other classes are inherited. for example:

class Basic { /* ... */ }; class Derived1 extends Basic { /* ... */ }; class Derived2 extends Basic { /* ... */ }; class Derived21 extends Derived2 { /* ... */ }; // . . . 

The hierarchy can be arbitrarily large and branched. Some of these classes need to be added to the list of the class manager who will somehow manage them, for example, create instances on demand, issue clients a list of classes available to them, etc.

Actually, the question. How to "register" these classes in the manager? It is clear that it can be done very simply - enter them into the code manually. But I don’t want to do this because the hierarchy is changing, and more than one person is changing, and there is a high probability of missing a class. Interested in the method of automatically building a list of required classes.

To solve the problem, you can use any constructions of the Java language (Java8 EE), you can generate a list both during compilation and during execution. But no external libraries (including Reflections) can be used. Maximum - built-in libraries WildFly 10, on which the application runs.

  • But did you try / watch this code for finding classes in a package? - YurySPb
  • Here 's something else - YuriySPb
  • Hmm ... For some reason did not come across. It looks like it will work. We give the necessary classes annotation and look for annotated classes among all. We will execute it once, when the application starts in the container, so the speed is not very critical. - user194374
  • one
    @ ЮрийСПб Yes, this is not something that thought, it is practically a solution! Thank! Went to encode. - user194374
  • 2
    @YuriySPb Be sure to write. - user194374

1 answer 1

The Servlet 3.0 specification introduced the ServletContainerInitializer interface. This interface has a void onStartup(Set<Class<?>> c, ServletContext ctx) method void onStartup(Set<Class<?>> c, ServletContext ctx) . This method is called by the application container (in my case WildFly) when the container initializes the application. For a class that implements this interface, you can set the @HandlesTypes annotation, which specifies a list of classes / interfaces / annotations in which a particular interface implementation is interested. This list will be passed to the first parameter of the onStartup method. (If there is no @HandlesTypes annotation, the first parameter will be null ).

To solve the problem, we created our own abstract, which marks the required classes. The implementation of the ServletContainerInitializer interface declares "interest" in this annotation and, as a result, the container, when the application is initialized, calls the onStartup method of this implementation, passing it a list of marked classes.

Below is a sample code.

File src / main / java / so / kff / autoregister / TestAnnotation.java :

 package so.kff.autoregister; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) // Аннотация сохраняется при выполнении. @Target(ElementType.TYPE) // Аннотация применяется только к классам. public @interface TestAnnotation { String value() default ""; } 

Class implementations:

 package so.kff.autoregister; class Basic { /* ... */ }; @TestAnnotation class Derived1 extends Basic { /* ... */ }; class Derived2 extends Basic { /* ... */ }; @TestAnnotation class Derived21 extends Derived2 { /* ... */ }; // . . . 

File src / main / java / so / kff / autoregister / Manager.java :

 package so.kff.autoregister; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.HandlesTypes; import java.util.Set; @HandlesTypes(TestAnnotation.class) public class Manager implements ServletContainerInitializer { @Override public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException { if (c != null) for (Class<?> clazz : c) System.out.println(clazz.getName()); } } 

In order for the container to launch the Manager.onStartup method during initialization, you need to create the src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer file in which to write the full names of the classes whose methods should be run. In our case, the content should be as follows:

 so.kff.autoregister.Manager 

For this technology to work, the implementation of the ServletContainerInitializer interface must lie in some jar file, which, in turn, is embedded in the WEB-INF/lib section of the application being deployed (the war file).

We collect and deploy our application. As a result, in the WildFly console we see the following:

 package so.kff.autoregister.Derived1; package so.kff.autoregister.Derived21; 

Thus we received the classes. Then simply process the resulting classes as we need.