But, I ran the hibernate wizard on spring 3 templates, and it actually seems as if it's close to the Groovy version, which means there aren't any mappings to be done at all. Let's find out why.
Checking app-context.xml, we find the following 3 statements
<jdbc:embedded-database id="dataSource" type="H2"/>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="xyz.sample.barehibernate" />
So, it looks like it's using an embedded HQL data source, supports transactions, and scans the package for components.
Next, let's look at the source code the template wizard create. First, there's a class called "Hibernate Configuration" which ought to be interesting:
I'll add comments to show my guesses as to what the code means:
package xyz.sample.barehibernate;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.dialect.H2Dialect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
@Configuration // this is used for configuration - not sure what that exactly means, but it's a java configuration vs. xml
// configuration
public class HibernateConfiguration {
@Value("#{dataSource}") // clearly pulling in the data source from app-context.xml.
private DataSource dataSource;
@Bean // A bean which will be scanned by the container
public AnnotationSessionFactoryBean sessionFactoryBean() { // method to generate an annotation-based Hibernate
// session, used by the container
Properties props = new Properties();
props.put("hibernate.dialect", H2Dialect.class.getName()); // set up the HSQL dialect to be used
props.put("hibernate.format_sql", "true"); // we like SQL
AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean(); // private instantiation
bean.setAnnotatedClasses(new Class[]{Item.class, Order.class}); // give it the classes to be "hibernated"
// this is the "magic" that saves mapping
bean.setHibernateProperties(props); // set the props
bean.setDataSource(this.dataSource); // set the data source
bean.setSchemaUpdate(true); // allow updates/
return bean;
}
// Give whoever needs the transaction manager the session factory bean decorated with the
// Hibernate transaction manager
@Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager( sessionFactoryBean().getObject() );
}
}
Now the domain classes, again with comments:
package xyz.sample.barehibernate;
import java.util.Collection;
import java.util.LinkedHashSet;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* An order.
*/
@Entity // It's a domain object
@Table(name="T_ORDER") // here's the table name
public class Order {
@Id // this is the id
@GeneratedValue(strategy=GenerationType.AUTO) // and it should be auto-generated
private Long id; // make it a long
private String customer;
@OneToMany(cascade=CascadeType.ALL) // it can have many items
@JoinColumn(name="ORDER_ID") // here's the column name to join it on
private Collection- items = new LinkedHashSet
- (); // and the list of items
// getters and setters
/**
* @return the customer
*/
public String getCustomer() {
return customer;
}
/**
* @param customer the customer to set
*/
public void setCustomer(String customer) {
this.customer = customer;
}
/**
* @return the items
*/
public Collection- getItems() {
return items;
}
/**
* @param items the items to set
*/
public void setItems(Collection- items) {
this.items = items;
}
/**
* @return the id
*/
public Long getId() {
return id;
}
}
// this is the order header
package xyz.sample.barehibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
/**
* An item in an order
*/
@Entity // It's a domain object (persistable)
public class Item {
@Id // see above
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne // many of these to one order
private Order order;
// pojo variables, getters and setters
private String product;
private double price;
private int quantity;
/**
* @return the order
*/
public Order getOrder() {
return order;
}
/**
* @return the product
*/
public String getProduct() {
return product;
}
/**
* @param product
* the product to set
*/
public void setProduct(String product) {
this.product = product;
}
/**
* @return the price
*/
public double getPrice() {
return price;
}
/**
* @param price
* the price to set
*/
public void setPrice(double price) {
this.price = price;
}
/**
* @return the quantity
*/
public int getQuantity() {
return quantity;
}
/**
* @param quantity
* the quantity to set
*/
public void setQuantity(int quantity) {
this.quantity = quantity;
}
/**
* @return the id
*/
public Long getId() {
return id;
}
}
So by a magic combination of scanning (to avoid coding the beans (and configuration?) in the spring beans file, a variety of annotations (Entity, manytoone, onetomany, id, generated value, and a hibernation configuration java class which uses the magic of reflection to set the properties, we have a full-blown hibernate system without mapping of specific fields.
Below is an example of how to utilize the data via some unit tests, aslo generated:
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class OrderPersistenceTests {
@Autowired
private SessionFactory sessionFactory;
@Test
@Transactional
public void testSaveOrderWithItems() throws Exception {
Session session = sessionFactory.getCurrentSession();
Order order = new Order();
order.getItems().add(new Item());
session.save(order);
session.flush();
assertNotNull(order.getId());
}
@Test
@Transactional
public void testSaveAndGet() throws Exception {
Session session = sessionFactory.getCurrentSession();
Order order = new Order();
order.getItems().add(new Item());
session.save(order);
session.flush();
// Otherwise the query returns the existing order (and we didn't set the
// parent in the item)...
session.clear();
Order other = (Order) session.get(Order.class, order.getId());
assertEquals(1, other.getItems().size());
assertEquals(other, other.getItems().iterator().next().getOrder());
}
@Test
@Transactional
public void testSaveAndFind() throws Exception {
Session session = sessionFactory.getCurrentSession();
Order order = new Order();
Item item = new Item();
item.setProduct("foo");
order.getItems().add(item);
session.save(order);
session.flush();
// Otherwise the query returns the existing order (and we didn't set the
// parent in the item)...
session.clear();
Order other = (Order) session
.createQuery( "select o from Order o join o.items i where i.product=:product")
.setString("product", "foo").uniqueResult();
assertEquals(1, other.getItems().size());
assertEquals(other, other.getItems().iterator().next().getOrder());
}
}
No comments:
Post a Comment