Get 50% discount from my Spring Data book! Use campaign code BIG50. The deal lasts only 4 days so be fast!

Spring Data JPA Tutorial Part Two: CRUD

Share
A water drop

The first part of my Spring Data JPA tutorial described, how you configure Spring Data JPA. This blog entry goes a bit deeper and describes how you can use Spring Data JPA for creating a simple CRUD application. The requirements of the application are following:

  • The person must have a first name and last name. Both of these properties are mandatory.
  • It must be possible to list persons.
  • It must be possible to add new persons.
  • It must be possible to edit the information of existing persons.
  • It must be possible to delete persons.

I have now described the requirements of the created application. Now it is time to get to work and start implementing it.

Required Steps

The implementation of CRUD application can be divided to following steps:

  • Implementing the Person model object
  • Creating a repository for the Person object
  • Using the created repository

Each of these steps is explained with more details in following.

Implementing the Model Object

The implementation of the Person class is pretty simple. However, there are few issues which I would like to point out:

  • A builder is used to to create new instances of Person class. This might seem like over engineering but I like this approach for two reasons: First, it makes code easier to read than using the telescopic constructor pattern. Second, it ensures that you cannot create an object which in an inconsistent state during its construction (This is something that the common JavaBeans pattern cannot guarantee).
  • The only way to change the information stored in a Person object is to call the update() method. I am fan of putting as much logic to the model objects as possible. This approach does not clutter the service layer with domain logic and and ensures that you do not end up with an anemic domain model.

The source code of my Person class is given in following:

import org.apache.commons.lang.builder.ToStringBuilder;

import javax.persistence.*;

/**
 * An entity class which contains the information of a single person.
 * @author Petri Kainulainen
 */

@Entity
@Table(name = "persons")
public class Person {
   
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
   
    @Column(name = "creation_time", nullable = false)
    private Date creationTime;
   
    @Column(name = "first_name", nullable = false)
    private String firstName;

    @Column(name = "last_name", nullable = false)
    private String lastName;
   
    @Column(name = "modification_time", nullable = false)
    private Date modificationTime;
   
    @Version
    private long version = 0;

    public Long getId() {
        return id;
    }

    /**
     * Gets a builder which is used to create Person objects.
     * @param firstName The first name of the created user.
     * @param lastName  The last name of the created user.
     * @return  A new Builder instance.
     */

    public static Builder getBuilder(String firstName, String lastName) {
        return new Builder(firstName, lastName);
    }
   
