Map Entities loaded dynamically from external jars or outside classpath - java

I need to map Entities that are not listed at hibernate.cfg.xml, those classes are loaded dynamically
from an arbitraty folder. I'm trying to register a ClassLoaderService to change the loading behavior, the
following code runs fine if the classes are defined at compile time and exist in the classpath, but if
I try to map a dinamically loaded class I get ClassNotFoundException. There are some questions about the same issue, but I didn't find any working solution.
URL file = ConsultaBase.class.getProtectionDomain().getCodeSource().getLocation().toURI().resolve("implementacao/").resolve("hibernate.cfg.xml").toURL();
Configuration configuration = new Configuration()
.addAnnotatedClass(Registro.class).configure(file);
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder (
new BootstrapServiceRegistryImpl(
new ClassLoaderServicePirilampo(Registro.class.getClassLoader()),
new LinkedHashSet<Integrator>()
)
)
.applySettings(configuration.getProperties())
.addService(ClassLoaderService.class, new ClassLoaderServicePirilampo())
.build();
//this line throws ClassNotFoundException
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
I extended the ClassLoaderServiceImpl in order to log the requested classes, and noticed that running from JUnit, from the project where the classes are defined, it works fine, I get the class loading log from the Service. But the Service never receives
the request for the same class if I addAnnotatedClass that was loaded dinamically (from GroovyClassLoader).
The last line throws de folowing error:
17:06:49 ERROR [AssertionFailure] HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): java.lang.ClassNotFoundException: implementacao.Registro
PersistentClass name cannot be converted into a Class
org.hibernate.AssertionFailure: PersistentClass name cannot be converted into a Class
at org.hibernate.cfg.BinderHelper.getPropertyOverriddenByMapperOrMapsId(BinderHelper.java:817)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2169)
at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:963)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:796)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3788)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3742)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1410)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
at implementacao.ConsultaBase.createSessionFactory(ConsultaBase.java:64)
at implementacao.ConsultaBase.consultar(ConsultaBase.java:92)
at implementacao.ConsultaBase$consultar.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at ConsultaBaseConector.run(ConsultaBaseConector.groovy:6)
at groovy.util.GroovyScriptEngine.run(GroovyScriptEngine.java:551)
at br.org.fplf.processo.maquinaexecucao.parser.ParserAtividadeAutomatica.executar(ParserAtividadeAutomatica.java:43)
at br.org.fplf.processo.maquinaexecucao.MaquinaExecucao.executarAtividadeAutomatica(MaquinaExecucao.java:1050)
at br.org.fplf.processo.maquinaexecucao.MaquinaExecucao.executarAtividadeFluxo(MaquinaExecucao.java:973)
at br.org.fplf.processo.maquinaexecucao.MaquinaExecucao.executar(MaquinaExecucao.java:646)
at br.org.fplf.processo.maquinaexecucao.MaquinaExecucao.run(MaquinaExecucao.java:368)
Caused by: java.lang.ClassNotFoundException: implementacao.Registro
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1702)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at org.hibernate.annotations.common.util.ReflectHelper.classForName(ReflectHelper.java:60)
at org.hibernate.annotations.common.reflection.java.JavaReflectionManager.classForName(JavaReflectionManager.java:138)
at org.hibernate.cfg.BinderHelper.getPropertyOverriddenByMapperOrMapsId(BinderHelper.java:813)
... 20 more

This worked for me:
Thread.currentThread().setContextClassLoader(DynamicallyLoadedClass.getClassLoader());
example:
URL file = ConsultaBase.class.getProtectionDomain().getCodeSource().getLocation()
.toURI().resolve("hibernate.cfg.xml").toURL();
Configuration configuration = new Configuration()
.addAnnotatedClass(Registro.class).configure(file);
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build();
Thread.currentThread().setContextClassLoader(Registro.class.getClassLoader());
sessionFactory = configuration.buildSessionFactory(serviceRegistry);

Related

Bootstrap Hibernate SessionFactory in Netty/Armeria handler method fails with ClassNotFoundException

I have a Java Application that uses Armeria for a Web Service. When I create my Hibernate SessionFactory in the main method it works fine. But I am trying to create the SessionFactory when a certain Http Endpoint is called. In the handler method the session factory can not be created
Exception in thread "Thread-1" org.hibernate.internal.util.config.ConfigurationException: Unable to perform unmarshalling at line number 0 and column 0 in RESOURCE hibernate.cfg.xml. Message: null
Caused by: javax.xml.bind.JAXBException
- with linked exception:
[java.lang.ClassNotFoundException: com/sun/xml/bind/v2/ContextFactory]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:226)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:441)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
at org.hibernate.boot.cfgxml.internal.JaxbCfgProcessor.unmarshal(JaxbCfgProcessor.java:122)
... 17 more
Caused by: java.lang.ClassNotFoundException: com/sun/xml/bind/v2/ContextFactory
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at javax.xml.bind.ContextFinder.safeLoadClass(ContextFinder.java:577)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:224)
... 21 more
All I could find about this error is that JaxB is not provided for Java > 8 but i am using Java 8 and it works fine if I just create it at Application launch.
I believe it's some sort of class path conflict. In Java 8, the following code fails with ClassNotFoundException: com/sun/xml/bind/v2/ContextFactory, as reported in the question:
public class MyService {
#Get("/start")
public HttpResponse start() throws Exception {
final StandardServiceRegistryBuilder registryBuilder =
new StandardServiceRegistryBuilder().configure();
...
}
}
However, the problem goes away after upgrading to a newer Java version, such as Java 11.
Fortunately, the problem can be worked around by specifying the context class loader explicitly:
#Get("/start")
public HttpResponse start() throws Exception {
Thread.currentThread().setContextClassLoader(MyService.class.getClassLoader());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
final StandardServiceRegistryBuilder registryBuilder =
new StandardServiceRegistryBuilder().configure();
...
}

