What is the best way to find all classes with a specific annotation in a JavaEE deployment? I work with a WildFly ApplicationServer and have created my own annotation. At the start of my deployment I would like to find all classes with my annotation and cache them for later access. What do I have to do to protect resources?
First of all Wildfly has modular class loading structure. In Wildfly doc:
Since JBoss AS 7, Class loading is considerably different to previous versions of JBoss AS. Class loading is based on the JBoss Modules project. Instead of the more familiar hierarchical class loading environment, WildFly's class loading is based on modules that have to define explicit dependencies on other modules. Deployments in WildFly are also modules, and do not have access to classes that are defined in jars in the application server unless an explicit dependency on those classes is defined.
As described above, if you have more .ear or .war package, they cannot see classes within each other unless explicit dependency defined. Each module can see its own class therefore each module should load and cache its own classes. You can not load all classes with a single class and single method.
With the following code you can see all loaded classes in the module.
Field f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Vector<Class> classes = (Vector<Class>) f.get(classLoader);
Related
I am working on a task that migrates the OSGI modules to Java SPI modules. Let's say I have three OSGI(A, B, C) modules. So each module has a class for activation and activation happening when starting the servers(at the beginning). Service registration and some other required method executions happening on the activation(#acctivate) class. Service, Service implementation, and Service registration are included in the same module.
but when migrating I have some questions,
1)Each OSGI module has a different class path. Therefore I can have different versions of dependency jars for the different modules ( A - aaa.jar(version-1.0), B - aaa.jar(version-2.0). But all the SPI modules will load in the same class path. So is it possible to have different versions of dependency jars for the different modules?
2)In Java SPI we don't have an activation class. Service loader is to load service implementations. is this lazy loading the solution for java SPI?
3)As I mentioned earlier. Some other method executions are happening in the OSGi activation class. So it will execute those methods when bundle activation happens(Starting the server ).what can be the solution in SPI modules(there is no activation class)?
When deploying a Springboot maven project(version 2.3.4.RELEASE) to an external Tomcat container,official guide says you need to mark the "spring-boot-starter-tomcat" dependency as provided ,but actually even if without doing that,the final war package which contains lib like "spring-boot-starter-tomcat","tomcat-embed-core" and "tomcat-embed-websocket" also works fine in tomcat8.5.54 or tomcat 9.0 ,so I am confused about that,"Do we really need set spring-boot-starter-tomcat as provided or not?" ,anyone could explains why?
"Traditional Deployment"
You don't want to have multiple versions of the same classes on the classpath. This can lead to many errors during runtime. For example, if you have a
public class MyServlet implements javax.servlet.Servlet
and you package both MyServlet.class and javax.servlet-api.jar (which contains javax.servlet.Servlet) into your application, you might get an error:
Servlet class MyServlet is not a javax.servlet.Servlet
What happens is: when the application classloader loads MyServlet, it looks for javax.servlet.Servlet in the application first and it finds it in javax.servlet-api.jar. The server compares this class with the one loaded by the server's classloader and concludes that they differ, since classes from different JARs are not equal. If the application is shipped without javax.servlet-api.jar this does not happen: the classloader does not find javax.servlet.Servlet in its own classpath, so it looks in the parent classloader.
Remark: This example can not actually be reproduced on Tomcat. Due probably to many incorrectly packaged applications the WebappClassLoader has an exception to the class loading rule: special classes such as those starting with javax.servlet or org.apache.tomcat are always loaded from the server's classloader (cf. the source code for a list of these exceptions).
TL;DR: due to the remark above, leaving spring-boot-starter-tomcat in the compile scope probably will do no harm, but it is a risk not worth taking.
I'm having a problem in an EAR package which contains a server deployed persistence unit in an EJB mdule, and a web app in a WAR module
EAR
|--- persistence unit (EJB module)
|--- web app (WAR)
...
Everything compiles and the deploy (under WildFly 10 CR5) is performed successfully. The persistnce unit is correctly deployed and the schema is created (using Hibernate schema generation during development).
Though, when I try to persist one of the entities like that
MyEntitiy e = new MyEntitiy();
e.setId(UUID.randomUUID().toString());
e.setName("name");
entityService.save(e);
I get a runtime error which root cause is:
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.String field x.y.z.MyEntity.id to x.y.z.MyEntity
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:393)
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:39)
Diving into the debugger, I tracked down to the method sun.reflect.UnsafeFieldAccessorImpl.ensureObj which perform a check via the method Class.isAssignableFrom between the classes
the class of the Field object (Field.getDeclaredClass())
the class of the entity to be persisted
This check returns false, due to the fact that the to classes have been loaded with different ClassLoaders (they are logically the same class).
How can I overcome this issue without changing the general layuot of the project (ie, keep the persistence unit as an EJB module to be shared across various modules)?
I believe, you might have included MyEntity class(or entities) in both ejb jar and war file and so they are getting loaded by both the class loaders. You may need to remove domain entities from war file and test it.
As per jboss docs, classes defined in ejb jar are available for classes in war file by default. And so they will loaded only once by ejb classloader only and will be used/available for classes in the war file as well.
Both will resolve package dependencies in osgi what is the difference between them
Bootdelegation is a hack that is needed because some code inside the VM assumed that application class loaders had visibility to com.sun.* classes. In OSGi, this is obviously NOT the case. Boot delegation is parameter that specifies for which packages the framework may do a lookup on the boot classpath. Since this is not modular, don't do it. It is global for the framework.
DynamicImport-Package is similar but only for the bundle it is defined in and only for exported packages. If a package cannot be found in the normal bundle contents or Import-Package then a DynamicImport-Package specifies the patterns of packages that are allowed to be searched in the set of exported packages. This idea is similar to the classpath, you've no idea what version you're going to get. Once a package is found, it is used forever. However, if it is not found every access will keep looking. I.e. you can install the package after the fact without restarting the bundle.
Packages imported via DynamicImport-Package are resolved every time a class from the package is needed. So if the package is not available due the resolving process, it will not fail.
By this way, ClassNotFoundExceptions may be thrown at runtime.
(compare this to optional imports)
BootDelegation classes will be loaded from the bootdelegation class loader, which is the class loader which loads the OSGi framework into the JVM
http://wiki.osgi.org/wiki/Boot_Delegation
http://www2.sys-con.com/itsg/virtualcd/java/archives/0808/chaudhri/index.html
http://de.slideshare.net/honnix/osgi-class-loading
We are working on Mavenizing our java project and we would like to setup a clean separation between interfaces and implementations for each module.
In order to do so, we want to split each module into two sub-modules one for interfaces and data objects used by them and another for implementations.
For example:
+commons
+commons-api
+commons-impl
The POMs of the modules will be configured such that no module depends on the impl sub-modules. This way no code from one module will be able to "see" implementation details of another module.
What we are having trouble with, is where to put our spring XMLs.
In our project we automatically import spring XML files using wildcard import like
<import resource="classpath*:**/*-beans.xml"/>
This way the location of Spring XMLs doesn't really matter at runtime, as all the modules get loaded into the same class loader and, the strict one way dependency rules in the POMs don't apply.
However, during development we want the IDE - we use Intellij IDEA - to recognize implementation classes referenced from the spring XMLs.
We also want IDEA to recognize beans defined in other modules.
If we put the spring XMLs in API sub-modules - they won't "see" the implementation classes in the impl sub-modules.
If we put them in the impl sub-modules, their beans won't be "seen" from other modules.
It is probably possible to configure the IDEA project to recognize spring XMLs from modules on which there is no dependency, but we prefer for our POMs to hold all the project structure information and not rely on IDEA project files.
We considered creating a third sub-module just to hold Spring XMLs (and perhaps hibernate xmls as well). For example:
+commons
+commons-api
+commons-impl
+commons-config
The external modules will depend on both commons-api and commons-config and commons-config will depend on both commons-api and commons-impl, with the dependency on commons-impl marked as "provided" (to prevent transitive resolution).
This however seems like a complex and awkward solution and we feel that there must be a better - simpler way to achieve interface/impl separation with Maven and Spring.
What you need is a runtime dependency scope:
runtime - This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
(https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)
Define a runtime dependency from one impl module to another impl module where you use the impl classes in the *-beans.xml config. Intellij will correctly recognize this in spring configuration files, but won't auto complete them in code (but it will do that in test code).
Also if anyone used the classes in the code, compilation through maven would fail, because the runtime dependency is not on a compile class path.
You can achieve decoupling of api and impl like this:
+ commons (pom)
+ pom.xml <--- serves as a parent aggregator (see below)
+ commons-api (jar) <--- contains models, interfaces and abstract classes only
+ commons-impl (jar) <--- depends on commons-api
+ commons-config (jar) <--- depends on commons-impl only (no need to depend on commons-api as it is brought in transitively)
+ external-project (war or jar) <--- has commons-config as a dependency
Parent aggregator pom (specify build order):
<modules>
<module>commons-api</module>
<module>commons-impl</module>
<module>commons-config</module>
</modules>
The config module can be omitted if it only contains spring application context configuration. The app configuration xml should be in the classpath and folder structure of the module that contains the artifact that you are deploying. So if you are building a war artifact, the app context should be in there.
The only configuration that should be in your commons module would be in a test package of your impl module.
In short you want Idea to override maven dependency graph but avoid keeping this configuration in idea project files?
One option is to group implementation dependencies in a maven profile. This profile would not be enabled by default but you should be able to mark it as active under idea.
Two ideas come to mind:
You will have one (or more) modules where all the modules (api+impl) are dependencies, you could place your spring configuration files there.
Place the spring configuration files in the api modules and declare a dependency on the impl module with scope provided this way the implementations will be known, while there is no dependency of the api for the deployment.
commons-impl at runtime scope in external modules
commons (pom dependencyManagement) =>
+commons-api (compile)
+commons-impl (compile)
+commons-config (compile)
commons-impl (pom dependencies) =>
+commons-api (compile)
+commons-config (compile)
external modules (pom dependencies) =>
+commons-impl (runtime)
+commons-api (compile)
+commons-config (compile)
keep modules number as little as possible;
This speeds up project build time and simplifies its layout.
keep modules structure as plain as possible: single root + all sub modules in the same folder, e. g.:
pom.xml
commons-api/
commons-runtime/
module-a-api/
module-a-runtime/
...
This simplifies navigation across the project, when modules number is really high (>50)
provide runtime-scoped dependencies to the runtime modules only when they are required;
This keeps your architecture clear. Use mocks instead of explicit dependency to another runtime module.
keep your api spring contexts in api modules, define your public beans as abstract bean + interface;
keep your implementation contexts in runtime modules, override api beans with your implementations via spring profiles (use <beans profile="default").
Result: simple, transparent layout and design; full ide support; no explicit dependencies on runtime module internals.