Como você faz referência a constantes com EL em uma página JSP?
Eu tenho uma interface Addresses
com uma constante chamada URL
. Eu sei que posso referenciá-lo com um scriplet indo:, <%=Addresses.URL%>
mas como faço isso usando EL?
Como você faz referência a constantes com EL em uma página JSP?
Eu tenho uma interface Addresses
com uma constante chamada URL
. Eu sei que posso referenciá-lo com um scriplet indo:, <%=Addresses.URL%>
mas como faço isso usando EL?
Respostas:
Se você já estiver no Java EE 7 / EL 3.0, o @page import
também importará constantes de classe no escopo EL.
<%@ page import="com.example.YourConstants" %>
Isso estará sob as capas importado por ImportHandler#importClass()
e estará disponível como ${YourConstants.FOO}
.
Observe que todas as java.lang.*
classes já foram importadas implicitamente e estão disponíveis como ${Boolean.TRUE}
e ${Integer.MAX_VALUE}
. Isso requer apenas um servidor de contêiner Java EE 7 mais recente, pois as versões anteriores apresentavam bugs. Por exemplo, GlassFish 4.0 e Tomcat 8.0.0-1x falham, mas GlassFish 4.1+ e Tomcat 8.0.2x + funcionam. E você precisa ter certeza absoluta de que web.xml
está em conformidade com a versão mais recente do servlet suportada pelo servidor. Assim, com um web.xml
Servlet 2.5 ou anterior declarado conforme, nenhum dos recursos do Servlet 3.0+ funcionará.
Observe também que esse recurso está disponível apenas em JSP e não em Facelets. No caso de JSF + Facelets, sua melhor aposta é usar OmniFaces<o:importConstants>
conforme abaixo:
<o:importConstants type="com.example.YourConstants" />
Ou adicionando um ouvinte de contexto EL que chama ImportHandler#importClass()
conforme abaixo:
@ManagedBean(eager=true)
@ApplicationScoped
public class Config {
@PostConstruct
public void init() {
FacesContext.getCurrentInstance().getApplication().addELContextListener(new ELContextListener() {
@Override
public void contextCreated(ELContextEvent event) {
event.getELContext().getImportHandler().importClass("com.example.YourConstants");
}
});
}
}
Isso não é possível no EL 2.2 e anteriores. Existem várias alternativas:
Coloque-os em um Map<String, Object>
que você colocou no escopo do aplicativo. Em EL, os valores do mapa são acessíveis da maneira usual de Javabean por ${map.key}
ou ${map['key.with.dots']}
.
Uso <un:useConstants>
do taglib Unstandard (maven2 repo aqui ):
<%@ taglib uri="http://jakarta.apache.org/taglibs/unstandard-1.0" prefix="un" %>
<un:useConstants className="com.example.YourConstants" var="constants" />
Desta forma, eles são acessíveis da maneira usual de Javabean ${constants.FOO}
.
Use o CCC de Javaranch <ccc:constantsMap>
conforme descrito em algum lugar no final deste artigo .
<%@ taglib uri="http://bibeault.org/tld/ccc" prefix="ccc" %>
<ccc:constantsMap className="com.example.YourConstants" var="constants" />
Desta forma, eles também são acessíveis da maneira usual de Javabean ${constants.FOO}
.
Se você estiver usando JSF2, então você poderia usar <o:importConstants>
de OmniFaces .
<html ... xmlns:o="http://omnifaces.org/ui">
<o:importConstants type="com.example.YourConstants" />
Desta forma, eles também são acessíveis da maneira usual de Javabean #{YourConstants.FOO}
.
Crie uma classe de wrapper que os retorne por meio de métodos getter no estilo javabeano.
Crie um resolvedor EL personalizado que primeiro verifica a presença de uma constante e, se ausente, delega ao resolvedor padrão; caso contrário, retorna o valor da constante.
unstandard-taglib
projeto de Jacarta ainda está vivo? existe alguma alternativa?
O seguinte não se aplica ao EL em geral, mas ao invés do SpEL (Spring EL) somente (testado com 3.2.2.RELEASE no Tomcat 7). Acho que vale a pena mencioná-lo aqui caso alguém procure por JSP e EL (mas usa JSP com Spring).
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<spring:eval var="constant" expression="T(com.example.Constants).CONSTANT"/>
Você geralmente coloca esses tipos de constantes em um Configuration
objeto (que tem getters e setters) no contexto do servlet e os acessa com${applicationScope.config.url}
url
uma propriedade String, nomeie-a Configuration
, instancie-a e defina url
como quiser. Depois disso, coloque esse Configuration
objeto em ServletContext
. Faça algo como servletContext.setAttribute("config", config)
,. E aí está.
ServletContext
? É só que você pode classificar as constantes de maneira mais precisa? por exemplo: applicationScope.config.url
vs applicationScope.url
.
Você não pode. Ele segue a convenção Java Bean. Portanto, você deve ter um getter para isso.
As propriedades estáticas não são acessíveis em EL. A solução alternativa que uso é criar uma variável não estática que se atribui ao valor estático.
public final static String MANAGER_ROLE = 'manager';
public String manager_role = MANAGER_ROLE;
Eu uso o lombok para gerar o getter e o setter, então é isso. Seu EL é parecido com este:
${bean.manager_role}
Código completo em http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el
Eu implementei como:
public interface Constants{
Integer PAGE_SIZE = 20;
}
-
public class JspConstants extends HashMap<String, String> {
public JspConstants() {
Class c = Constants.class;
Field[] fields = c.getDeclaredFields();
for(Field field : fields) {
int modifier = field.getModifiers();
if(Modifier.isPublic(modifier) && Modifier.isStatic(modifier) && Modifier.isFinal(modifier)) {
try {
Object o = field.get(null);
put(field.getName(), o != null ? o.toString() : null);
} catch(IllegalAccessException ignored) {
}
}
}
}
@Override
public String get(Object key) {
String result = super.get(key);
if(StringUtils.isEmpty(result)) {
throw new IllegalArgumentException("Check key! The key is wrong, no such constant!");
}
return result;
}
}
Próxima etapa colocar a instância desta classe em servlerContext
public class ApplicationInitializer implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
sce.getServletContext().setAttribute("Constants", new JspConstants());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
adicionar ouvinte a web.xml
<listener>
<listener-class>com.example.ApplicationInitializer</listener-class>
</listener>
acesso em jsp
${Constants.PAGE_SIZE}
Estou definindo uma constante em meu jsp logo no início:
<%final String URI = "http://www.example.com/";%>
Incluo o taglib principal em meu JSP:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
Em seguida, disponibilizo a constante para EL seguindo a seguinte declaração:
<c:set var="URI" value="<%=URI%>"></c:set>
Agora, posso usá-lo mais tarde. Aqui está um exemplo, onde o valor é escrito apenas como comentário HTML para fins de depuração:
<!-- ${URI} -->
Com sua classe constante, você pode simplesmente importar sua classe e atribuir as constantes às variáveis locais. Eu sei que minha resposta é uma espécie de hack rápido, mas a questão também surge quando se quer definir constantes diretamente no JSP.
<%=URI%>
: P
<%=URI%>
não funcionava, mas essa técnica funcionava.
Sim você pode. Você precisa de uma tag personalizada (se não conseguir encontrá-la em outro lugar). Eu fiz isso:
package something;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.TreeMap;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.taglibs.standard.tag.el.core.ExpressionUtil;
/**
* Get all class constants (statics) and place into Map so they can be accessed
* from EL.
* @author Tim.sabin
*/
public class ConstMapTag extends TagSupport {
public static final long serialVersionUID = 0x2ed23c0f306L;
private String path = "";
private String var = "";
public void setPath (String path) throws JspException {
this.path = (String)ExpressionUtil.evalNotNull ("constMap", "path",
path, String.class, this, pageContext);
}
public void setVar (String var) throws JspException {
this.var = (String)ExpressionUtil.evalNotNull ("constMap", "var",
var, String.class, this, pageContext);
}
public int doStartTag () throws JspException {
// Use Reflection to look up the desired field.
try {
Class<?> clazz = null;
try {
clazz = Class.forName (path);
} catch (ClassNotFoundException ex) {
throw new JspException ("Class " + path + " not found.");
}
Field [] flds = clazz.getDeclaredFields ();
// Go through all the fields, and put static ones in a Map.
Map<String, Object> constMap = new TreeMap<String, Object> ();
for (int i = 0; i < flds.length; i++) {
// Check to see if this is public static final. If not, it's not a constant.
int mods = flds [i].getModifiers ();
if (!Modifier.isFinal (mods) || !Modifier.isStatic (mods) ||
!Modifier.isPublic (mods)) {
continue;
}
Object val = null;
try {
val = flds [i].get (null); // null for static fields.
} catch (Exception ex) {
System.out.println ("Problem getting value of " + flds [i].getName ());
continue;
}
// flds [i].get () automatically wraps primitives.
// Place the constant into the Map.
constMap.put (flds [i].getName (), val);
}
// Export the Map as a Page variable.
pageContext.setAttribute (var, constMap);
} catch (Exception ex) {
if (!(ex instanceof JspException)) {
throw new JspException ("Could not process constants from class " + path);
} else {
throw (JspException)ex;
}
}
return SKIP_BODY;
}
}
e a tag é chamada:
<yourLib:constMap path="path.to.your.constantClass" var="consts" />
Todas as variáveis finais estáticas públicas serão colocadas em um mapa indexado por seu nome Java, portanto, se
public static final int MY_FIFTEEN = 15;
então a tag envolverá isso em um inteiro e você pode referenciá-lo em um JSP:
<c:if test="${consts['MY_FIFTEEN'] eq 15}">
e você não precisa escrever getters!
Você pode. Tente seguir o caminho
#{T(com.example.Addresses).URL}
Testado em TomCat 7 e java6
Mesmo sabendo que é um pouco tarde, e mesmo sabendo que isso é um pequeno hack - usei a seguinte solução para alcançar o resultado desejado. Se você é um amante de Java-Naming-Conventions, meu conselho é parar de ler aqui ...
Ter uma classe como essa, definindo constantes, agrupadas por classes vazias para criar uma espécie de hierarquia:
public class PERMISSION{
public static class PAGE{
public static final Long SEE = 1L;
public static final Long EDIT = 2L;
public static final Long DELETE = 4L;
...
}
}
pode ser usado de dentro de java PERMISSION.PAGE.SEE
para recuperar o valor1L
Para conseguir uma possibilidade de acesso semelhante de dentro de EL-Expressions, eu fiz o seguinte: (Se houver um deus da codificação - espero que ele me perdoe: D)
@Named(value="PERMISSION")
public class PERMISSION{
public static class PAGE{
public static final Long SEE = 1L;
public static final Long EDIT = 2L;
public static final Long DELETE = 4L;
...
//EL Wrapper
public Long getSEE(){
return PAGE.SEE;
}
public Long getEDIT(){
return PAGE.EDIT;
}
public Long getDELETE(){
return PAGE.DELETE;
}
}
//EL-Wrapper
public PAGE getPAGE() {
return new PAGE();
}
}
finalmente, a EL-Expression para acessar o mesmo Long
torna-se: #{PERMISSION.PAGE.SEE}
- igualdade para Java e EL-Access. Eu sei que isso está fora de qualquer convenção, mas funciona perfeitamente bem.
@Bozho já deu uma ótima resposta
Você geralmente coloca esses tipos de constantes em um objeto de configuração (que tem getters e setters) no contexto do servlet e os acessa com $ {applicationScope.config.url}
No entanto, sinto que é necessário um exemplo para trazer um pouco mais de clareza e poupar o tempo de alguém
@Component
public Configuration implements ServletContextAware {
private String addressURL = Addresses.URL;
// Declare other properties if you need as also add corresponding
// getters and setters
public String getAddressURL() {
return addressURL;
}
public void setServletContext(ServletContext servletContext) {
servletContext.setAttribute("config", this);
}
}
Há uma solução alternativa que não é exatamente o que você deseja, mas permite que você ative quase da mesma forma, tocando scriptlets de uma maneira mínima. Você pode usar o scriptlet para colocar o valor em uma variável JSTL e usar o código JSTL limpo posteriormente na página.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="com.whichever.namespace.Addresses" %>
<c:set var="ourUrl" value="<%=Addresses.URL%>"/>
<c:if test='${"http://www.google.com" eq ourUrl}'>
Google is our URL!
</c:if>