My ejb code:
#Stateless
public class EmployeeBean {
#PersistenceContext(unitName="Eclipselink_JPA")
private EntityManager entitymanager;
public void createEmployee(){
Employee employee = new Employee( );
employee.setEid( 1201 );
employee.setEname( "Gopal" );
employee.setSalary( 40000 );
employee.setDeg( "Technical Manager" );
entitymanager.persist( employee );
entitymanager.getTransaction( ).commit( );
entitymanager.close( );
}
}
Basically, nullpointer exception happens at the line where entitymanager.persist is called, which should not happen right?
My persistence.xml file
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="Eclipselink_JPA" transaction-type="RESOURCE_LOCAL">
<class>com.jpa.beans.Employee</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:file:E:\HQLDB_AJ"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value="password"/>
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbc.JDBCDriver"/>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
I have eclipselink.jar and other eclipselink jpa jars in my class path.
Here is my entity beans:
#Entity
#Table
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int eid;
private String ename;
private double salary;
private String deg;
public Employee(int eid, String ename, double salary, String deg) {
super( );
this.eid = eid;
this.ename = ename;
this.salary = salary;
this.deg = deg;
}
public Employee( ) {
super();
}
public int getEid( ) {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getEname( ) {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public double getSalary( ) {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDeg( ) {
return deg;
}
public void setDeg(String deg) {
this.deg = deg;
}
#Override
public String toString() {
return "Employee [eid=" + eid + ", ename=" + ename + ", salary=" + salary + ", deg=" + deg + "]";
}
}
Whats seems to be the problem? can anyone help? ive been figuring this out of a day now.
Problem solved: i shouldn't be using resource local because i was running it in an app server. thanks for the help anyway. well appreciated
When you set transaction-type="RESOURCE_LOCAL" in persistence.xml config file, it means that YOU (=your application's code) will take care of creating EntityManager and also will handle transactions yourself. In such case what you can demand to be injected by your underlying container is EntityManagerFactory and you can do it by using #PersistenceUnit annotation. On such object you simply call createEntityManager() that gives you EntityManager.
If you want to use EntityManager supplied by the container you must specify transaction-type="JTA". Then you annotate EntityManager exactly as in your code, and do not care of creating, committing or rolling back a transaction. It will be done by the container that will use JTA transaction and decide when to create, commit or rollback it.
Those two ways are commonly known as respectively Application Managed EntityManager and Container Managed EntityManager
You can find more details on how to work with each of two ways of handling transactions here or here
You dont have <provider> in your persistence.xml.. Try adding it.
Ex:
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
or <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider> or
<provider>org.hibernate.ejb.HibernatePersistence</provider>
depending on your container.
HTH
Related
I am trying to build a simple REST service, using JAX-RS, that will perform the standard CRUD operations on a database table. I am able to successfully query for records, but I cannot insert new ones. I do not get any errors and when I step through the code in debug mode everything looks good. I am using a transactional CDI bean running in a Glassfish 4.1 container.
It feels like it's just never committing the transaction. I'm pretty new to Java EE, but my understanding is that since the bean is transactional the container should handle the commit for me. Anyone know why it is not?
#Path("/recipes")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class RecipeResource {
#Inject
RecipesService recipesService;
#GET
public List<Recipe> getRecipes() {
return recipesService.getAllRecipes();
}
#POST
public void addRecipse(Recipe recipe) {
recipesService.addRecipe(recipe);
}
}
public class RecipesService {
#PersistenceContext(unitName="PANTRYDB", type=PersistenceContextType.TRANSACTION)
EntityManager em;
public RecipesService () {
}
public List<Recipe> getAllRecipes () {
List<Recipe> recipes = null;
try {
TypedQuery<Recipe> typedQuery = em.createQuery("select r from Recipe r", Recipe.class);
recipes = typedQuery.getResultList();
} catch (Exception e) {
System.out.println(e);
}
return recipes;
}
#Transactional
//This is the method that seems to not commit it's transaction
//The Recipe object is populated correctly, and the persist() doesn't
//throw any errors
public void addRecipe(Recipe recipe) {
try {
em.persist(recipe);
} catch (Exception e) {
System.out.println(e);
}
}
}
#Entity
#Table(name="RECIPES", schema="COOKBOOK")
public class Recipe {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column
private String name;
#Column(name="CREATED_DATE")
private Calendar createdDate;
#Column(name="LAST_MADE_DATE")
private Calendar lastMadeDate;
#Column
private String description;
#Column
private String notes;
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Calendar getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Calendar createdDate) {
this.createdDate = createdDate;
}
public Calendar getLastMadeDate() {
return lastMadeDate;
}
public void setLastMadeDate(Calendar lastMadeDate) {
this.lastMadeDate = lastMadeDate;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
#Override
public String toString() {
return name;
}
}
Persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="PANTRYDB" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.domain.Recipe</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:derby:/Users/development/eclipse/ws_playground/databases/pantry_db/PANTRYDB" />
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/>
<property name="javax.persistence.jdbc.user" value=""/>
<property name="javax.persistence.jdbc.password" value=""/>
</properties>
</persistence-unit>
</persistence>
I tried your application on a weblogic 12.2.1 and it successfully inserted in database and i do not have any problem with transaction.
Here is my code.
RecipeResource class (I modified the #Path to call it via web browser and also instanciated the Recipe manually):
#Path("/recipes")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class RecipeResource {
#Inject
RecipesService recipesService;
#GET
#Path("get")
public List<Recipe> getRecipes() {
return recipesService.getAllRecipes();
}
#GET
#Path("add")
public String addRecipse() {
Recipe recipe = new Recipe();
recipe.setDescription("desc");
recipesService.addRecipe(recipe);
return "OK";
}
}
The Recipe class is same as yours except that i commented the schema :
#Entity
#Table(name="RECIPES") //, schema="COOKBOOK")
public class Recipe {
}
My persistence.xml (I'm using in-memory database):
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns /persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="PANTRYDB" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/__default</jta-data-source>
<class>org.jvi.webservice.transactional.db.Recipe</class>
<properties>
<!--<property name="eclipselink.ddl-generation" value="create-tables"/>-->
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.logging.level.sql" value="FINE"/>
<property name="eclipselink.logging.parameters" value="true"/>
<property name="eclipselink.logging.logger" value="DefaultLogger"/>
<property name="eclipselink.cache.shared.default" value="false"/>
</properties>
</persistence-unit>
So your problem might come from the Application Server.
Did you try to deploy your webapp on another server?
When you are using JTA transaction management, responsibility for creating and managing database connections is provided by application server, not your application.
Basically, you have to configure your data source in your GlassFish server instance, not directly in persistence.xml via properties:
Configure connection pool and datasource JNDI name in your GlassFish server instance
Link data source configuration in your persistence.xml via <jta-data-source> element
Please check this answer for further details:
https://stackoverflow.com/a/9137741/1980178
Are you sure you are not mixing two frameworks. RecipeResource has a #Path annotation which is from the JavaEE framework, and the #Transactional annotation is from the Spring framework, I think you should replace it with #TransactionAttribute which is the equivalent JavaEE anotation.
Have a look here for details between transaction in Spring an JavaEE
I'm new to JPA, and i got this infamous error "no persistence provider for entitymanager named". I search far and wide on google, and tried every single solution available, to no extent i'm afraid.
Stack Trace
javax.persistence.PersistenceException: No Persistence provider for EntityManager named suplink
at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
at com.supinfo.suplink.util.PersistenceManager.getEntityManagerFactory(PersistenceManager.java:13)
Persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="suplink" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/SupLink" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
</properties>
<class>com.supinfo.suplink.entity.User</class>
</persistence-unit>
PersistenceManager
public class PersistenceManager {
private static EntityManagerFactory emf;
private PersistenceManager() { }
public static EntityManagerFactory getEntityManagerFactory() {
if(emf == null) {
emf = Persistence.createEntityManagerFactory("suplink");
}
return emf;
}
public static void closeEntityManagerFactory() {
if(emf != null && emf.isOpen()) emf.close();
}
}
Thanks for your help :)
try to remove the transaction-type="RESOURCE_LOCAL"
works on my machine without this code
Good luck for your graded exercise, try code underneath ;)
public class PersistenceManager {
private static final EntityManagerFactory emf;
private static final ThreadLocal<EntityManager> threadLocal;
private static final Logger logger;
static {
emf = Persistence.createEntityManagerFactory("SupLink");
threadLocal = new ThreadLocal<EntityManager>();
logger = Logger.getLogger("SupLink");
logger.setLevel(Level.ALL);
}
public static EntityManager getEntityManager() {
EntityManager manager = threadLocal.get();
if (manager == null || !manager.isOpen()) {
manager = emf.createEntityManager();
threadLocal.set(manager);
}
return manager;
}
public static void closeEntityManager() {
EntityManager em = threadLocal.get();
threadLocal.set(null);
if (em != null)
em.close();
}
public static void beginTransaction() {
getEntityManager().getTransaction().begin();
}
public static void commit() {
getEntityManager().getTransaction().commit();
}
public static void rollback() {
getEntityManager().getTransaction().rollback();
}
public static Query createQuery(String query) {
return getEntityManager().createQuery(query);
}
public static void log(String info, Level level, Throwable ex) {
logger.log(level, info, ex);
}
}
I'm using eclipse JPA project to create entities in Apache Derby. I'm using the JPA Tools:
"generate tables from entities.."
command. When I use this command, the tables are put into the database. I can see the tables, and that they have columns from the Eclipse "Data Source Explorer". When I log in to Derby through ij.
I type:
'show tables in schema x';
I get a list of the table names that correspond to the entities.
I type:
'select * from <table in x>'
I get:
ERROR 42X05: Table/View 'ADDRESS' does not exist.
Why do my tables not stick..? When I use the CREATE TABLE commands that are being entered in during use of the "generate tables from entities.." command, they produce tables there. When I type 'select * .." I get a table.
Second, probably related problem. I have a class. I use the following commands to obtain an entity manager:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("DataModelAccess");
EntityManager em = emf.createEntityManager();
If I run a test on my entities, such as this:
public void runTest()
{
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("DataModelAccess");
EntityManager em = emf.createEntityManager();
System.out.println(emf == null);
Address address = new Address();
address.setAddressID("1");
address.setAddressNumber(1746);
address.setStreetName("Howard");
address.setStreetType("Court");
address.setCity("Lennyville");
address.setState("CT");
address.setZipcode(73625);
em.persist(address);
em.close();
emf.close();
// reassign:
emf = Persistence.createEntityManagerFactory("DataModelAccess");
em = emf.createEntityManager();
Address address2 = em.find(Address.class, "1");
System.out.println(address2.getCity());
I get a NullPointerException on the last line.
If I do not re-assign to emf and em, It will print the city to the console.
So,
1. Why do tables not appear for SELECT * FROM <TABLE_NAME>?
But do appear for SHOW TABLES IN <SCHEMA>?
2. Why is my data not persistent across sessions?
I'm running this in Eclipse, from a plain old Java SE object. There is no Java EE container. It's an Eclipse JPA project. There is a persistence.xml file. There is a connection called 'derby' that is managed by eclipse. Maybe I have a persistence.xml file problem? Maybe this is a common problem for everyone. Maybe JPA and eclipselink do this by default because of some differing access protocol? Maybe not having a Java EE Container is making it difficult?
========
As requested:
the address class is totally irrelevant. I've tried both field and property based access also. It makes no difference to IJ. Both attempts fail equally well. This is a summary:
#Entity
#Table(name="ADDRESS")
public class Address
implements Serializable
...
#Id
public String getAddressID()
every thing else is fields, constructor, getters and setters. No annotations. I just added a new JPA entity by right-clicking on my package and selecting
New --> JPA Entity
I put the fields in it using the eclipse wizard. I made it property-based. I thought maybe field-based access would change things, so I tried field-based, but it made no difference.
where you see this: address.setStreetName("Howard");
there is the field:
private String streetName;
and two corresponding methods
setStreetName(String x);
and
String getStreetName();
The same formula exists for all fields in the class. Each field has a getter and a setter. There are no more methods than the getters and the setters. 1 field per each getter/setter method pair. There are no more annotations than I mentioned.
Just for information: I do not set all of the properties for the Address class. The fields in the table were all entered into the database as NULLABLE. Yet, IJ does not find any TABLE. – user1405870 11 hours ago
=========
Here's the Address and Address_ classes:
package dataAccess.customer;
import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;
#Generated(value="Dali", date="2012-05-18T21:44:02.229-0500")
#StaticMetamodel(Address.class)
public class Address_
{
public static volatile SingularAttribute<Address, String> addressID;
public static volatile SingularAttribute<Address, Integer> addressNumber;
public static volatile SingularAttribute<Address, String> streetName;
public static volatile SingularAttribute<Address, String> streetType;
public static volatile SingularAttribute<Address, String> building;
public static volatile SingularAttribute<Address, String> floor;
public static volatile SingularAttribute<Address, String> unit;
public static volatile SingularAttribute<Address, String> landmarkName;
public static volatile SingularAttribute<Address, String> city;
public static volatile SingularAttribute<Address, String> state;
public static volatile SingularAttribute<Address, Integer> zipcode;
}
package dataAccess.customer;
import java.io.Serializable;
import java.lang.Integer;
import java.lang.String;
import javax.persistence.*;
/**
* Entity implementation class for Entity: Address
*
*/
#Entity
#Table(name="ADDRESS")
public class Address
implements Serializable
{
private String addressID;
private Integer addressNumber;
private String streetName;
private String streetType;
private String building;
private String floor;
private String unit;
private String landmarkName;
private String city;
private String state;
private Integer zipcode;
private static final long serialVersionUID = 1L;
public Address()
{
}
#Id
public String getAddressID()
{
return addressID;
}
public void setAddressID(String addressID)
{
this.addressID = addressID;
}
public Integer getAddressNumber()
{
return this.addressNumber;
}
public void setAddressNumber(Integer addressNumber)
{
this.addressNumber = addressNumber;
}
public String getStreetName()
{
return this.streetName;
}
public void setStreetName(String streetName)
{
this.streetName = streetName;
}
public String getStreetType()
{
return this.streetType;
}
public void setStreetType(String streetType)
{
this.streetType = streetType;
}
public String getBuilding()
{
return this.building;
}
public void setBuilding(String building)
{
this.building = building;
}
public String getFloor()
{
return this.floor;
}
public void setFloor(String floor)
{
this.floor = floor;
}
public String getUnit()
{
return this.unit;
}
public void setUnit(String unit)
{
this.unit = unit;
}
public String getLandmarkName()
{
return this.landmarkName;
}
public void setLandmarkName(String landmarkName)
{
this.landmarkName = landmarkName;
}
public String getCity()
{
return this.city;
}
public void setCity(String city)
{
this.city = city;
}
public String getState()
{
return this.state;
}
public void setState(String state)
{
this.state = state;
}
public Integer getZipcode()
{
return this.zipcode;
}
public void setZipcode(Integer zipcode)
{
this.zipcode = zipcode;
}
}
Here's the persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="DataModelAccess" transaction-type="RESOURCE_LOCAL">
<class>dataAccess.customer.Person</class>
<class>dataAccess.customer.Address</class>
<class>dataAccess.customer.PhoneNumber</class>
<class>dataAccess.customer.Customer</class>
<class>dataAccess.customer.TwoFieldTest</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.ddl-generation.output-mode" value="database"></property>
<property name="eclipselink.target-database" value="derby"/>
<property name="eclipselink.target-server" value="None"/>
<property name="eclipselink.exclude-eclipselink-orm" value="true"/>
<property name="eclipselink.jdbc.batch-writing" value="JDBC"/>
<property name="eclipselink.jdbc.cache-statements" value="true"/>
<property name="eclipselink.jdbc.native-sql" value="true"/>
<property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/sample;create=true"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="eclipselink.jdbc.bind-parameters" value="false"/>
<property name="eclipselink.jdbc.exclusive-connection.mode" value="Transactional"/>
<property name="eclipselink.orm.validate.schema" value="true"/>
<property name="eclipselink.orm.throw.exceptions" value="true"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>
Comments:
calling
em.flush();
is exactly what I did, in order to check if the data was persisting across sessions (which it does not). In other words, when I run the method "runTest()" I get the correct print statements, under the original runTest() method. I have posted the altered "runTest()" method (see the: //reassign "comment"). Now, when I have a customer, which I build out of three entities: address, phoneNumber, and, person, the customer can instantiated through finding the other three entities "in the database", with the entity manager. However, if I comment out everything, except for the code that looks up the three entities in the database and creates a new customer, then I find that I cannot get the data out of the database.
that looks like this:
Customer c = new Customer();
c.setAddress(em.find(Address.class, "1"));
c.setPhoneNumber(em.find(PhoneNumber.class, "1"));
c.setName(em.find(Person.class, "1"));
c.setCustomerID("123");
em.persist(c);
*/
Customer actual = em.find(Customer.class, "123");
and when I comment out everything until after em.persist(c), I do not get any Customer actual.
normally, I get this:
Customer:
Name:
Mr. Howard T Stewart III
Address:
1746 Howard Court
Lennyville, CT 73625
Phone:
(215) 256-4563
But when I comment out everything until
Customer actual = em.find(Customer.class, "123");
(now.. I instantiated the em in a previous line, but I did not now create person, phone_number, or address.)
Then, .. I get,
(actual == null)
evaluates to true.
Am I misusing the "find()" command? Am I supposed to do something else to load a current connection to the database or something (in terms of commands through em (em.method())?
Remember that there is no Java EE container here. I'm just doing this in eclipse, running main methods in j2se programs, in a JPA project in eclipse, using eclipselink 2.3. But this is not EJB, nor is it ManagedBeans or etc.
So..
I found this:
#Resource
UserTransaction utx;
...
try {
utx.begin();
bookDBAO.buyBooks(cart);
utx.commit();
} catch (Exception ex) {
try {
utx.rollback();
} catch (Exception exe) {
System.out.println("Rollback failed: "+exe.getMessage());
}
...
Unfortunately, I didn't find anything about UserTransaction until I got to the Web portion of the java ee tutorial, so, as such, I was unable to find the sentence that said "user transaction" amidst all the implication that em.persist() is all that it takes. Also, #Resource might not work outside of a Java EE Container.
Daniel: thank you for the comment, it gave me the answer that I needed.
Even though I had found the above items, and although I was doing this:
em.getTransaction().begin();
// .. set fields of address ..
em.persist(address);
em.getTransaction().commit();
em.close();
It still wasn't working. When I changed the persistence.xml file to only CREATE tables, the test method runs correctly, and, when I comment out everything but retrieve the customer from the database, that returns correctly as well.
I have also tried:
SELECT * FROM <SCHEMA>.ADDRESS;
and that works fine as well. Thank you so much, as finding out what the entity manager is actually doing because of the "DROP AND CREATE TABLES" directive would likely be a very hard thing to track down amongst tutorials.
In your persistence.xml you have,
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
This means every time you create a new EntityManagerFactory you will recreate your database, loosing all of the data.
Either remove this, or change it to "create-tables" to only create.
For your first issue, try ., i.e. x.address
since you are using Eclipselink JPA, it will not follow standard syntax of SQL query if you are using standard "createQuery" method
You need to use this:
select t from table1 t
instead of
select * from table1
It follows syntax of JPQL. See this link for more info.
But if you want to use native sql method, use "createNativeMethod" from manager instance
I create a hibernate project with 'hibernate tools'provide by JBoss to Eclipse.
Generated the Entities (POJO's) and then the DAO's.
This way for example:
#Entity
#Table(name = "area", catalog = "project_schema", uniqueConstraints = #UniqueConstraint(columnNames = "area"))
public class Area implements java.io.Serializable {
private Integer id;
private String area;
public Area() {
}
public Area(String area) {
this.area = area;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "area", unique = true, nullable = false, length = 45)
public String getArea() {
return this.area;
}
public void setArea(String area) {
this.area = area;
}
}
And then the respectely DAO class (generated by Hibernate Tools too):
#Stateless
public class AreaHome {
private static final Log log = LogFactory.getLog(AreaHome.class);
#PersistenceContext
private EntityManager entityManager;
public void persist(Area transientInstance) {
log.debug("persisting Area instance");
try {
entityManager.persist(transientInstance);
log.debug("persist successful");
} catch (RuntimeException re) {
log.error("persist failed", re);
throw re;
}
}
public void remove(Area persistentInstance) {
log.debug("removing Area instance");
try {
entityManager.remove(persistentInstance);
log.debug("remove successful");
} catch (RuntimeException re) {
log.error("remove failed", re);
throw re;
}
}
public Area merge(Area detachedInstance) {
log.debug("merging Area instance");
try {
Area result = entityManager.merge(detachedInstance);
log.debug("merge successful");
return result;
} catch (RuntimeException re) {
log.error("merge failed", re);
throw re;
}
}
public Area findById(Integer id) {
log.debug("getting Area instance with id: " + id);
try {
Area instance = entityManager.find(Area.class, id);
log.debug("get successful");
return instance;
} catch (RuntimeException re) {
log.error("get failed", re);
throw re;
}
}
}
But when I try to call AreaHome.persist() it launchs an exception 'NullPointerException'.
I configure my project with hibernate.cfg.xml and everything works fine though:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password"><password></property>
<property name="hibernate.connection.url">jdbc:mysql://<hostname>:3306/<schema></property>
<property name="hibernate.connection.username">root</property>
<!-- <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- SQL -->
<property name="hibernate.format_sql">true</property>
<property name="hibernate.show_sql">true</property>
<!-- C3P0 -->
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.timeout">180</property>
<property name="hibernate.c3p0.idle_test_period">100</property>
<!-- Classes -->
<mapping class="com.suaparte.pojo.Area" />
</session-factory>
</hibernate-configuration>
This works fine when I try:
public void persist(Area area) throws ExceptionHandler {
Session session = HibernateUtil.getSessionFactory().openSession();
try {
session.beginTransaction();
session.save(area);
session.getTransaction().commit();
} catch (HibernateException he) {
session.getTransaction().rollback();
throw new ExceptionHandler(he.getCause());
} finally {
if (session != null) {
session.close();
}
}
}
But I want to use the DAO's generated by Hibernate Tools because they have EntityManager (which is supposed to be injected, but isn't apparentely).
What I have to do ? Any idea ?
Sorry by the long question, but I wanna to be very clear about my problem.
In fact you need to implement a EntityManagerFactory.
Create a persistence.xml file that resides in the META-INF folder.
Take a look at example
http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html_single/#setup-configuration-packaging
after the commands to create the EntityManagerFactory and EntityManager then:
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("JavaStackOver");
EntityManager entityManager = entityManagerFactory.createEntityManager();
Resolve dependencies, I used maven:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.5.6-Final</version>
</dependency>
Inject on your Dao JPA and Done!
The advantage of working with EntityManager is to have the option to change the Hibernate in futuro. Otherwise could use the Session.
I want to build a minimalistic local app that reads/writes HBase via JPA2 without orm.xml and without maven2.
Thereby I use Eclipse with the DataNucleus Plugin whose Enhancer is enabled for the project.
Inspired by
http://matthiaswessendorf.wordpress.com/2010/03/17/apache-hadoop-hbase-plays-nice-with-jpa/
I got the following Entities:
#Entity
#Table(name="account_table")
public class Account
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private String id;
String firstName = null;
String lastName = null;
int level = 0;
#Embedded
Login login = null;
public Account() { }
public Account(String firstName, String lastName, int level, Login login) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.level = level;
this.login = login;
}
and
#Embeddable
public class Login
{
private String login = null;
private String password = null;
public Login() {
// TODO Auto-generated constructor stub
}
public Login(String login, String password) {
super();
this.login = login;
this.password = password;
}
}
The src/META-INF/persistence.xml
<persistence
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
−
<persistence-unit name="hbase-addressbook"
transaction-type="RESOURCE_LOCAL">
<class>de.syrtec.jpa2hbase.entities.Login</class>
<class>de.syrtec.jpa2hbase.entities.Account</class>
<properties>
<property name="datanucleus.ConnectionURL" value="hbase" />
<property name="datanucleus.ConnectionUserName" value="" />
<property name="datanucleus.ConnectionPassword" value="" />
<property name="datanucleus.autoCreateSchema" value="true" />
<property name="datanucleus.validateTables" value="false" />
<property name="datanucleus.Optimistic" value="false" />
<property name="datanucleus.validateConstraints" value="false" />
</properties>
</persistence-unit>
</persistence>
the DAO:
public class TestDAO {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hbase-addressbook");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = null;
Account a1 = new Account("myPre", "mySur", 1, new Login("a", "b"));
tx = em.getTransaction();
tx.begin();
em.persist(a1);
tx.commit();
}
}
But when first line of the test DAO is executed...
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hbase-addressbook");
..I get:
11/09/01 06:57:05 INFO DataNucleus.MetaData: Class "de.syrtec.jpa2hbase.entities.Account" has been specified with JPA annotations so using those.
11/09/01 06:57:05 INFO DataNucleus.MetaData: Class "de.syrtec.jpa2hbase.entities.Login" has been specified with JPA annotations so using those.
Exception in thread "main" javax.persistence.PersistenceException: Explicit persistence provider error(s) occurred for "hbase-addressbook" after trying the following discovered implementations: org.datanucleus.api.jpa.PersistenceProviderImpl from provider: org.datanucleus.api.jpa.PersistenceProviderImpl
at javax.persistence.Persistence.createPersistenceException(Persistence.java:242)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:184)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:70)
at de.syrtec.jpa2hbase.start.TestDAO.main(TestDAO.java:15)
Caused by: org.datanucleus.exceptions.NucleusUserException: Errors were encountered when loading the MetaData for the persistence-unit "hbase-addressbook". See the nested exceptions for details
at org.datanucleus.metadata.MetaDataManager.loadPersistenceUnit(MetaDataManager.java:879)
at org.datanucleus.api.jpa.JPAEntityManagerFactory.initialiseNucleusContext(JPAEntityManagerFactory.java:745)
at org.datanucleus.api.jpa.JPAEntityManagerFactory.<init>(JPAEntityManagerFactory.java:422)
at org.datanucleus.api.jpa.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:91)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:150)
... 2 more
Caused by: org.datanucleus.exceptions.ClassNotResolvedException: Class "−
de.syrtec.jpa2hbase.entities.Login" was not found in the CLASSPATH. Please check your specification and your CLASSPATH.
at org.datanucleus.JDOClassLoaderResolver.classForName(JDOClassLoaderResolver.java:247)
at org.datanucleus.JDOClassLoaderResolver.classForName(JDOClassLoaderResolver.java:412)
at org.datanucleus.metadata.MetaDataManager.loadPersistenceUnit(MetaDataManager.java:859)
... 6 more
Before I ran the DAO I triggered class enhancing by datanucleus succesfully:
DataNucleus Enhancer (version 3.0.0.release) : Enhancement of classes
DataNucleus Enhancer completed with success for 2 classes. Timings : input=623 ms, enhance=101 ms, total=724 ms. Consult the log for full details
Although I don't understand that enhancing isn't triggered automatically (referring to the logs) despite of having auto-enhancement for the project activated..
Does anybody know why my entities aren't found?
And that minus sign in persistence.xml ?