0

I have written (with Eclipse) a small program which uses JPA. Now I want to manualy compile and run this program using command line. I have also placed all source files in a separate directory (not within Eclipse's work space). The directory looks like:

directory
  |- src
  |   |- javax
  |   |   |- persistence
  |   |        |- <...>
  |   |- main
  |   |- META-INF
  |   |   |- javax
  |   |   |    |- persistence
  |   |   |- persistence.xml
  |   |
  |   |- <..>
  |- run.bat

Note: I purposely have 2 javax directories with all the class files in them.

run.bat contains lines:

javac -cp ./src ./src/main/Main.java
java -cp ./src main.Main

As far as I understand I am getting errors not because of the issue with the META-INF/persistence.xml file (not like many other people on stackoverflow). I am saying so because I have writen following lines in my Main:

<...>
Thread.currentThread().setContextClassLoader(new ClassLoader() {
            @Override
            public Enumeration<URL> getResources(String name) throws IOException {
                System.out.println("resource requested=" + name);
                if (name.equals("META-INF/services/javax.persistence.spi.PersistenceProvider")) {
        <--- MARK --->     return Collections.enumeration(Arrays.asList(new File("src/javax/persistence/spi/PersistenceProvider.class")
                            .toURI().toURL()));
                } else if (name.equals("META-INF/persistence.xml")) {
                    return Collections.enumeration(Arrays.asList(new File("src/META-INF/persistence.xml")
                            .toURI().toURL()));
                }
                return super.getResources(name);
            }
        });
emFactory = Persistence.createEntityManagerFactory("uzduotis");
<...>

So when I launch run.bat the program prints:

resource name=name=META-INF/services/javax.persistence.spi.PersistenceProvider

(it never gets to the part where program asks for "META-INF/persistence.xml" resource)

then it breaks and gives me an error:

enter image description here

If I change MARKED statement to

return super.getResources("src/" + name);

then the error says only:

enter image description here

What am I missing?

Peristence.xml:

enter image description here

EDIT: Program prety simple: no hibernate, just a few classes which retrieve some info from REST service and work with it, mainly using javax and w3c external libraries. Photo of the project explorer to depict its simplicity.

enter image description here

EDIT 2. SOLUTION

I found a way to make it work although I am not entirely sure about the causes. So if anyone could answer why the following changes solved the issue I would gladly mark it as an answer

I added eclipselink and mysql-connector-java jars to the src directory. eclipselink.jar fixed the issue and mysql-connector-java.jar was needed because I got other error (I am working with database afterall). Finally I changed line in the run.bat file from

java -cp ./src main.Main

to

java -cp ./src;./src/eclipselink.jar;./src/mysql-connector-java.jar; main.Main
sdafsDGZvb
  • 49
  • 1
  • 2
  • 10
  • Maybe this answer can help: http://stackoverflow.com/a/1285436/1506009 – Rozart Jan 13 '16 at 18:04
  • Which part on that post do think can solve my problem? – sdafsDGZvb Jan 13 '16 at 18:19
  • Well it seems that you didn't specify the persistence provider in your persistence.xml file. So i would try to specify it as in the linked answer. Simply try to add `org.hibernate.ejb.HibernatePersistence` inside `` element. Remember that you need to have dependencies resolved for HibernatePersistence. – Rozart Jan 13 '16 at 18:29
  • Oh. I probably should specify my program. Will edit question info shortly. Just so you know I am not using hibernate and as I said on the question I don't think that this issie with the persistence.xml file because this resource is never requested. But if you think that is not the case please prove me wrong – sdafsDGZvb Jan 13 '16 at 18:36
  • Ok. I'll look into this once again, right after you edit information. ;) – Rozart Jan 13 '16 at 18:44
  • Instead of screenshotting your code, copy-paste it as text into a code block, please – randers Jan 13 '16 at 18:50
  • Its easier to printscreen than align all the rows so they would look good sometimes – sdafsDGZvb Jan 13 '16 at 19:26

1 Answers1

0

It seems that your application is a standard Java SE application. JPA does not work automatically, as standard Java SE environment does not contain any implementation of JPA interfaces. It seems that Eclipse adds eclipselink to the classpath under the cover, therefore your program works when you run it from within Eclipse. But when you run your program from command line, you need to add eclipselink, which is a library that contains functionality for JPA interfaces.

You may try to generate Ant build file from eclipse project, and you would see if it adds eclipselink into the classpath in build.xml file. Or even better, I recommend to turn your project into project with Maven build - you would be able to build and run your project using Maven command in the same way as Eclipse would execute it (as Eclipse uses Maven under the cover for Maven-based projects).

Edit - explanation of the role of eclipselink in JPA

Packages starting javax.persistence are mostly interfaces, annotations, they have very few classes in fact. They only define how your application communicates with underlying persistence mechanism in standard way. On the other hand, you need to include also library with implementations (classes) for the standard JPA interfaces. javax.persistence.Persistence is just a facade, which delegates all the hard work onto an implementation, which might be Eclipselink, Hibernate, or something else.

The relationship between javax.persistence and EclipseLink is similar to relationship between interfaces and classes. You may use interfaces in your code, but your application will work only if you supply interfaces with real classes at some point.

It is also possible to use Eclipselink directly and skip whole javax.persistence layer, similarly as it is possible to work with real classes directly without through interfaces. But then you need learn internal API of Eclipselink and it is not possible to change Eclipselink library for alternatives like Hibernate. Nor will you be able to reuse the knowledge of Eclipselink-specific API to a project, which uses Hibernate. Reusability of a standard API is the most important case for standardized javax.persistence interfaces.

Maybe you wonder, how the persistence API knows where it should delegate the required functionality. There are multiple hooks, how it can find out. It is possible to include path to the main implementation class in persistence.xml using provider element. Or, it simply works if you include Eclipselink into the classpath, as Eclipselink library contains special text file at standardized path, which contains required information. This special file is inside Eclipselink JAR at path META-INF/services/javax.persistence.spi.PersistenceProvider - does it ring the bell?

OndroMih
  • 7,280
  • 1
  • 26
  • 44
  • Can you tell more about what exactly eclipselink does in this scenario and why javax dont have the so needed implmenetations? – sdafsDGZvb Jan 14 '16 at 17:16
  • I added more explanation into the answer. – OndroMih Jan 15 '16 at 15:34
  • Have a look at this question http://stackoverflow.com/questions/19322827/no-persistence-provider-for-entitymanager-named-x/22224589#22224589. It contains additional technical details. – OndroMih Jan 15 '16 at 15:35