Bug in the Spring query code with Hibernate

1

I have a problem, I'm studying spring mvc with hibernate and I ended up getting into a bug where it returns the following exception "java.lang.NullPointerException", it follows the codes:

ContactController

package br.com.agenda.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import br.com.agenda.services.ContactService;

@Controller
@RequestMapping("/contact")
public class ContactController {

    @RequestMapping(method=RequestMethod.GET)
    public ModelAndView listContact() {
        ContactService contactService = new ContactService();
        ModelAndView modelAndView = new ModelAndView("contacts");
        modelAndView.addObject("contacts", contactService.listAll());
        return modelAndView;
    }
}

IContactService

package br.com.agenda.interfaces;

import java.util.List;
import br.com.agenda.models.Contact;

public interface IContactService {

    public void save(Contact contact);

    public Contact searchId(Integer id);

    public List<Contact> listAll();

    public List<Contact> listSpecific(String field, String value);
}

ContactService

package br.com.agenda.services;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import br.com.agenda.daos.ContactDAO;
import br.com.agenda.interfaces.IContactService;
import br.com.agenda.models.Contact;

public class ContactService implements IContactService {

    @Autowired
    private ContactDAO contactDAO = new ContactDAO();

    public void save(Contact contact) {
        contactDAO.save(contact);
    }

    public Contact searchId(Integer id) {
        return contactDAO.search(id);
    }

    public List<Contact> listAll() {
        return contactDAO.listAll();
    }

    public List<Contact> listSpecific(String field, String value) {
        return null;
    }
}

ContactDA

package br.com.agenda.daos;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;

import org.springframework.stereotype.Repository;

import br.com.agenda.models.Contact;

@Repository
public class ContactDAO {

    @PersistenceContext
    private EntityManager manager;

    public void save(Contact contact) {
        try {
            if (contact.getId() != null) {
                manager.persist(contact);
            } else {
                manager.merge(contact);
            }
        } catch(RuntimeException e) {
            System.out.println(e.getMessage());
        } catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public Contact search(Integer id) {
        try {
            return manager.find(Contact.class, id);
        } catch(RuntimeException e) {
            System.out.print(e.getMessage());
            return null;
        } catch(Exception e) {
            System.out.println(e.getMessage());
            return null;
        }
    }

    public List<Contact> listAll() {
        try {
            return manager
                .createQuery("select distinct(c) from tblContacts c join fetch c.phones", Contact.class)
                .getResultList();
        } catch(PersistenceException e) {
            System.out.println(e.getMessage());
            return null;
        }
    }
}

Contact

package br.com.agenda.models;

import java.util.List;

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

import org.hibernate.validator.constraints.NotBlank;

import br.com.agenda.models.Phone;

@Entity
@Table(name="tblContacts")
public class Contact {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="idContacts")
    private Integer id;

    @NotBlank
    @Column(name="nameContacts")
    private String name;

    @NotBlank
    @Column(name="emailContacts")
    private String email;

    @ElementCollection
    private List<Phone> phones;

    public void addPhone(Phone phone) {
        phones.add(phone);
    }

    public List<Phone> getPhones() {
        return phones;
    }

    public void setPhones(List<Phone> phones) {
        this.phones = phones;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Phone

package br.com.agenda.models;

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

import org.hibernate.validator.constraints.NotBlank;

@Entity
@Table(name = "tblPhones")
@Embeddable
public class Phone {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="idPhones")
    private Integer id;

    @NotBlank
    @Column(name="dddPhones")
    private Integer ddd;

    @NotBlank
    @Column(name="numberPhones")
    private Integer number;

    public Integer getDdd() {
        return ddd;
    }

    public void setDdd(Integer ddd) {
        this.ddd = ddd;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }       
}

Stack of Errors

type Exception report

message Request processing failed; nested exception is java.lang.NullPointerException

description The server encountered an internal error that prevented it from fulfilling this request.

exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root cause

java.lang.NullPointerException
    br.com.agenda.daos.ContactDAO.listAll(ContactDAO.java:52)
    br.com.agenda.services.ContactService.listAll(ContactService.java:23)
    br.com.agenda.controllers.ContactController.listContact(ContactController.java:19)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:498)
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
note The full stack trace of the root cause is available in the Apache Tomcat/8.5.11 logs.

- Configuration Files -

AppWebConfiguration

package br.com.agenda.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import br.com.agenda.controllers.IndexController;
import br.com.agenda.daos.ContactDAO;

