I don't think there is a build in way to do this because then the container needed to remember expired sessionIds and their associated users. As far as I know the container will just delete this information on session-timeout.
But you could try to do this on your own:
Implement a HttpSessionListener and store expired SessionIDs in some kind of cache. Most likely you want to show this "your session expired" message only to authorized users but a HTTP-Session may also be created for non-authorized users. So you need to check if the user was authorized. As you don't have access to the UserPrincipal in the SessionListener you need to store some information in the session on your own.
@WebListener
public class HttpSessionChecker implements HttpSessionListener {
@Inject
private SessionIdCache cache;
public void sessionCreated(HttpSessionEvent event) {}
public void sessionDestroyed(HttpSessionEvent event) {
if (event.getSession().getAttribute("someAuthInformation") != null) { // whatever you've stored
cache.put(event.getSession().getId(), new Date());
}
}
}
In Your ExceptionMapper you can now check if a JSESSIONID-Cookie was part of the request-headers and if the passed sessionID is found in your cache.
@Provider
public class ExMapper implements ExceptionMapper<Exception> {
@Inject
private SessionIdCache cache;
@Context
private HttpServletRequest request;
@Override
public Response toResponse(Exception ex) {
for (Cookie cookie : request.getCookies()) {
if ("JSESSIONID".equals(cookie.getName())) {
String sessionId = cookie.getValue().substring(0, cookie.getValue().lastIndexOf('.')); // ignore .hostname
if (cache.contains(sessionId)) {
return Response.serverError().entity("Your session timed out").build();
}
}
}
return Response.serverError().build();
}
}
You should think of cleaning up your cache from time to time.