How do you reference an constants with EL on a JSP page?
I have an interface Addresses with a constant named URL. I know I can reference it with a scriplet by going: <%=Addresses.URL%>, but how do I do this using EL?
EL 3.0 or newer
If you're already on Java EE 7 / EL 3.0, then the #page import will also import class constants in EL scope.
<%# page import="com.example.YourConstants" %>
This will under the covers be imported via ImportHandler#importClass() and be available as ${YourConstants.FOO}.
Note that all java.lang.* classes are already implicitly imported and available like so ${Boolean.TRUE} and ${Integer.MAX_VALUE}. This only requires a more recent Java EE 7 container server as early versions had bugs in this. E.g. GlassFish 4.0 and Tomcat 8.0.0-1x fails, but GlassFish 4.1+ and Tomcat 8.0.2x+ works. And you need to make absolutely sure that your web.xml is declared conform the latest servlet version supported by the server. Thus with a web.xml which is declared conform Servlet 2.5 or older, none of the Servlet 3.0+ features will work.
Also note that this facility is only available in JSP and not in Facelets. In case of JSF+Facelets, your best bet is using OmniFaces <o:importConstants> as below:
<o:importConstants type="com.example.YourConstants" />
Or adding an EL context listener which calls ImportHandler#importClass() as below:
#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");
}
});
}
}
EL 2.2 or older
This is not possible in EL 2.2 and older. There are several alternatives:
Put them in a Map<String, Object> which you put in the application scope. In EL, map values are accessible the usual Javabean way by ${map.key} or ${map['key.with.dots']}.
Use <un:useConstants> of the Unstandard taglib (maven2 repo here):
<%# taglib uri="http://jakarta.apache.org/taglibs/unstandard-1.0" prefix="un" %>
<un:useConstants className="com.example.YourConstants" var="constants" />
This way they are accessible the usual Javabean way by ${constants.FOO}.
Use Javaranch's CCC <ccc:constantsMap> as desribed somewhere at the bottom of this article.
<%# taglib uri="http://bibeault.org/tld/ccc" prefix="ccc" %>
<ccc:constantsMap className="com.example.YourConstants" var="constants" />
This way they are accessible the usual Javabean way by ${constants.FOO} as well.
If you're using JSF2, then you could use <o:importConstants> of OmniFaces.
<html ... xmlns:o="http://omnifaces.org/ui">
<o:importConstants type="com.example.YourConstants" />
This way they are accessible the usual Javabean way by #{YourConstants.FOO} as well.
Create a wrapper class which returns them through Javabean-style getter methods.
Create a custom EL resolver which first scans the presence of a constant and if absent, then delegate to the default resolver, otherwise returns the constant value instead.
The following does not apply to EL in general, but instead to SpEL (Spring EL) only (tested with 3.2.2.RELEASE on Tomcat 7).
I think it is worth mentioning it here in case someone searches for JSP and EL (but uses JSP with Spring).
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<spring:eval var="constant" expression="T(com.example.Constants).CONSTANT"/>
You usually place these kinds of constants in a Configuration object (which has getters and setters) in the servlet context, and access them with ${applicationScope.config.url}
You can't. It follows the Java Bean convention. So you must have a getter for it.
I'm defining a constant in my jsp right at the beginning:
<%final String URI = "http://www.example.com/";%>
I include the core taglib in my JSP:
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
Then, I make the constant available to EL by following statement:
<c:set var="URI" value="<%=URI%>"></c:set>
Now, I can use it later. Here an example, where the value is just written as HTML comment for debugging purposes:
<!-- ${URI} -->
With your constant class, you can just import your class and assign the constants to local variables. I know that my answer is a sort of quick hack, but the question also bumps up when one wants to define constants directly in the JSP.
I implemented like:
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;
}
}
Next step put instance of this class into servlerContext
public class ApplicationInitializer implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
sce.getServletContext().setAttribute("Constants", new JspConstants());
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
add listener to web.xml
<listener>
<listener-class>com.example.ApplicationInitializer</listener-class>
</listener>
access in jsp
${Constants.PAGE_SIZE}
Static properties aren't accessible in EL. The workaround I use is to create a non-static variable which assigns itself to the static value.
public final static String MANAGER_ROLE = 'manager';
public String manager_role = MANAGER_ROLE;
I use lombok to generate the getter and setter so that's pretty well it. Your EL looks like this:
${bean.manager_role}
Full code at https://rogerkeays.com/access-java-static-methods-and-constants-from-el
Yes, you can. You need a custom tag (if you can't find it somewhere else). I've done this:
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;
}
}
and the tag is called:
<yourLib:constMap path="path.to.your.constantClass" var="consts" />
All public static final variables will be put into a Map indexed by their Java name, so if
public static final int MY_FIFTEEN = 15;
then the tag will wrap this in an Integer and you can reference it in a JSP:
<c:if test="${consts['MY_FIFTEEN'] eq 15}">
and you don't have to write getters!
You can. Try in follow way
#{T(com.example.Addresses).URL}
Tested on TomCat 7 and java6
Even knowing its a little late, and even knowing this is a little hack - i used the following solution to achieve the desired result. If you are a lover of Java-Naming-Conventions, my advice is to stop reading here...
Having a class like this, defining Constants, grouped by empty classes to create kind of a hierarchy:
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;
...
}
}
can be used from within java as PERMISSION.PAGE.SEE to retrieve the value 1L
To achieve a simliar access-possibility from within EL-Expressions, I did this:
(If there is a coding-god - he hopefully might forgive me :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();
}
}
finally, the EL-Expression to access the very same Long becomes: #{PERMISSION.PAGE.SEE} - equality for Java and EL-Access. I know this is out of any convention, but it works perfectly fine.
#Bozho already provided a great answer
You usually place these kinds of constants in a Configuration object (which has getters and setters) in the servlet context, and access them with ${applicationScope.config.url}
However, I feel an example is needed so it brings a bit more clarity and spare someone's time
#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);
}
}
There is a workaround that is not exactly what you want, but lets you active almost the same with touching scriptlets in a quite minimal way. You can use scriptlet to put value into a JSTL variable and use clean JSTL code later in the page.
<%# 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>
Related
I'm struggling since a couple of hours trying to get MapStruct generate a valid mapper for JAXB generated classes. The particularity of these classes is that they don't have neither setters nor adders for collections. For example:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "IndividualType", propOrder = {"addressTypes","pensionTypes"})
public class IndividualType
{
...
#XmlElement(name = "addressType")
protected List<AddressType> addressTypes;
#XmlAttribute(name = "firstName", required = true)
protected String firstName;
...
public List<AddressType> getAddressTypes()
{
if (addressTypes == null) {
addressTypes = new ArrayList<AddressType>();
}
return this.addressTypes;
}
public String getFirstName()
{
return firstName;
}
public void setFirstName(String value)
{
this.firstName = value;
}
...
}
The class avove have a getter and a setter for attributes (firstName in this example) but for collections (List here) it only has a getter. Hence it's the consumer responsibility to access via getAddressTypes(add (new AddressType(...)).
The MapStruct mapper for such a class is as follows:
#Mapper(collectionMappingStrategy = CollectionMappingStrategy.TARGET_IMMUTABLE, uses = {AddressTypeMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = "spring")
public interface IndividualTypeMapper
{
IndividualType toIndividualType(IndividualEntity individual);
#InheritInverseConfiguration
IndividualEntity fromIndividualType(IndividualType individualType);
}
And the MapStruct generated code is:
#Override
public IndividualEntity fromIndividualType(IndividualType individualType)
{
if ( individualType == null )
return null;
IndividualEntity individualEntity = new IndividualEntity();
individualEntity.setFirstName( individualType.getFirstName() );
...
return individualEntity;
}
In the generated code above, only the properties having a setter get initialized despite the usage of the TARGET_IMMUTABLE strategy.
Any suggestions please ? Of course, a simple constructor would perfectly do but, for some reason, people seems to prefer complicated and nonworking solutions to simple working ones and, consequently, I have to use MapStruct :-(
Many thanks in advance.
Marie-France
The reason why it is not working is due to the fact that you are using CollectionMappingStrategy.TARGET_IMMUTABLE. With that you are basically telling MapStruct my collection targets are immutable and will throw an exception if you try to modify the collection returned by the getter.
I would suggest removing the collectionMappingStrategy and see whether it works without it.
I'm coding in Groovy and am having trouble with the Java 8 #Repeatable meta-annotation. I think I'm doing everything right, but it appears that Groovy is not recognizing #Repeatable. Here's my sample code; I'm expecting the information from both annotations to get stored in MyAnnotationArray:
import java.lang.annotation.*
class MyClass
{
#MyAnnotation(value = "val1")
#MyAnnotation(value = "val2")
void annotatedMethod()
{
println("annotated method called")
}
public static void main(String... args)
{
MyClass ob = new MyClass()
ob.annotatedMethod()
java.lang.reflect.Method m = ob.getClass().getMethod("annotatedMethod")
List annos = m.getAnnotations()
println("annos = $annos")
}
}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Repeatable(MyAnnotationArray)
public #interface MyAnnotation
{
String value() default "val0";
}
public #interface MyAnnotationArray
{
MyAnnotation[] MyAnnotationArray()
}
What happens is that I get this error:
Caught: java.lang.annotation.AnnotationFormatError: Duplicate annotation for class: interface MyAnnotation: #MyAnnotation(value=val2)
java.lang.annotation.AnnotationFormatError: Duplicate annotation for class: interface MyAnnotation: #MyAnnotation(value=val2)
Which is exactly what I get if I leave out the #Repeatable meta-annotation.
The code works fine if I leave out one of the duplicate MyAnnotations; then there is no error, and I then can read the annotation value as expected.
Is it possible that Groovy doesn't support the #Repeatable meta-annotation? I couldn't find any documentation that states this outright, though this page hints that maybe this is the case (scroll down to item 88).
seems to be not supported
i used java 1.8 and groovy 2.4.11
after compiling and de-compilig the same code i got this:
java:
#MyAnnotationArray({#MyAnnotation("val1"), #MyAnnotation("val2")})
public void annotatedMethod()
{
System.out.println("annotated method called");
}
groovy:
#MyAnnotation("val1")
#MyAnnotation("val2")
public void annotatedMethod()
{
System.out.println("annotated method called");null;
}
so, as workaround in groovy use
//note the square brackets
#MyAnnotationArray( [#MyAnnotation("val1"), #MyAnnotation("val2")] )
public void annotatedMethod()
{
System.out.println("annotated method called");
}
full script (because there were some errors in annotation declaration)
import java.lang.annotation.*
class MyClass
{
//#MyAnnotation(value = "val1")
//#MyAnnotation(value = "val2")
#MyAnnotationArray( [#MyAnnotation("val1"), #MyAnnotation("val2")] )
public void annotatedMethod()
{
System.out.println("annotated method called");
}
public static void main(String... args)
{
MyClass ob = new MyClass()
ob.annotatedMethod()
java.lang.reflect.Method m = ob.getClass().getMethod("annotatedMethod")
List annos = m.getAnnotations()
println("annos = $annos")
}
}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Repeatable(MyAnnotationArray)
public #interface MyAnnotation
{
String value() default "val0";
}
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotationArray
{
MyAnnotation[] value()
}
also tried against groovy 3.0.0-SNAPSHOT - the result is the same as for 2.4.11
Yes, Groovy has supported "repeatable" annotations for a long time even in Java 5 so long as retention policy was only SOURCE. This is what allows multiple #Grab statements for instance without the outer #Grapes container annotation. Being only retained in SOURCE makes them useful for AST transformations and within the Groovy compiler itself (and other source processors) but not really useful anywhere else. We don't currently support #Repeatable at all but plan to in a future version.
I would like to override some Liferay's modules tranlations. I am fallowing: https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/overriding-a-modules-language-keys
It works but not for all strings. First of all I would like to override some strings in journal-lang module (com.liferay.journal.lang), but this module doesn't have servlet context name. I have tried to skip that but it doesn't work. How can I override these strings?
I'm also trying to override some core strings (from portal-impl) but some of them remains untranslated. For example "Add Field" (add-field) from defining new form view. Any possible solutions?
journal-lang is a language components. In order to override some string from them you have to create a component for bundle com.liferay.journal.web or com.liferay.journal.service.
You've to create a CustomResourceBundle with extends ResourceBundle
#Component(immediate = true, property = { "language.id=en_US" }, service = ResourceBundle.class)
public class DefaultCustomResourceBundle extends ResourceBundle {
#Override
public Enumeration<String> getKeys() {
return _resourceBundle.getKeys();
}
#Override
protected Object handleGetObject(String key) {
return _resourceBundle.getObject(key);
}
private final ResourceBundle _resourceBundle = ResourceBundle.getBundle("content.Language", UTF8Control.INSTANCE);
}
And this should override translations accross the portal.
In JSF 2.0, if a message is not found in the message bundle, then by default, the key is surrounded with ???. This is a very usable hint during development. However, in my particular case, I really would like that those ??? were not present. I prefer that only the key would be rendered.
E.g. when I do
#{msg.hello}
and the key 'hello' doesn't exist, then the page displays
???hello???
but I would like to show the bare key
hello
The message bundle is loaded in a JSF page as follows:
<f:loadBundle basename="resources.text" var="msg" />
The <f:loadBundle> tag doesn't seem to have an attribute to manipulate the way values are retrieved from that bundle. Should I overwrite some class or how to intercept the way messages are retrieved from the bundle?
I've found a very interesting article on this: Context Sensitive Resource Bundle entries in JavaServer Faces applications – going beyond plain language, region & variant locales. However, in my case, I just want to omit the ???. I think this solution is rather complicated. How can I achieve it anyway?
The basename can point to a fullworthy ResourceBundle class. E.g.
<f:loadBundle basename="resources.Text" var="msg" />
with
package resources;
public class Text extends ResourceBundle {
public Text() {
setParent(getBundle("resources.text", FacesContext.getCurrentInstance().getViewRoot().getLocale()));
}
#Override
public Enumeration<String> getKeys() {
return parent.getKeys();
}
#Override
protected Object handleGetObject(String key) {
return parent.getObject(key);
}
}
You can overridde the bundle message handling in handleGetObject. JSF by default (by spec) calls getObject(), catches MissingResourceException and returns "???" + key + "???" when caught. You can do it differently.
#Override
protected Object handleGetObject(String key) {
try {
return parent.getObject(key);
} catch (MissingResourceException e) {
return key;
}
}
You could also create a simple bean that takes care of the string manipulation. This approach is a lot better if you don't need to remove the default surroundings everywhere but only on a specific place(s). The second function is a lot safer to use, since it also takes care of the case where translation starts and ends with the ???.
#ApplicationScoped
#Named
public class LocaleUtils {
public String getMessage(String s) {
return clearMessage(s);
}
public Object getMessage(ResourceBundle propertyResourceBundle, String key) {
try {
return propertyResourceBundle.getObject(key);
}
catch (MissingResourceException e) {
return clearMessage(key);
}
}
private static String clearMessage(String s) {
String clearMessage = s;
String prefix = "???", suffix = "???";
if (s != null && s.startsWith(prefix) && s.endsWith(suffix)) {
s = s.substring(prefix.length());
clearMessage = s.substring(0, s.length() - suffix.length());
}
return clearMessage;
}
}
Usage:
<h:outputText value="#{localeUtils.getMessage(msg['hello'])}"/>
<h:outputText value="#{localeUtils.getMessage(msg, 'hello')}"/>
I have an input (JSF) that should be bound to a property in my bean. This property represents another bean and has an auxiliar method that checks if it's null (I use this method a lot).
The problem is that the binding is failing to get the proper getter and setter. Instead of reading the method that returns the bean, it reads the one that return a boolean value.
The property name is guest. The methods are:
getGuest;
setGuest;
isGuest (checks if guest is null).
JSF is trying to bind the object to isGuest and setGuest, instead of getGuest and setGuest.
I cannot rename isGuest to guestIsNull or something, because that would'nt make to much sense (see the class below).
Finally, my question is: how can I bind this property to the object without renaming my methods? Is it possible?
I also accept suggestions of a better method name (but the meaning must be the same).
Entity
#Entity
public class Passenger {
private Employee employee;
private Guest guest;
public Passenger() {
}
#Transient
public boolean isEmployee() {
return null != this.employee;
}
#Transient
public boolean isGuest() {
return null != this.guest;
}
#OneToOne
public Employee getEmployee() {
return this.employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
#OneToOne
public Guest getGuest() {
return this.guest;
}
public void setGuest(Guest guest) {
this.guest = guest;
}
}
JSF
<h:inputText value="#{passenger.employee}" />
<h:inputText value="#{passenger.guest}" />
Change the method name to isGuestNull.
The problem you're seeing is due to the fact that the EL lets you use getFoo or isFoo as the naming style for getter methods that return booleans.
No, that's not possible. You've to rename them.
Another way is to add a single getter returning an enum which covers all cases.
public enum Type {
GUEST, EMPLOYEE;
}
public Type getType() {
return guest != null ? Type.GUEST
: employee != null ? Type.EMPLOYEE
: null;
}
with
<h:something rendered="#{passenger.type == 'GUEST'}">
Binding to any property using any method is possible and quite easy if you create your custom ELResolver (apidocs). elresolvers are registered in faces config, and they are responsible, given an Object and a String defining a property, for determining the value and type of the given properties (and, as the need arises, to change it).
You could easily write your own ELResolver that would only work for your chosen, single type, and use (for example in a switch statement) the specific methods you need to write and read properties. And for other types it would delegate resolving up the resolver chain. It's really easy to do, much easier than it sounds.
But don't do it. The standard naming pattern of properties predates EL by many years. It is part of the JavaBeans™ standard - one of the very few undisputed standards in Javaland, working everywhere - from ant scripts, through spring configuration files to JSF. Seeing methods isPerson and getPerson in one class actually makes me fill uneasy, as it breaks something I always take for granted and can always count on.
If you like DDD and want to have your method's names pure, use an adapter. It's easy, fun, and gives a couple of additional lines, which is not something to sneer at if you get paid for the ammount of code produced:
public class MyNotReallyBean {
public String checkName() { ... }
public String lookUpLastName() { ... }
public String carefullyAskAboutAge() { ... }
public class BeanAdapter {
public String getName() { return checkName(); }
public String getLastName() { return lookUpLastName(); }
public String getAge() { return carefullyAskAboutAge(); }
}
private static BeanAdapter beanAdapter = new BeanAdapter();
private BeanAdapter getBeanAdapter(){ return beanAdapter; }
}