Missing artifact sun.jdk:jconsole:jar:jdk

On October 5, 2016, in Uncategorized, by lucasterdev

Problem:

You get this message in Eclipse (command line mvn has no issues):

“Missing artifact sun.jdk:jconsole:jar:jdk”

Workaround:

	<dependency>
		<groupId>org.wildfly</groupId>
		<artifactId>wildfly-cli</artifactId>
		<version>${org.wildfly}</version>
		<exclusions>
			<exclusion>
				<groupId>sun.jdk</groupId>
				<artifactId>jconsole</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
 
 

PrimeFaces’ betrayal

On March 24, 2013, in JSF, Open Source, PrimeFaces, Rants, by lucasterdev

PrimeFaces is now PrimeFace$, and isn’t open source anymore.

Their license page still reads:

PrimeFaces is open source, completely free to use and licensed under Apache License V2. Briefly you can use PrimeFaces in open source or commercial projects following the terms of the license.

Apache License

Version 2.0, January 2004

That’s not the case anymore, since private branches exist now that are only available to paying clients.

PrimeTek will now make sure that, from now on, only bug rigged, released once in a blue moon pre-alpha versions will be made available to the community, who will serve as a bunch of free beta testers.

 

Gracefully Handling ViewExpiredException

On March 17, 2013, in Java EE 6, JSF, JSF 2.0, by lucasterdev

ViewExpiredException usually occurs whena postback is triggered after the Session has expired. Here are a couple of ways to handle it:

Method #1: just use web.xml

<error-page>
	<exception-type>javax.faces.application.ViewExpiredException</exception-type>
	<location>/ViewExpiredException.xhtml</location>
</error-page>

Method #2: use JSF’s ExceptionHandler mechanism

Create an ExceptionHandlerFactory

package foo;

import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;

public class MyExceptionHandlerFactory extends ExceptionHandlerFactory {

	private ExceptionHandlerFactory parent;

	// This injection is handled by JSF
	public MyExceptionHandlerFactory(ExceptionHandlerFactory parent) {
		this.parent = parent;
	}

	@Override
	public ExceptionHandler getExceptionHandler() {
		return new MyExceptionHandler(parent.getExceptionHandler());
	}

}

Implement your ExceptionHandler by extending ExceptionHandlerWrapper and overriding the handle() method

package foo;

import java.util.Iterator;
import java.util.logging.Logger;

import javax.faces.application.FacesMessage;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;

public class MyExceptionHandler extends ExceptionHandlerWrapper {

	private ExceptionHandler wrapped;

	Logger log;
	FacesContext fc;

	public MyExceptionHandler(ExceptionHandler exceptionHandler) {
		wrapped = exceptionHandler;
		log = Logger.getLogger(this.getClass().getName());
		fc = FacesContext.getCurrentInstance();
	}

	@Override
	public ExceptionHandler getWrapped() {
		return wrapped;
	}

	@Override
	public void handle() {

		Iterator<ExceptionQueuedEvent> i = super.getUnhandledExceptionQueuedEvents().iterator();

		while (i.hasNext()) {

			Throwable t = i.next().getContext().getException();

			if (t instanceof ViewExpiredException) {
				try {
					// Handle the exception, for example:
					log.severe("ViewExpiredException occurred!");
					fc.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "An exception occurred",
							"ViewExpiredException happened!"));
					fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "ViewExpiredException");
				}
				finally {
					i.remove();
				}
			}

			/*
			else if (t instanceof SomeOtherException) {
				// handle SomeOtherException
			}
			*/

		}

		// let the parent handle the rest
		getWrapped().handle();
	}

}

Register your ExceptionHandlerFactory in faces-config.xml

<factory>
	<exception-handler-factory>foo.MyExceptionHandlerFactory</exception-handler-factory>
</factory>
Tagged with:  
  • As a Developer, I want to only have to extend the base class:
    public class BookCRUD extends CRUD<T> {}
  • As a Developer, I want to use vanilla Java EE 6, so that the controller is portable
  • As a Developer, I want database accesses to be executed transactionally
  • As a Developer, I want the controller to not contain any view logic, so that business logic and view logic are decoupled
  • As a Developer, I want the controller to support any navigation pattern ou-of-the-box, so that changes in the view logic don’t require changes in the controller code
  • As a Developer, I want the controller to support entities of any kind and complexity
  • As a Developer, I want supporting entities with collections to require minimal code change
  • As a Developer, I do not want to use f:viewParam or f:event, so that views don’t contain controller logic
  • As a Developer, I do not want the controller to interfere with my app, so that it can be added to existing projects without side effects
 

Requirements:
JBoss Developer Studio 5
JBoss AS 7.1.1.Final
Seam 3.1.0.Final Validation Module (for dependency injection in validators)
Seam 3.1.0.Final Solder Module (needed by Validation Module)
de.hashcode:jsr303-validators:1.1 (for some utility methods in the validator)

Annotation

package org.lucaster.validator;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = { UniqueValidator.class })
public @interface Unique {

	String message() default "Field is not unique!";

	/**
	 * EL expression evaluating to the producer method of the entity bean
	 * instance we are validationg.<br/>
	 * <br/>
	 *
	 * Example: "#{controllerName.getInstance}"
	 *
	 * @return
	 */
	String beanInstanceEL();

	/**
	 * Name of the property/column that is unique
	 *
	 * @return
	 */
	String propertyName();

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};
}

Validator

package org.lucaster.validator;

import static org.lucaster.util.ReflectionUtils.getIdField;
import static org.lucaster.util.ReflectionUtils.getPropertyValue;

import java.util.List;

import javax.faces.validator.FacesValidator;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder;
import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext;

import org.jboss.solder.el.Expressions;

@FacesValidator("uniqueFieldValidator")
public class UniqueValidator implements ConstraintValidator<Unique, Object> {

	private Unique constraintAnnotation;
	private String beanInstanceEL;
	private String propertyName;

