hi i'm using netbeans+glassfish
i'm trying to run this code:
i only create DB without any table ( by running this code i want to create tables and persist my object)
public static void main(String[] args) {
SmartphoneService ss = new SmartphoneService();
Smartphone smart = new Smartphone(0, 0, null, null, null);
ss.create(smart);
}
but i got this error :
Unable to lookup JNDI name
my persistence.xml:
<persistence-unit name="manager1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:comp/env/jdbc/mysql</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="create"/>
</properties>
my class smartphoneservice:
#Stateless
public class SmartphoneService implements IDao<Smartphone> {
private static final String JPQL_SELECT_PAR_ID = "SELECT u FROM Smartphone u WHERE u.idSmartphone=:id";
private EntityManagerFactory emf;
private EntityManager em;
public SmartphoneService() {
emf = Persistence.createEntityManagerFactory("manager1");
em = emf.createEntityManager();
}
public boolean create( Smartphone smart) {
try {
em.getTransaction().begin();
em.persist(smart);
em.getTransaction().commit();
return true;
} catch (Exception e) {
if (em.getTransaction() != null) {
em.getTransaction().rollback();
}
} finally {
em.close();
emf.close();
}
return false;
}}
i checked my connection pool ping ( Ping Succeeded )
thanks for ur help
You're mixing up a JavaSE and with a JavaEE environment.
Your datasource looks like it's configured on Glassfish (Java EE environment). So the JNDI name java:comp/env/jdbc/mysql will only be available in a Java EE context.
Your SmartphoneService is being run in a Java SE context (via a public static void main() method. When you try to do a lookup of java:comp/env/jdbc/mysql, it's not going to be there because the DataSource only exists in your Glassfish (Java EE) environment.
You will need to perform JNDI lookups from the same context that the resources were registered in. My suggestion would be to make your SmartphoneService code run on Glassfish. There are lots of ways to drive that -- EJBs, Servlets, etc...
Related
I'm trying to run a simple web application on which I want run some tests on Jakarta EE 9.1(Full platform). I deployed my application on Glassfish 6.2.5. While I was running some code with jpa implementation this exception is thrown(the persistence provider is EclipseLink 3.0.2):
jakarta.persistence.PersistenceException: Exception [EclipseLink-4002]
(Eclipse Persistence Services - 3.0.2.v202107160933):
org.eclipse.persistence.exceptions.DatabaseException Internal
Exception: java.sql.SQLException: No suitable driver found for
jdbc:mysql://localhost:3306;create=true Error Code: 0
The persistence.xml is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
<persistence-unit name="GestoreDB" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>testJPA.ValueBeen</class>
<properties>
<property name="jakarta.persistence.schema-generation.action" value="drop-and-create"/>
<property name="jakarta.persistence.schema-generation.scripts.create-target" value="database-and-scripts"/>
<property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306;create=true"/>
<property name="jakarta.persistence.jdbc.user" value="root"/>
<property name="jakarta.persistence.jdbc.password" value="myPwd"/>
</properties>
</persistence-unit>
</persistence>
The Entity is(getters and setters omitted):
#Entity
#NamedQuery(name = "ValueBeen.selectTable", query = "select u from ValueBeen u")
public class ValueBeen
{
public ValueBeen(){
}
public ValueBeen(String value)
{
this.value = value;
}
public ValueBeen(int id, String value)
{
this.id = id;
this.value = value;
}
#Id
#GeneratedValue
private int id;
#NotNull
private String value;
...
}
And the WebServlet who perform persistency is:
#WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
{
ValueBeen valueBeen=new ValueBeen("Hello");
//Manager persistence and manager been
EntityManagerFactory managerPersistence = Persistence.createEntityManagerFactory("GestoreDB");
EntityManager entityManager = managerPersistence.createEntityManager();
//Do persistence
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(valueBeen);
transaction.commit();
//close managers
entityManager.close();
managerPersistence.close();
}
}
I put the jdbc connector jar (Mysql connector 8.0.28) in .\glassfish-6.2.5\glassfish\domains\domain1\lib
As you deploy your app to glassfish container then "transaction-type" in persistence.xml i guess should be "JTA", and property "jakarta.persistence.jdbc.url" is invalid because you do not indicate any database / schema name after ":3306". Glassfish documentation provides instructions and examples how to setup global jdbc connections and those limited to only application scope.
I'm trying to create EntityManager in my webapp, but it's failing with:
No suitable driver found for jdbc:postgresql:://localhost/database
However the same persistance unit and the same code for creating EntityManager works when I run it as JavaSE console application (from main() ).
Googling gave me several common problems causing that error:
JDBC url is wrong
Shouldn't be since it works from main
JDBC Driver is not in the class path
I can create a Class object using Class.forName("org.postgresql.Driver"); for the driver so I think it is in the classpath.
Other things I tried:
I thought maybe the driver jar from glassfish/lib and the webapp/WEB-INF/lib are conflicting somehow so I tried with both of them together and separately, no luck.
Recreated a small new webapp hoping the problem will go away, it didn't :-)
Inject #PersistanceUnit - also didn't work, don't know is it the same issue or I didn't use it properly as I'm still learning about injection and EJBs
Thanks
Full error:
javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLException: No suitable driver found for jdbc:postgresql://localhost/database Error Code: 0
Here is the code:
ManagedBean in webapp:
#ManagedBean
public class TestBean {
private String entry;
private String driver;
public String getFromDatabase(){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Unit1");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
EntityOne one = new EntityOne();
one.id = 1;
one.entry = "Bla bla";
em.persist(one);
tx.commit();
em.close();
return "done";
}
public String createDriver(){
try {
Class d = Class.forName("org.postgresql.Driver");
driver = d.getName();
} catch (ClassNotFoundException e) {
driver = "Class not found";
return "";
}
return "";
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getEntry() {
return entry;
}
public void setEntry(String entry) {
this.entry = entry;
}
}
Same code working in main:
public class Standalone {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Unit1");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
EntityOne one = new EntityOne();
one.id = 1;
one.entry = "Bla bla";
em.persist(one);
tx.commit();
em.close();
}
}
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="Unit1" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.test.EntityOne</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/database"/>
<property name="javax.persistence.jdbc.user" value="darko"/>
<property name="javax.persistence.jdbc.password" value="sifra"/>
<property name="eclipselink.target-database" value="PostgreSQL"/>
</properties>
</persistence-unit>
Place the posgres jdbc driver into the lib of glassfish. Its something like this.
[glassfish_home]/glassfish/domains/YOUR_DOMAIN/lib/
Also, restart the server after this.
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
How should I test an EJB 3.1 which gets an instance of EntityManager injected?
A possible EJB:
#Stateless
#LocalBean
public class CommentService {
#PersistenceContext
private EntityManager em;
public List<Comment> findAll() {
TypedQuery<Comment> query = em.createNamedQuery(
Comment.FIND_ALL, Comment.class
);
return query.getResultList();
}
}
A possible test:
#Test
public void testFindAll() {
List<Comment> all = service.findAll();
Assert.assertEquals(8, all.size());
}
I am only using GlassFish 3.1 and Eclipse Indigo for Java EE Developers. I already tried things like that:
#Before
public void setUp() throws Exception {
ejbContainer = EJBContainer.createEJBContainer();
service = (CommentService) ejbContainer.getContext()
.lookup("java:global/classes/CommentService");
}
But all I got was:
javax.ejb.EJBException:
No EJBContainer provider available: no provider names had been found.
The accepted answer requires mocking a lot of code, including the persistence layer. Use an embedded container to test the actual beans, instead; otherwise, mocking the persistence layer results in code that barely tests anything useful.
Use a session bean with an entity manager that references a persistence unit:
#Stateless
public class CommentService {
#PersistenceContext(unitName = "pu")
private EntityManager em;
public void create(Comment t) {
em.merge(t);
}
public Collection<Comment> getAll() {
Query q = em.createNamedQuery("Comment.findAll");
Collection<Comment> entities = q.getResultList();
return entities;
}
}
The entity bean:
#Entity
#NamedQueries({#NamedQuery(name = "Comment.findAll", query = "select e from Comment e")})
public class Comment implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
This persistence unit is defined in the persistence.xml file as follows:
<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="pu" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>org.glassfish.embedded.tempconverter.Comment</class>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>
The transaction type must be JTA.
Then write a test that creates and destroys the EJB container (GlassFish embedded container):
public class CommentTest extends TestCase {
private Context ctx;
private EJBContainer ejbContainer;
#BeforeClass
public void setUp() {
ejbContainer = EJBContainer.createEJBContainer();
System.out.println("Opening the container" );
ctx = ejbContainer.getContext();
}
#AfterClass
public void tearDown() {
ejbContainer.close();
System.out.println("Closing the container" );
}
public void testApp() throws NamingException {
CommentService converter = (CommentService) ctx.lookup("java:global/classes/CommentService");
assertNotNull(converter);
Comment t = new Comment();
converter.create(t);
t = new Comment();
converter.create(t);
t = new Comment();
converter.create(t);
t = new Comment();
converter.create(t);
Collection<Comment> ts = converter.getAll();
assertEquals(4, ts.size());
}
}
Next, add two dependencies (such as to a Maven POM):
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.glassfish.main.extras</groupId>
<artifactId>glassfish-embedded-all</artifactId>
<version>3.1.2</version>
<scope>compile</scope>
</dependency>
Having the dependencies, session and entity bean, persistence file, test files implemented exactly as shown, then the test(s) should pass. (The examples on the Internet are woefully inadequate.)
First of all, make sure you distinguish between unit tests and integration tests. JUnit is just a framework that helps you organize and run the tests, but you have to determine the scope of your tests.
I assume you're interested in defining a unit test of CommentService.findAll(). What does that mean? That means I'll verify that calling the findAll() method results in CommentService invoking the named query named by the FIND_ALL string constant.
Thanks to dependency injection and stubbing, you can easily achieve that using e.g. Mockito to stub out the EntityManager. For the unit test, we're only focusing on the business logic in findAll(), so I won't bother testing lookup of the Comment service either--testing that the Comment service can be looked up and is wired to a proper entity manager instance is in the scope of an integration test, not a unit test.
public class MyCommentServiceUnitTest {
CommentService commentService;
EntityManager entityManager;
#Before
public void setUp() {
commentService = new CommentService();
entityManager = mock(EntityManager.class);
commentService.setEm(entityManager); // inject our stubbed entity manager
}
#Test
public void testFindAll() {
// stub the entity manager to return a meaningful result when somebody asks
// for the FIND_ALL named query
Query query = mock(Query.class);
when(entityManager.createNamedQuery(Comment.FIND_ALL, Comment.class)).thenReturn(query);
// stub the query returned above to return a meaningful result when somebody
// asks for the result list
List<Comment> dummyResult = new LinkedList<Comment>();
when(query.getResultList()).thenReturn(dummyResult);
// let's call findAll() and see what it does
List<Comment> result = commentService.findAll();
// did it request the named query?
verify(entityManager).createNamedQuery(Comment.FIND_ALL, Comment.class);
// did it ask for the result list of the named query?
verify(query).getResultList();
// did it return the result list of the named query?
assertSame(dummyResult, result);
// success, it did all of the above!
}
}
With the unit test above, I tested the behavior of the findAll() implementation. The unit test verified that the correct named query is obtained and that the result returned by the named query was returned to the callee.
What's more, the unit test above verifies that the implementation of findAll() is correct independently of the underlying JPA provider and the underlying data. I don't want to test JPA and the JPA provider unless I suspect there are bugs in the 3rd party code, so stubbing out these dependencies lets me focus the test entirely on the business logic of the Comment service.
It can take a little while to adjust to the mindset of testing behavior using stubs, but it is a very powerful technique for testing the business logic of your EJB 3.1 beans because it lets you isolate and narrow the scope of each test to exclude external dependencies.
Why not using Arquillian to write even unit tests and run them in a real container!?
No more mocks. No more container lifecycle and deployment hassles. Just real tests!
Mocks can be tactical, but more often than not, they are used to make code work outside of a real environment. Arquillian let's you ditch the mocks and write real tests. That's because Arquillian brings your test to the runtime, giving you access to container resources, meaningful feedback and insight about how the code really works.
More about Arquillian features.
It's possible to write unit tests that run against a container, but the caveat is that the container/appserver has to be up. Since that's not really practical, the general approach is to use a "mock" container to run your unit tests against. For that, check out JUnitEE or ejb3unit:
junitee
ejb3unit
Is there a way to initialize the EntityManager without a persistence unit defined? Can you give all the required properties to create an entity manager? I need to create the EntityManager from the user's specified values at runtime. Updating the persistence.xml and recompiling is not an option.
Any idea on how to do this is more than welcomed!
Is there a way to initialize the EntityManager without a persistence unit defined?
You should define at least one persistence unit in the persistence.xml deployment descriptor.
Can you give all the required properties to create an Entitymanager?
The name attribute is required. The other attributes and elements are optional. (JPA specification). So this should be more or less your minimal persistence.xml file:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
SOME_PROPERTIES
</persistence-unit>
</persistence>
In Java EE environments, the jta-data-source and non-jta-data-source elements are used to specify the global JNDI name of the JTA and/or non-JTA data source to be used by the persistence provider.
So if your target Application Server supports JTA (JBoss, Websphere, GlassFish), your persistence.xml looks like:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<!--GLOBAL_JNDI_GOES_HERE-->
<jta-data-source>jdbc/myDS</jta-data-source>
</persistence-unit>
</persistence>
If your target Application Server does not support JTA (Tomcat), your persistence.xml looks like:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<!--GLOBAL_JNDI_GOES_HERE-->
<non-jta-data-source>jdbc/myDS</non-jta-data-source>
</persistence-unit>
</persistence>
If your data source is not bound to a global JNDI (for instance, outside a Java EE container), so you would usually define JPA provider, driver, url, user and password properties. But property name depends on the JPA provider. So, for Hibernate as JPA provider, your persistence.xml file will looks like:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>br.com.persistence.SomeClass</class>
<properties>
<property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="hibernate.connection.url" value="jdbc:derby://localhost:1527/EmpServDB;create=true"/>
<property name="hibernate.connection.username" value="APP"/>
<property name="hibernate.connection.password" value="APP"/>
</properties>
</persistence-unit>
</persistence>
Transaction Type Attribute
In general, in Java EE environments, a transaction-type of RESOURCE_LOCAL assumes that a non-JTA datasource will be provided. In a Java EE environment, if this element is not specified, the default is JTA. In a Java SE environment, if this element is not specified, a default of RESOURCE_LOCAL may be assumed.
To insure the portability of a Java SE application, it is necessary to explicitly list the managed persistence classes that are included in the persistence unit (JPA specification)
I need to create the EntityManager from the user's specified values at runtime
So use this:
Map addedOrOverridenProperties = new HashMap();
// Let's suppose we are using Hibernate as JPA provider
addedOrOverridenProperties.put("hibernate.show_sql", true);
Persistence.createEntityManagerFactory(<PERSISTENCE_UNIT_NAME_GOES_HERE>, addedOrOverridenProperties);
Yes you can without using any xml file using spring like this inside a #Configuration class (or its equivalent spring config xml):
#Bean
public LocalContainerEntityManagerFactoryBean emf(){
properties.put("javax.persistence.jdbc.driver", dbDriverClassName);
properties.put("javax.persistence.jdbc.url", dbConnectionURL);
properties.put("javax.persistence.jdbc.user", dbUser); //if needed
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setPersistenceProviderClass(org.eclipse.persistence.jpa.PersistenceProvider.class); //If your using eclipse or change it to whatever you're using
emf.setPackagesToScan("com.yourpkg"); //The packages to search for Entities, line required to avoid looking into the persistence.xml
emf.setPersistenceUnitName(SysConstants.SysConfigPU);
emf.setJpaPropertyMap(properties);
emf.setLoadTimeWeaver(new ReflectiveLoadTimeWeaver()); //required unless you know what your doing
return emf;
}
Here's a solution without Spring.
Constants are taken from org.hibernate.cfg.AvailableSettings :
entityManagerFactory = new HibernatePersistenceProvider().createContainerEntityManagerFactory(
archiverPersistenceUnitInfo(),
ImmutableMap.<String, Object>builder()
.put(JPA_JDBC_DRIVER, JDBC_DRIVER)
.put(JPA_JDBC_URL, JDBC_URL)
.put(DIALECT, Oracle12cDialect.class)
.put(HBM2DDL_AUTO, CREATE)
.put(SHOW_SQL, false)
.put(QUERY_STARTUP_CHECKING, false)
.put(GENERATE_STATISTICS, false)
.put(USE_REFLECTION_OPTIMIZER, false)
.put(USE_SECOND_LEVEL_CACHE, false)
.put(USE_QUERY_CACHE, false)
.put(USE_STRUCTURED_CACHE, false)
.put(STATEMENT_BATCH_SIZE, 20)
.build());
entityManager = entityManagerFactory.createEntityManager();
And the infamous PersistenceUnitInfo
private static PersistenceUnitInfo archiverPersistenceUnitInfo() {
return new PersistenceUnitInfo() {
#Override
public String getPersistenceUnitName() {
return "ApplicationPersistenceUnit";
}
#Override
public String getPersistenceProviderClassName() {
return "org.hibernate.jpa.HibernatePersistenceProvider";
}
#Override
public PersistenceUnitTransactionType getTransactionType() {
return PersistenceUnitTransactionType.RESOURCE_LOCAL;
}
#Override
public DataSource getJtaDataSource() {
return null;
}
#Override
public DataSource getNonJtaDataSource() {
return null;
}
#Override
public List<String> getMappingFileNames() {
return Collections.emptyList();
}
#Override
public List<URL> getJarFileUrls() {
try {
return Collections.list(this.getClass()
.getClassLoader()
.getResources(""));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
#Override
public URL getPersistenceUnitRootUrl() {
return null;
}
#Override
public List<String> getManagedClassNames() {
return Collections.emptyList();
}
#Override
public boolean excludeUnlistedClasses() {
return false;
}
#Override
public SharedCacheMode getSharedCacheMode() {
return null;
}
#Override
public ValidationMode getValidationMode() {
return null;
}
#Override
public Properties getProperties() {
return new Properties();
}
#Override
public String getPersistenceXMLSchemaVersion() {
return null;
}
#Override
public ClassLoader getClassLoader() {
return null;
}
#Override
public void addTransformer(ClassTransformer transformer) {
}
#Override
public ClassLoader getNewTempClassLoader() {
return null;
}
};
}
I was able to create an EntityManager with Hibernate and PostgreSQL purely using Java code (with a Spring configuration) the following:
#Bean
public DataSource dataSource() {
final PGSimpleDataSource dataSource = new PGSimpleDataSource();
dataSource.setDatabaseName( "mytestdb" );
dataSource.setUser( "myuser" );
dataSource.setPassword("mypass");
return dataSource;
}
#Bean
public Properties hibernateProperties(){
final Properties properties = new Properties();
properties.put( "hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect" );
properties.put( "hibernate.connection.driver_class", "org.postgresql.Driver" );
properties.put( "hibernate.hbm2ddl.auto", "create-drop" );
return properties;
}
#Bean
public EntityManagerFactory entityManagerFactory( DataSource dataSource, Properties hibernateProperties ){
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource( dataSource );
em.setPackagesToScan( "net.initech.domain" );
em.setJpaVendorAdapter( new HibernateJpaVendorAdapter() );
em.setJpaProperties( hibernateProperties );
em.setPersistenceUnitName( "mytestdomain" );
em.setPersistenceProviderClass(HibernatePersistenceProvider.class);
em.afterPropertiesSet();
return em.getObject();
}
The call to LocalContainerEntityManagerFactoryBean.afterPropertiesSet() is essential since otherwise the factory never gets built, and then getObject() returns null and you are chasing after NullPointerExceptions all day long. >:-(
It then worked with the following code:
PageEntry pe = new PageEntry();
pe.setLinkName( "Google" );
pe.setLinkDestination( new URL( "http://www.google.com" ) );
EntityTransaction entTrans = entityManager.getTransaction();
entTrans.begin();
entityManager.persist( pe );
entTrans.commit();
Where my entity was this:
#Entity
#Table(name = "page_entries")
public class PageEntry {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String linkName;
private URL linkDestination;
// gets & setters omitted
}
With plain JPA, assuming that you have a PersistenceProvider implementation (e.g. Hibernate), you can use the PersistenceProvider#createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) method to bootstrap an EntityManagerFactory without needing a persistence.xml.
However, it's annoying that you have to implement the PersistenceUnitInfo interface, so you are better off using Spring or Hibernate which both support bootstrapping JPA without a persistence.xml file:
this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
this.persistenceUnitInfo,
getJpaPropertyMap()
);
Where the PersistenceUnitInfo is implemented by the Spring-specific MutablePersistenceUnitInfo class.
DataNucleus JPA that I use also has a way of doing this in its docs. No need for Spring, or ugly implementation of PersistenceUnitInfo.
Simply do as follows
import org.datanucleus.metadata.PersistenceUnitMetaData;
import org.datanucleus.api.jpa.JPAEntityManagerFactory;
PersistenceUnitMetaData pumd = new PersistenceUnitMetaData("dynamic-unit", "RESOURCE_LOCAL", null);
pumd.addClassName("mydomain.test.A");
pumd.setExcludeUnlistedClasses();
pumd.addProperty("javax.persistence.jdbc.url", "jdbc:h2:mem:nucleus");
pumd.addProperty("javax.persistence.jdbc.user", "sa");
pumd.addProperty("javax.persistence.jdbc.password", "");
pumd.addProperty("datanucleus.schema.autoCreateAll", "true");
EntityManagerFactory emf = new JPAEntityManagerFactory(pumd, null);