SyntaxHighlighter

Showing posts with label Spring JPA. Show all posts
Showing posts with label Spring JPA. Show all posts

Friday, April 5, 2013

Spring Integration JPA and REST

Spring Integration JPA and REST


here's a little sample project i put together to illustrate how to expose JPA objects via REST using Spring Integration.  it's a bit rough but it does the following;
- PUT a new entity
- GET an entity by id
- GET all entities

here's the entity;

package de.incompleteco.spring.jpa.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="simple_entity")
public class SimpleEntity implements Serializable {

 private static final long serialVersionUID = 1l;

 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 private Long id;
 
 @Column
 private String stuff;

 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 public String getStuff() {
  return stuff;
 }

 public void setStuff(String stuff) {
  this.stuff = stuff;
 }

 @Override
 public String toString() {
  return "SimpleEntity [id=" + id + ", stuff=" + stuff + "]";
 }
 
}


here's the entity manager factory;



 
  
  
  
   
    
   
  
 
 
 
  

  
   
   
  

 



here's the Spring Integration for the JPA service



 
 
 
 
  
 
 
 
 
 
 
   
 

 
 
 
 
   
 
 



here's the Spring Integration for the HTTP endpoint



 
 
 
 
 

 
  
  
 

 
 
 
 
  
  
 
 
 
 
 
  
  
  
  
 

 
 
 

 




and here's a test showing it all

package de.incompleteco.spring.jpa;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;

import javax.annotation.Resource;

import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.web.context.WebApplicationContext;

import de.incompleteco.spring.jpa.domain.SimpleEntity;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration({"classpath:/META-INF/spring/*-context.xml"})
@ActiveProfiles("junit")
public class IntegrationTest {

 @Resource
 private WebApplicationContext context;
 
 private ObjectMapper mapper;
 
 private MockMvc mvc;
 
 @Before
 public void before() throws Exception {
  //setup
  mapper = new ObjectMapper();//json
  mvc = webAppContextSetup(context).build();  
 }

 @Test
 public void test() throws Exception {
  //create an object
  SimpleEntity entity = new SimpleEntity();
  entity.setStuff("hello world");
  //convert
  String json = mapper.writeValueAsString(entity);
  //execute
  MvcResult result = mvc.perform(put("/simpleEntity").contentType(MediaType.APPLICATION_JSON).content(json))
   .andExpect(status().isOk()).andReturn();
  //now convert back
  SimpleEntity resultEntity = mapper.readValue(result.getResponse().getContentAsByteArray(), SimpleEntity.class);
  //now check
  assertTrue(resultEntity.getId() > 0);
  assertEquals(entity.getStuff(),resultEntity.getStuff());
  //retrieve by the id
  result = mvc.perform(get("/simpleEntity").param("id", resultEntity.getId().toString()))
   .andExpect(status().isOk()).andReturn();
  //now convert
  SimpleEntity retrievedEntity = mapper.readValue(result.getResponse().getContentAsByteArray(), SimpleEntity.class);
  //now check
  assertEquals(entity.getStuff(),retrievedEntity.getStuff());
  //retrieve all
  result = mvc.perform(get("/simpleEntity"))
    .andExpect(status().isOk()).andReturn();
  //now it *should* be an array of SimpleEntity
  SimpleEntity[] entities = mapper.readValue(result.getResponse().getContentAsByteArray(),SimpleEntity[].class);
  //test
  assertNotNull(entities);
  assertTrue(entities.length > 0);
  
 }
}


if you want the code, it's here; https://github.com/incomplete-code/spring-integration-jpa

Thursday, December 20, 2012

Caching, Spring and Reducing the 'first hit' Time

Caching, Spring and Reducing the 'first hit' Time


recently a colleague was working on a Jdbc Caching issue.  The underlying database supporting was of a similar nature to SQLFire; that is, distributed with a cache on top.  What was the pain was that the 'first hit' to the database triggered the underlying service to go and gather all the information from the distribution and cache the query's result set.  This lead to about a 6x performance cost compared to subsequent caches.  The question was, how to reduce this from the poor user who hits it first?