@EnableWebMvc
@Configuration
@ComponentScan(basePackageClasses={IndexController.class, ContactDAO.class})
public class AppWebConfiguration extends WebMvcConfigurerAdapter {
    //Configurado pasta raiz das viewers e o suffix .jsp para as mesmas que serão carregadas
    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

JPAConfiguration

package br.com.agenda.conf;

import java.util.Properties;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
public class JPAConfiguration {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory()
    {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());

        em.setPackagesToScan(new String[] {"br.com.agenda.models"});
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());

        return em;

    }

    @Bean
    public DataSource dataSource()
    {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/agenda");
        dataSource.setUsername("root");
        dataSource.setPassword("");

        return dataSource;
    }

    private Properties additionalProperties()
    {
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        properties.setProperty("hibernate.show_sql", "true");

        return properties;
    }

    @Bean
    public PlatformTransactionManager transactionManager (EntityManagerFactory emf)
    {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }
}

ServletSpringMVC

package br.com.agenda.conf;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class ServletSpringMVC extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() 
    {
        return null;
    }

    //definido de onde vira as cofiguracoes para rodar as classes
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{AppWebConfiguration.class, JPAConfiguration.class};
    }

    //indica a pasta raiz mappeando o servlet
    @Override
    protected String[] getServletMappings() 
    {
        return new String[] {"/"};
    }
}

Help me and / or make corrections please, thank you in advance.

    
asked by anonymous 03.02.2017 / 00:38

1 answer

1

NullPointerException is occurring because you are manually instantiating the ContactService and ContactDAO classes, so Spring does not inject EntityManager .

Change these snippets of code to:

ContactService:

@Service
public class ContactService implements IContactService {

    @Autowired
    private ContactDAO contactDAO;

    //os seus métodos
}

ContactController:

@Controller
@RequestMapping("/contact")
public class ContactController {

    @Autowired
    private IContactService contactService;

    @RequestMapping(method=RequestMethod.GET)
    public ModelAndView listContact() {
        ModelAndView modelAndView = new ModelAndView("contacts");
        modelAndView.addObject("contacts", contactService.listAll());
        return modelAndView;
    }
}

Issue:

Below is the complete code that worked with me without throwing any exceptions. If you still face an exception, it is likely that this exception is different from the one in your question and is caused by some other class that has not been listed.

That way, if an exception is thrown, I suggest you create another project with the files I'll put below, and gradually add the remaining classes / features to find out where the problem is. If you have any questions, you can ask.

pom.xml

I use maven to manage my dependencies, if you use another manager or need to add / replace dependencies, adjust to your needs.

<project xmlns="http://maven.apache.org/POM/4.0.0" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                            http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>br.com.agenda</groupId>
    <artifactId>agenda</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>agenda</name>
    <url>http://maven.apache.org</url>

    <properties>
        <log4j2.version>2.7</log4j2.version>
        <org.springframework.version>4.3.4.RELEASE</org.springframework.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.2.5.Final</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.39</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-jcl</artifactId>
            <version>${log4j2.version}</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.0.Final</version>
        </dependency>

        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>agenda</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.0.0</version>
                    <configuration>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

AppWebConfiguration.java

package br.com.agenda.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@EnableWebMvc
@Configuration
@ComponentScan(basePackages={"br.com.agenda"})
public class AppWebConfiguration extends WebMvcConfigurerAdapter {

    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

JPAConfiguration.java

Do not forget to add the username and password for your database.

package br.com.agenda.conf;

import java.util.Properties;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
public class JPAConfiguration {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());

        em.setPackagesToScan(new String[] {"br.com.agenda.models"});
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());

        return em;

    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/agenda?useSSL=false");
        dataSource.setUsername("");
        dataSource.setPassword("");

        return dataSource;
    }

    private Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL57InnoDBDialect");
        properties.setProperty("hibernate.show_sql", "true");

        return properties;
    }

    @Bean
    public PlatformTransactionManager transactionManager (EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }
}

ServletSpringMVC.java

package br.com.agenda.conf;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class ServletSpringMVC extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{AppWebConfiguration.class, JPAConfiguration.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }
}

ContactDA.java

I changed the ContactDAO to an interface and created an implementation called JPAContactDAO :

package br.com.agenda.daos;

import java.util.List;
import java.util.Optional;

import br.com.agenda.models.Contact;

public interface ContactDAO {

    public void save(Contact contact);

    public Contact update(Contact contact);

