JSF Parametros por Get Request RESTFull

Olá tudo bem?

Como utilizar passagem de parâmetros via URL utilizando JSF? Creio que será o menor post aqui do blog, pois é muito simples.

Ao final do post você irá encontrar o link para download do código de hoje.

Os outros posts sobre JSF são: JSF Exemplos Simples com AjaxJSF Exibindo Objeto e Mensagens após Redirect, Validação de Login de Usuário com JSF e JAASJSF: Converter and Bean AutoCompleteJSF – Hello World, AutoComplete, Tratando Exceções em uma Aplicação Web, Autenticação de Usuários (Filter/Servlet), Criando um WebServer..

Veja como é simples o código para receber parâmetros via URL no JSF 2.0:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
	<f:metadata>
		<f:viewParam name="email" value="#{user.email}" />
		<f:viewParam name="name" value="#{user.name}" />
	</f:metadata>
</h:head>
<h:body>
	<h:form>
		Your email is: #{user.email} <br/>
		Your name is: #{user.name} <br/>
		Your name and email from MB: #{user.nameAndEmail} <br/>
	</h:form>
</h:body>
</html>
package demo;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = "user")
@RequestScoped
public class User {

	private String email;
	private String name;

	public String getEmail() {
		return email;
	}

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

	public String getName() {
		return name;
	}

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

	public String getNameAndEmail(){
		return email + " " + name;
	}
}

A URL utilizada foi: http://localhost:8080/RequestParameter/values.xhtml?email=Read+Romans&name=Chapter10+Ver+09.

Como você pode ver a página espera dois parâmetros e existe um método que utiliza os dois parâmetros; seria o método em que você iria disparar a consulta no banco de dados ou qualquer outra ação necessária.

E como criar um link para o usuário navegar? Fácil, olhe e página abaixo:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>

</h:head>
<h:body>
	<h:form>
		01) A pre-formed link: <br/>
		<h:link outcome="values?email=Read Romans&amp;name=Chapter10 Ver 09" value="Let us go!" />
		<br/>
		<br/>
		02)Link with the f:param component<br/>
		<h:link outcome="values" value="Write all params and let us go!" >
			<f:param name="email" value="Read Romans" />
			<f:param name="name" value="Chapter10 Ver 09" />
		</h:link>
		<br/>
		<br/>
		03) <h:commandLink value="Redirect Me!" action="values?faces-redirect=true&amp;email=Read Romans&amp;name=Chapter10 Ver 09" />
	</h:form>
</h:body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
	<f:metadata>
		<f:viewParam name="email" value="#{user.email}" />
		<f:viewParam name="name" value="#{user.name}" />
	</f:metadata>
</h:head>
<h:body>
	<h:form>
		Your email is: #{user.email} <br/>
		Your name is: #{user.name} <br/>
		Your name and email from MB: #{user.nameAndEmail} <br/>

		04) <h:link outcome="values" value="Get everybody and leave this place" includeViewParams="true" />
	</h:form>
</h:body>
</html>

Vou comentar agora sobre cada abordagem utilizada na criação do link (de acordo com a numeração utilizada no código fonte “01,02…”):

  • 01)  Foi um link já formado onde todos os parâmetros estão escritos.
  • 02)  Utilizamos o componente “f:param” que acaba por deixar mais legível o código.
  • 03)  A navegação é feita através de um redirect e utilizando o commandLink. ATENÇÃO: até o dia de hoje, ainda não é possível utilizar o componente “f:param” junto com um redirect. Por isso que escrevi a URL toda de uma vez com o redirect no link. “<h:commandLink action=”values?faces-redirect=true.
  • 04) Com esse modo de link, com a opção (includeViewParams=”true”), você irá levar automaticamente todos os “f:viewParam” presentes na tela. Você nem irá precisar escrever os parâmetros progamaticamente. O JSF irá automaticamente pegar todos os parâmetros para você.

Você pode adicionar parâmetros de navegação após um redirect utilizando a faces-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
	<navigation-rule>
		<navigation-case>
			<from-outcome>redirectMe</from-outcome>
			<to-view-id>/myPage.xhtml</to-view-id>
			<redirect include-view-params="true">
				<view-param>
					<name>calculatedValue</name>
					<value>#{myBean.value}</value>
				</view-param>
			</redirect>
		</navigation-case>
	</navigation-rule>
</faces-config>

O código de hoje funciona com os componentes “<h:link />” e “<h:commandLink />” ambos podendo ser utilizados com ou sem a opção redirect.

Lembro também que seu link pode ser escrito em seu ManagedBean e seu valor acessado por #{meuMB.createTheURL} nos componentes link/commandLink.

Click aqui para fazer o download do código do post de hoje.

Espero que esse post possa te ajudar.

Qualquer dúvida/pergunta/colocação basta postar.

Até a próxima pessoal.

