- In general, even when using Hibernate or other ORM, don't have to overwrite the Object's hashCode() and equals().
- However, you need to do it if both conditions below are true in your case:
- you use dettach() with later reAttach(), and
- you use your identity in Sets
- Hibernate uses equals() (and/or hashCode() ?) only to tell that two objects represent the same entity and not whether it's values have changed (it iterates over the attributes for this purpose).
- If you use entities in a Set, never change any component of the hashCode() while the object is in the Set. The best way is to make the business key immutable.
- For overwriting hashCode()/equals(), you can use EqualsBuilder and HashCodeBuilder from the Apache Commons Lang library. Or semit-auto generate them both, always both of them, using eclipse.
Showing posts with label hibernate. Show all posts
Showing posts with label hibernate. Show all posts
Friday, November 14, 2014
hashCode() vs. equals() vs. Hibernate: Are These Two Persons Exact Twins?
Basics:
Thursday, April 1, 2010
JPA with Hibernate on Glassfish 3
Intro
This post is simply a summary of a simple proof of concept. It shows how to:
Entity
EJB Bean
The interface:
And the bean implementation:
The annotation @Stateless with the mappedName make the bean to get registered with JNDI. The
The persistence.xml file (put it into META-INF folder under src folder so it will be deployed onto the server)
The "hibernate." prefix in persistence.xml file is not optional when adding properties of the JPA provider (Hibernate in this case). They are ignored without it, without a warning.
Glassfish Setup
Nothing other than installing the Hibernate component using the Glassfish console.
Unit Tests
The unit test:
A Few Notes
A few things to try in the next proof of concept:
This post is simply a summary of a simple proof of concept. It shows how to:
- create a stateless EJB3 bean
- persist an entity using JPA with Hibernate as a JPA provider
- configure JPA to use a datastore defined on Glassfish (uses pre-installed java/__default datastore, which uses pre-installed Derby/JavaDB)
Entity
@Entity
public class Book implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String title;
private float price;
public Book() {
super();
}
...
}
Here, I have annotated the property, rather than the getter (not shown for brevity), since it feels more intuitive to me. I don't know if there is any advantage/difference of one vs the other other than my personal preference. The "@GeneratedValue(...)" annotation for primary key in JPA entity definition is not optional, as I expected. Using just the "@Id" annotation results in the primary key being not set (set to 0).EJB Bean
The interface:
@Remote
public interface BookManager {
public abstract int addBook(Book book);
public abstract Book find(int bookId);
}
And the bean implementation:
@Stateless(name="BookManager", mappedName = "ejb/BookManagerJNDI")
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class BookManagerImpl implements BookManager {
// Dependency injection of Entity Manager for
// the given persistence unit
@PersistenceContext(unitName="pu1") EntityManager em;
public int addBook(Book book) {
// Transitions new instances to managed. On the
// next flush or commit, the newly persisted
// instances will be inserted into the datastore.
em.persist(book);
return book.getId();
}
@Override
public Book find(int bookId) {
return em.find(Book.class, bookId);
}
}
The annotation @Stateless with the mappedName make the bean to get registered with JNDI. The
TransactionAttributeType.REQUIRED tells the container to wrap each method in the class with a transaction. JPA SetupThe persistence.xml file (put it into META-INF folder under src folder so it will be deployed onto the server)
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="pu1">
<!-- Persistence provider -->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/__default</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
The "hibernate." prefix in persistence.xml file is not optional when adding properties of the JPA provider (Hibernate in this case). They are ignored without it, without a warning.
Glassfish Setup
Nothing other than installing the Hibernate component using the Glassfish console.
Unit Tests
The unit test:
try {
InitialContext ctx = new InitialContext();
BookManager bean = (BookManager) ctx.lookup("ejb/BookManagerJNDI");
Book book = new Book("Chocolate Rain", 25.10f);
int bookId = bean.addBook(book );
book = null;
book = bean.find(bookId);
Assert.assertEquals("Chocolate Rain", book.getTitle());
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Assert.fail("Failed. Exception thrown.");
}
A Few Notes
- Can JPA be used to create and index? Yes and no. Not in general. But it provides a limited capability. To create a unique constrain on a table, use @UniqueConstraint(columnNames={"EMP_BDAY", "EMP_NAME"})
- How to specify the character column type length? Use @Column(length=50).
- What the client can understand about the remote exception, in case the EJB bean fails? The remote exception is wrapped in a EJBException and returned to the client. For example, if the password for the DB is incorrect, the org.hibernate.exception.GenericJDBCException will be returned with a message "Cannot open connection" (when Hibernate is used as JPA provider).
A few things to try in the next proof of concept:
- test the rollback function, if second of two persistence operations failed when both are in the same method of the BookManager class.
- do a parent/child relationship.
Thursday, March 11, 2010
Hibernate Session and Transaction Management
It seems, there are several approaches to manage Hibernate sessions and transactions:
Basic Approach: Managed by Application
Here's a code sample from hibernate document:
- explicitly by the application
- explicitly by the application with ThreadLocal pattern (example)
- via Hibernate transaction demarcation with JTA
- via Hibernate transaction demarcation with plain JDBC
- using Spring Framework
- using EJB / CMT (container-managed transactions)
Basic Approach: Managed by Application
Here's a code sample from hibernate document:
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
// Do some work
session.load(...);
session.persist(...);
tx.commit(); // Flush happens automatically
}
catch (RuntimeException e) {
tx.rollback();
throw e; // or display error message
}
finally {
session.close();
}
You choose the approach.
Friday, February 19, 2010
JSON RESTfull Service Using Jersey with Hibernate Persistence on Glassfish
Tips:
Code:
Complete web service implementation class code (in RESTfull, call a resource):
Open Questions:
- to setup Hibernate to use a datasource defined under Glassfish, see my other post.
- usefull Jersey annotations:
- for the resource class: @Path("/person/")
- for a method: @GET @Path("{personId}/") @Produces("application/json"). Then, you can use public Person getUser(@PathParam("personId") int personId) for method declaration.
- add @Consumes("application/json") with public Person post(Person person) method declaration. Jersey takes care of unmarshaling the Json into Person object.
- to return an error code from the restfull webservice, throw a new WebApplicationException(Response.Status.NOT_FOUND), for example. This one would return 404 error. No Need to declare the jersey handler method as "throws ...".
- to unit test the service, use com.sun.jersey.api.client.Client:
Person result = Client.create().resource("http://localhost:8080/myapp/person") .type("application/json") .post(Person.class,new Person("Jon Smith",133)); Assert.assertEquals("Jon Smith", result.getName()); - To pass an object retrieved via Hibernate as a response from a webservice, it needs to be serializable. But objects retrieved this way have additional members and so they need to be converted to a pure entity object (Person, in my case). I have used the Dozer library for this purpose (see the code below).
- The entity classes (Person and PersonCollection, in my example)need to be annotated with @XmlRootElement.
Code:
Complete web service implementation class code (in RESTfull, call a resource):
package olcc.jersey.service;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import olcc.entity.HibernateUtil;
import olcc.entity.Person;
import olcc.entity.PersonCollection;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
@Path("/person/")
public class PersonResource {
@GET @Path("{personId}/") @Produces("application/json")
public Person getPerson(@PathParam("personId") int personId) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = null;
Person personClean;
try{
tx = session.beginTransaction();
Person person = (Person) session.load(Person.class,personId);
Mapper mapper = new DozerBeanMapper();
personClean = mapper.map(person,Person.class);
session.getTransaction().commit();
} catch( Exception ex) {
if( tx != null ) tx.rollback();
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return personClean;
}
@GET @Produces("application/json")
public PersonCollection get() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List<person> result = session.createQuery("from Person").list();
Mapper mapper = new DozerBeanMapper();
PersonCollection persons = new PersonCollection();
for( Person person : result ) {
persons.add(mapper.map(person,Person.class));
}
session.getTransaction().commit();
return persons;
}
@POST @Consumes("application/json")
@Produces("application/json")
public Person post(Person person) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
session.save(person);
session.getTransaction().commit();
return person;
}
@GET @Path("delete/{personId}/") @Produces("application/json")
public Person deleteOne(@PathParam("personId") int personId) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Transaction tx = null;
Person personClean;
try{
tx = session.beginTransaction();
Person person = (Person) session.load(Person.class,personId);
session.delete(person);
Mapper mapper = new DozerBeanMapper();
personClean = mapper.map(person,Person.class);
session.getTransaction().commit();
} catch( Exception ex) {
if( tx != null ) tx.rollback();
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return personClean;
}
}Open Questions:
- I'm not sure where the Hibernate session should be closed. I don't think this can be done at the end of each handler method.
- How to use JTA for transaction management instead of direct JDBC transaction management?
- Most of the Hibernate-specific code should go into a DAO, with most of it into a generic DAO. But the recommended by Hibernate documentation generic DAO is defined in terms of state-oriented data access API (makePersistent() and makeTransient() methods), which are less intuitive for me. What is the advantage of using them and how to use them from CRUD operations?
Wednesday, February 17, 2010
Configure Hibernate to Use A Datasource
I'm using Glassfish application server, on which (using its Console) I have created a JDBC datasource (JDBC Resource). I'd like configure the hibernate framework to use it. The resons:
HibernateUtil.java File
The Application Code
- Connection pooling (it's true that I could use the Hibernate's own connection pooling)
- Portability: moving the application to another application server is easy, as long as they both provide a datasource with the same name (Hibernate dialect may still need to be changed appropriately).
<?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 name="hibernate/sessionFactory">
<property name="connection.datasource">jdbc/derbydb</property>
<property name="dialect">org.hibernate.dialect.DerbyDialect</property>
<property name="current_session_context_class">thread</property>
<property name="hbm2ddl.auto">create</property>
<mapping resource="olcc/entity/Person.hbm.xml"/>
</session-factory>
</hibernate-configuration>
HibernateUtil.java File
private static SessionFactory buildSessionFactory() {
return new Configuration().configure().buildSessionFactory();
}
The Application Code
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Wednesday, May 20, 2009
Using Unit Testing to Test GWT RCP Calls
This is a short note. I'm working on a GWT application and ran into a problem with an RPC call which gets some objects from the database using Hibernate and passes them back to the client. I'm going to solve the problem using Dozer, but I needed to confirm this was the problem and simplify the testing of this in future. So, I decided I want to unit test this service from the client's perspective. Here are my notes from this exercise:
- The easiest way to create a GWTTestCase is using the GWT's jUnitCreator. Creating it by hand is possible but tricky.
- The asynchronous test needs to use delayTestFinish(delayMs) and finishTest(). In my case, I had to set 5000 Ms. For some reason, 500Ms, which I thought would be more than enough was timing out.
- The good news is, that when using Eclipse plugin for GWT, starting initiating Run as JUnit Test on the GWTTestCase test starts for you also the server. And doing the same with Debug as JUnit Test allows to debug the client as well as server code.
Monday, December 29, 2008
Struts, Hibernate Development with Eclipse
I'm developing an web application to test algorithms for Romba-like devices. I have some algorithms in mind, that I want to test, so I decided I develop an application for the purpose of testing these algorithms or any algorithms.
I wanted to use Java standard frameworks, for now Struts and Hibernate and Eclipse as the. It took me some time to figure out what free plugins to use with Eclipse to add support to Struts and Hibernate. I looked for some time and finally found the following set of plugins:
A few notes:
I wanted to use Java standard frameworks, for now Struts and Hibernate and Eclipse as the. It took me some time to figure out what free plugins to use with Eclipse to add support to Struts and Hibernate. I looked for some time and finally found the following set of plugins:
- Tomcat plugin from EclipseTotale.com.
- Hibernate Core Plugin from Hibernate Team
- StrutsIDE - Project Amateras plugin
- DB Development plugin (from Eclipse.org)
- QuantumDB
- Derby plugin (from Eclipse.org)
A few notes:
- Tomcat plugin doesn't come with a documentation, but the website has a decent one. Plugin works nicely. Starts Tomcat in debug mode, unless user disables this feature in plugin preferences. Switch to Debug perspective and you can debug your application.
- QuantumDB is a well known plugin, but I had problems with it. I couldn't find in it the tables that were in the database. Possibly, I'll learn how to use it. DB Development plugin is easier to learn it.
Labels:
eclipse,
hibernate,
plugin,
software development,
struts,
web applications
Subscribe to:
Posts (Atom)