	private Object instance;
	private Class<?> entityClass;
	private String idPropertyName;
	private Object idValue;

	@Inject private EntityManager entityManager;
	@Inject private Expressions expressions;

	@Override
	public void initialize(Unique constraintAnnotation) {
		this.constraintAnnotation = constraintAnnotation;
		beanInstanceEL = constraintAnnotation.beanInstanceEL();
		propertyName = constraintAnnotation.propertyName();
		instance = expressions.evaluateMethodExpression(beanInstanceEL);
		entityClass = instance.getClass();
	}

	@Override
	public boolean isValid(Object value, ConstraintValidatorContext context) {

		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();
		Root<?> root = criteriaQuery.from(entityClass);

		Predicate uniquePropertyPredicate = criteriaBuilder.equal(root.get(propertyName), value);

		try {

			idPropertyName = getIdField(entityClass).getName();

			idValue = getPropertyValue(instance, getIdField(entityClass).getName());

			if (idValue != null) {
				Predicate idNotEqualsPredicate = criteriaBuilder.notEqual(root.get(idPropertyName), idValue);
				criteriaQuery.select(root).where(uniquePropertyPredicate, idNotEqualsPredicate);
			} else {
				criteriaQuery.select(root).where(uniquePropertyPredicate);
			}			

		} catch (final Exception e) {
			throw new RuntimeException("An error occurred when trying to create the jpa predicate for the @Unique '" + constraintAnnotation.propertyName() + "' on bean " + entityClass + ".", e);
		}

		final List<Object> resultSet = entityManager.createQuery(criteriaQuery).getResultList();

		if (!resultSet.isEmpty()) {
			ConstraintViolationBuilder cvb = context.buildConstraintViolationWithTemplate(constraintAnnotation.message());
			NodeBuilderDefinedContext nbdc = cvb.addNode(constraintAnnotation.propertyName());
			ConstraintValidatorContext cvc = nbdc.addConstraintViolation();
			cvc.disableDefaultConstraintViolation();
			return false;
		}

		return true;

	}

}

Usage in entity bean

package org.lucaster.model;

import javax.persistence.Column;
import javax.persistence.Entity;

import org.hibernate.validator.constraints.NotEmpty;
import org.lucaster.validator.Unique;

@Entity
public class Book extends Model {

	private static final long serialVersionUID = 8519973666976987438L;

	@NotEmpty @Column(unique = true) @Unique(beanInstanceEL = "#{bookHomeCRUD.getInstance}", propertyName = "title") private String title;
	private String author;
	private int pages;

	@Override
	public String toString() {
		return title + ", " + author + ", " + pages;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public int getPages() {
		return pages;
	}

	public void setPages(int pages) {
		this.pages = pages;
	}
}

Usage in controller

@Named("bookHomeCRUD")
@Stateful
@RequestScoped
@AutoValidating
@Logged
public class BookCRUD implements Serializable {
	// ...
	private Book instance;
	// ...
	public Book getInstance() {
		return instance;
	}
	// ...
}

The 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:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:p="http://primefaces.org/ui"
	xmlns:s="http://jboss.org/seam/faces"
	xmlns:pm="http://primefaces.org/mobile">

<h:head>
	<title>Book</title>
	<style type="text/css">
		.ui-widget, .ui-widget .ui-widget {
			font-size: 90% !important;
		}
	</style>
</h:head>

<h:body>

	<p:messages globalOnly="false" autoUpdate="true" showDetail="true" showSummary="true"/>

	<p:fieldset legend="Book #{bookHomeCRUD.idDefined ? bookCRUD.id : ''}">
		<h:form id="bookForm">
			<h:panelGrid columns="3" >
				<p:outputLabel for="title" value="Title"/>
				<p:inputText id="title" value="#{bookCRUD.title}" required="true" type="text">

				</p:inputText>
				<p:message for="title" />
				<p:outputLabel for="author" value="Author"/>
				<p:inputText id="author" value="#{bookCRUD.author}" required="true" type="text"/>
				<p:message for="author" />
				<p:outputLabel for="pages" value="Pages"/>
				<p:inputText id="pages" value="#{bookCRUD.pages}" required="true" type="number">
					<f:convertNumber integerOnly="true" maxFractionDigits="0"/>
				</p:inputText>
				<p:message for="pages" />
			</h:panelGrid>
			<p:commandButton value="Save" action="#{bookHomeCRUD.persist}"  rendered="#{!bookHomeCRUD.idDefined}" ajax="false" >

			</p:commandButton>
			<p:commandButton value="Update" action="#{bookHomeCRUD.update}" rendered="#{bookHomeCRUD.idDefined}" ajax="false" >
				<f:param name="id" value="#{bookCRUD.id}"/>
			</p:commandButton>

		</h:form>
		<h:link value="Create New"/>
	</p:fieldset>

	<p:separator />

	<p:dataTable id="bookList" value="#{bookListCRUD}" var="_book">
		<f:facet name="header">Books</f:facet>
		<p:column headerText="Id">#{_book.id}</p:column>
		<p:column headerText="Title">#{_book.title}</p:column>
		<p:column headerText="Author">#{_book.author}</p:column>
		<p:column headerText="Pages">#{_book.pages}</p:column>
		<p:column>
			<h:form>
				<h:link value="Edit" outcome="bookCRUD.xhtml">
					<f:param name="id" value="#{_book.id}" />
				</h:link>
				<p:spacer width="5"/>
				<p:commandLink value="Remove" action="#{bookHomeCRUD.remove}" ajax="false">
					<f:param name="id" value="#{_book.id}" />
				</p:commandLink>
			</h:form>
		</p:column>
	</p:dataTable>

</h:body>
</html>

Remarks
With this approach you finally get to annotate the interested property in the entity class.
Constraint violations are detected during the PROCESS_VALIDATIONS phase, as desired.
There is coupling between the entity class and the bean that saves the entity, which is bad.
If you have more beans that save the entity, you’ll get bad side effects.

 

Requirements:
JBoss Developer Studio 5
JBoss AS 7.1.1.Final
Seam 3.1.0.Final Validation Module (for dependency injection in validators)
Seam 3.1.0.Final Solder Module (needed by Validation Module)
de.hashcode:jsr303-validators:1.1 (for some utility methods in the validator)

Annotation

package org.lucaster.validator;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Constraint(validatedBy = { UniqueKeysValidator.class })
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueKeys {

	String[] columnNames();

	String message() default "Values are not unique";

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};

