Java EE server independent way to locate JAR containing javax.persistence classes - java

I have a Java EE application where you can define variables of a certain type. To validate that the value expression is valid for it's type, I create a string containing a small class:
public class CompilableExpression {
private <type> expression = <expression>;
}
.. and try to compile it using JavaCompiler:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
Iterable<? extends JavaFileObject> compilationUnits =
Arrays.asList(stringContainingCompilableExpression);
CompilationTask task = compiler.getTask(
null, null, diagnostics, options, null, compilationUnits
);
task.call();
This works fine if you are using type: String and expression: "my string", or type: Integer and expression: 10.
I also want to validate types using the #Entity annotation.
When I try to do so I get an error:
Cannot find annotation method name() in type javax.persistence.Table: class file for javax.persistence.Table not found
So, I need to add a JAR containing javax.persistence classes to the class path somehow. Is there a generic way to find this JAR? I'm using GlassFish, and don't want to build a GlassFish only solution.
Or is adding it to my project as a normal (non provided) dependency the way to go?
Update
I'm trying to at least find the location in GlassFish (at ~/glassfish-4.1/glassfish):
find ./ -name '*ee*.jar'
./lib/javaee.jar
./modules/security-ee.jar
./modules/amx-javaee.jar
./modules/javaee-kernel.jar
./modules/autostart/osgi-javaee-base.jar
./modules/autostart/osgi-ee-resources.jar
./modules/deployment-javaee-full.jar
./modules/deployment-javaee-core.jar
./modules/glassfish-ee-api.jar
./modules/javax.management.j2ee-api.jar
My best guess is to use ./lib/javaee.jar, but when I check the contents it's almost empty:
$JAVA_HOME/bin/jar tf ./lib/javaee.jar
META-INF/
META-INF/MANIFEST.MF
META-INF/maven/
META-INF/maven/org.glassfish.main.extras/
META-INF/maven/org.glassfish.main.extras/javaee/
META-INF/maven/org.glassfish.main.extras/javaee/pom.xml
META-INF/maven/org.glassfish.main.extras/javaee/pom.properties
Does anyone know where (in the GlassFish installation) to get the JAR including the javax.persistence classes?

The JAR you are looking for is in $GLASSFISH_HOME/glassfish/modules/javax.persistence.jar
If you are deploying to a JavaEE App Server, the JAR with the #Entity annotation will already be in your application's runtime classpath. You shouldn't have to load any JAR files in code (as you described in your comment).
During development you typically configure your App Server in your IDE and that process should include the JAR with the annotation into your compilation classpath.
You might need to manually include it in the project compile classpath / application server libraries classpath depending on how your IDE handles this. For Glassfish all the API JARs are where you were looking in the modules directory.
Even though this ties your project to finding the JAR for compilation in a specific location relative to the app server install I find it's still a better approach then copying JARs into you project for compilation. This ensures you are compiling against the correct JARs that are deployed to the app server and so long as these are JavaEE APIs your application will deploy fine into any app server.
You could also set up your project to use Maven, include the required deps for the persistence APIs and it will find the compile time deps in your maven cache.
Also you might want to check out Jar Explorer which lets you search for classes etc inside JARs, folders of JARs etc. Its pretty convenient for finding these things.

Related

Resolving to correct dependencies when loading classes with custom classloaders

So I have this generic backend server that loads shaded jars in memory and then loads it through a custom Classloader.
E.g.
MyClass class = c.newInstance();
It works fine until the shaded Jar dependencies conflicts with the server classes.
E.g.
Server contains (with Custom Classloader):
com.fasterxml.jackson.jackson-databind:2.6.0
While the shaded jar contains
com.fasterxml.jackson.jackson-databind:2.9.9
When the method in the class that requires the said library e.g. class.doSomeThing(); it throws an error Caused by java.lang.NoSuchFieldError: because the loaded jackson-databind is 2.6.0 instead of 2.9.9
The question here is when the class is loaded from the shaded jar is there a way to make sure that the shaded dependencies are the ones used?
The question here is when the class is loaded from the shaded jar is there a way to make sure that the shaded dependencies are the ones used?
If you are using the default Class loader then the order of resolution will work as the order of the classpath. Within your code you can use
System.out.println(System.getProperty("system.class.path").replaceAll(":", "\n"));
And inspect the classpath. Usually such runtime environment (for example apache spark) has such features to allow you to prepend the classpath. You can check with your runtime server environment for such feature.