JSF RESTFull Get Request Parameters

Hello, how are you?

How can we pass parameters through a URL using JSF 2.0? I believe this will be smallest post here.

At the end of this post you will find the link to download the created source code.

The other posts about JSF/Web Applications you can find in here: JSF Simple Ajax SamplesJSF Persisting Objects and Messages after a Redirect ,User Login Validation with JAAS and JSFJSF: Converter and Bean AutoCompleteJSF – Hello World, Auto CompleteHandling Exceptions on a WebAppUser Authentication (Filter/Servlet)Creating a WebServer.

Take a look bellow to see that is very easy to receive a parameter through a URL:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
	<f:metadata>
		<f:viewParam name="email" value="#{user.email}" />
		<f:viewParam name="name" value="#{user.name}" />
	</f:metadata>
</h:head>
<h:body>
	<h:form>
		Your email is: #{user.email} <br/>
		Your name is: #{user.name} <br/>
		Your name and email from MB: #{user.nameAndEmail} <br/>
	</h:form>
</h:body>
</html>
package demo;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = "user")
@RequestScoped
public class User {

	private String email;
	private String name;

	public String getEmail() {
		return email;
	}

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

	public String getName() {
		return name;
	}

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

	public String getNameAndEmail(){
		return email + " " + name;
	}
}

The used URL to access that page is: http://localhost:8080/RequestParameter/values.xhtml?email=Read+Romans&name=Chapter10+Ver+09.

As you can see the page expects two parameters and in our ManagedBean exists a method that uses both parameters; in this method you could search for your entities in the database or any other action that you need.

How can we create a link to be navigated by the user? Piece of cake, take a look at the page/code bellow:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>

</h:head>
<h:body>
	<h:form>
		01) A pre-formed link: <br/>
		<h:link outcome="values?email=Read Romans&amp;name=Chapter10 Ver 09" value="Let us go!" />
		<br/>
		<br/>
		02)Link with the f:param component<br/>
		<h:link outcome="values" value="Write all params and let us go!" >
			<f:param name="email" value="Read Romans" />
			<f:param name="name" value="Chapter10 Ver 09" />
		</h:link>
		<br/>
		<br/>
		03) <h:commandLink value="Redirect Me!" action="values?faces-redirect=true&amp;email=Read Romans&amp;name=Chapter10 Ver 09" />
	</h:form>
</h:body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
	<f:metadata>
		<f:viewParam name="email" value="#{user.email}" />
		<f:viewParam name="name" value="#{user.name}" />
	</f:metadata>
</h:head>
<h:body>
	<h:form>
		Your email is: #{user.email} <br/>
		Your name is: #{user.name} <br/>
		Your name and email from MB: #{user.nameAndEmail} <br/>

		04) <h:link outcome="values" value="Get everybody and leave this place" includeViewParams="true" />
	</h:form>
</h:body>
</html>


I will talk about each approach used in the codes to generate the links (according to each number used like 01, 02…):

  • 01)  A pre-formed link that has all the parameters written in it.
  • 02)  We are using the “f:param” component that gives us a cleaner code.
  • 03)  A link that will use the redirect to navigate through the commandLink component. BE CAREFULL: until today, the JSF will not send paramters in a redirect if you use the “f:param” component. That is why I wrote all URL in the link with the redirect. “<h:commandLink action=”values?faces-redirect=true”.
  • 04)  Using this approach with the option (includeViewParams=”true”) you will automatically includ all the “f:viewParam” that are present in the view. You will not need to write them in the “h:link” component. JSF will gather all the parameters for you.

You can also add parameters when you use the navigation through the “faces-config.xml”:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
	<navigation-rule>
		<navigation-case>
			<from-outcome>redirectMe</from-outcome>
			<to-view-id>/myPage.xhtml</to-view-id>
			<redirect include-view-params="true">
				<view-param>
					<name>calculatedValue</name>
					<value>#{myBean.value}</value>
				</view-param>
			</redirect>
		</navigation-case>
	</navigation-rule>
</faces-config>

The code from this post will work with the “h:link” or the “h:commandLink” and both can be used with the redirect option.

I also want to remind you that your URL can be wrote in a ManagedBean and the value used like #{youMB.createTheURL} in the “link/commandLink” components.

Click here to download the source code.

I hope this post helps you.

If you have any question/doubt/suggestion just post it.

See you soon. o_

JSF Exemplos Simples com Ajax

Olá, tudo bem?

Hoje vamos exibir alguns simples modos de fazer chamadas Ajax utilizando JSF 2.0.

Para ver outros posts sobre Web Applications/JSF basta acessar os links a seguir: JSF Exibindo Objeto e Mensagens após Redirect, Validação de Login de Usuário com JSF e JAASJSF: Converter and Bean AutoCompleteJSF – Hello World, AutoComplete, Tratando Exceções em uma Aplicação Web, Autenticação de Usuários (Filter/Servlet), Criando um WebServer.