Instantiating a hibernate Configuration throws error: Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

I am fairly new to the hibernate framework and I'm creating a simple application with a Udemy course. I've continually been getting a 'java.lang.NoClassDefFoundError' on the following stack. It appears that when I create a org.hibernate.cfg.Configuration object the exception is thrown. Any guidance would be appreciated on how to solve the following issue, is it possible that this hibernate version is buggy and I need to backtrack to a previous version?
Hibernate-Core Version: 5.3.0.Final
Hibernate-Annotations: 3.5.6.Final
My-SQL Server Version: 8.0.12
DEBUG - Logging Provider: org.jboss.logging.Log4jLoggerProvider
DEBUG - Adding Integrator [org.hibernate.cfg.beanvalidation.BeanValidationIntegrator].
DEBUG - Adding Integrator [org.hibernate.secure.spi.JaccIntegrator].
DEBUG - Adding Integrator [org.hibernate.cache.internal.CollectionCacheInvalidator].
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
at org.hibernate.boot.spi.XmlMappingBinderAccess.<init>(XmlMappingBinderAccess.java:43)
at org.hibernate.boot.MetadataSources.<init>(MetadataSources.java:86)
at org.hibernate.cfg.Configuration.<init>(Configuration.java:123)
at org.hibernate.cfg.Configuration.<init>(Configuration.java:118)
at com.dataPack.data.HibernateUtil.buildSessionFactory(HibernateUtil.java:16)
at com.dataPack.data.HibernateUtil.<clinit>(HibernateUtil.java:10)
at com.dataPack.data.Application.main(Application.java:9)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
... 7 more
Here is the HibernateUtil class I created to build the sessionFactory.
package com.dataPack.data;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
Configuration configuration = null;
try {
configuration = new Configuration();
return configuration
.buildSessionFactory(new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build());
} catch(Exception e) {
e.printStackTrace();
throw new RuntimeException("Issue Building Session Factory!");
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
Here is the hibernate.properties file we are suppose to use.
hibernate.connection.username=user
hibernate.connection.password=password
hibernate.connection.url=jdbc:mysql://localhost:3306/ifinances
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
Since this project is known to work, it's likely that others have used a different Java version as the jaxb Apis were removed from Java SE. There are multiple ways to address this (as detailed in How to resolve java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException in Java 9 ) but the most reliable is to add the jaxb API dependency (groupId javax.xml.bind, artifactId jaxb-api -https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api/2.3.0) to the pom.xml or gradle build file.
Then rebuild and if you still hit ClassNotFound errors then see https://stackoverflow.com/a/43574427/9705485

Getting exception while refreshing Spring ApplicationContext in Spring Boot application

We are using Spring Boot for our application.
After starting the application, in the runtime we are adding(loading) a new Bean to the existing Applicationcontext.
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext();
appContext.register(NewBean.class);
appContext.refresh();
after adding the bean we are doing a refresh of applicationContext
During the refresh the MBean is trying to reregister some endpoints and we are getting the following error
(getting error for all these endpoints - requestMappingEndpoint, environmentEndpoint, healthEndpoint, beansEndpoint, infoEndpoint, metricsEndpoint, traceEndpoint, dumpEndpoint,
autoConfigurationAuditEndpoint, shutdownEndpoint, configurationPropertiesReportEndpoint)
Caused by: javax.management.InstanceAlreadyExistsException: org.springframework.boot:type=Endpoint,name=configurationPropertiesReportEndpoint
at com.sun.jmx.mbeanserver.Repository.addMBean(Unknown Source)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(Unknown Source)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(Unknown Source)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(Unknown Source)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(Unknown Source)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(Unknown Source)
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195)
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:662)
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:605)
Can anyone please tell how to skip this exception?
I have tried the following too
#EnableIntegrationMBeanExport(registration = RegistrationPolicy.REPLACE_EXISTING)
but getting the below exception
Caused by: org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [org.springframework.integration.monitor.IntegrationMBeanExporter#16c5464] with key 'integrationMbeanExporter'; nested exception is javax.management.InstanceAlreadyExistsException: org.springframework.integration.monitor:name=integrationMbeanExporter,type=IntegrationMBeanExporter
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:609)
at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:534)
at org.springframework.jmx.export.MBeanExporter.afterPropertiesSet(MBeanExporter.java:416)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
... 22 more
Caused by: javax.management.InstanceAlreadyExistsException: org.springframework.integration.monitor:name=integrationMbeanExporter,type=IntegrationMBeanExporter
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195)
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:662)
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:599)
... 26 more
Before you call refresh on an existing ApplicationContext, you should first destroy it else beans keep running.
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext();
appContext.register(NewBean.class);
appContext.refresh();
What you show here is that you are constructing a new context instead of reusing an existing one. The register method is also intended for #Configuration classes not arbitrary beans. If you want to add those just use one of the methods on the ApplicationContext like, registerSingleton. But in general adding beans at runtime should be a bad thing (imho).
Some applicationContext can refresh times, but not AnnotationConfigApplicationContext.
when you construct AnnotationConfigApplicationContext, which had run the refresh method, so it will be reported exception, you can destroy it first, and then refresh

