问题
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?
回答1:
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 filessrc\main\resources- source folder for resourcestarget\generated-sources\xjc- source folder for the generated code.- Important: not
target\generated-sourceslike you have buttarget\generated-sources\xjc. - This folder contains the generated Java classes. (Hyperjaxb adds JPA annotations to them).
- It also contains
META-INF\persistence.xmlwhich is a persistence unit descriptor. TheMETA-INF\persistence.xmlresource 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
RoundtripTestclass somewhere. This is a JUnit test class, it should be possible to execute it directly. (Run As > JUnit Test)
- Important: not
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\javacontainsmaintest\MainandTestFunctions. If you're trying to write a test, put your test classes intosrc\test\java, notsrc\main\java.src\main\resourcescontainspersistence.xml,sun-jaxb.episode,persistence.propertiesandschema.xsd. Onlyschema.xsdshould be there.persistence.xmlandsun-jaxb.episodeare generated files. And, see above, you must not move them.persistence.propertiesdefines the connection to the database used for testing. So it must be in test resources, namelysrc\test\resources. Putting it intosrc\main\resourceswill 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.propertiesshould be here.target\generated-sources- this is wrong, this should betarget\generated-sources\xjcorg.jvnet.hyperjaxb3.ejb.test.popackage is undertarget\generated-sources. It is generated undertarget\generated-sources\xjc, so what I see means you've moved. Don't do this, see above.xjcis displayed as package. This is actually a leftover after you've (incorrectly) configuredtarget\generated-sourcesas a source folder. This folder must contain all of the generated sources, now it only contains theRoundtripTest. 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.
回答2:
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);
来源:https://stackoverflow.com/questions/26366556/no-persistence-provider-for-entitymanager-named-persistence-xml