Ao final do post de hoje você verá o código para download. No post (Validação de Login de Usuário com JSF e JAAS) é exibido como instalar o JBoss 6 caso você queira executar o código do post de hoje. Você precisará instalar o JBoss Tools em seu Eclipse.

Veja a tela abaixo e seu respectivo código.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}"/>
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!"/>
		<br />
	</h:form>
</h:body>
</html>

Como exibir o nome digitado na mesma tela utilizando Ajax? Fácil, basta adicionar o comando “f:ajax” na linha e pronto. Veja a alteração e o resultado na página:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}"/>
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!">
			<f:ajax render="myName" execute="inputname" />
		</h:commandButton>
		<br />
		<br />
		<h:outputText id="myName" value="#{user.name}" />
	</h:form>
</h:body>
</html>

Viu como é simples? Passei apenas o valor que será levado,  para o ManagedBean, através do parâmetro “execute” e quem eu gostaria que o JSF atualizasse através do parâmetro “render”.

Repare que o nome digitado aparece no console também.

Esse exemplo serve para atualizar todos os tipos de componentes. Vamos para mais um?

Vamos fazer com que uma mensagem de erro seja exibida caso o nome preenchido tenha menos que 4 letras.

Veja o novo código da página e a mensagem exibida:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		<h:messages id="myMessage" globalOnly="true" showDetail="true"/>
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}"/>
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!">
			<f:ajax render="myName myMessage" execute="inputname" />
		</h:commandButton>
		<br />
		<br />
		<h:outputText id="myName" value="#{user.name}" />
	</h:form>
</h:body>
</html>
package demo;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = "user")
@RequestScoped
public class User {

	private String name;

	public String sayHello() {
		if (isNameIncorrect()) {
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Too small", "Can you write it a little bigger?"));
		}

		System.out.println(name);
		return null;
	}

	private boolean isNameIncorrect() {
		return "".equals(name.trim()) || name.length() < 3;
	}

	public String getName() {
		return name;
	}

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

Note no código que foi colocado um “h:messages” e ele tem seu ID utilizado pelo componente “f:ajax”.  Essa solução também funciona quando você tem um componente do tipo “h:message for=”YYY””.

Vamos trabalhar agora com comboboxes? Iremos exibir um combobox que contenha no máximo 4 itens quando temos um nome com menos de 6 caracteres ou uma lista com mais de 4 itens quando temos um nome com mais de 6 caracteres:

package demo;

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

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UISelectItems;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = "user")
@RequestScoped
public class User {

	private String name;

	private List<String> cars;

	private String selectedCar;
	private HtmlSelectOneMenu htmlSelectCars;

	private static final String SELECT_A_CAR = "Select One Car";

	public User() {
		cars = new ArrayList<String>();
	}

	public String sayHello() {
		if (isNameInCorrect()) {
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Too small", "Can you write it a little bigger?"));
		}

		System.out.println(name);
		return null;
	}

	private boolean isNameInCorrect() {
		return name == null || "".equals(name.trim()) || name.length() < 3;
	}

	public String getName() {
		return name;
	}

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

	public void editMyCarsList(AjaxBehaviorEvent event) {
		if (htmlSelectCars == null) {
			htmlSelectCars = new HtmlSelectOneMenu();
		}

		htmlSelectCars.getChildren().clear();

		UISelectItems items = new UISelectItems();
		items.setValue(getCars());
		htmlSelectCars.getChildren().add(items);
	}

	public List<String> getCars() {
		cars.clear();

		cars.add(SELECT_A_CAR);

		if (!isNameInCorrect() && name.length() >= 6) {
			cars.add("Ferrari");
			cars.add("Porch");
			cars.add("Beetle");
			cars.add("Opala");
			cars.add("Passat");
			cars.add("Vectra");
			cars.add("Chevet");
			cars.add("Corvet");
		} else {
			cars.add("Ferrari");
			cars.add("Porch");
			cars.add("Beetle");
			cars.add("Opala");
		}

		return cars;
	}

	public void setCars(List<String> cars) {
		this.cars = cars;
	}

	public String getSelectedCar() {
		return selectedCar;
	}

	public void setSelectedCar(String selectedCar) {
		this.selectedCar = selectedCar;
	}

	public HtmlSelectOneMenu getHtmlSelectCars() {
		editMyCarsList(null);

		return htmlSelectCars;
	}

	public void setHtmlSelectCars(HtmlSelectOneMenu htmlSelectCars) {
		this.htmlSelectCars = htmlSelectCars;
	}
}