ApplicationListener is feature in Spring that allows you to create your own implementation and received the context just after it's started up.  In this case, this would allow the application context to have all the accessible beans fully populated and initialized.  This allows us, in the case above, to call the respective Service during startup time, triggering the underlying data service to run the 'first hit'.  The end result is that the 'first hit' is taken care of on startup, and, depending on how caching is managed, the user shouldn't experience the 'first hit' lag (as it's already completed) when they access their services.

here's a sample

Saturday, September 29, 2012

Spring LocalContainerEntityManagerFactoryBean, packagesToScan and JTA

Spring LocalContainerEntityManagerFactoryBean, packagesToScan and JTA


here's an interesting one, Hibernate 4, Spring JPA (using LocalContainerEntityManagerFactoryBean) and JTA.  the scenario is, testing in JUnit and need to specify (and emulate) a JTA transaction. unfortunately, it's not all straight out-of-the-box, but here it is;

first, LocalContainerEntityManagerFactoryBean treats everything as a non-JTA transaction, so there's a little extra configuration to be done.  To switch it out, Spring does provide a postProcessor for the PersistenceUnit and a mutable persistent unit to it, but we have to write our own switch.  (it's pretty straight forward, but maybe we can ask the nice chaps to include it out of the box in 3.2.x?)

here's my cut - you can roll/cut & paste your own

package org.incompletecode.spring.batch.jpa;
 
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
 
public class JTAPersistenceUnitPostProcessor implements
  PersistenceUnitPostProcessor {
 
 @Override
 public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
  //switch the nonJTA to JTA
  pui.setJtaDataSource(pui.getNonJtaDataSource());
  pui.setNonJtaDataSource(null);
 }
 
}

and now here's a quick example of using Bitronix as your JTA provider


 
 
 
 
     
 
  
 
 
 
     
 
 
 
     
     
 
 
 
 
 
      
      
      
      
      
      
          
              jdbc:h2:mem:a;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1
          
        
 
 



Wednesday, August 8, 2012

Spring Data JPA & Hibernate & EhCache

Spring Data JPA & Hibernate & EhCache

here's a simple setup to run an EhCache configuration on Spring Data JPA

first the maven



  4.0.0
  org.incomplete.spring
  spring-jpa-cache
  0.0.1-SNAPSHOT
  war
  spring-jpa-cache
  
  	
	  
	    org.apache.maven.plugins
	    maven-compiler-plugin
	    2.3.2
	    
	        1.6
	        1.6
	    
	    	
  	
  
  
  	
  		org.springframework.data
  		spring-data-jpa
  		1.1.0.RELEASE
  	
  	
  		org.hibernate
  		hibernate-entitymanager
  		4.1.4.Final
  	
  	
  		org.hibernate
  		hibernate-validator
  		4.3.0.Final
  	
  	
  		org.hsqldb
  		hsqldb
  		2.2.8
  		test
  	
  	
  		org.springframework
  		spring-test
  		3.1.0.RELEASE
  		test
  	
  	
  		junit
  		junit
  		4.8.2
  		test
  	
  	
  		log4j
  		log4j
  		1.2.14
  	
  	
  		org.slf4j
  		slf4j-log4j12
  		1.6.0
  	
  	
  		net.sf.ehcache
  		ehcache-core
  		2.6.0
  	
  	
  		org.hibernate
  		hibernate-ehcache
  		4.1.4.Final
  	
  


then our basic entity

package org.incompletecode.spring.domain;
 
import java.io.Serializable;
 
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
 
@Cacheable
@Entity
@Table(name="simple_entity")
public class SimpleEntity implements Serializable {
 
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
 
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private Long id;
	
	@Column
	private String name;
	
	@Column
	private String description;
 
	public Long getId() {
		return id;
	}
 
	public void setId(Long id) {
		this.id = id;
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public String getDescription() {
		return description;
	}
 
	public void setDescription(String description) {
		this.description = description;
	}
 
	@Override
	@Transient
	public String toString() {
		return "SimpleEntity [id=" + id + ", name=" + name + ", description="
				+ description + "]";
	}
	
	
	
}

our DAO

package org.incompletecode.spring.dao;
 
import org.incompletecode.spring.domain.SimpleEntity;
import org.springframework.data.jpa.repository.JpaRepository;
 
public interface SimpleEntityDAO extends JpaRepository< SimpleEntity, Long > {
 
}

now our Spring Config for the key parts (Spring Data, JPA, Transaction Manager)



 
	
	
	
 
	
		
		
		
			
				
					
		
		
			
				org.hibernate.cache.SingletonEhCacheProvider
				/META-INF/cache/ehcache.xml
				true
				true
				org.hibernate.cache.ehcache.EhCacheRegionFactory
			
		
	
 
	
		
		
	
	


and of course our database stuff



 
	
 


the cache config




and now for a unit test

package org.incompletecode.spring.dao;
 
import static org.junit.Assert.assertNotNull;
 
import java.util.ArrayList;
import java.util.List;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hsqldb.jdbc.JDBCDataSource;
import org.incompletecode.spring.domain.SimpleEntity;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.StopWatch;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:/META-INF/spring/data-context.xml",
	"classpath:/META-INF/spring/datasource-context.xml"})
