Packaging JPA entities in a jar inside a Spring Boot application - jpa

I am refactoring a JEE REST (using JAX-RS 2.0) application as a Spring Boot application. My old app is packaged in a .war and has a jar file with entities and the persistence.xml configuration file for JPA. This jar is copied into WEB-INF/lib directory. I know Spring JPA works a different way and I don't use persistence.xml now but I wonder if I can package my JPA entity classes in a jar and include them in my Spring Boot apps just like I am doing now. This way I can easily reuse that jar in different Spring Boot Applications.

I'm pretty certain you can do this since I have done the same on one of my projects very recently. The only thing you need to do is make sure that you add an #EntityScan annotation on your main Spring Boot config class with the base package of your entities in the JAR.
#EntityScan("my.external.jar.entity.package")

Spring Boot doesn't really care whether the JPA entities are packages as a separate jar or included into the application. Its a runtime framework and in runtime classes can be loaded from the jar (it should reside in BOOT-INF/lib or 'directly' from the *.class files in the spring boot artifact.
Now there is a rule in spring boot, that says that it will scan for beans (including entities) only in the package where your "main" class resides or under it. This is done in order to avoid long process of analysis of, say, third-party classes that you might use. These third-party classes are usually not spring aware at all, at certainly do not contain any spring beans.
Example:
Say, you place your "main" class (the one annotated with #SpringBootApplication) in the package: com.mycompany.myapp
In this case, the following packages will be scanned (just a couple of examples):
com.mycompany.myapp
com.mycompany.myapp.web
com.mycompany.myapp.services.bl
com.mycompany.myapp.whatever.doesnt.matter
...
The following packages won't be scanned however (again, examples, not the full list):
com.mycompany
com.anothercompany
org.hibernate
If you want to to "alter" this default rule and place the entities in the package that doesn't adhere this convention, for example com.mycompany.jpa.entities then you should indeed use #EntityScan annotation as our colleagues have already suggested.
You can read about this topic here. You might also need to get familiar with #EnableJpaRepositories if you're using spring data but, while related, its a different topic.

In my case I had this problem, and after importing the library in the application's pom.xml, in the SpringBoot Project Main class, insert an #EntityScan annotation with the first package and *. Like this: #EntityScan ("br.*")

Related

Does Spring Data JPA internally use Hibernate & why my app is working if I am not giving dialect property?

I just started learning Spring Data JPA, I connected to mysql in localhost and able to save a record but I am unable to understand why it is working if I am not giving dialect property in properties file and is hibernate a default implementation of spring data instead of ibatis or Eclispe link, because in my pom.xml I just added the dependency of spring-data-jpa and never mentioned what kind of JPA implementation I want to use.
application.properties
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.
spring.datasource.url=jdbc:mysql://localhost:3306/initsoftware
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=ppppppp
spring.datasource.password=xxxxxxx
logging.level.root=DEBUG
spring.jpa.show-sql=true
Since you have an application.properties I assume you are using Spring Boot and not just Spring Data JPA.
In order to use JPA with Spring Boot you would typically add spring-boot-starter-data-jpa to your dependencies. This indeed comes with Hibernate out of the box as you can see when you inspect the dependencies.
Spring Data JPA itself doesn't come with a JPA implementation. You have to add that.
iBatis is not a JPA implementation.
If the assumption above doesn't match your scenario you can use the maven dependency plugin to inspect your (transient) dependencies. The following is a good starting point.
mvn dependency:tree -Dverbose
If you use a different build tool, it probably has a similar feature.

Is possible to make a library jpa based?

I'm looking to create some projects with common classes for every other project I create, web or standard.
In eclipse I'd already created two projects with the maven quickstart archetype without the jpa facet, but with the eclipselink libraries in the maven POM to anotate entities and jpa stuff. One project is for generic JPA access and another project for security (user entities, user services, user repository) that uses the JPA access project.
Then I create a 3rd project with the same archetype from last 2 project for testing the previous 2, but this have the JPA facet and the Persistence.xml. When I try to do something JPA related, it says the metamodel is empty. Then I found on the internet and the documentation says I have to use the tag in my persistence.xml, but I dont know how since Im including the previous two project in the build path of eclipse, not exactly any jar file. How can I achieve this?
Excuse my english translation.
You probably need an Composite Peristence Unit. Also, it will probably require some care in your built/deployment scripts.

jaxws and EclipseLink refuses to use enums from lib

I have a maven multimodule project with a ejb with a webservice, a lib, and a batch app. The batch app and the ejb module shares some enums, which then is located in the lib module. When attempting to return one of these enums from the lib in a webservice method it claims that there are no valid ejbs in the ejb jar file. Also, when using another one of these enums as attributes in an JPA entity using #Enumerated(EnumType.STRING) I get an error saying
"...is not a valid type for an enumerated mapping. The attribute must be defined as a Java enum."
I am simply wondering why using these enums in this way is a problem? Are there any workarounds besides declaring them twice?
I ran into the same problem, and it was because I was testing with Arquillian and for some reason I had forgotten to add the package containing the actual enum in the shrinkwrap.
So maybe there is something preventing the persistence provider (eclipselink in my case) from seeing your enum class. That's what I would bet is happening in your case, because you have multiple modules.
I had the same problem with a project i was working on. I have a common bundle which holds the general interfaces (and enums) which the persistence bundle did not recognise. As a result, I got the above exception (even though the persistence bundle had dependencies to the common bundle through the imported packages.
I solved this problem by including the common bundle in the Java build path of the persistence bundle:
project -> project properties -> Java build path / Projects ;//add the bundle that contains the enums here

Seam Gives Unknow Entity Exception For Entities in Jars

I am trying to use Seam to persist my jpa entities, when I reference an entity that is in a jar seam says unknown entity. I don't want to add all classes in persistence.xml I want seam to scan my jars and auto detect entities (as done by spring).
What am I missing?
It actually depends a lot on the environment of your application.
If it's Java SE (for example war packaged application deployed on tomcat), your jars are not scanned for entities that compose your persistence unit. Those classes are seen as normal java classes, entity manager doesn't care about them that much... And you have to point them manually, or switch to Java EE and ear...

In an OSGi environment, how are the classpaths and classloaders set up?

I'm confused about class visibility in OSGi. I'm running Apache Felix and loading the following bundles:
the antlr, asm, jpa and core bundles from eclipselink
an OSGi-fied jar for javax.persistence 1.99
an OSGi-fied jar with the com.mysql.jdbc driver
a bundle of my own that contains annotated entity classes and a persistence.xml
another bundle of my own that calls Persistence.createEntityManagerFactory(String, Map)
Now, what I'm confused about is which bundle must be able to see the MySQL driver. I thought this would be the bundle creating the EntityManagerFactory, but I get ClassNotFound errors when I import in that manifest. Next, I tried importing it from the eclipselink jpa bundle's manifest, but wrong again. Only when I import it from the manifest of the bundle containing the persistence unit (entity classes and persistence.xml), it works.
So, seemingly the database driver is looked up by the clasloader for the PU's bundle, but that doesn't make sense to me. What's going on?
I can't seem to find a straightforward documentation for this. These slides give some hints, but aren't exactly comprehensive.
I'm familiar with the OSGi classpath issues around Hibernate and JDBC and I can give you my reasoning on what's happening based on the slides you linked to.
I'm assuming you've added the JDBC driver entry to the persistence.xml inside your PU bundle?
EclipseLink is using the extender pattern to do work on the PU bundle's behalf. The extender is listening for bundles starting, checking if they have a persistence.xml and then doing the work of setting it up. It expects the PU bundle to import all the types you may reference in the persistence.xml, including the JDBC driver.
Think about it. The EclipseLink bundle won't import every known JDBC driver (and it shouldn't) - only your bundles can know which database driver they need, so it's reasonable to expect your PU bundle to import the JDBC driver class.
You shouldn't need to modify the manifests of the 3rd-party libraries if they are already OSGi-ified, such as EclipseLink.
I found this pdf to be quite informative regarding classloading:
http://www.martinlippert.org/events/WJAX2008-ClassloadingTypeVisibilityOSGi.pdf