Repare agora nosso código na página:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		<h:messages id="myMessage" globalOnly="true" showDetail="true" />
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}" />
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!">
			<f:ajax render="myName myCars myMessage" execute="inputname" listener="#{user.editMyCarsList}" />
		</h:commandButton>
		<br />
		<br />
		<h:outputText id="myName" value="#{user.name}" />
		<br />
		<br />
		Choose your car: <h:selectOneMenu id="myCars" binding="#{user.htmlSelectCars}" value="#{user.selectedCar}" />
		<br />
		<br />
	</h:form>
</h:body>
</html>

Como você pode perceber no código acima, o combobox tem seu valor alterado de acordo com o nome digitado. Ao final do post, irei explicar por que utilizei o binding ao componente HtmlSelectOneMenu ao invés de passar uma lista (List<String>) diretamente.

Como último exemplo, vamos fazer com que tenha um combobox invisível que só apareça quando o usuário tiver selecionado algum carro.

Veja como ficar nosso ManagedBean:

package demo;

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

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UISelectItems;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = "user")
@RequestScoped
public class User {

	private String name;

	private List<String> cars;
	private List<String> colors;

	private String selectedCar;
	private String selectedColor;
	private HtmlSelectOneMenu htmlSelectCars;

	private static final String SELECT_A_CAR = "Select One Car";

	public User() {
		cars = new ArrayList<String>();
		colors = new ArrayList<String>();

		colors.add("Red");
		colors.add("Blue");
		colors.add("Orange");
		colors.add("Pink --> O.o");
	}

	public String sayHello() {
		if (isNameInCorrect()) {
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Too small", "Can you write it a little bigger?"));
		}

		System.out.println(name);
		return null;
	}

	private boolean isNameInCorrect() {
		return name == null || "".equals(name.trim()) || name.length() < 3;
	}

	public String getName() {
		return name;
	}

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

	public void editMyCarsList(AjaxBehaviorEvent event) {
		if (htmlSelectCars == null) {
			htmlSelectCars = new HtmlSelectOneMenu();
		}

		htmlSelectCars.getChildren().clear();

		UISelectItems items = new UISelectItems();
		items.setValue(getCars());
		htmlSelectCars.getChildren().add(items);
	}

	public List<String> getCars() {
		cars.clear();

		cars.add(SELECT_A_CAR);

		if (!isNameInCorrect() && name.length() >= 6) {
			cars.add("Ferrari");
			cars.add("Porch");
			cars.add("Beetle");
			cars.add("Opala");
			cars.add("Passat");
			cars.add("Vectra");
			cars.add("Chevet");
			cars.add("Corvet");
		} else {
			cars.add("Ferrari");
			cars.add("Porch");
			cars.add("Beetle");
			cars.add("Opala");
		}

		return cars;
	}

	public void setCars(List<String> cars) {
		this.cars = cars;
	}

	public String getSelectedCar() {
		return selectedCar;
	}

	public void setSelectedCar(String selectedCar) {
		this.selectedCar = selectedCar;
	}

	public List<String> getColors() {
		return colors;
	}

	public void setColors(List<String> colors) {
		this.colors = colors;
	}

	public boolean isColorsAlloweToDisplay() {
		if (isNameInCorrect()) {
			return false;
		}

		if (selectedCar == null || selectedCar.trim().equals("") || selectedCar.equals(SELECT_A_CAR)) {
			return false;
		}

		return true;
	}

	public String getSelectedColor() {
		return selectedColor;
	}

	public void setSelectedColor(String selectedColor) {
		this.selectedColor = selectedColor;
	}

	public HtmlSelectOneMenu getHtmlSelectCars() {
		editMyCarsList(null);

		return htmlSelectCars;
	}

	public void setHtmlSelectCars(HtmlSelectOneMenu htmlSelectCars) {
		this.htmlSelectCars = htmlSelectCars;
	}
}

Repare que foram alterações bem simples, onde adicionamos um List um método que irá dizer quando a lista deve ser exibida ou não.

Veja como ficou nossa página:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		<h:messages id="myMessage" globalOnly="true" showDetail="true" />
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}" />
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!">
			<f:ajax render="myName myCars myMessage myColors" execute="inputname" listener="#{user.editMyCarsList}" />
		</h:commandButton>
		<br />
		<br />
		<h:outputText id="myName" value="#{user.name}" />
		<br />
		<br />
		Choose your car:
		<h:selectOneMenu id="myCars" binding="#{user.htmlSelectCars}" value="#{user.selectedCar}">
			<f:ajax render="myColors" execute="inputname myCars"/>
		</h:selectOneMenu>
		<br />
		<br />
		<h:panelGroup id="myColors">
			<h:selectOneMenu value="#{user.selectedColor}" rendered="#{user.colorsAlloweToDisplay}">
				<f:selectItems value="#{user.colors}" />
			</h:selectOneMenu>
		</h:panelGroup>
	</h:form>
	</h:body>
</html>

