This is not a duplicate as the tag above purports. This question has not yet been answered.
I am trying to set up this tutorial to get hyperjaxb
to work in an eclipse project. How can I get it to see a persistence provider? hbm2ddl
has NOT created the table structure in the database yet. Is that why the app is not seeing a persistence provider? Or is it because the contents of persistence.xml
in target/generated-sources
are not accessible from the src/main/java
directory in which my TestFunctions.java
is trying to call it? Here are the specifics... This line of code:
entityManagerFactory = Persistence.createEntityManagerFactory("persistence.xml", persistenceProperties);
Is throwing this error:
Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named persistence.xml
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
at maintest.TestFunctions.setUpPersistence(TestFunctions.java:119)
at maintest.Main.main(Main.java:10)
The code throwing the error is in this method:
public void setUpPersistence(){
final Properties persistenceProperties = new Properties();
InputStream is = null;
try {
Class<? extends TestFunctions> c = getClass();
ClassLoader cl = c.getClassLoader();
is = cl.getResourceAsStream("persistence.properties");
persistenceProperties.load(is);
}catch (IOException i) {i.printStackTrace();}
finally {if (is != null) {try {is.close();} catch (IOException ignored) {}}}
entityManagerFactory = Persistence.createEntityManagerFactory("persistence.xml", persistenceProperties);
}
persistence.xml
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd
http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<persistence-unit name="org.jvnet.hyperjaxb3.ejb.tests.po">
<class>org.jvnet.hyperjaxb3.ejb.tests.po.Items</class>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.Items$Item</class>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.PurchaseOrderType</class>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.USAddress</class>
</persistence-unit>
</persistence>
persistence.properties
is:
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.username=someusername
hibernate.connection.password=somepassword
hibernate.connection.url=jdbc:mysql://localhost/somedatabasename
hibernate.hbm2ddl.auto=create-drop
hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
hibernate.jdbc.batch_size=0
The directory structure for the eclipse project is:
**EDIT: **
Just for kicks, I moved the META-INF
folder to the same level as the calling class, but I get the same error. Here are two new screen shots showing locations of persistence.xml in which the error is still thrown:
SECOND EDIT:
I added Class c = Class.forName("org.eclipse.persistence.jpa.PersistenceProvider");
at line 116 of TestFunctions.java
, which triggers the following error when I right click on Main.java
and do Run As..Java Application
:
Exception in thread "main" java.lang.ClassNotFoundException: org.eclipse.persistence.jpa.PersistenceProvider
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at maintest.TestFunctions.setUpPersistence(TestFunctions.java:116)
at maintest.Main.main(Main.java:10)
Here is the new TestFunctions.setUpPersistence()
method:
public void setUpPersistence() throws ClassNotFoundException{
final Properties persistenceProperties = new Properties();
InputStream is = null;
try {
Class<? extends TestFunctions> c = getClass();
ClassLoader cl = c.getClassLoader();
is = cl.getResourceAsStream("persistence.properties");
persistenceProperties.load(is);
}catch (IOException i) {i.printStackTrace();}
finally {if (is != null) {try {is.close();} catch (IOException ignored) {}}}//org.jvnet.hyperjaxb3.ejb.tests.po
Class c = Class.forName("org.eclipse.persistence.jpa.PersistenceProvider");
entityManagerFactory = Persistence.createEntityManagerFactory(/*"org.jvnet.hyperjaxb3.ejb.tests.po"*//*"persistence.xml"*/"org.jvnet.hyperjaxb3.ejb.tests.po", persistenceProperties);
}
When I replace Class c = Class.forName("org.eclipse.persistence.jpa.PersistenceProvider");
with Class c = Class.forName("org.hibernate.ejb.HibernatePersistence");
, I get a similar error. However, Class c = Class.forName("javax.persistence.spi.PersistenceProvider");
does not throw any error, so the program continues until the same javax.persistence.PersistenceException: No Persistence provider for EntityManager named org.jvnet.hyperjaxb3.ejb.tests.po
error gets thrown further downstream.
Does this tell us more about the cause of the error? Also, hyperjaxb
creates a persistence.xml
and places it in the target folder. This error occurred when persistence.xml
was in that location, and has persisted when I move persistence.xml
as shown above. Is hyperjaxb
causing this problem by not playing nicely with eclipse?
I just can't resist, this is my final attempt to help. :) I'm writing this for you and for any users who may encounter similar issues.
I believe you simply have a problem in the Eclipse project configuration. The paths in your Eclipse project do not seem correct.
Normally, when you import an existing Maven project into Eclipse using File > Import... > Existing Maven Projects
, m2eclipse
should analyse the structure of the Maven project and create Eclipse project with (.classpath
and .project
files) automatically.
The paths in these projects are derived from your Eclipse pom.xml
. So you actually should not create/modify/add/remove/copy/move/whatever Eclipse source folders. If you do this, your Eclipse project will no longer be synchronized with your Maven project and you'll get really weird results.
Sometimes m2eclipse
does not do its job well. Sometimes you don't get the right source folders, things go missing etc. From my experience, this got radically better over the time and right now m2eclipse
works like a charm. From what I saw in your struggles, it might be that you have an older version of m2eclipse
. Maybe not, but I'd suggest to check it anyway.
Next, sometimes m2eclispe
still clamps. In this cases it is highly recommended to do the following things:
- Clean the project:
Project > Clean...
- Update the Maven project (Alt + F5). Make sure to update the project configuration from
pom.xml
Finally you should get the following project structure:
Specifically, you should get the following source folders:
src\main\java
- source folder for your main Java files
src\main\resources
- source folder for resources
target\generated-sources\xjc
- source folder for the generated code.
- Important: not
target\generated-sources
like you have but target\generated-sources\xjc
.
- This folder contains the generated Java classes. (Hyperjaxb adds JPA annotations to them).
- It also contains
META-INF\persistence.xml
which is a persistence unit descriptor. The META-INF\persistence.xml
resource is specified by the JPA spec. This is where the persistence unit will be loaded from.
- If you've generated a roundtrip test (xml-to-the-db-and-back), then you'll also see a
RoundtripTest
class somewhere. This is a JUnit test class, it should be possible to execute it directly. (Run As > JUnit Test
)
src\test\java
- test classes.
src\test\resources
- test resources
This is a standard directory layout for Maven projects. The only peculiarity is the target\generated-sources\xjc
source folder which holds the code generated by the schema compiler. And even this is absolutely standard, it is a usual convention for Maven code-generation plugins to generate code in target\generated-sources\some-tool
directories.
Below I post the .classpath
file from my project:
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry including="**/*.java" kind="src" output="target/classes" path="target/generated-sources/xjc">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
Important
If you don't have this directory structure (and your screenshots show that you don't) DO NOT move on. It will fail (it does for you). Fix your project structure first. Do not move on, don't try to run anything, you'll run into all kinds of strange things like not found resources etc. (which you do).
Regenerate project structure from pom.xml
and clean the project in Eclipse. Open your .classpath
file and compare it line-by-line with what I posted. But please do fix the project structure first.
Next, it is important that you understand that you are not supposed to move or drag-and-drop the generated code. It is not the right thing to do. Don't do it. Please don't move on until you accept this as an imperative. Don't move or modify the generated code. If you do, you overtake the responsibility for this code. Things are generated the way they are because it works this way. So if you change it it is very likely that it won't work anymore (it does not for you). If you will need to change anything, you change the pom.xml
which configures the generation, not the resulting code.
Now, let us analyse your current project structure based on the following screenshot:
What I can notice:
src\main\java
contains maintest\Main
and TestFunctions
. If you're trying to write a test, put your test classes into src\test\java
, not src\main\java
.
src\main\resources
contains persistence.xml
, sun-jaxb.episode
, persistence.properties
and schema.xsd
. Only schema.xsd
should be there.
persistence.xml
and sun-jaxb.episode
are generated files. And, see above, you must not move them.
persistence.properties
defines the connection to the database used for testing. So it must be in test resources, namely src\test\resources
. Putting it into src\main\resources
will finally add this file into the resulting JAR, it's like telling everyone username and password of the database you use for testing
src\test\java
- this is OK, but your test classes should be here.
src\test\resources
- persistence.properties
should be here.
target\generated-sources
- this is wrong, this should be target\generated-sources\xjc
org.jvnet.hyperjaxb3.ejb.test.po
package is under target\generated-sources
. It is generated under target\generated-sources\xjc
, so what I see means you've moved. Don't do this, see above.
xjc
is displayed as package. This is actually a leftover after you've (incorrectly) configured target\generated-sources
as a source folder. This folder must contain all of the generated sources, now it only contains the RoundtripTest
. Which means you moved the generated code. Don't do this, see the imperative above.
So your Eclipse project configuration as displayed above is invalid. Here's my theory on why this happened. I think that your m2eclipse
did not process the pom.xml
correctly, you were probably missing folders etc. But instead of getting the Eclipse project files to be correctly generated my m2eclipse
you have manually added the target\generated-sources
and started moving the generated code around. This is not the right way.
Please check and re-check your .classpath
until it is equivalent to what I posted. I have zipped and uploaded my sample project which definitely works for me. You can unzip and import it using File > Import... > Existing Projects into Eclipse
(not as Maven project).
Finally, you must be able to execute the RoundtripTest
as a JUnit test. The test will probably fail, but it must run, you should not be getting NPEs etc. I don't have a MySQL database at hand, so this is what I get at the moment:
Detected [file:/C:/Projects/workspaces/hj3/hyperjaxb3-ejb-template-basic-0.6.0/target/classes/META-INF/persistence.xml].
RoundtripTest
Loading entity manager factory properties.
RoundtripTest
Loading entity manager factory properties from [file:/C:/Projects/workspaces/hj3/hyperjaxb3-ejb-template-basic-0.6.0/target/test-classes/persistence.properties].
RoundtripTest
Could not obtain connection to query metadata
org.hibernate.cfg.SettingsFactory
com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception:
** BEGIN NESTED EXCEPTION **
java.net.ConnectException
MESSAGE: Connection refused: connect
This means that entity manager started correctly but could not connect to the database. If you've configured your test database in the src\test\resources\persistence.properties
corretcly, you should be able to connect to the database. And if you'll put a po.xml
file to src\test\samples
, the roundtrip test will:
- unmarshal this files
- save it into the database
- load it back
- compare it to the original result
Please get the roundrip test run first before you start your own experiments. Don't copy the code, don't modify it, don't try to bend it to your directory structure. It must run as it is. Don't move on until it does.
Good luck.
Update.
You might also be facing an issue with unresolved dependencies. Please make sure your dependencies are resolved correctly. This is what I see:
If you don't see this, it is bad. Something is wrong with your workspace. Check if you have any error messages in Eclipse. Maybe you have something like:
Plugin execution not covered by lifecycle configuration: org.codehaus.mojo:hibernate3-maven-plugin
Quick-fix it first ("Permanently mark goal ... as ignored in Eclispe build"). Don't move on until this error is gone. This is a blocker.
The parameter you should pass is the persistence-unit. (Not the file name.)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence version="1.0" ... >
<persistence-unit name="generated">
<class>generated.Items</class>
<class>generated.Items$Item</class>
<class>generated.PurchaseOrderType</class>
<class>generated.USAddress</class>
</persistence-unit>
</persistence>
So it should be generated
for the persistence.xml
above:
entityManagerFactory = Persistence.createEntityManagerFactory("generated", persistenceProperties);
For your persistence, should be:
entityManagerFactory = Persistence.createEntityManagerFactory("org.jvnet.hyperjaxb3.ejb.tests.po", persistenceProperties);