WFLYEE0040: A component named '...' is already defined in this module

I get this error in a Java maven project. The weird thing is, it doesn't appear on every machine so I assume it has something to do with a configuration issue.
The class RoleKeyCacheImpl is a #Startup #Singleton:
#Startup
#Singleton
public class RoleKeyCacheImpl implements RoleKeyCache { ... }
That's the error Wildfly triggers when deploying the service.
Caused by: java.lang.IllegalArgumentException: WFLYEE0040: A component
named 'RoleKeyCacheImpl' is already defined in this module at
org.jboss.as.ee.component.EEModuleDescription.addComponent(EEModuleDescription.java:167)
at
org.jboss.as.ejb3.deployment.processors.EJBComponentDescriptionFactory.addComponent(EJBComponentDescriptionFactory.java:58)
I've tried:
installing a new Wildfly (V10, V13) on the same machine -> doesn't help
installing a completely new Eclipse on this machine -> doesn't help
cleaning & rebuilding all related projects
making sure the deployments-folder is empty and doesn't contain old versions of the same WAR
read the related question here which also didn't help (they use Spring): A component named 'XXX' is already defined in this module in JBoss 7.1.1
read and tried this q&a: Wrong dependencies with EJB in JBoss Wildfly (server-clean) -> doesn't help
deleted and rebuilt the local maven rep (".m2") -> no effect
checking out the same source on another computer -> does work on one machine, on another it gives the same error
I have absolutely no clue what the issue is or even could be. On one machine, we check it out and it runs without errors. On others, the exact same error happens.
Does anybody have an idea?
I had this same issue multiple times with EAP 7.1 and now again with WildFly 21.0.0. I know by experience this is an issue caused by Eclipse who tries to deploy automatically to a configured WildFly instance. During the deployment (or undeployment) some concurrent file issue arises and files who should be removed, are still on the filesystem, causing this error that a component is already defined.
In fact it is not already defined, it is just WildFly that is confused because it finds in his temporary directories some old files which shouldn't be there and reference your exact same component.
Solution: remove in the WildFly standalone directory the content in the 'deployments' directory and the 'tmp' directory. Rest assured, all what is there is okay to remove safely. Reboot and the error message will be gone ;-)
You should pay attention to not have two #Stateless EJB annotations on top of two classes with the same name - in the same module.
You may differentiate them by using the name attribute in the annotation and put different values in each class
Looks like the class already exists. Check if it does...you may have to rewrite that part of EEModuleDescription to use its own private methods (which would be what you would write) rather than overriding methods in RoleKeyCacheImpl. If the class actually does not exist then right-click on the project -> Maven 2 Tools -> Generate Eclipse Artifacts (Check for Updates). That will regenerate all of the dependencies that the project uses. Also please be sure that you have not added any new projects to the classpath by mistake as that may also cause this error.
I just ran into this today when a colleague added a maven dependency.
Turns out this dependency was a jar with a nasty classpath entry or "../" in the manifest.
I edited the jar's manifest.mf that was cached in my local maven repository using 7-zip and removed the "../" classpath entry.
Then re-packaged my war file (maven clean install) and bingo, it works!
In my case it was caused by org.libreoffice jurt version 5.4.2 (but other versions I checked also have the classpath nastiness).
Unfortunately I was lucky we pinpointed it to a dependency, YMMV!

JDBC driver not found (servlet, DAO, mariaDB) [duplicate]