Agora farei diversas observações sobre o código e práticas adotadas:

  • HtmlSelectOneMenu – Eu utilizei o componente ao invés de uma simples lista por um pequeno detalhe. O JSF ainda não se dá bem na hora de construir os objetos na tela (DOM Tree). Com isso, se a primeira lista tinha 4 itens e depois, via ajax, você adiciona mais itens ele não irá reconhecer os itens mais novos. Com isso mesmo com uma lista contendo um novo valor o JSF não irá reconhecer, e você irá apenas poder utilizar os valores antigos. Você pode tentar com List<String> ao invés do component HtmlSelectOneMenu apenas e ver o que vai acontecer, fiquei umas 3~4 horas de pesquisa para achar uma solução.
  • HtmlSelectOneMenu dentro do “h:panelGroup” – Adicionei o selectOne dentro do panelGroup pois toda vez que um objeto não é exibido e você deseja exibi-lo é necessário atualizar todo seu container. Ou seja, se o segundo selectOne (cores) estivesse no mesmo “form”, você deveria utilizar seu “render” em todo o form.

Click Aqui para fazer o download do código do programa de hoje.

Espero que o post de hoje possa te ajuda.

Qualquer dúvida/pergunta/comentário poste abaixo.

Até a próxima

JSF Simple Ajax Samples

Hello, how are you?

Today we will see some Simple Samples of Ajax with JSF.

If you want to see other posts about JSF/Web Applications click on the next links: JSF Persisting Objects and Messages after a Redirect ,User Login Validation with JAAS and JSFJSF: Converter and Bean AutoComplete, JSF – Hello World, Auto Complete, Handling Exceptions on a WebApp, User Authentication (Filter/Servlet), Creating a WebServer.

In the end of this post you will find the link to download the source code of the samples. In this post (User Login Validation with JAAS and JSF) I show how to install the JBoss 6 in case you want to run the project from today. You will need to install the JBoss tools plugin in your Eclipse.

Take a look at the page bellow and its code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}"/>
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!"/>
		<br />
	</h:form>
</h:body>
</html>

How could we display the typed name in the same screen using Ajax? Piece of cake, just add the “f:ajax” component. Check the code update and the result:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}"/>
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!">
			<f:ajax render="myName" execute="inputname" />
		</h:commandButton>
		<br />
		<br />
		<h:outputText id="myName" value="#{user.name}" />
	</h:form>
</h:body>
</html>

It is very easy right? We just need to pass the value that will be carried to the ManagedBean by the “execute” parameter; with the “render” parameter we will tell to the JSF which component will be “refreshed”.

Notice also that the typed name appears in the Console.

With this code we can “refresh” all kind of components. Let us see another sample?

Let us display an error message if the user types a name with less than 4 characters.

Check our new message and the new code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		<h:messages id="myMessage" globalOnly="true" showDetail="true"/>
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}"/>
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!">
			<f:ajax render="myName myMessage" execute="inputname" />
		</h:commandButton>
		<br />
		<br />
		<h:outputText id="myName" value="#{user.name}" />
	</h:form>
</h:body>
</html>
package demo;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = "user")
@RequestScoped
public class User {

	private String name;

	public String sayHello() {
		if (isNameIncorrect()) {
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Too small", "Can you write it a little bigger?"));
		}

		System.out.println(name);
		return null;
	}

	private boolean isNameIncorrect() {
		return "".equals(name.trim()) || name.length() < 3;
	}

	public String getName() {
		return name;
	}

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

Notice that we have the component “h:messages” and its ID is used in the “f:ajax” component. This code also works when you use the “h:message for=“YYY”” component.

What if we work now with comboboxes? Let us display a combobox that will contain 4 items when we have a name with less than 6 characters, and a list with more than 4 items if the typed name has more than 6 characters.

package demo;

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

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UISelectItems;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = "user")
@RequestScoped
public class User {

	private String name;

	private List<String> cars;

	private String selectedCar;
	private HtmlSelectOneMenu htmlSelectCars;

	private static final String SELECT_A_CAR = "Select One Car";

	public User() {
		cars = new ArrayList<String>();
	}

	public String sayHello() {
		if (isNameInCorrect()) {
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Too small", "Can you write it a little bigger?"));
		}

		System.out.println(name);
		return null;
	}

	private boolean isNameInCorrect() {
		return name == null || "".equals(name.trim()) || name.length() < 3;
	}

	public String getName() {
		return name;
	}

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

	public void editMyCarsList(AjaxBehaviorEvent event) {
		if (htmlSelectCars == null) {
			htmlSelectCars = new HtmlSelectOneMenu();
		}

		htmlSelectCars.getChildren().clear();

		UISelectItems items = new UISelectItems();
		items.setValue(getCars());
		htmlSelectCars.getChildren().add(items);
	}