public class SimpleEntityDAOTest {
 
	private static final Log logger = LogFactory.getLog(SimpleEntityDAOTest.class);
	
	public static final int count = 10000;
	
	@Autowired
	private SimpleEntityDAO simpleEntityDAO;
	
	private StopWatch stopWatch = new StopWatch();
	
	@BeforeClass
	public static void beforeClass() throws Exception {
		SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
		//build
		JDBCDataSource dataSource = new JDBCDataSource();
		dataSource.setUrl("jdbc:hsqldb:mem:a");
		//bind
		builder.bind("jdbc/datasource", dataSource);
	}
	
	@Before
	public void before() throws Exception {
		List< SimpleEntity > simpleEntities = new ArrayList< SimpleEntity >(count);
		//create a list
		stopWatch.start();
		for (int i=0; i< count; i++) {
			SimpleEntity simpleEntity = new SimpleEntity();
			simpleEntity.setName("code" + i);
			simpleEntities.add(simpleEntity);
		}//end for
		stopWatch.stop();
		logger.info("time to create: " + stopWatch.getLastTaskTimeMillis() + "ms");
		//save
		stopWatch.start();
		simpleEntityDAO.save(simpleEntities);
		stopWatch.stop();
		logger.info("time to save: " + stopWatch.getLastTaskTimeMillis() + "ms");
	}
	
	@After
	public void after() throws Exception {
		stopWatch.start();
		simpleEntityDAO.deleteAllInBatch();
		stopWatch.stop();
		logger.info("time to delete in batch: " + stopWatch.getLastTaskTimeMillis() + "ms");
	}
	
	@Test
	public void test() throws Exception {
		//create an entity
		SimpleEntity simpleEntity = new SimpleEntity();
		simpleEntity.setName("hi");
		//save
		simpleEntityDAO.save(simpleEntity);
		//check
		assertNotNull(simpleEntity.getId());
	}
	
	@Test
	public void testRetrieveAll() throws Exception {
		stopWatch.start();
		simpleEntityDAO.findAll();
		stopWatch.stop();
		logger.info("time to retrieve all: " + stopWatch.getLastTaskTimeMillis() + "ms");
	}
	
	@Test
	public void testMultipleRetrieveAll() throws Exception {
		for (int i=0;i<10;i++) {
			testRetrieveAll();
		}
	}
	
}



here's some stats on the unit test above; running it on my local machine inside STS, i can squeeze a 20% performance improvement with caching enabled.  not too shabby

Friday, July 27, 2012

Spring Data JPA - Custom Implementation IllegalArgument Problem - Solved!

Spring Data JPA - Custom Implementation IllegalArgument Problem - Solved!

here's a catch for you, when you're building a custom implementation to use in the JpaRepository, you have to be careful of the naming convention.  For example, the Impl must be named for the JpaRepository extension.


here's a sample




Friday, July 13, 2012

Spring Data JPA - How To

Spring Data JPA - in a few minutes

Spring Data JPA is a fantastic tool that take so much of the boiler plate out of the JPA process and leaves you to get down to the nitty gritty.  To get it up and running and supporting your basic CRUD functions, here's a couple of steps I use.

Maven Setup (yes, I'm still using Maven)

- grab the latest release packages of spring data jpa


Note: 1.1.0.RELEASE has an auto dependency on spring-tx.3.2.0.M1 and spring-orm.3.2.0.M1 which can cause some headaches in STS.  Override this by explicitly declaring 3.1.0.RELEASE versions of both and you should be good

Simple Entity

here's a simple target entity marked up with regular old JPA annotations


Simple Entity DAO

here's a Spring Data JPA DAO interface extending the JpaRepository


(that's it by the way, no implementation of this interface, nothing)

The Spring Work

i like to keep a separation of concerns for the stuff that changes (resource references) and the stuff that doesn't (EntityManagerFactory) so i'll create two files

first the spring data magic


Note: I'm using spring-orm.3.1.0 so i don't need to use a persistence.xml if i'm using annotations

and now my resources (database setup stuff)



A Unit Test

and now here's a quick sample JUnit test that tests for optimistic locking issues (version changes outside of EntityManager


Wrap Up

imho, Spring Data JPA is one of the best things to happen since Hibernate.  really increases developer productivity and gets them away from grinding out boilerplate and into the tricky stuff where they should be focused.   the people on Spring Data JPA did a great job, go and have a look at their stuff