    public Date getCreationTime() {
        return creationTime;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    /**
     * Gets the full name of the person.
     * @return  The full name of the person.
     */

    @Transient
    public String getName() {
        StringBuilder name = new StringBuilder();
       
        name.append(firstName);
        name.append(" ");
        name.append(lastName);
       
        return name.toString();
    }

    public Date getModificationTime() {
        return modificationTime;
    }

    public long getVersion() {
        return version;
    }

    public void update(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
   
    @PreUpdate
    public void preUpdate() {
        modificationTime = new Date();
    }
   
    @PrePersist
    public void prePersist() {
        Date now = new Date();
        creationTime = now;
        modificationTime = now;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    /**
     * A Builder class used to create new Person objects.
     */

    public static class Builder {
        Person built;

        /**
         * Creates a new Builder instance.
         * @param firstName The first name of the created Person object.
         * @param lastName  The last name of the created Person object.
         */

        Builder(String firstName, String lastName) {
            built = new Person();
            built.firstName = firstName;
            built.lastName = lastName;
        }

        /**
         * Builds the new Person object.
         * @return  The created Person object.
         */

        public Person build() {
            return built;
        }
    }

    /**
     * This setter method should only be used by unit tests.
     * @param id
     */

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

Creating the Repository

Implementing a repository which provides CRUD operations for the Person model object is pretty straightforward. All you have to do is to create an interface which extends the JpaRepository interface. The JpaRepository interface is a JPA specific extension to the Repository interface and it gives you the access to following methods which are used to implement the CRUD application:

  • delete(T entity) which deletes the entity given as a parameter.
  • findAll() which returns a list of entities.
  • findOne(ID id) which returns the entity using the id given a parameter as a search criteria.
  • save(T entity) which saves the entity given as a parameter.

The source code of my PersonRepository interface is given in following:

import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Specifies methods used to obtain and modify person related information
 * which is stored in the database.
 * @author Petri Kainulainen
 */

public interface PersonRepository extends JpaRepository<Person, Long> {
}

Using the Created Repository

You have now created both the model object and the repository which is needed to communicate with the database. The next step is to implement a service class which acts as an intermediary between the controllers and the implemented repository. The structure of the service layer is described next.

The PersonDTO is a simple DTO object which is used as a form object in my example application. Its source code is given in following:

import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.validator.constraints.NotEmpty;

/**
 * A DTO object which is used as a form object
 * in create person and edit person forms.
 * @author Petri Kainulainen
 */

public class PersonDTO {
   
    private Long id;

    @NotEmpty
    private String firstName;

    @NotEmpty
    private String lastName;

    public PersonDTO() {

    }

    public Long getId() {
        return id;
    }

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

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}

The PersonService interface specifies the methods which are provided by the actual implementation. Its source code is given in following:

/**
 * Declares methods used to obtain and modify person information.
 * @author Petri Kainulainen
 */

public interface PersonService {

    /**
     * Creates a new person.
     * @param created   The information of the created person.
     * @return  The created person.
     */

    public Person create(PersonDTO created);

    /**
     * Deletes a person.
     * @param personId  The id of the deleted person.
     * @return  The deleted person.
     * @throws PersonNotFoundException  if no person is found with the given id.
     */

    public Person delete(Long personId) throws PersonNotFoundException;

    /**
     * Finds all persons.
     * @return  A list of persons.
     */

    public List<Person> findAll();

    /**
     * Finds person by id.
     * @param id    The id of the wanted person.
     * @return  The found person. If no person is found, this method returns null.
     */

    public Person findById(Long id);

    /**
     * Updates the information of a person.
     * @param updated   The information of the updated person.
     * @return  The updated person.
     * @throws PersonNotFoundException  if no person is found with given id.
     */

    public Person update(PersonDTO updated) throws PersonNotFoundException;
}

The source code of the RepositoryPersonService class which implements the PersonService interface is given in following:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * This implementation of the PersonService interface communicates with
 * the database by using a Spring Data JPA repository.
 * @author Petri Kainulainen
 */

@Service
public class RepositoryPersonService implements PersonService {
   
    private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryPersonService.class);
   
    @Resource
    private PersonRepository personRepository;

    @Transactional
    @Override
    public Person create(PersonDTO created) {
        LOGGER.debug("Creating a new person with information: " + created);
       
        Person person = Person.getBuilder(created.getFirstName(), created.getLastName()).build();
       
        return personRepository.save(person);
    }

    @Transactional(rollbackFor = PersonNotFoundException.class)
    @Override
    public Person delete(Long personId) throws PersonNotFoundException {
        LOGGER.debug("Deleting person with id: " + personId);
       
        Person deleted = personRepository.findOne(personId);
       
        if (deleted == null) {
            LOGGER.debug("No person found with id: " + personId);
            throw new PersonNotFoundException();
        }
       
        personRepository.delete(deleted);
        return deleted;
    }

    @Transactional(readOnly = true)
    @Override
    public List<Person> findAll() {
        LOGGER.debug("Finding all persons");
        return personRepository.findAll();
    }

    @Transactional(readOnly = true)
    @Override
    public Person findById(Long id) {
        LOGGER.debug("Finding person by id: " + id);
        return personRepository.findOne(id);
    }

    @Transactional(rollbackFor = PersonNotFoundException.class)
    @Override
    public Person update(PersonDTO updated) throws PersonNotFoundException {
        LOGGER.debug("Updating person with information: " + updated);
       
        Person person = personRepository.findOne(updated.getId());
       
        if (person == null) {
            LOGGER.debug("No person found with id: " + updated.getId());
            throw new PersonNotFoundException();
        }
       
        person.update(updated.getFirstName(), updated.getLastName());

        return person;
    }

    /**
     * This setter method should be used only by unit tests.
     * @param personRepository
     */

    protected void setPersonRepository(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }
}

The last part of this step was to write unit tests for the RepositoryPersonService class. The source code of these unit tests is given in following:

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.*;

public class RepositoryPersonServiceTest {

    private static final Long PERSON_ID = Long.valueOf(5);
    private static final String FIRST_NAME = "Foo";
    private static final String FIRST_NAME_UPDATED = "FooUpdated";
    private static final String LAST_NAME = "Bar";
    private static final String LAST_NAME_UPDATED = "BarUpdated";
   
    private RepositoryPersonService personService;

    private PersonRepository personRepositoryMock;

    @Before
    public void setUp() {
        personService = new RepositoryPersonService();

        personRepositoryMock = mock(PersonRepository.class);
        personService.setPersonRepository(personRepositoryMock);
    }
   
    @Test
    public void create() {
        PersonDTO created = PersonTestUtil.createDTO(null, FIRST_NAME, LAST_NAME);
        Person persisted = PersonTestUtil.createModelObject(PERSON_ID, FIRST_NAME, LAST_NAME);
       
        when(personRepositoryMock.save(any(Person.class))).thenReturn(persisted);
       
        Person returned = personService.create(created);

        ArgumentCaptor<Person> personArgument = ArgumentCaptor.forClass(Person.class);
        verify(personRepositoryMock, times(1)).save(personArgument.capture());
        verifyNoMoreInteractions(personRepositoryMock);

        assertPerson(created, personArgument.getValue());
        assertEquals(persisted, returned);
    }
   
    @Test
    public void delete() throws PersonNotFoundException {
        Person deleted = PersonTestUtil.createModelObject(PERSON_ID, FIRST_NAME, LAST_NAME);
        when(personRepositoryMock.findOne(PERSON_ID)).thenReturn(deleted);
       
        Person returned = personService.delete(PERSON_ID);
       
        verify(personRepositoryMock, times(1)).findOne(PERSON_ID);
        verify(personRepositoryMock, times(1)).delete(deleted);
        verifyNoMoreInteractions(personRepositoryMock);
       
        assertEquals(deleted, returned);
    }
   
    @Test(expected = PersonNotFoundException.class)
    public void deleteWhenPersonIsNotFound() throws PersonNotFoundException {
        when(personRepositoryMock.findOne(PERSON_ID)).thenReturn(null);
       
        personService.delete(PERSON_ID);
       
        verify(personRepositoryMock, times(1)).findOne(PERSON_ID);
        verifyNoMoreInteractions(personRepositoryMock);
    }
   
    @Test
    public void findAll() {
        List<Person> persons = new ArrayList<Person>();
        when(personRepositoryMock.findAll()).thenReturn(persons);
       
        List<Person> returned = personService.findAll();
       
        verify(personRepositoryMock, times(1)).findAll();
        verifyNoMoreInteractions(personRepositoryMock);
       
        assertEquals(persons, returned);
    }
   
    @Test
    public void findById() {
        Person person = PersonTestUtil.createModelObject(PERSON_ID, FIRST_NAME, LAST_NAME);
        when(personRepositoryMock.findOne(PERSON_ID)).thenReturn(person);
       
        Person returned = personService.findById(PERSON_ID);
       
        verify(personRepositoryMock, times(1)).findOne(PERSON_ID);
        verifyNoMoreInteractions(personRepositoryMock);
       
        assertEquals(person, returned);
    }
   
    @Test
    public void update() throws PersonNotFoundException {
        PersonDTO updated = PersonTestUtil.createDTO(PERSON_ID, FIRST_NAME_UPDATED, LAST_NAME_UPDATED);
        Person person = PersonTestUtil.createModelObject(PERSON_ID, FIRST_NAME, LAST_NAME);
       
        when(personRepositoryMock.findOne(updated.getId())).thenReturn(person);
       
        Person returned = personService.update(updated);
       
        verify(personRepositoryMock, times(1)).findOne(updated.getId());
        verifyNoMoreInteractions(personRepositoryMock);
       
        assertPerson(updated, returned);
    }
   
    @Test(expected = PersonNotFoundException.class)
    public void updateWhenPersonIsNotFound() throws PersonNotFoundException {
        PersonDTO updated = PersonTestUtil.createDTO(PERSON_ID, FIRST_NAME_UPDATED, LAST_NAME_UPDATED);
       
        when(personRepositoryMock.findOne(updated.getId())).thenReturn(null);

        personService.update(updated);

        verify(personRepositoryMock, times(1)).findOne(updated.getId());
        verifyNoMoreInteractions(personRepositoryMock);
    }

    private void assertPerson(PersonDTO expected, Person actual) {
        assertEquals(expected.getId(), actual.getId());
        assertEquals(expected.getFirstName(), actual.getFirstName());
        assertEquals(expected.getLastName(), expected.getLastName());
    }
}

What is Next?

I have now demonstrated to you how you can implement a simple CRUD application with Spring Data JPA. If you are interested of seeing my fully functional example in action, you can get it from Github. The third part of my Spring Data JPA tutorial describes how you can create custom queries with query methods.

If you enjoy reading similar content, you should follow me on Twitter:

About the Author

Petri Kainulainen is passionate about software development and continuous improvement. He specializes in software development with the Spring Framework and is the author of Spring Data book.

About Petri Kainulainen →

106 comments… add one

  • Great stuff.

    Reply
  • Hello,

    Thanks for your article. But where is the controller.createRedirectViewPath(REDIRECT_PATH) method in the net.petrikainulainen.spring.datajpa.controller.AbstractControllerTest class?

    Best regards.

    Chris

    Reply
    • Hi Chris,

      it is good to hear that you liked the article. The method you mentioned is found from the net.petrikainulainen.spring.datajpa.controller.AbstractController class. The AbstractControllerTest class declares the inner class called TestController only because the AbstractController class is abstract and it cannot be instantiated.

      Reply
  • Why bother with dtos? I thought that was ejb 2 nonsense

    Reply
    • Hi Rance,

      Thanks for your comment. I prefer using DTOs as form objects from following reasons:

      1) Since the transaction boundary is on the service layer, the model object is no longer associated with the persistence context when the transaction ends (unless you use an extended persistence context but that is an another story). This means that if you are using them as a form objects, you will have to synchronize its state with the database. Even though you “can” use the merge() method of the EntityManager interface, it can be PITA, and a source of interesting features. Thus, I prefer to avoid this if possible.

      2) The domain model should not be designed to make sense as a form object. It should be designed and implemented to make sense in the context of its domain. Also, you have to often make some ORM related compromises. This means that the building forms by using entity classes as form objects can be cumbersome. It is often easier to use DTOs even though it is not so “sexy”.