	public List<String> getCars() {
		cars.clear();

		cars.add(SELECT_A_CAR);

		if (!isNameInCorrect() && name.length() >= 6) {
			cars.add("Ferrari");
			cars.add("Porch");
			cars.add("Beetle");
			cars.add("Opala");
			cars.add("Passat");
			cars.add("Vectra");
			cars.add("Chevet");
			cars.add("Corvet");
		} else {
			cars.add("Ferrari");
			cars.add("Porch");
			cars.add("Beetle");
			cars.add("Opala");
		}

		return cars;
	}

	public void setCars(List<String> cars) {
		this.cars = cars;
	}

	public String getSelectedCar() {
		return selectedCar;
	}

	public void setSelectedCar(String selectedCar) {
		this.selectedCar = selectedCar;
	}

	public HtmlSelectOneMenu getHtmlSelectCars() {
		editMyCarsList(null);

		return htmlSelectCars;
	}

	public void setHtmlSelectCars(HtmlSelectOneMenu htmlSelectCars) {
		this.htmlSelectCars = htmlSelectCars;
	}
}

Take a look now at our page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		<h:messages id="myMessage" globalOnly="true" showDetail="true" />
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}" />
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!">
			<f:ajax render="myName myCars myMessage" execute="inputname" listener="#{user.editMyCarsList}" />
		</h:commandButton>
		<br />
		<br />
		<h:outputText id="myName" value="#{user.name}" />
		<br />
		<br />
		Choose your car: <h:selectOneMenu id="myCars" binding="#{user.htmlSelectCars}" value="#{user.selectedCar}" />
		<br />
		<br />
	</h:form>
</h:body>
</html>

Notice that our combobox items size is updated according to the typed name. At the end of this post I will talk more about why I used the binding attribute to the HtmlSelectOneMenu instead returning the List<String>.

As our last sample, let us create a combobox that will appear and disappear according to the selected value in the Car combobox.

Take a look at our ManagedBean:

package demo;

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

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UISelectItems;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = "user")
@RequestScoped
public class User {

	private String name;

	private List<String> cars;
	private List<String> colors;

	private String selectedCar;
	private String selectedColor;
	private HtmlSelectOneMenu htmlSelectCars;

	private static final String SELECT_A_CAR = "Select One Car";

	public User() {
		cars = new ArrayList<String>();
		colors = new ArrayList<String>();

		colors.add("Red");
		colors.add("Blue");
		colors.add("Orange");
		colors.add("Pink --> O.o");
	}

	public String sayHello() {
		if (isNameInCorrect()) {
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Too small", "Can you write it a little bigger?"));
		}

		System.out.println(name);
		return null;
	}

	private boolean isNameInCorrect() {
		return name == null || "".equals(name.trim()) || name.length() < 3;
	}

	public String getName() {
		return name;
	}

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

	public void editMyCarsList(AjaxBehaviorEvent event) {
		if (htmlSelectCars == null) {
			htmlSelectCars = new HtmlSelectOneMenu();
		}

		htmlSelectCars.getChildren().clear();

		UISelectItems items = new UISelectItems();
		items.setValue(getCars());
		htmlSelectCars.getChildren().add(items);
	}

	public List<String> getCars() {
		cars.clear();

		cars.add(SELECT_A_CAR);

		if (!isNameInCorrect() && name.length() >= 6) {
			cars.add("Ferrari");
			cars.add("Porch");
			cars.add("Beetle");
			cars.add("Opala");
			cars.add("Passat");
			cars.add("Vectra");
			cars.add("Chevet");
			cars.add("Corvet");
		} else {
			cars.add("Ferrari");
			cars.add("Porch");
			cars.add("Beetle");
			cars.add("Opala");
		}

		return cars;
	}

	public void setCars(List<String> cars) {
		this.cars = cars;
	}

	public String getSelectedCar() {
		return selectedCar;
	}

	public void setSelectedCar(String selectedCar) {
		this.selectedCar = selectedCar;
	}

	public List<String> getColors() {
		return colors;
	}

	public void setColors(List<String> colors) {
		this.colors = colors;
	}

	public boolean isColorsAlloweToDisplay() {
		if (isNameInCorrect()) {
			return false;
		}

		if (selectedCar == null || selectedCar.trim().equals("") || selectedCar.equals(SELECT_A_CAR)) {
			return false;
		}

		return true;
	}

	public String getSelectedColor() {
		return selectedColor;
	}

	public void setSelectedColor(String selectedColor) {
		this.selectedColor = selectedColor;
	}

	public HtmlSelectOneMenu getHtmlSelectCars() {
		editMyCarsList(null);

		return htmlSelectCars;
	}

	public void setHtmlSelectCars(HtmlSelectOneMenu htmlSelectCars) {
		this.htmlSelectCars = htmlSelectCars;
	}
}

Our ManagedBean were lightly updated, we just added a List with a method that return a list of colors that will populate our combobox; we added also a method that will return a Boolean – true if the combobox is allowed to be displayed.