Persistence configuration question

I have a web application (GWT/Vaadin based), which up to now I launched via
mvn jetty:run
Now I want to run it on another web server (also Jetty) and get database connection problems.
In the WAR file there is no persistence.xml file. Can this be the reason for the failure?
If yes, how should I configure the persistence, if
а) I'm using Java DB (Derby),
b) Hibenate and
c) now configure the DB connection like shown below
?
Thanks in advance
Dmitri
private void tryToOpenSession(final String aConnectionString)
throws Throwable {
...
state = PersistenceState.OPENING_CONNECTION;
final Configuration cnf = new Configuration();
cnf.setProperty(Environment.DRIVER,
"org.apache.derby.jdbc.EmbeddedDriver");
cnf.setProperty(Environment.URL, aConnectionString);
cnf.setProperty(Environment.DIALECT, DerbyDialect.class.getName());
cnf.setProperty(Environment.SHOW_SQL, "true");
cnf.setProperty(Environment.HBM2DDL_AUTO, "update");
cnf.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread");
cnf.addResource("persistence/Entity1.hbm.xml");
cnf.addResource("persistence/Entity2.hbm.xml");
...
cnf.addResource("persistence/EntityN.hbm.xml");
sessionFactory = cnf.buildSessionFactory();
session = getSession();
...
state = PersistenceState.CONNECTION_OPEN;
}
UPD: Here's the exception:
java.lang.NoClassDefFoundError: Could not initialize class org.apache.derby.jdbc.EmbeddedDriver
at java.lang.Class.forName0(Native Method) ~[na:1.6.0_20]
at java.lang.Class.forName(Class.java:186) ~[na:1.6.0_20]
at org.hibernate.connection.DriverManagerConnectionProvider.configure(DriverManagerConnectionProvider.java:80) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:143) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:84) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.cfg.SettingsFactory.createConnectionProvider(SettingsFactory.java:459) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:91) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2833) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2829) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1840) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
Exception clearly says that org.apache.derby.jdbc.EmbeddedDriver or some of its dependencies can't be found in the classpath. Usually you need to put required jar files into /WEB-INF/lib (or declare them in pom.xml to make Maven put them automatically).

Hibernate configuration

I'm trying to get started with Hibernate, and when executing my program I get an error during initialization.
The exception is thrown by this class, copied from here:
package net.always_data.bastien_leonard;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
Here is the stacktrace:
> java net/always_data/bastien_leonard/Main
Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration
Exception in thread "main" java.lang.ExceptionInInitializerError
at net.always_data.bastien_leonard.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
at net.always_data.bastien_leonard.HibernateUtil.<clinit>(HibernateUtil.java:8)
at net.always_data.bastien_leonard.Main.main(Main.java:17)
Caused by: java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration
at net.always_data.bastien_leonard.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
... 2 more
Caused by: java.lang.ClassNotFoundException: org.hibernate.cfg.Configuration
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:336)
... 3 more
I don't know where the problem comes from, so I don't really know where to look:
Problem of installation? This was handled by Maven, so I guess it's correct.
Hibernate can't find the configuration file?
Problem of classpath?
I'm invoking the program from the root of the classpath, which contains my hibernate.cfg.xml file.
Here is how it looks like in practice:
> pwd
/home/bastien/info/java/hibernate/test/Test/target/classes
> echo $CLASSPATH
/home/bastien/info/java/hibernate/test/Test/target/classes
> ls -F
hibernate.cfg.xml net/
> ls -FR
.:
hibernate.cfg.xml net/
./net:
always_data/
./net/always_data:
bastien_leonard/
./net/always_data/bastien_leonard:
Event.class Event.hbm.xml HibernateUtil.class Main.class
I've tried looking into the tutorial examples provided with Hibernate, but Maven can't compile them; it complains about missing artifacts.
By the way, Maven only lets me use Hibernate 3.3.1. Is it possible to use 3.3.2 and still let Maven handle the installation?
"java.lang.NoClassDefFoundError", indicating that the class loader can't find org.hibernate.cfg.Configuration says you've got a CLASSPATH problem.
echo $CLASSPATH
/home/bastien/info/java/hibernate/test/Test/target/classes
You've got to add all the Hibernate JARs and dependencies into the CLASSPATH as well. I don't see them in this echo.

Categories