    public void remove(Contact contact);

    public Optional<Contact> find(int identifier);

    public List<Contact> listAll();
}

JPAContactDAO.java

package br.com.agenda.daos;

import static java.util.Objects.requireNonNull;

import java.util.List;
import java.util.Optional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Repository;

import br.com.agenda.models.Contact;

@Repository
public final class JPAContactDAO implements ContactDAO {

    @PersistenceContext
    private EntityManager manager;

    @Override
    public void save(Contact contact) {
        requireNonNull(contact, "contact cannot be null");
        manager.persist(contact);
    }

    @Override
    public Contact update(Contact contact) {
        requireNonNull(contact, "contact cannot be null");
        return manager.merge(contact);
    }

    @Override
    public void remove(Contact contact) {
        requireNonNull(contact, "contact cannot be null");
        manager.remove(contact);
    }

    @Override
    public Optional<Contact> find(int identifier) {
        return Optional.ofNullable(manager.find(Contact.class, identifier));
    }

    @Override
    public List<Contact> listAll() {
        return manager.createQuery("SELECT DISTINCT(c) FROM Contact c JOIN FETCH c.phones", Contact.class)
                    .getResultList();
    }
}

ContactService.java

I changed the name of IContactService to ContactService and the implementation was renamed DefaultContactService .

package br.com.agenda.services;

import java.util.List;
import java.util.Optional;

import br.com.agenda.models.Contact;

public interface ContactService {

    public void save(Contact contact);

    public Contact update(Contact contact);

    public void remove(Contact contact);

    public Optional<Contact> find(int identifier);

    public List<Contact> listAll();
}

DefaultContactService.java

package br.com.agenda.services;

import static java.util.Objects.requireNonNull;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import br.com.agenda.daos.ContactDAO;
import br.com.agenda.models.Contact;

@Service
public final class DefaultContactService implements ContactService {

    @Autowired
    private ContactDAO contactDAO;

    @Override
    @Transactional
    public void save(Contact contact) {
        requireNonNull(contact, "contact cannot be null");
        contactDAO.save(contact);
    }

    @Override
    @Transactional
    public Contact update(Contact contact) {
        requireNonNull(contact, "contact cannot be null");
        return contactDAO.update(contact);
    }

    @Override
    @Transactional
    public void remove(Contact contact) {
        requireNonNull(contact, "contact cannot be null");
        contactDAO.remove(contact);
    }

    @Override
    public Optional<Contact> find(int identifier) {
        return contactDAO.find(identifier);
    }

    @Override
    public List<Contact> listAll() {
        return contactDAO.listAll();
    }
}

Contact.java

I changed the relationship between Contact and Phone @ElementCollection to @OneToMany :

package br.com.agenda.models;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.Valid;

import org.hibernate.validator.constraints.NotBlank;

@Entity
@Table(name="tblContacts")
public class Contact {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="idContacts")
    private int id;

    @NotBlank
    @Column(name="nameContacts")
    private String name;

    @NotBlank
    @Column(name="emailContacts")
    private String email;

    @OneToMany(cascade=CascadeType.ALL)
    @Valid
    private List<Phone> phones = new ArrayList<>();

    public void addPhone(Phone phone) {
        phones.add(phone);
    }

    public List<Phone> getPhones() {
        return phones;
    }

    public void setPhones(List<Phone> phones) {
        this.phones = phones;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Phone.java

package br.com.agenda.models;

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 = "tblPhones")
public class Phone {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="idPhones")
    private Integer id;

    @Column(name="dddPhones")
    private int ddd;

    @Column(name="numberPhones")
    private int number;

    public int getDdd() {
        return ddd;
    }

    public void setDdd(int ddd) {
        this.ddd = ddd;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }       
}

ContactController.java

package br.com.agenda.controllers;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import br.com.agenda.models.Contact;
import br.com.agenda.services.ContactService;

@Controller
@RequestMapping("/contact")
public class ContactController {

    @Autowired
    private ContactService contactService;

    @RequestMapping(value="/all", method=RequestMethod.GET)
    public ModelAndView listContact() {
        ModelAndView modelAndView = new ModelAndView("contact-list");
        modelAndView.addObject("contacts", contactService.listAll());
        return modelAndView;
    }
}

contact-list.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Contact List</title>
    </head>
    <body>
        <c:forEach var="contact" items="${contacts}">
            <label>${contact.name}</label><br />
        </c:forEach>
    </body>
</html>
    
03.02.2017 / 01:25