Check our new page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
	<h:form>
		<h:messages id="myMessage" globalOnly="true" showDetail="true" />
		Your Name: <h:inputText id="inputname" label="${msgs.prompt}" value="#{user.name}" />
		<br />
		<h:commandButton action="#{user.sayHello}" value="Display my name here, now!">
			<f:ajax render="myName myCars myMessage myColors" execute="inputname" listener="#{user.editMyCarsList}" />
		</h:commandButton>
		<br />
		<br />
		<h:outputText id="myName" value="#{user.name}" />
		<br />
		<br />
		Choose your car:
		<h:selectOneMenu id="myCars" binding="#{user.htmlSelectCars}" value="#{user.selectedCar}">
			<f:ajax render="myColors" execute="inputname myCars"/>
		</h:selectOneMenu>
		<br />
		<br />
		<h:panelGroup id="myColors">
			<h:selectOneMenu value="#{user.selectedColor}" rendered="#{user.colorsAlloweToDisplay}">
				<f:selectItems value="#{user.colors}" />
			</h:selectOneMenu>
		</h:panelGroup>
	</h:form>
	</h:body>
</html>

I will talk about the code used in the post:

  • HtmlSelectOneMenu – I used the component instead a List because the JSF is not so good in render the components in the user screen (DOM Tree). If your combobox has 4 lines and by using ajax you add more lines to the List, the JSF/Ajax will not recognize the new added lines; you will be able to use only the older values. You can try to use the code with a List<String> instead using the HtmlSelectOneMenu and see the result; I spend like 3~4 hours to understand this by a lot of searches on the internet.
  • HtmlSelectOneMenu inside the “h:panelGroup” component – I did this because every time you want to render a non rendered component you need to update its container. If our selectOne were inside the same form of the car selectOne you would need to render all form.

Click here to download the code from this post.

I hope this post might help you.

If you have any question/doubt/suggestion just post it.

See you later. o_

JPA Uma Tabela por Classe

EXISTE UMA NOVA VERSÃO DESSE POST.
CLICK AQUI: http://uaihebert.com/?p=1622&page=14

Olá pessoal, tudo bem?

Vamos falar hoje em como criar uma tabela por classe em uma herança onde cada tabela tem apenas as colunas da sua classe. No último post foi visto como persistir toda a herança em uma tabela apenas.

Irei utilizar o mesmo exemplo do ultimo post já colocando aqui como deve ser o código correto para utilizar essa abordagem.

Ao final do post você encontrará o link para download do projeto de hoje.

Click nos links a seguir para ver o último post sobre o assunto ou qualquer outro post sobre JPA: JPA Uma tabela por herança, Ordernando listas e utilizando Map como atributo mapeado, @ManyToMany Unidirecional e Bidirecional, JPA @OneToMany e @ManyToOne Unidirecional e Bidirecional, @OneToOne Unidirecional e Bidirecional, Mapeando Duas Tabelas em uma Classe, Mapeando Datas (Date) e Enum, Chave Primária Composta, SequenceGenerator, TableGenerator – Chave Primária Simples, Auto Create Schema Script com: Ant, Hibernate 3 e JPA 2, Tutorial Hibernate 3 com JPA 2.

Veja como ficará nosso código:

package com.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Table(name="CAR")
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Car {
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private int id;
	private String name;

	public String getName() {
		return name;
	}

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

	public int getId() {
		return id;
	}

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

import javax.persistence.Entity;

@Entity
public class Beetle extends Car {
	private int gasCapacity;

	public void talk(){
		System.out.println("Herbie!");
	}

	public int getGasCapacity() {
		return gasCapacity;
	}

	public void setGasCapacity(int gasCapacity) {
		this.gasCapacity = gasCapacity;
	}
}
package com.model;

import javax.persistence.Entity;

@Entity
public class Ferrari extends Car {
	private int model;

	// The newest new models will fly... some day! =P
	public void fly() {

	}

	public int getModel() {
		return model;
	}

	public void setModel(int model) {
		this.model = model;
	}
}

Após executar a classe Main, veja como nossas tabelas ficaram:

Agora para cada tabela temos os dados pertinentes a sua respectiva classe.

Gostaria de deixar apenas uma alerta.

Repare que os IDs de todas as nossas classes têm o nome “id”. Caso sua classe tenha um id diferente de sua super classe, será necessário mapear de modo diferente.

Imagine que nossa classe Beetle teria seu id como beetleId, nosso mapeamento teria que apresentar a seguinte anotação a mais:

package com.model;

import javax.persistence.Entity;
import javax.persistence.PrimaryKeyJoinColumn;

@Entity
@PrimaryKeyJoinColumn(name="beetleId")
public class Beetle extends Car {

	private int gasCapacity;

	public void talk() {
		System.out.println("Herbie!");
	}

	public int getGasCapacity() {
		return gasCapacity;
	}

	public void setGasCapacity(int gasCapacity) {
		this.gasCapacity = gasCapacity;
	}
}


Repare que a chave primária agora tem o id com nome diferente da classe Car e Ferrari.

Lembre-se: se sua classe filha tem o nome do campo de id diferente da classe pai, você terá que usar a anotação @PrimaryKeyJoinColumn onde o campo “name” indica qual a coluna a ser mapeada. E caso você queira alterar qual a coluna de ligação na classe pai, basta você utilizar o parâmetro “referencedColumnName”.

Finalizando, vejamos vantagens e desvantagens:

  • Vantagem: Você poderá ter campos not null em sua classe ao contrário da estratégia de uma tabela para toda a herança. E tem vantagens em sobre o próximo tipo mapeamento que veremos: “Uma tabela para cada Sub-Classe com todos os campos da herança”. E segundo o livro “Enterprise JavaBens 3.0” essa estratégia será melhor do que a “Uma tabela para cada Sub-Classe com todos os campos da herança” caso SQL Union não seja suportado por seu banco de dados.
  • Desvantagem: Seu desempenho é pior do que a estratégia de Uma Tabela Para toda a Herança.

Clique aqui para fazer o download do post de hoje. Não esqueça de alterar a senha de conexão e o usuário.

Espero que esse post possa te ajudar.

Qualquer dúvida/colocação basta postar.

Até! o_

JPA One Table Per SubClass

THERE IS A NEW VERSION OF THIS POST.
CLICK HERE: http://uaihebert.com/?p=1674&page=14

Hello, how are you?

Let us talk today about how to create a database table per subclass of your hierarchy; each table will have only the data of its class. In the last post we had seen how to persist all hierarchy in one table.

I will use the same code from the last post but with the code already edited.

In the end of this post, you will find the source code of the application.

In the following links you can find the last post about this subject and the others post about JPA: JPA Single Table per Class Hierarchy, @ManyToMany Unidirectional and Bidirectional, @OneToMany and @ManyToOne Unidirectional and Bidirectional, OneToOne Unidirectional and Bidirectional, Mapping two Tables in one Class, Mapping Date and Enum, Composite Primary-Key, SequenceGenerator, TableGenerator – Simple Primay Key, Auto Create Schema Script with: Ant, Hibernate 3 and JPA 2, Tutorial Hibernate 3 with JPA 2.

Take a look and see how the code has to be:

package com.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Table(name="CAR")
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Car {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;
    private String name;

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

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

import javax.persistence.Entity;

@Entity
public class Beetle extends Car {
    private int gasCapacity;

    public void talk(){
        System.out.println("Herbie!");
    }

    public int getGasCapacity() {
        return gasCapacity;
    }

    public void setGasCapacity(int gasCapacity) {
        this.gasCapacity = gasCapacity;
    }
}
package com.model;

import javax.persistence.Entity;

@Entity
public class Ferrari extends Car {
    private int model;

    // The newest new models will fly... some day! =P
    public void fly() {

    }

    public int getModel() {
        return model;
    }

    public void setModel(int model) {
        this.model = model;
    }
}

After we run the Main class let us take a look and see how our tables will look like:

Now each table has the data of its respective class.

I would like to call your attention to a situation.

Notice that every class of our hierarchy has the id with the same name “id”. If your subclass has a different id attribute name, you will have to map this with a different annotation.

Imagine that the Beetle class has its table id named as “beetleId”; we need to add an annotation in the Beetle class:

package com.model;

import javax.persistence.Entity;
import javax.persistence.PrimaryKeyJoinColumn;

@Entity
@PrimaryKeyJoinColumn(name="beetleId")
public class Beetle extends Car {

    private int gasCapacity;

    public void talk() {
        System.out.println("Herbie!");
    }

    public int getGasCapacity() {
        return gasCapacity;
    }

    public void setGasCapacity(int gasCapacity) {
        this.gasCapacity = gasCapacity;
    }
}


Notice that the primary key now has a different name than Car and Ferrari.

Remember this: if your subclass id field has a name that is not the same of your super class, you will need to use the @PrimaryKeyJoinColumn annotation; the “name” parameter indicates which column will be mapped. If you need to set up the Super Class id column you can use the parameter: “referencedColumnName”.

Let us see now the advantages and the disadvantages of this approach:

  • Advantage: You will be able to have null attributes in your subclasses; you would not be able to do this if you use the one table for all hierarchy strategy. There is a good sql performance over the next pattern that we will see: “One table with all fields per Subclasses”. In the book “Enterprise JavaBens 3.0” the author says that this approach is better than “One table with all fields per Subclasses” only if the database SQL Union is not supported by your database.
  • Disadvantage: It has a lower performance than “One table to all hierarchy strategy”.

Click here to download the source code of this post. Just do not forget to change the user/password.

I hope this post may help you.

If you have any comments/questions just post it.

See you later! o_