      3) Often you have to add validation related metadata to the form objects. Adding these annotations to an entity object will object produce messy outcome, since entities are already annotated with JPA related annotations.

      I know that using DTOs as form objects means that I have to write some boilerplate code. However, it helps me to isolate the different layers of my software and to avoid weird features, which are sponsored by the used ORM.

      Reply
      • Hi.

        First of all congratulations for your blog and for the tutorials that you post, they are very interesting and useful! I’ve also read your Spring Data book, and I have found this page that your are the author :) !

        I’ve reached this page searching google for DTO. So my problem is more related to usage of DTO than to the usage of JPA, but if you have few minutes to spare, I would make you my question.

        Most likely you have had to deal with applications where the same domain Entity must be able to be modified by users with different privileges, and depending on the user privilege, only a subset of the fields could be editable.

        I think that it is one of the case where usage of DTOs make sense!

        In my case I have a Job entity that can be modified by different user with different roles, and based on the role only some field can be modified.

        So my question: a good approach could be to define an entity related DTO for each user ROLE? (For example: JobAdminDTO, JobUserDTO, JobGuestDTO).

        So in MVC application controller, given the user role i create the correct DTO and pass it to the view. I think that could be a bit harder to handle the correct type of the object returned from the view..

        In your opinion, could it be a good approach?

        Thanks again and sorry if I’ve bored
        Marco

        Reply
        • Hi Marco,

          That is an interesting question because the requirement which you have to implement is quite common. As always, there are many ways to implement this requirement.

          You found the first one which often comes to mind (use different DTOs for different roles).

          This approach has four problems:

          1. You have to implement different DTOs for different roles. Creating different DTOs is a minor annoyance but the bigger problem is that you have to implement the logic which creates these DTOs.
          2. Each DTO must have a different view.
          3. You have to implement handling logic for each role specific DTO. This leads into a situation where you will have to implement several methods which are pretty much doing the same thing.
          4. When you add a new role to the system, you have to: create a new DTO, create a new view for the created DTO and implement the logic which processes the created DTO. It is a lot of work. On the other hand, if you are sure that new roles are not added very often, this is not a problem.

          The second option is to use the same DTO for all roles and limit the editability of the form fields by using the authorize tag of the Spring Security JSP tag library.

          You can also create a custom HandlerMethodArgumentResolver which makes it possible to add the logged in user as a method parameter to your controller method.

          This approach has two problems:

          1. The logic which handles the form submission must select the updated fields by using the user role of the logged in user. This means that the implementation can be quite complex.
          2. The code of your view can be quite complex because you have to add the authorization logic in it.

          There is also a third option but it might not be usable if you are implementing a “normal” Spring MVC application (no REST API) because it requires that you add several submit buttons to your page. This option is that you are create one form for the fields which are common for all users and one form per each user role.

          As you can see, this problem has no “right” answer. There are several ways to implement this requirement and each one has different pros and cons. However, I hope that was able to give you something to think about.

          Reply
  • Great tutorial, it really helped clear up some confusion I had. I have been playing with this code and i was wondering if you could show how to use Jersey REST instead of Spring MVC? I have not been able to replace the Servlet with the Jersey SpringServlet because of the need to load the context programatically (which I love how you did).

    I tried this in the DataJPAExampleInitializer but of course it failed:
    rootContext.addApplicationListener(new org.springframework.web.context.request.RequestContextListener());
    rootContext.addApplicationListener(new org.springframework.web.util.Log4jConfigListener());
    SpringServlet springServlet = new com.sun.jersey.spi.spring.container.servlet.SpringServlet();
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, springServlet);

    Any ides on how this might work?

    Reply
    • David,

      Thanks for your comments. It is good to hear that this tutorial was useful to you. Regarding to your problem:

      The attached source code does not set an url mapping for the springServlet. What kind of exception are you getting? Is it related to the missing url mapping?

      Reply
      • Petri,

        I was trying to use the Jersey Spring Servlet instead of the DispatchServlet. But two things convinced me to change my direction and stick with SpringMVC:

        1) Version 3.1.1 added much better REST support, which previous attempts were so kludgy I went with Jersey.
        2) While looking at the Jersey site for a solution, I see that they will be releasing 2.0 that will not be backwards compatible, and I really don’t feel like rewriting my work for that in the near future.

        Thank you again for a great tutorial, and I look forward to learning how SpringMVC and JPA work together now.

        Reply
        • Hi David,

          I am happy to hear that you found an answer to your problem. Also, I agree that the REST support of Spring Framework is rather good at the moment.

          Please remember that you can use JPA with Spring Framework without using Spring Data JPA but that does not really make any sense if you can build your applications from scratch.

          On the other hand, if you are working with existing applications, you might not want to replace existing persistence layer with Spring Data JPA repositories.

          Reply
  • Hi Petri,

    Great articles on spring data jpa. One thing I noticed was the update method on the serviceImpl is not actually updating. I tested the code and the updates don’t seem to get persisted. Am I making a mistake or is it really missing? Let me know. I am a bit confused because after so many views, none have pointed that one out.

    -Ramesh

    Reply
    • Hi Ramesh,

      Thanks for your feedback. Did you experience this issue when running my example application? The reason why I am asking this is that I just tested the example application (https://github.com/pkainulainen/Examples/tree/master/Spring/data-jpa/tutorial-part-two) and found out that updating the information of a person works on my computer (Yeah, epic excude). Anyway, if you are running this example application application and the update method does not work, could you let me know. Also, if you have made any changes to the code, could you paste them to Pastebin so that I can help you out.

      If you are trying to apply the principles mentioned in this blog entry in another application, ensure that when the update method is called, you are inside a read-write transaction. The save() method of the repository is not called in my example because all changes made to persistent objects are flushed back to the database when a read-write transaction is committed.

      Reply
      • Thanks for the reply Petri. I was not exactly trying out your example, but had followed your example in a sample project of mine. I’ve extracted the relevant pieces and loaded it into paste bin at http://pastebin.com/SMR9fbWV. I have the disable method as a part of the transaction. Please take a look and let me know. In the meantime, I will also test our your application as it is.

        Reply
        • Hi Ramesh,

          The codes you pasted in Pastebin seems fine to me. It would be helpful if you could answer to following questions:

          - Are you using Hibernate or some other persistence provider? Which version do you use?
          - Which version of the Spring Data JPA are you using?
          - Which transaction manager are you using?
          - Which database you are using?

          This would help me to replicate your environment which helps me to find the reason of your problem.

          Reply
          • Hi Petri,

            - Are you using Hibernate or some other persistence provider? Which version do you use?
            I am using hibernate 3.5.6
            - Which version of the Spring Data JPA are you using?
            1.0.3
            - Which transaction manager are you using?
            Spring’s transaction manager
            - Which database you are using?
            HSQLDB

            I have the relevant parts of the POM in paste bin here http://pastebin.com/igSc1MK9

          • Hi Ramesh,

            I tried changing the dependency versions of my example application to match yours, and updating the information of a person is working without calling the save() method of the PersonRepository. When you said that you are using Spring’s transaction manager, were you referring to the JpaTransactionManager (I use it in my example application)?

          • Hi Petri,

            I was not able to reply to your last comment. So doing it here. First, thank you for your patience and persistence in trying to find the cause. It rare to find people like that. In my case, I pretty much use the same configuration as yours, but I use XML instead of java for configuration. Relevant parts of my configuration are at http://pastebin.com/ix2v6hmY. I have not yet tried your exact application. I will do so tonight and update you.

            Thanks,
            Ramesh

          • Hi Ramesh,

            It is always nice to do some detective work and solve interesting problems. :)

            I looked at the configuration, which you added at Pastebin, and it looked fine to me. However, have you enabled the annotation driven transaction management in your application context configuration file? If you are using XML, you can do this by adding the following line to your application context configuration (or by adding the @EnableTransactionManagement annotation to your application context configuration class):

            <tx:annotation-driven transaction-manager="transactionManager"/>

            More information about this is found at the reference documentation of Spring Framework 3.1.x:

            http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#transaction-declarative-annotations

  • Hi Petri,

    very nice tutorial, learning new things, very helpful.

    can you just show how to block crud operations.
    I created one entity and repository using spring-data-Jpa extending CrudRepository. But I dont want to allow CRUD operations, I need to block them. For in case if I want to delete any entry in database throu service I need to get an error code. Is there any way to block crud operations? Thanks

    Reply
    • Hi Applebee,

      I would use Spring Security to deny access to unwanted operations. Check out the homepage of the Spring Security project: http://static.springsource.org/spring-security/site/.

      Reply
      • can you show with an example how to use Spring Security to deny access?

        Reply
        • Hi Applebee,

          The exact process is too long to be described in a comment but there are several Spring Security tutorials available on the internet. Here are few of them:

          Reply
          • Hi Petri,

            Thanks for your reply. I have one more question, from the above Person example

            when I created the PersonRepository I added one method findByFirstName which I am able to get the results. Here I don’t want to add findBy for other attributes.

            So when I was trying to search with other attibutes it is giving 500 Internal Server Error. Is there any way to customize that kind of exceptions.

            Thank you.

          • Hi Applebee,

            If you are talking about the exceptions that are thrown by Spring Data JPA or Spring Framework, it is not possible to customize them without changing the source code of the framework in question.

            However, it is possible to configure an exception handler that specifies the view that is rendered when a specific exception is thrown. More information about this is found from the reference manual of Spring Framework:

            http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-exceptionhandlers

            Also, I would probably use the approaches described in later parts of my Spring Data JPA tutorial for implementing the search function you mentioned. Using the query generation from method name strategy for this purpose is not very user friendly because is not possible to implement a case insensitive search with it.

  • Hi Petri,

    I have a database view “Example”

    Example
    id name
    ——————–
    100 HELLO
    100 HELLO WORLD
    200 TEST
    200 TEST123
    300 APPLE

    Created entity and repository for Example using JPA Annotations
    Entity: Example.java and the repository class ExampleRepository extends CrudRepository

    HTTP GET to the application:

    localhost:8080/data

    {
    “_links” : [ {
    "rel" : "data",
    "href" : "http://localhost:8080/data/data"
    } ]
    }

    localhost:8080/data/data

    {
    “_links” : [ {
    "rel" : "data.Example.100",
    "href" : "http://localhost:8080/data/data/100"
    }, {
    "rel" : "data.Example.100",
    "href" : "http://localhost:8080/data/data/100"
    }, {
    "rel" : "data.Example.200",
    "href" : "http://localhost:8080/data/data/200"
    }, {
    "rel" : "data.Example.200",
    "href" : "http://localhost:8080/data/data/200"
    }, {
    "rel" : "data.Example.300",
    "href" : "http://localhost:8080/data/data/300"
    }, {
    "rel" : "data.search",
    "href" : "http://localhost:8080/data/data/search"
    } ]
    }

    Is there any way I can search using multiple parameters like
    localhost:8080/data/data/search/id?id=(100,200)

    or using IN operator

    Thanks

    Reply
    • Hi Applebee,

      One comment about your web layer:

      I would consider using POST and sending the search conditions as JSON in the request body. This makes a lot more sense than your current approach since it seems that you want to send 0..* ids to your controller method.

      About the query creation:

      I would use Querydsl or the JPA Criteria API to build the actual query. If you have no experience from these techniques, you might want to check out these blog entries:

      However, the creation of a query that uses the IN operator is not described in those entries. I managed to find one article that has an example of the usage of IN operator and the JPA Criteria API: Dynamic, typesafe queries with JPA 2.0.

      Reply
  • Hi Petri,

    Your tutorial is honestly the best source of information about Spring Data right now, you are also very good at explaining everything.

    Unfortunately, I recently encountered a problem and didn’t really figured out any easy way to deal with it.

    Let’s say you want to add the following Column to Person.java
    @Column(name = “Alias”, unique = true)
    private String alias;

    How would you ensure the Uniqueness of this alias. So far, adding a custom validator that check for unicity using a query at the DTO level doesn’t really solve the problem as any concurrent transaction could modify data after a manual check but before the commit of the ongoing transaction. And secondly, as I’m not using @Validator on the Entity itself but on the DTO, there’s isn’t any straightforward way to get the errors and feed it back to my view.

    Any idea on how to solve this problem?

    Thank you

    Reply
    • Hi Marc,

      It is good to hear that you like my tutorial. About your problem:

      This is indeed a tricky one since you cannot really know whether a unique constraint is broken until you save the entity to the database (I am assuming that you have got unique constraint for the Alias column at database). There are some useful pointers at stackoverflow:

      It seems that there is no elegant and portable way to handle this. However, we can do something about it. I would try to minimize the chance that the unique constraint is broken by following these steps:

      1. Implement a controller method that processes Ajax requests and finds out if a certain alias is free. This controller method would be used to do some client side validation (or to provide a check availability function).
      2. When a new person is added, I would check the availability of the alias at the controller method that processes the request. This way I can add an error to the BindingResult object if the alias is already in use.
      3. As you pointed out, this does not solve a situation where a concurrent transaction modifies the data after the alias has been checked manually but before the ongoing transaction is committed. The third step would be to take of this problem. I would probably catch the exception that is thrown when the unique constraint is broken and add an error to the BindingResult object. However, finding out the cause of the exception can be ugly as explained in the links that I pasted before.

      What do you think about this solution?

      Reply
  • Petri,

    Thanks for the wonderful tutorials!

    It is not rare for real-world application to involve a couple of hundred database tables. Normally we would use code-generation tools such as Jboss Tools to reverse-engineer an existing database and automatically generate entity classes and JPA annotations. The Person class in your tutorial is highly customized. How do you generate that kind of customized code if you have to deal with a couple of hundred tables?

    Reply
    • Hi Don,

      It was nice to hear to that you like my tutorials. Also, I want to thank for an excellent question.

      Unfortunately, as far as I know, there is no way generate “customized” domain model classes automatically. As you said, one can use code generators to generate entities from an existing database but typically this leads in to a anemic domain model. For a quite long time I was writing applications that used this approach and I was perfectly happy with it.

      However, then I read a book called Domain Driven Design and saw the light. The problem with my old approach was that I kind of got all the problems caused by object-relational mismatch and got none of the benefits. All my business logic was scattered around the service layer, which made my service classes look like a mess. Now, when I moved the business logic from the service layer to the domain model, I got the following benefits:

      • The service layer is clean and it is responsible of application logic.
      • All business logic is put into a single place: to the domain model. This way I always know where I can find it. I don’t have to search it from a messy service layer anymore.
      • Structuring the code this way makes it easier to write GOOD unit tests for it.

      Because of these benefits I am ready accept that I will spend a lot of time working with my domain model. Also, since I have been mostly participated in software development projects that uses Agile methods, the implementation and design of the application is divided in to sprints so I never have to face the horrible task of fixing the whole domain model at once (As you stated, it would be a huge task since the databases of real world applications tend to have a lot of tables).

      Reply
  • Why is it so difficult to write package statements in the code?
    some libraries is not in the initial pom file e.g. apache lang commons

    Reply
    • Hi Mladen,

      I left the import statements out because I felt that including them would make this blog entry too long. Also, since I have included a fully functional example application, I thought that adding them would add little value. It seems that I might have rethink my attitude and add import statements (I will leave the obvious ones out though) to the code samples that are attached to my blog entries. This might take some time so be patient. :)

      Regarding to your second point, the pom file of my example application declares all the required dependencies (including commons lang).

      Reply
  • Hi Petri,

    Great tutorial!! Excellent Job!! I’m having some trouble running the tutorial on Tomcat could you guide me on how to migrate it from jetty to tomcat? I tried removing the webdefault.xml and writting an new web.xml but it isn’t working the Spring context is not beeing loaded.

    Thanks in advance

    Mildo

    Reply
    • Hi Mildo,

      Thanks for your comment. It is nice to know that you like this tutorial.

      Are you trying to deploy the created war file directly to Tomcat or are you using the Tomcat Maven plugin? The webdefault.xml file is required only because the sample project is using an old version of the Jetty Maven plugin. I should probably update this plugin and remove the unnecessary files from the sample project.

      Update: Check this comment out if you are using Tomcat 6.

      Reply
  • Hi Petri

    Thanks for the wonderful article but cannot deploy the example on tomcat
    Can you please send me a web.xml for tomcat asap

    Regards
    Vipul

    Reply
    • Hi Vipul,

      Thanks for your comment!

      This example requires that a Servlet 3.0 compliant servlet container is used and it should work fine with Tomcat 7. If you are using an older version of Tomcat, you cannot configure your web application by using programmatic configuration. In other words, you have to delete the DataJPAExampleInitializer class and create a web.xml file. This process is explained in the following article:

      Bootstrapping a web application with Spring 3.1 and Java based Configuration, part 1

      Also, let me know if you are using Tomcat 7 and cannot deploy the example application.

      Reply
  • Petri,

    Perhaps I’m missing the advantage of using the builder pattern because of the simplicity of its use in the Person class, but it doesn’t seem like it is buying you anything more than a straight constructor or a static method would. Instead by using it you have to construct an extra object and make an extra call.

    What am I missing?

    Reply
    • Hi Josh,

      you are right. In this example the builder pattern is definitely an overkill and it would be better to use a regular constructor. However, I used it on this example because wanted to emphasize that it is a good way to create new objects (especially when the created object has a lot of optional parameters). The alternatives of the builder pattern are:

      • The first option is to use the telescoping constructor pattern to create objects that have multiple optional parameters. This means that you up writing many constructors (the actual amount depends from the number of optional parameters). This has two disadvantages: it is hard to create objects (especially if the parameters have the same type), and the code becomes really messy and hard to read. However, this approach is one advantage: it ensures that your code is thread safe.
      • The second option is to use so called Javabeans style construction. The problem with this approach is that even though the resulting code is quite easy to read, the created object is in inconsistent state during its creation and it prevents you from making your class immutable. Also, you have to manually ensure that your code is thread safe.

      The builder pattern combines the safety of the telescoping constructor pattern and the readability of the Javabeans style construction. That is why it should be used on model objects unless you have a REALLY good reason not to use it.

      Reply
      • So, perhaps the issue I’m having in seeing the applicability is that all of the main fields in the Person object are required. How does this pattern take care of the telescoping constructor pattern for optional parameters? Say you add height, weight, and hairColor to Person. Do you just end up with telescoping parameters in your builder object? Or do you construct the object with the builder and then resume using the setters for the rest?

        When I searched for the pattern online the applicability seemed to center on complex construction tasks, like in the cases where object creation involves the coordination of several other objects or involves some tricky sequencing.

        Thanks

        Reply
        • Hi Josh,

          Optional properties are dealt with by creating so called property methods that are used to set the optional parameters. Here is the source code of the Person class that has the optional parameters you suggested:

          public class Person {
             
              private String firstName;
              private Color hairColor;
              private int height;
              private String lastName;
              private int weight;
              
              //This sucks but it is required by Hibernate
              public Person() {
              }
          
              //Getters and other methods. No Setters
          
              public static Builder getBuilder(String firstName, String lastName) {
                  return new Builder(firstName, lastName);
              }
          
              public static class Builder {
                  Person built;
          
                  Builder(String firstName, String lastName) {
                      built = new Person();
                      built.firstName = firstName;
                      built.lastName = lastName;
                  }
          
                  public Builder hairColor(Color hairColor) {
                      built.hairColor = hairColor;
                      return this;
                  }
          
                  public Builder height(int height) {
                      built.heigth = height;
                      return this;
                  }
          
                  public Builder weight(int weight) {
                      built.weight = weight;
                      return this;
                  }
          
                  public Person build() {
                      return built;
                  }
              }
          }
          


          Here are some examples that illustrate the usage of these property methods:

          //Only mandatory properties are set
          Person onlyMandatory = Person.getBuilder("John", "Smith").build();
          
          //Sets first name, last name and hair color
          Person blonde = Person.getBuilder("Jane", "Smith").hairColor(Color.YELLOW).build();
          
          //Creates new person and sets the values of all properties
          Person person = Person.getBuilder("John", "Smith")
          		.hairColor(Color.BROWN)
          		.height(100)
          		.weight(100)
          		.build();
          


          I hope that this example answered to your question.

          Reply
          • Thanks, yes that helps. So from your latest example I can see where you could put some integrity checks in the build() method allowing you to ensure that the optional attributes are set consistently with each other before giving access to the Person object. However, I can also see where you would need to be careful with this pattern as your objects could easily become immutable or very difficult to update without client classes also maintaining a reference to the builder that created the object in the first place.

          • what is difference bettween setId(String id) and id(String id)
            is the second method so helpfull ?

          • You should take a look at the blog post titled: The builder pattern in practice. It provides a very nice explanation of the builder pattern and describes its benefits as well.

  • Hi,

    First of all a big thank you – this is the tutorial I have been looking for, great job!

    I do have one issue. I guess it is a configuration issue (or a stupid typo I did as it works for everyone else). I created my own application using yours as a template. I use tomcat 7, I start it from Eclipse (Juno).

    Server starts without issues at http://localhost:8080/myapp/ and shows me the list of records I put in the database.

    As soon as I click any of the links, my url becomes:
    http://localhost:8080/person/edit/2

    … which does not exist (is your app designed to run as ROOT.war in Tomcat by any chance?)

    As soon as I change the URL to http://localhost:8080/myapp/person/edit/2, I get to the edit view.

    However, all the links on the edit page change either to
    http://localhost:8080/ (back)
    or
    http://localhost:8080/person/edit (save)

    so needles to say, both save and back do not work.

    To sum it up: How do I change the configuration when using Java configuration in Spring so that I can deploy your application just like I did?

    Thank you,
    Jan

    Reply
    • Hi Jan,

      Good to hear that you liked this tutorial.

      I have to confess that I was a bit lazy when I created the user interface of the example application. Like you suspected, the links are working correctly only if the context path of the application is ‘/’.

      Luckily, this problem should be pretty easy to fix: You can use the url tag to construct an url that contains the context path. Check out this StackOverflow question for more details about this: how to use <spring:url /> with an <a> tag?

      Reply
      • Hi Petri,

        Thank you for your quick answer. I will try the solution first thing in the morning tomorrow. I got a bit rusty on the subject of creating a new project from the scratch … and in the meantime the world has changed ;-).

        Oh I would not dare to call you lazy after all the tutorial parts you published and after answering all the questions on your page!

        If you ever come to Holland, I owe you a beer ;)

        Regards,
        Jan

        Reply
        • Jan,

          I have to come to visit Holland then!

          About the fix, let me know if it did the trick. I know at least one other way to fix this but that fix is kind of ugly. That is why I did not suggest it as the first option.

          Reply
  • Excellent article. It got me interested in your book. I can’t import part five, six and eight of the source code as there’s an error when setting up maven plugin connectors in Eclipse Juno ( SpringSource Tool Suite 3.1): “No marketplace entries found to handle /pom.xml in Eclipse.”

    I installed m2e-apt from Jboss. This is not enough? Anyone know?

    Reply
  • I had to replace the bean definition in applicationContext.xml:

    and update Spring Data Jpa to 1.2 in the pom in order to avoid the error “sch.props.correct.2: A schema cannot contain two global components of the same name” in Springsource Tool Suite.

    “Spring Data- JPA Schema validation error in STS” https://jira.springsource.org/browse/DATAJPA-160

    Reply
    • MiB,

      Good to hear that you were able to solve your problem. Also, if you want to get rid of the XML configuration file which is used to configure Spring Data JPA, you can simply add the @EnableJpaRepositories annotation (supported in Spring Data JPA 1.2) to your application context configuration class and delete the XML configuration file.

      Reply
  • Well, I also had to set m2e to ignore execution of the maven-apt-plugin.
    I got this classic before that:
    “Plugin execution not covered by lifecycle configuration: com.mysema.maven:maven-apt-plugin:1.0.2:process (execution: default, phase: generate-sources)”

    Then run that generate-sources phase, set source folder, then clean build. For some reason in some cases — Part five I think — I had to run the tests as junit tests and not maven tests in order for them to run green.

    Reply
    • Unfortunately the Maven APT plugin does not work very well with Eclipse. However, at least one of my readers has managed to configure it. See the comment written by Eric B for more details.

      Reply
  • Thanks!

    Reply
    • You are welcome.

      Reply
  • Thank you very much for your tutorials!

    I’m currently digging into Spring Data, Hibernate and JPA. The goal is to build a simple application that involves Wicket for web logic and Spring Data for easy persistence support. I’m struggling a bit with configure Spring Data outside of a Spring MVC context: What configuration files are relevant and where to put them? For example you named you applicationContext-persistence.xml instead of just applicationContext.xml. Does this have impact on how the file is handled? Do you have examples for how to use Spring Data outside of a Spring MVC application? Do I have to understand the whole Spring framework at the end or is it possible to use just a potion of the framework without getting to much invovled with the others?

    Furthermore, I learn a lot about application infrastructure and patterns just by reading your comments. Thank you for sharing your expertise!

    Reply
    • The example application configures the Spring application context by using a combination of Java and XML configuration. This approach is described in the first part of my Spring Data JPA tutorial.

      I have also written a comment to that blog entry which describes how you can configure Spring Data JPA, Hibernate and Spring transaction management by using XML configuration.

      I guess the question is: Do you want to configure your application context by using Java configuration or XML configuration files?

      About Wicket and Spring Data:

      Unfortunately, all my Spring Data examples use Spring MVC. However, I have used Spring with Wicket (1.4.x) in the past and I think that I can give you some pointers which should help you to get started:

      I hope that this answered to your question. If you have any other questions, feel free to ask them!

      Reply
  • Hi Petri,
    Your example is very good for beginners to start with as an console based application. Can u give me simple example of Spring Data JPA with MVC integration using MySql and Maven.
    If u can help me out in this , it would be great help for me

    Thankxxxx

    Reply
    • Hi Ankit,

      You can enable the MySQL support of the example application by following these steps:

      1. Remove the H2 database dependency from the pom.xml file.
      2. Uncomment the MySQL connector dependency declaration found from the pom.xml file.
      3. Open the application.properties file and set the used JDBC driver, database url and Hibernate dialect. This file contains valid MySQL configuration which is commented out by default. In other words, all you have to do is to remove the H2 configuration and enable the MySQL configuration.

      I hope that this answered to your question.

      Reply
  • Hi Petri, great tutorial to begin the journey of Spring Data JPA :D
    i see your code in the Github and there’s no Unit Test for Repository class
    my assumption is because it is part of the framework, so we just can trust the author lol
    if we want to test how can we do it, i didn’t see you write the implementation of the Repository interface

    thanks,

    Reply
    • wupss i meant Integration Test

      Reply
      • I answered your original comment before I saw this comment. :)

        Anyway, check out my answer to your original comment. It has an link to an example application which has integration tests for its repository interface.

        Reply
    • Hi Agung,

      Thank you for your comment.

      The reason why there is no unit test for the repository interface is that when you are using Spring Data JPA, you don’t have to implement your repository interfaces. Spring Data JPA is capable of providing an implementation for them as long as your repository interfaces extends one of the “special” interfaces of Spring Data. The base interface of these “special” interfaces is the Repository interface.

      You can however write integration tests to your repository interfaces. I have been planning to write a blog post about for some time now. Perhaps I should do it in the near future?

      In the meanwhile, you can check out the example application of my blog post which describes how you can use Querydsl in a multi-module Maven project. This application has integration tests for the repository interface.

      Update: I took look at the project and it seems that I wrote integration tests for the service implementation. You can, however, use the same technique when you are writing integration tests for your repositories. It seems that I should probably write a blog post about this soon.

      I hope that this answered to your question.

      Reply
  • HI ,
    great work there , i’m new to webapps i was wondering how can i deploy this application on jboss 7.1.0 as

    Reply
  • Hello Petri, you are really a great writter. Like every one else, I have seen a lot of tutorial websites, however, you are the only person who literally replies to every single comment. I greatly admire your spirit. Wish you have even greater success on your future career.

    Reply
    • Hi Bowen,

      Thank you for your kind words. I really appreciate them.

      Yes, I like to reply to every comment I get (especially if there is a question) because I feel that it makes no point to give a reader the possibility to comment your blog posts unless you are willing to communicate with them.

      I think that the comments I get are valuable in two ways:

      1. They might reveal a problem in my blog post. These comments are extremely valuable because I can avoid making the same mistake in the future. Also, I get a chance to fix the original blog post.
      2. They force me to look the solved problem from a different perspective. Again, this is a good thing because usually I learn something new during the process.

      I wish you all the best in your future career as well!

      Reply
  • Hi Petri, I’ve followed this tutorial (thanks a lot) and everything worked perfectly until I added a one-to-many relationship. I’m encountering an EntityNotFoundException and just can’t figure it out. I’ve tried so many different methods, but still stuck. Posted a question on stackoverflow if you have time to check it out. Thanks. http://stackoverflow.com/questions/18237689/hibernate-4-2-onetomany-entitynotfoundexception/

    Reply
    • It seems that you found the answer to your question while I was sleeping (based on the StackOverflow question). Am I correct?

      Reply
  • Petri, it appeared to be working but ran into an issue after I added subsequent records. The primary key on the keywords table is text in my solution, but I wanted it to be the docid. Didn’t realize that until I had duplicate keywords in other documents. Any ideas?

    Reply
    • So your problem is that you cannot add new documents because the same keyword appears in more than one document?

      You have to add a new field to the Keyword class and use that field as the id of the entity. You cannot use the docid column as the private key because this means that you could add only one keyword per document (private key has to be unique).

      Reply
      • That’s right, each `Document` could have similar keywords. Last night I experimented with a `kywd_id` on the `Keyword` class, but then the keywords were duplicated on updates. `kywd_id` was auto-incrementing.

        Say `Document` has keywords: one, two, three. And the `docid` is `abcd`.

        Then the table rows looked like,

        1, one, abcd
        2, two, abcd
        3, three, abcd

        If I added a new keyword to `abcd`, then the table looked like,

        1, one, abcd
        2, two, abcd
        3, three, abcd
        4, one, abcd
        5, two, abcd
        6, three, abcd
        7, four, abcd

        I’m expecting,

        1, one, abcd
        2, two, abcd
        3, three, abcd
        4, four, abcd

        If I added a new document `efgh` and it has the same keywords, I’d expect the table to have,

        1, one, abcd
        2, two, abcd
        3, three, abcd
        4, four, abcd
        5, one, efgh
        6, two, efgh
        7, three, efgh
        8, four, efgh

        I can’t figure out the primary keys or constraints for this scenario. I was thinking the keywords table could have a unique constraint on `docid` and `text` and both be primary keys.

        Reply
        • Something I just realized might not be handled automatically is if we remove keywords from a document.

          Reply
        • I assume that you are not loading the document (and its keywords) from the database when you are updating it?

          Because the Keyword objects of your document are transient, new rows are added to the database.

          You don’t get duplicate documents because the your Document has a docid (I assume that you read it from the XML file). The repository implementation notices this and calls the merge() method of the EntityManager class instead of the persist() method.

          I recommend that you you follow this approach (inside a read-write transaction):

          1. Load Document object from the database.
          2. If no document is found, save a new object.
          3. If a document is found, update this object instead of saving the object which you created from the XML file.
          Reply
  • That sounds like a nice approach. One question before I get into that. On `Document` I have, @JoinColumn(name = “docid_fk”). Is there any way to make `docid_fk` and `text` both primary keys on `kywd_t` since `docid_fk` isn’t directly defined on `Keyword`?

    Reply
  • I’d rather not make it unnecessarily complex if possible. Seems many people agree with you too. Right now I’m tinkering with a @JoinTable but it has some issues as well.

    In `Document`,

    @OneToMany(cascade = CascadeType.ALL)
    @JoinTable(
    name = “mtdt_kywd_t”,
    joinColumns = {
    @JoinColumn(name=”docid”, referencedColumnName=”docid”, unique = true)
    },
    inverseJoinColumns = {
    @JoinColumn(name=”text”, referencedColumnName=”text”)
    }
    )
    @XmlPath(“head/meta/kb:keywords/kb:keyword”)
    private Set keywords;

    And in `Keyword`,

    @OneToOne(cascade = CascadeType.ALL)
    @JoinTable(
    name = “mtdt_kywd_t”,
    joinColumns = {
    @JoinColumn(name=”text”, referencedColumnName=”text”, unique = true)
    },inverseJoinColumns = {
    @JoinColumn(name=”docid”, referencedColumnName=”docid”)
    }
    )
    private Document document;

    I don’t want to take anymore of your time, you’ve been most helpful. If/When I discover a solution I’ll report back. Thanks Petri.

    Reply
  • Petri, been working on this for quite a while with a coworker and he figured it out yesterday afternoon. Here’s what we came up with.

    On `Document` we have,

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
    @OrderColumn
    @JoinColumn(name = “docid”)
    @XmlPath(“head/meta/kb:keywords/kb:keyword”)
    private Set keywords;

    On `Keyword` we have an auto-generated id now,

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @XmlTransient
    private Long id;

    and,

    @ManyToOne
    @JoinColumn(name = “docid”, insertable = false, updatable = false)
    @XmlTransient
    private Document document;

    Thanks again for the help.

    Reply
    • You are welcome! Also, it is great to hear that you could solve your problem.

      Reply
  • Hello Petri,

    First of all I want to thank you for your excellent work here.. you are simply great. you explained things very simply…. I worked in Spring , Hibernate projects in 2006 / 2007 after that I had to work in a middleware Microsoft Biztalk sever. But recently I started looking my old old skills and happened to find your articles.
    I have some Questions to you. :-)

    Do we have any tools that support following sequence of development?
    1. Develop Database tables and relationships first using any tool.
    2. Then based on those tables auto generate Java entity classes and Service for CRUD operations
    3. Then Auto Generate the Skeleton for the controller classes.
    4. Then Auto generate Model/View for those CRUD operations.
    5. Then Build and Deploy.

    My aim is to generate an initial working web application skeleton with minimal or zero lines of java code manually. Later we can change and customize the auto generated code.

    Is this Possible Using Eclipse latest version? If so would it be possible to post the minimal sequence of steps that need to perform to make a working skeleton of REST full java web app. I

    Any help would be greatly appreciated.

    Regards
    Vikas

    Reply
    • You are welcome! I am happy to hear that I could help you get started again.

      You might want to check out the following projects:

      These are a bit different projects but they have the same goal: help you to get started as soon as possible.

      Based on your questions, Spring Roo might be what you are looking for. I haven’t personally tried it out, but the reference manual of Spring Roo looks quite promising.

      Also, I think that Hibernate Tools can create domain model classes from an existing database.

      Reply
  • Once again Thank you Petri .. I will explore these and see how fast we can develop
    Vikas

    Reply
  • Petri, I followed your steps in this post to set up my repository. But when I try to test it against real database, updated data wasn’t actually reflected in database unless I call save. Any idea what could be the problem?

    Reply
    • Hi Katie,

      One possible reason is that your code is not executed inside a read-write transaction. Have you annotated your service method with the @Transactional annotation?

      The changes made to persistent objects should be updated back to the database as long as changes are made inside a read-write transaction. That is why you don’t have to call the save() method when you are updating information inside a read-write transaction.

      Also, you might find want to read my blog post which talks about the integration testing of Spring Data JPA repositories.

      If this didn’t solve your problem, please let me know. :)

      Reply
  • Petri,
    I use your tutorial and it’s very helpful but in my application I have to use postgresql and I don’t know how to configure it. When I uncomment in your application parts about postgres (in pom and application.properties) it doesn’t work. I start app, got info:
    ‘DEBUG – LogicalConnectionImpl – Obtaining JDBC connection’
    and nothing happens. Could you tell me what should I change to fix it?
    Thanks,
    Alicja

    Reply
    • If you want to use PostgreSQL, you have to make following changes to the example application:

      1. Remove the H2 database driver dependency from the pom.xml file.
      2. Uncomment the PostgreSQL driver dependency found from the pom.xml file.
      3. Change the configuration found from the application.properties file.

      If you want to use PostgreSQL, the database and Hibernate configuration found from the src/main/resources/application.properties file looks as follows:

      
      #Database Configuration
      db.driver=db.driver=org.postgresql.Driver
      db.url=jdbc:postgresql://localhost/datajpa
      db.username=username
      db.password=password
      
      #Hibernate Configuration
      hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
      hibernate.format_sql=true
      hibernate.hbm2ddl.auto=create-drop
      hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
      hibernate.show_sql=true
      
      

      I hope that this answered to your question.

      Reply
  • Great blog and tutorials! How do you handle entities that have a lot of properties (5 or more)? The update method’s parameter list gets too large in these cases and it seems having setters would be a bit cleaner.

    Reply
    • Thank your for your kind words. I really appreciate them.

      You are absolutely right. If entities have a lot of properties, having a single update method is not practical. Typically I separate the properties into value objects (e.g. Address and so on) and create a separate update method per value object.

      On other hand, if the properties are entities, I try to follow a pattern called aggregate. At the moment it seems to make perfect sense to me but I might change my mind after a few years or so (this happens).

      I hope that you find this answer useful.

      Reply
  • @Petri … Awesome Job … As Expected… ;-)

    FYI … Running a modified version of this on Glassfish required me to implement Serializable on the DTO or I was getting Invalid Attribute errors …. FWIW …

    Great Job Chief!!!

    Reply
    • Thank you for you kind words. I really appreciate them.

      Also, thanks for leaving a note regarding the Glassfish & Serializable problem. Maybe It will be useful to someone.

      Reply
  • Hi Petri
    I have three entities like below

    1. CompanyInfo

    
    @Entity
    public class CompanyInfo {
    	@Id
    	@GeneratedValue
    	private long companyId;
    	private String companyName;
    
    	@OneToMany(mappedBy = "companyInfo")
    	private Collection userInfos = new ArrayList();
    }
    
    

    2. UserInfo

    
    @Entity
    public class UserInfo {
    	@Id
    	@GeneratedValue
    	private long userId;
    	private String userName;
    
    	@ManyToOne
    	@JoinColumn(name = "COMPANY_ID")
    	private CompanyInfo companyInfo;        
    
    	@ManyToMany
    	@JoinTable(name = "USER_ROLES", 
    			joinColumns = @JoinColumn(name = "USER_ID"), 
    			inverseJoinColumns = @JoinColumn(name = "ROLE_ID")
    	)
    	private Collection roles = new ArrayList();
    }
    
    

    3. Roles

    
    @Entity
    public class Roles {
    	@Id
    	@GeneratedValue
    	private long roleId;
    
    	private String roleName;
            
    	@ManyToMany(mappedBy = "roles")
    	private UserInfo userInfo;
    	
    	private List userInfos = new ArrayList();
    }
    
    

    and created the repositories for the above three entities now I want to query using hibernate relations like

    In CompanyInfoRepository

    1. I have userId and I want get the user companyInfo. we can get using two ways, one is from UserInfoRepository table which is straight forward and the other is from companyInfo table. Now the problem is I tried to query from CompanyInfoRepository but didn’t succeeded.

    
    @query("select c from CompanyInfo c where :userId IN c.userInfo.id ")
    List findByUserId(@param("userId") long userId);
    
    

    I kept :userID for the argument and I used “IN” because in companyInfo UserInfos is a list

    In UserInfoRepository

    similary I have roleId and I want query it from UserInfoRepository(relation between UserInfo and Roles is ManyToMany) and here also I am getting error , I have userId and want to query from Roles table

    Reply
    • Hi Varun,

      Have you tried using inner join instead of the IN expression? Here is an example JPQL query which uses inner join (you can use the same approach for getting the users which have a specific role):

      
      @query("SELECT DISTINCT c from CompanyInfo c INNER JOIN c.userInfos u where u.id=:userId")
      List findByUserId(@param("userId") long userId);
      
      
      Reply
  • Hi Petri,

    First of all, thanks a lot for such a nice tutorial. I am learning JPA and your tutorials are really helpful. As a matter of study, I have tried creating a maven project using the example you have given above through eclipse and then added JPA and JSF facets to the project. The necessary jar files are in place. My problem is whenever I call inbuilt methods findOne(), findAll(), save() etc of the JPARepository, It throws Null Pointer Exception. I am stuck up at this point.

    I have uploaded my project files on dropbox public folder and sharing the same here. Kindly help me on this.

    Entity:- Person.java
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/Person.java

    Repository:- PersonRepository.java (This extends JPARepository)
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/PersonRepository.java

    Service:- PersonService.java
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/PersonService.java

    Service Implementation:- RepositoryPersonService.java
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/RepositoryPersonService.java

    Transfer Object:- PersonDTO.java
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/PersonDTO.java

    UI:- PersonController.java
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/PersonController.java

    Webpage:- index.xhtml
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/index.xhtml

    Also attached pom.xml, persistence.xml, applicationContext.xml, faces-config.xml and web.xml for reference.
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/pom.xml
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/applicationContext.xml
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/faces-config.xml
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/web.xml
    https://dl.dropboxusercontent.com/u/16250517/JPA%20Project/persistence.xml

    Thanks in Advance,
    Nikhil

    Reply
    • Hi Nikhil,

      Thank you for your kind words. I really appreciate them.

      I have never used JSF so I have no idea how you can use Spring beans in an application which uses JSF. However, I did find this blog post which describes how you can integrate JSF and Spring Framework (It seems to use Spring Data JPA as well). Maybe it will help you to solve your problem.

      Reply
      • Hi Petri,

        Thanks for the link. I will go through the same. Meanwhile, I tried to find the mistake from my side and it looks like the repository is not getting initialized. So, it looks like the methods are not throwing NullPointer but the repository is. Is there any way to check whether repository is initialized or not? Please let me know.

        Thanks in Advance,
        Nikhil

        Reply
  • Hi Petri,

    I am totally new to spring mvc. Currently i am working with struts 2, spring and hibernate with Model driven. I see too many classes here to do CRUD operations. The way i use i have one struts layer class and one service layer class and the domain object class(Entity) and the DAO class. I feel like some kind of messy here. Please don’t misunderstand me. I just need to learn the technology with a good design pattern. :)

    Reply
  • I’m trying to run your application with Postgres however it fails with the following stacktrace:

    Caused by:
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactoryBean’ defined in class net.petrikainulaine
    n.spring.datajpa.config.ApplicationContext: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreExc
    eption: Factory method [public org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean net.petrikainulainen.spring.datajpa.config.Applicati
    onContext.entityManagerFactoryBean() throws java.lang.ClassNotFoundException] threw exception; nested exception is java.lang.IllegalStateException: re
    quired key [hibernate.hbm2ddl.auto] not found

    Reply
    • Did you make any changes to the example application? The reason why I am asking this is that the error message suggests that the property hibernate.hbm2ddl.auto was not found.

      This property is found from the application.properties file and the ApplicationContext class sets the Hibernate properties to the LocalContainerEntityManagerFactoryBean.

      If you didn’t change anything, let me know so that I can investigate this issue.

      Also, thank you for asking this question. It helped me to notice that this wasn’t mentioned in the first part of my Spring Data JPA tutorial. I think that I will have to update that blog post next week.

      Reply
  • Hi Petri:

    Your blog is amazing .. honestly. Your examples are very pertinent and useful – thanks!

    I have a question about this example. I’m also going to pull down your github example on this and test out your code with this scenario.

    You use ‘version’ and the annotation, but you don’t set the version in your DTO and you don’t set it in your Builder classes. Why? Doesn’t this mean that version (i.e. optimistic locking) is therefore being ignored?

    In my application, if I use findOne and do not detach I am able to save Entities that ‘violate’ the version property (i.e. second version overwrites first). If I use findOne and then detach and update, I get the update…. OR if I create a brand new Entity and set the ID in (if it existed) and then save I also get the Optimistic Locking Exception.

    So I’m curious why you don’t have a version property in your DTO and how your example would work with optimistic locking otherwise?

    I’ve also read your book and in your chapter on this you do not manage Version there either.

    Thanks!!
    Jim

    Reply
    • Hi Jim,

      Thank you for your kind words. I really appreciate them!

      About your question: The optimistic locking isn’t handled properly in this blog post (or in my book) because handling it isn’t really a Spring Data JPA specific issue. Another reason why I decided to not handle it was that it keeps the code a bit cleaner. Now that I think about this, I should have probably mentioned this in the book. :(

      Like you said, the ideal way to handle this is to put the version field to the DTO and check its value in the service method before updating the information of the entity. If you use this approach, you can decide how you should handle this. You can either overwrite the information or ask user to decide what to do.

      Also, like you suspected, the optimistic locking is ignored if other transactions haven’t changed the data when the current transaction is committed (this is the typical case). If other transactions have modified the data when the current transaction is committed, an OptimisticLockException is thrown and the current transaction is rolled back (this is a rare situation but it can happen).

      Reply
      • Thanks for the confirmation Petri.

        Makes perfect sense to me, it’s funny that most examples use the @Version but I haven’t really seen 1 example that discusses the implications of this if you are going to use a DTO based approach, maybe b/c most examples assume the entity will be surfaced at all tiers.

        Which brings me to another question I wonder if you know the answer to. The key to the above approach working is either detaching the object PRIOR to copying any edits from the DTO class OR creating a new entity (detached) and then setting the primary key id into it .. which essentially is the same result (i.e. the JPA figures out what the row is and updates it accordingly).

        What I don’t understand is WHY the entity needs to be detached for the updates to work? I would have thought the end result was the same, but I’m obviously missing something.

        Any insight appreciated. Thanks again!
        Jim

        Reply
  • Hi Petri,
    An awesome work, thanks for it and am using spring-data-dynamodb and I used annotation based confuguration and for validation is it possible to configure through annotation at present. Am struggling in that phase because am entirely new to spring environment. If its possible please guide me with a good link/sample to go through in it.

    Reply
  • Overall like the article but I think tests should be the first step not the last step. Write a failing test that does what you expect users to do then build the bare minimum you need to pass it, rinse and repeat. It will help stop things such as scope creep and adding in code that is not needed.

    Reply
    • I agree that TDD is very useful design tool but I am not sure if the test first approach works very well in tutorials (unless you are writing a TDD tutorial). However, I think that I might use this approach when I write my testing book.

      Reply

Leave a Comment