I developer a web application using Java. When I deploy it to my application server (Jetty, Tomcat, JBoss, GlassFish, etc.) throws an error. I can see this error message in the stacktrace:
java.lang.ClassNotFoundException
Or
java.lang.NoClassDefFoundError
What does this mean and how can I fix it?
What does this mean?
First, let's see the meaning of java.lang.ClassNotFoundException:
Thrown when an application tries to load in a class through its string name using:
The forName method in class Class.
The findSystemClass method in class ClassLoader.
The loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found.
Usually, this happens when trying to open a connection manually in this form:
String jdbcDriver = "...'; //name of your driver
Class.forName(jdbcDriver);
Or when you refer to a class that belongs to an external library and strangely this class cannot be loaded when the application server tries to deploy the application.
Let's see the meaning of java.lang.NoClassDefFoundError (emphasis mine):
Thrown if the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.
The last part says it all: the class existed at compile time i.e. when I compiled the application through my IDE, but it is not available at runtime i.e. when the application is deployed.
how can I fix it?
In Java web applications, all third party libraries used by your application must go in WEB-INF/lib folder. Make sure that all the necessary libraries (jars) are placed there. You can check this easily:
- <webapp folder>
- WEB-INF
- lib
+ jar1
+ jar2
+ ...
- META-INF
- <rest of your folders>
This problem usually arises for JDBC connectivity jars (MySQL, Derby, MSSQL, Oracle, etc.) or web MVC frameworks libraries like JSF or Spring MVC.
Take into account that some third party libraries rely on other third party libraries, so you have to add all of them in WEB-INF/lib in order to make the application work. A good example of this is RichFaces 4 libraries, where you have to download and add the external libraries manually.
Note for Maven users: you should not experience these problems unless you have set the libraries as provided, test or system. If set to provided, you're responsible to add the libraries somewhere in the classpath. You can find more info about the dependency scopes here: Introduction to the Dependency Mechanism
In case the library must be shared among several applications that will be deployed on your application server e.g. MySQL connector for two applications, there's another alternative. Instead of deploying two war files each with their own MySQL connector library, place this library in the common library folder of the server application, this will enable the library to be in the classpath of all the deployed applications.
This folder vary from application server.
Tomcat 7/8: <tomcat_home>/lib
JBoss 7/Wildfly: <jboss_home>/standalone/lib
The class must exist under WEB-INF/classes or be inside a .jar file under WEB-INF/lib. Make sure it does.
Same problem happen with me.
Might be possible one of your libraries are using some classes internal which is not available
in your lib or maven dependency pom.xml.
Thats means you have analyze your error logs and identify these classes and then import all dependencies in maven or lib folder.
I have fixed this error by the same way.
because some of my libraries are using activation.jar and json.jar internally.

Gradle remove version number from the dependency name

I would like to use derbyrun.jar created by the Apache Derby project in my application in order to run a derby database as a Windows or Linux service.
The problem is that derbyrun.jar references in its manifest other derby jars without any version number in their names, like Class-Path: derby.jar derbyclient.jar derbytools.jar derbynet.jar. While my application (with many subprojects) uses "maven/gradle" format derby-10.13.1.1.jar, derbyclient-10.13.1.1.jar, etc..
Is there a simple way in gradle to name those derby jars without a version number, like
compile("org.apache.derby:derby:10.11.1.1") {
artifact {
name = 'derby'
}
}
that should result in just derby.jar.
I do not like an idea of renaming derby-10.13.1.1.jar into derby.jar in a separate task as we reference those artifact names in many places using configurations.runtime, etc. (e.g. when deploying or creating manifest files for our own jars). And this renaming approach seems to complicate the script unnecessary (+ all the future maintenance effort when the derby version will be changed).
Is there a better way to achieve this? Sure, the mentioned above artifact { name = 'derby' } does not remove the version number from the jar's file name.

Get Information about the used Libraries of application

Is there a chance to get an information about libraries used in my java application?
Example: If I deploy my application on glassfish, the glassfish has it's own libraries and my application has own. If I use a newer version of a lib as the glassfish has, I want to test/log that my lib is used.
The reflection API lets you find some information about classes loaded into the application. For example assuming the library that includes SomeClass is loaded from a .jar file that includes version information you can use:
Package libPackage = SomeClass.class.getPackage();
String libVersion = libPackage.getSpecificationVersion();
If the .jar file does not include version information you can still find out its name with:
URL classLocation = SomeClass.class.getProtectionDomain().getCodeSource().getLocation();

Categories