	@Target({ ElementType.TYPE })
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	@interface List {
		UniqueKeys[] value();
	}
}

Validator

package org.lucaster.validator;

import static de.hashcode.validation.ReflectionUtils.getIdField;
import static de.hashcode.validation.ReflectionUtils.getPropertyValue;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder;
import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext;

public class UniqueKeysValidator implements	ConstraintValidator<UniqueKeys, Serializable> {

	@Inject private EntityManager entityManager;

	private UniqueKeys constraintAnnotation;

	private String[] columnNames;

	public UniqueKeysValidator() {}

	@Override
	public void initialize(final UniqueKeys constraintAnnotation) {
		this.columnNames = constraintAnnotation.columnNames();
		this.constraintAnnotation = constraintAnnotation;
	}

	@Override
	public boolean isValid(Serializable target,	ConstraintValidatorContext context) {

		final Class<?> entityClass = target.getClass();

		final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

		final CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();

		final Root<?> root = criteriaQuery.from(entityClass);

		List<Predicate> predicates = new ArrayList<Predicate>(columnNames.length);

		try {

			for (int i = 0; i < columnNames.length; i++) {

				String propertyName = columnNames[i];
				PropertyDescriptor desc = new PropertyDescriptor(propertyName, entityClass);
				Method readMethod = desc.getReadMethod();
				Object propertyValue = readMethod.invoke(target);

				Predicate predicate = criteriaBuilder.equal(root.get(propertyName), propertyValue);

				predicates.add(predicate);
			}

			Field idField = getIdField(entityClass);
			String idProperty = idField.getName();
			Object idValue = getPropertyValue(target, idProperty);

			if (idValue != null) {
				Predicate idNotEqualsPredicate = criteriaBuilder.notEqual(root.get(idProperty), idValue);
				predicates.add(idNotEqualsPredicate);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		criteriaQuery.select(root).where(predicates.toArray(new Predicate[predicates.size()]));

		TypedQuery<Object> typedQuery = entityManager.createQuery(criteriaQuery);

		List<Object> resultSet = typedQuery.getResultList();

		if (!resultSet.isEmpty()) {

			// This string will contain all column names separated by a comma. Example: "title,author,editor"
			String names = "";
			for (String columnName : columnNames) {
				names += columnName;
				names += ",";
			}
			names = names.substring(0, names.length() - 1);

			ConstraintViolationBuilder cvb = context.buildConstraintViolationWithTemplate(constraintAnnotation.message());
			NodeBuilderDefinedContext nbdc = cvb.addNode(names);
			ConstraintValidatorContext cvc = nbdc.addConstraintViolation();
			cvc.disableDefaultConstraintViolation();
			return false;
		}

		return true;
	}
}

Usage in entity bean

package org.lucaster.model;

import javax.persistence.Column;
import javax.persistence.Entity;

import org.hibernate.validator.constraints.NotEmpty;
import org.lucaster.validator.UniqueKeys;

@Entity
@UniqueKeys(columnNames = { "title", "author" }) // multiple column constraint
// @UniqueKeys(columnNames = { "title" }) // single column constraint
// @UniqueKeys.List(value = { @UniqueKeys(columnNames = { "title", "author" }), @UniqueKeys(columnNames = { "pages" }) }) // multiple constraints
public class Book extends Model {

	private static final long serialVersionUID = 8519973666976987438L;

	@NotEmpty @Column(unique = true) private String title;
	private String author;
	private int pages;

	@Override
	public String toString() {
		return title + ", " + author + ", " + pages;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public int getPages() {
		return pages;
	}

	public void setPages(int pages) {
		this.pages = pages;
	}
}

Usage in controller – version 1

public boolean persist() {

	try {

		instance = entityManager.merge(instance);
		entityManager.flush();
		id = instance.getId();
		return true;

	}
	// We expect only unique constraint violations
	catch (ConstraintViolationException e) {

		e.printStackTrace();

		Set<ConstraintViolation<?>> violations = e.getConstraintViolations();

		for (Object violationObject : violations.toArray()) {

			@SuppressWarnings("unchecked")
			ConstraintViolation<Book> violation = (ConstraintViolation<Book>) violationObject;

			// Comma separated list of property names
			String names = violation.getPropertyPath().toString();

			// Get an array of single property names
			String[] properties = names.split(",", -1);

			// Add FacesMessage near each input field
			for (String property : properties) {
				FacesUtil.error("bookForm-" + property,	violation.getMessage(), violation.getMessage());
			}

			// Add also a global FacesMessage
			FacesUtil.error(null, violation.getMessage(), "Combination of properties '" + names + "' must be unique");
		}
		return false;
	}
}

Usage in controller – version 2

(omissis)

The 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:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:p="http://primefaces.org/ui"
	xmlns:s="http://jboss.org/seam/faces"
	xmlns:pm="http://primefaces.org/mobile">

<h:head>
	<title>Book</title>
	<style type="text/css">
		.ui-widget, .ui-widget .ui-widget {
			font-size: 90% !important;
		}
	</style>
</h:head>

<h:body>

	<p:messages globalOnly="false" autoUpdate="true" showDetail="true" showSummary="true"/>

	<p:fieldset legend="Book #{bookHomeCRUD.idDefined ? bookCRUD.id : ''}">
		<h:form id="bookForm">
			<h:panelGrid columns="3" >
				<p:outputLabel for="title" value="Title"/>
				<p:inputText id="title" value="#{bookCRUD.title}" required="true" type="text">

				</p:inputText>
				<p:message for="title" />
				<p:outputLabel for="author" value="Author"/>
				<p:inputText id="author" value="#{bookCRUD.author}" required="true" type="text"/>
				<p:message for="author" />
				<p:outputLabel for="pages" value="Pages"/>
				<p:inputText id="pages" value="#{bookCRUD.pages}" required="true" type="number">
					<f:convertNumber integerOnly="true" maxFractionDigits="0"/>
				</p:inputText>
				<p:message for="pages" />
			</h:panelGrid>
			<p:commandButton value="Save" action="#{bookHomeCRUD.persist}"  rendered="#{!bookHomeCRUD.idDefined}" ajax="false" >

			</p:commandButton>
			<p:commandButton value="Update" action="#{bookHomeCRUD.update}" rendered="#{bookHomeCRUD.idDefined}" ajax="false" >
				<f:param name="id" value="#{bookCRUD.id}"/>
			</p:commandButton>

		</h:form>
		<h:link value="Create New"/>
	</p:fieldset>

	<p:separator />

	<p:dataTable id="bookList" value="#{bookListCRUD}" var="_book">
		<f:facet name="header">Books</f:facet>
		<p:column headerText="Id">#{_book.id}</p:column>
		<p:column headerText="Title">#{_book.title}</p:column>
		<p:column headerText="Author">#{_book.author}</p:column>
		<p:column headerText="Pages">#{_book.pages}</p:column>
		<p:column>
			<h:form>
				<h:link value="Edit" outcome="bookCRUD.xhtml">
					<f:param name="id" value="#{_book.id}" />
				</h:link>
				<p:spacer width="5"/>
				<p:commandLink value="Remove" action="#{bookHomeCRUD.remove}" ajax="false">
					<f:param name="id" value="#{_book.id}" />
				</p:commandLink>
			</h:form>
		</p:column>
	</p:dataTable>

</h:body>
</html>

Remarks
This approach lets you define single column AND multiple column constraints.
Constraint violations are detected when the EntityManager flushes, during INVOKE_APPLICATION phase, instead of as part of PROCESS_VALIDATIONS phase.
Constraints violations must be handed programmatically to display messages near the interested input fields.
You need to establish a convention between input fields ids and property names. If you change the input fields ids, you also have to change the code. You must also consider the convention used by the validator to communicate the column names (see code).
Usage in controller – version 1: Notice how the property names are extracted, in respect to the convetion used by the validator.
Usage in controller – version 2: It would be very similar to the one in Part 1.

 

Requirements:
JBoss Developer Studio 5
JBoss AS 7.1.1.Final
Seam 3.1.0.Final Validation Module (for dependency injection in validators)
Seam 3.1.0.Final Solder Module (needed by Validation Module)
de.hashcode:jsr303-validators:1.1 (for some utility methods in the validator)

Annotation

package org.lucaster.validator;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Constraint(validatedBy = { org.lucaster.validator.UniqueKeyValidator.class })
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueKey {

	String property();

	String message() default "Value is not unique";

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};

	@Target({ ElementType.TYPE })
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	@interface List {
		UniqueKey[] value();
	}

}

Validator

package org.lucaster.validator;

import static de.hashcode.validation.ReflectionUtils.getIdField;
import static de.hashcode.validation.ReflectionUtils.getPropertyValue;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder;
import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext;

public class UniqueKeyValidator implements
		ConstraintValidator<UniqueKey, Serializable> {

	@Inject private EntityManager entityManager;

	private UniqueKey constraintAnnotation;

	public UniqueKeyValidator() {}

	public UniqueKeyValidator(final EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

	@Override
	public void initialize(final UniqueKey constraintAnnotation) {
		this.constraintAnnotation = constraintAnnotation;
	}

	@Override
	public boolean isValid(final Serializable target,
			final ConstraintValidatorContext context) {

		if (entityManager == null) {
			// eclipselink may be configured with a BeanValidationListener that
			// validates an entity on prePersist
			// In this case we don't want to and we cannot check anything (the
			// entityManager is not set)
			//
			// Alternatively, you can disalbe bean validation during jpa
			// operations
			// by adding the property "javax.persistence.validation.mode" with
			// value "NONE" to persistence.xml
			return true;
		}

		final Class<?> entityClass = target.getClass();

		final CriteriaBuilder criteriaBuilder = entityManager
				.getCriteriaBuilder();

		final CriteriaQuery<Object> criteriaQuery = criteriaBuilder
				.createQuery();

		final Root<?> root = criteriaQuery.from(entityClass);

		try {
			final Object propertyValue = getPropertyValue(target,
					constraintAnnotation.property());
			final Predicate uniquePropertyPredicate = criteriaBuilder.equal(
					root.get(constraintAnnotation.property()), propertyValue);

			final Field idField = getIdField(entityClass);
			final String idProperty = idField.getName();
			final Object idValue = getPropertyValue(target, idProperty);

			if (idValue != null) {
				final Predicate idNotEqualsPredicate = criteriaBuilder
						.notEqual(root.get(idProperty), idValue);
				criteriaQuery.select(root).where(uniquePropertyPredicate,
						idNotEqualsPredicate);
			} else {
				criteriaQuery.select(root).where(uniquePropertyPredicate);
			}

		} catch (final Exception e) {
			throw new RuntimeException(
					"An error occurred when trying to create the jpa predicate for the @UniqueKey '"
							+ constraintAnnotation.property()
							+ "' on bean "
							+ entityClass + ".", e);
		}

		final List<Object> resultSet = entityManager.createQuery(criteriaQuery)
				.getResultList();

		if (!resultSet.isEmpty()) {
			ConstraintViolationBuilder cvb = context
					.buildConstraintViolationWithTemplate(constraintAnnotation
							.message());
			NodeBuilderDefinedContext nbdc = cvb.addNode(constraintAnnotation
					.property());
			ConstraintValidatorContext cvc = nbdc.addConstraintViolation();
			cvc.disableDefaultConstraintViolation();
			return false;
		}

		return true;
	}

}

Usage in entity bean

package org.lucaster.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import org.hibernate.validator.constraints.NotEmpty;

@Entity
@UniqueKey(property = "title")
// @UniqueKey.List(value = { @UniqueKey(property = { "title" }), @UniqueKey(property = { "author" }) }) // more than one unique keys
public class Book extends Model {

	private static final long serialVersionUID = 8519973666976987438L;

	@NotEmpty @Column(unique = true) private String title;
	private String author;
	private int pages;

	@Override
	public String toString() {
		return title + ", " + author + ", " + pages;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public int getPages() {
		return pages;
	}

	public void setPages(int pages) {
		this.pages = pages;
	}
}

Usage in controller – version 1

public boolean persist() {

	try {

		instance = entityManager.merge(instance);
		entityManager.flush();
		id = instance.getId();
		return true;

	} catch (ConstraintViolationException e) {

		e.printStackTrace();

		Set<Book> violations = e.getConstraintViolations();

		for (Object violationObject : violations.toArray()) {
			ConstraintViolation violation = (ConstraintViolation) violationObject;
			FacesUtil.error("bookForm-" + violation.getPropertyPath().toString(), violation.getMessage(), violation.getMessage());
		}

		return false;
	}
}

Usage in controller – version 2

@Inject private javax.validation.Validator validator;

public boolean persist() {

	Set<Book> violations = validator.validate(instance);

	if (!violations.isEmpty()) {
		for (Object violationObject : violations.toArray()) {
			ConstraintViolation violation = (ConstraintViolation) violationObject;
			FacesUtil.error("bookForm-" + violation.getPropertyPath().toString(), violation.getMessage(), violation.getMessage());
		}
		return false;
	}

	else {
		instance = entityManager.merge(instance);
		entityManager.flush();
		id = instance.getId();
		return true;
	}
}

The 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:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:p="http://primefaces.org/ui"
	xmlns:s="http://jboss.org/seam/faces"
	xmlns:pm="http://primefaces.org/mobile">

<h:head>
	<title>Book</title>
	<style type="text/css">
		.ui-widget, .ui-widget .ui-widget {
			font-size: 90% !important;
		}
	</style>
</h:head>

<h:body>

	<p:messages globalOnly="false" autoUpdate="true" showDetail="true" showSummary="true"/>

	<p:fieldset legend="Book #{bookHomeCRUD.idDefined ? bookCRUD.id : ''}">
		<h:form id="bookForm">
			<h:panelGrid columns="3" >
				<p:outputLabel for="title" value="Title"/>
				<p:inputText id="title" value="#{bookCRUD.title}" required="true" type="text">

				</p:inputText>
				<p:message for="title" />
				<p:outputLabel for="author" value="Author"/>
				<p:inputText id="author" value="#{bookCRUD.author}" required="true" type="text"/>
				<p:message for="author" />
				<p:outputLabel for="pages" value="Pages"/>
				<p:inputText id="pages" value="#{bookCRUD.pages}" required="true" type="number">
					<f:convertNumber integerOnly="true" maxFractionDigits="0"/>
				</p:inputText>
				<p:message for="pages" />
			</h:panelGrid>
			<p:commandButton value="Save" action="#{bookHomeCRUD.persist}"  rendered="#{!bookHomeCRUD.idDefined}" ajax="false" >

			</p:commandButton>
			<p:commandButton value="Update" action="#{bookHomeCRUD.update}" rendered="#{bookHomeCRUD.idDefined}" ajax="false" >
				<f:param name="id" value="#{bookCRUD.id}"/>
			</p:commandButton>

		</h:form>
		<h:link value="Create New"/>
	</p:fieldset>

	<p:separator />

	<p:dataTable id="bookList" value="#{bookListCRUD}" var="_book">
		<f:facet name="header">Books</f:facet>
		<p:column headerText="Id">#{_book.id}</p:column>
		<p:column headerText="Title">#{_book.title}</p:column>
		<p:column headerText="Author">#{_book.author}</p:column>
		<p:column headerText="Pages">#{_book.pages}</p:column>
		<p:column>
			<h:form>
				<h:link value="Edit" outcome="bookCRUD.xhtml">
					<f:param name="id" value="#{_book.id}" />
				</h:link>
				<p:spacer width="5"/>
				<p:commandLink value="Remove" action="#{bookHomeCRUD.remove}" ajax="false">
					<f:param name="id" value="#{_book.id}" />
				</p:commandLink>
			</h:form>
		</p:column>
	</p:dataTable>

</h:body>
</html>

Remarks
Remember to use THIS version of the UniqueKey class, otherwise you will end up using the one from the Maven dependency and everything will break!
This approach only lets you define single column unique constraints.
Constraint violations are detected when the EntityManager flushes, during INVOKE_APPLICATION phase, instead of as part of PROCESS_VALIDATIONS phase.
Constraints violations must be handed programmatically to display messages near the interested input fields.
You need to establish a convention between input fields ids and property names. If you change the input fields ids, you also have to change the code.
Usage in controller – version 2: in this version you check for constraints before persisting, preventing the exception from happening. However, if your entity bean has some @NotNull properties that are set in the @PrePersist or @PreUpdate, you’ll get constraint violations for those fields.
Usage in controller – version 1: this version is more robust, considering the above statement, because the only constraint violation you’ll get will be most probably the unique constraint violation you expect.

 

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>com.lucaster.jeewp</groupId>
	<artifactId>javaeeWebProject</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>Java EE 6 webapp project</name>
	<description>A starter Java EE 6 webapp project for use on JBoss AS 7.1 / EAP 6, generated from the jboss-javaee6-webapp archetype</description>

	<properties>
		<!-- Explicitly declaring the source encoding eliminates the following
			message: -->
		<!-- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered
			resources, i.e. build is platform dependent! -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<!-- Define the version of JBoss' Java EE 6 APIs and Tools we want to import. -->
		<jboss.bom.version>1.0.0.M7</jboss.bom.version>
		<!-- Alternatively, comment out the above line, and un-comment the line
			below to use version 1.0.0.M7-redhat-1 which is a release certified to work
			with JBoss EAP 6. It requires you have access to the JBoss EAP 6 maven repository. -->
		<!-- <jboss.bom.version>1.0.0.M7-redhat-1</jboss.bom.version>> -->
		<seam.version>3.1.0.Final</seam.version>
		<freemarker.version>2.3.9</freemarker.version>
		<org.apache.httpcomponents.version>4.2</org.apache.httpcomponents.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<!-- JBoss distributes a complete set of Java EE 6 APIs including a Bill
				of Materials (BOM). A BOM specifies the versions of a "stack" (or a collection)
				of artifacts. We use this here so that we always get the correct versions
				of artifacts. Here we use the jboss-javaee-6.0-with-tools stack (you can
				read this as the JBoss stack of the Java EE 6 APIs, with some extras tools
				for your project, such as Arquillian for testing) and the jboss-javaee-6.0-with-hibernate
				stack you can read this as the JBoss stack of the Java EE 6 APIs, with extras
				from the Hibernate family of projects) -->
			<dependency>
				<groupId>org.jboss.bom</groupId>
				<artifactId>jboss-javaee-6.0-with-tools</artifactId>
				<version>${jboss.bom.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>org.jboss.bom</groupId>
				<artifactId>jboss-javaee-6.0-with-hibernate</artifactId>
				<version>${jboss.bom.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>org.jboss.seam</groupId>
				<artifactId>seam-bom</artifactId>
				<version>${seam.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<repositories>
		<!-- For PrimeFaces -->
		<repository>
			<id>prime-repo</id>
			<name>PrimeFaces Maven Repository</name>
			<url>http://repository.primefaces.org</url>
			<layout>default</layout>
		</repository>
		<!-- For Seam -->
		<repository>
			<id>jboss-public</id>
			<url>http://repository.jboss.org/nexus/content/groups/public-jboss/</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

	<dependencies>

		<!-- First declare the APIs we depend on and need for compilation. All
			of them are provided by JBoss AS 7 -->

		<!-- Import the CDI API, we use provided scope as the API is included in
			JBoss AS 7 -->
		<dependency>
			<groupId>javax.enterprise</groupId>
			<artifactId>cdi-api</artifactId>
			<scope>provided</scope>
		</dependency>

		<!-- Import the Common Annotations API (JSR-250), we use provided scope
			as the API is included in JBoss AS 7 -->
		<dependency>
			<groupId>org.jboss.spec.javax.annotation</groupId>
			<artifactId>jboss-annotations-api_1.1_spec</artifactId>
			<scope>provided</scope>
		</dependency>

		<!-- Import the JAX-RS API, we use provided scope as the API is included
			in JBoss AS 7 -->
		<dependency>
			<groupId>org.jboss.spec.javax.ws.rs</groupId>
			<artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
			<scope>provided</scope>
		</dependency>

		<!-- Import the JPA API, we use provided scope as the API is included in
			JBoss AS 7 -->
		<dependency>
			<groupId>org.hibernate.javax.persistence</groupId>
			<artifactId>hibernate-jpa-2.0-api</artifactId>
			<scope>provided</scope>
		</dependency>

		<!-- Import the EJB API, we use provided scope as the API is included in
			JBoss AS 7 -->
		<dependency>
			<groupId>org.jboss.spec.javax.ejb</groupId>
			<artifactId>jboss-ejb-api_3.1_spec</artifactId>
			<scope>provided</scope>
		</dependency>

		<!-- JSR-303 (Bean Validation) Implementation -->
		<!-- Provides portable constraints such as @Email -->
		<!-- Hibernate Validator is shipped in JBoss AS 7 -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<scope>provided</scope>
			<exclusions>
				<exclusion>
					<groupId>org.slf4j</groupId>
					<artifactId>slf4j-api</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<!-- Import the JSF API, we use provided scope as the API is included in
			JBoss AS 7 -->
		<dependency>
			<groupId>org.jboss.spec.javax.faces</groupId>
			<artifactId>jboss-jsf-api_2.1_spec</artifactId>
			<scope>provided</scope>
		</dependency>

		<!-- Now we declare any tools needed -->

		<!-- Annotation processor to generate the JPA 2.0 metamodel classes for
			typesafe criteria queries -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-jpamodelgen</artifactId>
			<scope>provided</scope>
		</dependency>

		<!-- Annotation processor that raising compilation errors whenever constraint
			annotations are incorrectly used. -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator-annotation-processor</artifactId>
			<scope>provided</scope>
		</dependency>

		<!-- Needed for running tests (you may also use TestNG) -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- Optional, but highly recommended -->
		<!-- Arquillian allows you to test enterprise code such as EJBs and Transactional(JTA)
			JPA from JUnit/TestNG -->
		<dependency>
			<groupId>org.jboss.arquillian.junit</groupId>
			<artifactId>arquillian-junit-container</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.jboss.arquillian.protocol</groupId>
			<artifactId>arquillian-protocol-servlet</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- PrimeFaces and PrimeFaces Mobile. PrimeFaces version is still 9.2
			for compatibility with Mobile 0.9.2 0.9.3 will be compatible with 3.3 -->
		<dependency>
			<groupId>org.primefaces</groupId>
			<artifactId>primefaces</artifactId>
			<version>3.2</version>
		</dependency>
		<dependency>
			<groupId>org.primefaces</groupId>
			<artifactId>primefaces-mobile</artifactId>
			<version>0.9.2</version>
		</dependency>

		<!-- Seam Solder module now includes also Seam Catch module, Seam Config module, Seam
			Solder Logging module and Seam Servlet module -->

		<dependency>
			<groupId>org.jboss.solder</groupId>
			<artifactId>solder-api</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.solder</groupId>
			<artifactId>solder-impl</artifactId>
			<scope>runtime</scope>
		</dependency>

		<!-- Seam Persistence module -->

		<dependency>
			<groupId>org.jboss.seam.persistence</groupId>
			<artifactId>seam-persistence-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.persistence</groupId>
			<artifactId>seam-persistence</artifactId>
			<scope>runtime</scope>
		</dependency>

		<!-- Seam Faces module and its dependencies -->

		<dependency>
			<groupId>org.jboss.seam.faces</groupId>
			<artifactId>seam-faces-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.faces</groupId>
			<artifactId>seam-faces</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.international</groupId>
			<artifactId>seam-international-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.international</groupId>
			<artifactId>seam-international</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>joda-time</groupId>
			<artifactId>joda-time</artifactId>
		</dependency>
		<dependency>
			<groupId>com.ocpsoft</groupId>
			<artifactId>prettyfaces-jsf2</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.persistence</groupId>
			<artifactId>seam-persistence-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.persistence</groupId>
			<artifactId>seam-persistence</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.security</groupId>
			<artifactId>seam-security-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.security</groupId>
			<artifactId>seam-security</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-compiler</artifactId>
		</dependency>

		<!-- Seam Security module and its dependencies -->

		<dependency>
			<groupId>org.jboss.seam.security</groupId>
			<artifactId>seam-security-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.security</groupId>
			<artifactId>seam-security</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.international</groupId>
			<artifactId>seam-international-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.international</groupId>
			<artifactId>seam-international</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>joda-time</groupId>
			<artifactId>joda-time</artifactId>
		</dependency>
		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-compiler</artifactId>
		</dependency>

		<!-- Seam Validation module -->

		<dependency>
			<groupId>org.jboss.seam.validation</groupId>
			<artifactId>seam-validation-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.validation</groupId>
			<artifactId>seam-validation</artifactId>
			<scope>runtime</scope>
		</dependency>

		<!-- Seam Mail module and its dependencies -->

		<dependency>
			<groupId>org.jboss.seam.mail</groupId>
			<artifactId>seam-mail-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.mail</groupId>
			<artifactId>seam-mail</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity</artifactId>
		</dependency>
		<dependency>
			<groupId>freemarker</groupId>
			<artifactId>freemarker</artifactId>
			<version>${freemarker.version}</version>
		</dependency>

		<!-- Seam Remoting module and its dependentices (seam-remoting-api doesn't exist -->

		<dependency>
			<groupId>org.jboss.seam.remoting</groupId>
			<artifactId>seam-remoting</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.international</groupId>
			<artifactId>seam-international-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.international</groupId>
			<artifactId>seam-international</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>joda-time</groupId>
			<artifactId>joda-time</artifactId>
		</dependency>

		<!-- Seam Social module -->

		<dependency>
			<groupId>org.jboss.seam.social</groupId>
			<artifactId>seam-social-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.social</groupId>
			<artifactId>seam-social</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.social</groupId>
			<artifactId>seam-social-facebook</artifactId>
			<version>${seam.version}</version>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.social</groupId>
			<artifactId>seam-social-linkedin</artifactId>
			<version>${seam.version}</version>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.social</groupId>
			<artifactId>seam-social-twitter</artifactId>
			<version>${seam.version}</version>
		</dependency>

		<!-- Seam JMS module (requires standalone-full.xml)-->

		<dependency>
			<groupId>org.jboss.seam.jms</groupId>
			<artifactId>seam-jms-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.jms</groupId>
			<artifactId>seam-jms</artifactId>
			<scope>runtime</scope>
		</dependency>

		<!-- Seam JCR module -->

		<dependency>
			<groupId>org.jboss.seam.jcr</groupId>
			<artifactId>seam-jcr-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.jcr</groupId>
			<artifactId>seam-jcr</artifactId>
			<scope>runtime</scope>
		</dependency>

		<!-- Seam Reports module -->

		<dependency>
			<groupId>org.jboss.seam.reports</groupId>
			<artifactId>seam-reports-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.reports</groupId>
			<artifactId>seam-reports-jasper</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.reports</groupId>
			<artifactId>seam-reports-pentaho</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.reports</groupId>
			<artifactId>seam-reports-xdocreport</artifactId>
			<scope>runtime</scope>
		</dependency>

		<!-- Seam REST module -->
		<!-- To solve "Multiple TemplatingProviders found on classpath. Select the prefered one." add this to seam-beans.xml: -->
		<!--
		<beans xmlns:rest="urn:java:org.jboss.seam.rest:org.jboss.seam.rest.exceptions">
			<rest:SeamRestConfiguration preferedTemplatingProvider="org.jboss.seam.rest.templating.freemarker.FreeMarkerProvider"/>
		</beans>
		-->

		<dependency>
			<groupId>org.jboss.seam.rest</groupId>
			<artifactId>seam-rest-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam.rest</groupId>
			<artifactId>seam-rest</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity</artifactId>
		</dependency>
		<dependency>
			<groupId>freemarker</groupId>
			<artifactId>freemarker</artifactId>
			<version>${freemarker.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpcore</artifactId>
			<version>${org.apache.httpcomponents.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>${org.apache.httpcomponents.version}</version>
		</dependency>

	</dependencies>

	<build>
		<!-- Maven will append the version to the finalName (which is the name
			given to the generated war, and hence the context root) -->
		<finalName>${project.artifactId}</finalName>
		<plugins>
			<!-- Compiler plugin enforces Java 1.6 compatibility and activates annotation
				processors -->
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.1.1</version>
				<configuration>
					<!-- Java EE 6 doesn't require web.xml, Maven needs to catch up! -->
					<failOnMissingWebXml>false</failOnMissingWebXml>
				</configuration>
			</plugin>
			<!-- The JBoss AS plugin deploys your war to a local JBoss AS container -->
			<!-- To use, run: mvn package jboss-as:deploy -->
			<plugin>
				<groupId>org.jboss.as.plugins</groupId>
				<artifactId>jboss-as-maven-plugin</artifactId>
				<version>7.1.1.Final</version>
			</plugin>
		</plugins>
	</build>

	<profiles>
		<profile>
			<!-- The default profile skips all tests, though you can tune it to run
				just unit tests based on a custom pattern -->
			<!-- Seperate profiles are provided for running all tests, including Arquillian
				tests that execute in the specified container -->
			<id>default</id>
			<activation>
				<activeByDefault>true</activeByDefault>
			</activation>
			<build>
				<plugins>
					<plugin>
						<artifactId>maven-surefire-plugin</artifactId>
						<version>2.4.3</version>
						<configuration>
							<skip>true</skip>
						</configuration>
					</plugin>
				</plugins>
			</build>
		</profile>

		<profile>
			<!-- An optional Arquillian testing profile that executes tests in your
				JBoss AS instance -->
			<!-- This profile will start a new JBoss AS instance, and execute the
				test, shutting it down when done -->
			<!-- Run with: mvn clean test -Parq-jbossas-managed -->
			<id>arq-jbossas-managed</id>
			<dependencies>
				<dependency>
					<groupId>org.jboss.as</groupId>
					<artifactId>jboss-as-arquillian-container-managed</artifactId>
					<scope>test</scope>
				</dependency>
			</dependencies>
		</profile>

		<profile>
			<!-- An optional Arquillian testing profile that executes tests in a remote
				JBoss AS instance -->
			<!-- Run with: mvn clean test -Parq-jbossas-remote -->
			<id>arq-jbossas-remote</id>
			<dependencies>
				<dependency>
					<groupId>org.jboss.as</groupId>
					<artifactId>jboss-as-arquillian-container-remote</artifactId>
					<scope>test</scope>
				</dependency>
			</dependencies>
		</profile>

		<profile>
			<!-- When built in OpenShift the 'openshift' profile will be used when
				invoking mvn. -->
			<!-- Use this profile for any OpenShift specific customization your app
				will need. -->
			<!-- By default that is to put the resulting archive into the 'deployments'
				folder. -->
			<!-- http://maven.apache.org/guides/mini/guide-building-for-different-environments.html -->
			<id>openshift</id>
			<build>
				<plugins>
					<plugin>
						<artifactId>maven-war-plugin</artifactId>
						<version>2.1.1</version>
						<configuration>
							<outputDirectory>deployments</outputDirectory>
							<warName>ROOT</warName>
						</configuration>
					</plugin>
				</plugins>
			</build>
		</profile>

	</profiles>
</project>

seam-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:s="urn:java:ee"
	xsi:schemaLocation="

http://java.sun.com/xml/ns/javaee

http://docs.jboss.org/cdi/beans_1_0.xsd"

	xmlns:rest="urn:java:org.jboss.seam.rest:org.jboss.seam.rest.exceptions"
	xmlns:mail="urn:java:org.jboss.seam.mail.core">

	<!-- Requires Seam REST module dependencies to work -->
	<rest:SeamRestConfiguration preferedTemplatingProvider="org.jboss.seam.rest.templating.freemarker.FreeMarkerProvider"/>

	<!-- Requires Seam Mail module dependencies to work -->
	<mail:MailConfig serverHost="my-server.test.com"
		serverPort="25" username="abcdef" password="123456" >
		<s:modifies />
	</mail:MailConfig>

</beans>

If you have both Seam Mail and one or more among Seam Persistence, Seam Security, Seam Faces, building you project will give these errors:

Error
Sun Jun 03 15:06:14 CEST 2012
Errors running builder 'CDI (Context and Dependency Injection) Builder' on project 'javaeeWebProject'.

java.lang.NullPointerException
	at org.jboss.tools.cdi.seam.core.persistence.CDISeamPersistenceExtension.buildBeans(CDISeamPersistenceExtension.java:109)
	at org.jboss.tools.cdi.internal.core.impl.CDIProject.update(CDIProject.java:1121)
	at org.jboss.tools.cdi.internal.core.impl.definition.DefinitionContext.applyWorkingCopy(DefinitionContext.java:390)
	at org.jboss.tools.cdi.core.CDICoreBuilder.build(CDICoreBuilder.java:230)
	at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:728)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:199)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:239)
	at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:292)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:295)
	at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:351)
	at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:374)
	at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:143)
	at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:241)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
eclipse.buildId=unknown
java.version=1.6.0_31
java.vendor=Sun Microsystems Inc.
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_GB
Framework arguments:  -product com.jboss.jbds.product.product
Command-line arguments:  -os win32 -ws win32 -arch x86 -product com.jboss.jbds.product.product

Error
Sun Jun 03 15:06:14 CEST 2012
Problems occurred when invoking code from plug-in: "org.eclipse.core.resources".

java.lang.NullPointerException
	at org.jboss.tools.cdi.seam.core.persistence.CDISeamPersistenceExtension.buildBeans(CDISeamPersistenceExtension.java:109)
	at org.jboss.tools.cdi.internal.core.impl.CDIProject.update(CDIProject.java:1121)
	at org.jboss.tools.cdi.internal.core.impl.definition.DefinitionContext.applyWorkingCopy(DefinitionContext.java:390)
	at org.jboss.tools.cdi.core.CDICoreBuilder.build(CDICoreBuilder.java:230)
	at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:728)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:199)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:239)
	at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:292)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:295)
	at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:351)
	at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:374)
	at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:143)
	at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:241)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

Despite those, the build process will complete successfully and you’ll be able to deploy the app on JBoss AS 7.1.1.Final