I'm practicing JSF+JPA and got stuck with the following exception:
19/03/2013 00:04:18 org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() for servlet [Faces Servlet] in context with path [/K19-Futebol] threw exception [/times.xhtml @11,60 <ui:include src="formulario-novo-time.xhtml"> Invalid path : formulario-novo-time.xhtml] with root cause
javax.faces.view.facelets.TagAttributeException: /times.xhtml @11,60 <ui:include src="formulario-novo-time.xhtml"> Invalid path : formulario-novo-time.xhtml
[...]
at filters.JPAFilter.doFilter(JPAFilter.java:42)
[...]
As I followed the BalusC link (How to include another XHTML in XHTML using JSF 2.0 Facelets?) I think the problem does not concern about Facelets, but this filter:
@WebFilter(servletNames = {"Faces Servlet"})
public class JPAFilter implements Filter {
private EntityManagerFactory factory;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.factory = Persistence.createEntityManagerFactory("K19-Futebol-PU");
}
@Override
public void destroy() {
this.factory.close();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// CHEGADA
EntityManager manager = this.factory.createEntityManager();
request.setAttribute("EntityManager", manager);
manager.getTransaction().begin();
// CHEGADA
// FACES SERVLET
chain.doFilter(request, response);
// FACES SERVLET
// SAÍDA
try {
manager.getTransaction().commit();
} catch (Exception e) {
manager.getTransaction().rollback();
} finally {
manager.close();
}
// SAÍDA
}
}
I also ask your opinion if using filter this way is a good pratice, I mean, using a filter for the model/persistence layer.
Other classes to clarify:
@Entity
public class Time implements Serializable { //in portuguese 'Time' means Team (e.g.:football Team)
@Id
@GeneratedValue
private Long id;
private String nome;
private String tecnico;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getTecnico() {
return tecnico;
}
public void setTecnico(String tecnico) {
this.tecnico = tecnico;
}
}
The managed bean:
@ManagedBean
public class TimeBean {
public Time getTime() {
return time;
}
public void setTime(Time time) {
this.time = time;
}
public void setTimes(List<Time> times) {
this.times = times;
}
private Time time = new Time();
private List<Time> times;
public void adiciona() {
EntityManager manager = this.getManager();
TimeRepository repository = new TimeRepository(manager);
if (this.time.getId() == null) {
repository.adiciona(this.time);
} else {
repository.atualiza(this.time);
}
this.time = new Time();
this.times = null;
}
public void preparaAlteracao() {
Map<String, String> params = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap();
Long id = Long.parseLong(params.get("id"));
EntityManager manager = this.getManager();
TimeRepository repository = new TimeRepository(manager);
this.time = repository.procura(id);
}
public void remove() {
Map<String, String> params = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap();
Long id = Long.parseLong(params.get("id"));
EntityManager manager = this.getManager();
TimeRepository repository = new TimeRepository(manager);
repository.remove(id);
this.times = null;
}
public List<Time> getTimes() {
if (this.times == null) {
EntityManager manager = this.getManager();
TimeRepository repository = new TimeRepository(manager);
this.times = repository.getLista();
}
return this.times;
}
private EntityManager getManager() {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
HttpServletRequest request = (HttpServletRequest) ec.getRequest();
return (EntityManager) request.getAttribute(" EntityManager ");
}
}
The "repository" class:
public class TimeRepository {
private EntityManager manager;
public TimeRepository(EntityManager manager) {
this.manager = manager;
}
public void adiciona(Time time) {
this.manager.persist(time);
}
@SuppressWarnings("unchecked")
public void remove(Long id) {
Time time = this.procura(id);
Query query = this.manager.createQuery("select x from Jogador x");
List<Jogador> jogadores = query.getResultList();
for (Jogador jogador : jogadores) {
jogador.setTime(null);
}
this.manager.remove(time);
}
public Time atualiza(Time time) {
return this.manager.merge(time);
}
public Time procura(Long id) {
return this.manager.find(Time.class, id);
}
@SuppressWarnings("unchecked")
public List<Time> getLista() {
Query query = this.manager.createQuery("select x from Time x");
return query.getResultList();
}
}
How can I fix this?
javax.faces.view.facelets.TagAttributeException: /times.xhtml @11,60
<ui:include src="formulario-novo-time.xhtml">
Invalid path : formulario-novo-time.xhtml
This problem is not caused by the filter. It just happens to be in the call stack because it's invoked before the faces servlet.
This particular exception will be thrown when FaceletContext#includeFacelet()
threw an IOException
. This IOException
is in turn unfortunately not wrapped as root cause, it's only logged on FINE
level. You may want to turn on FINE
(or ALL
) logging in order to see it. See also this answer how to configure logging for JSF: JSF2 logs with tomcat
One of the most common causes is that the file is not there where you think it is. E.g. the path is really invalid. The <ui:include>
path is resolved relative to the path of the parent file. You should strive to using absolute paths in <ui:xxx>
tags to avoid maintenance problems when you restructure the file hierarchy, i.e. start the path with /
and thus essentially make it relative to the webcontent root. E.g.
<ui:include src="/WEB-INF/includes/foo.xhtml" />
If you're absolutely positive that the path is correct, another probable cause is that the desired include file is saved using an unknown or wrong character encoding which causes problems during parsing the XML tree. You need to verify if your editor is properly configured to save all files as UTF-8.