90

I'm new to JSP. I tried connecting MySQL and my JSP pages and it works fine. But here is what I needed to do. I have a table attribute called "balance". Retrieve it and use it to calculate a new value called "amount". (I'm not printing "balance").

 <c:forEach var="row" items="${rs.rows}">
        ID: ${row.id}<br/>
        Passwd: ${row.passwd}<br/>
        Amount: <%=Calculate.getAmount(${row.balance})%>
 </c:forEach>

It seems it's not possible to insert scriptlets within JSTL tags.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
John Eipe
  • 10,922
  • 24
  • 72
  • 114

9 Answers9

134

You cannot invoke static methods directly in EL. EL will only invoke instance methods.

As to your failing scriptlet attempt, you cannot mix scriptlets and EL. Use the one or the other. Since scriptlets are discouraged over a decade, you should stick to an EL-only solution.

You have basically 2 options (assuming both balance and Calculate#getAmount() are double).

  1. Just wrap it in an instance method.

    public double getAmount() {
        return Calculate.getAmount(balance);
    }
    

    And use it instead:

    Amount: ${row.amount}
    

  2. Or, declare Calculate#getAmount() as an EL function. First create a /WEB-INF/functions.tld file:

    <?xml version="1.0" encoding="UTF-8" ?>
    <taglib 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
        version="2.1">
    
        <display-name>Custom Functions</display-name>    
        <tlib-version>1.0</tlib-version>
        <uri>http://example.com/functions</uri>
    
        <function>
            <name>calculateAmount</name>
            <function-class>com.example.Calculate</function-class>
            <function-signature>double getAmount(double)</function-signature>
        </function>
    </taglib>
    

    And use it as follows:

    <%@taglib uri="http://example.com/functions" prefix="f" %>
    ...
    Amount: ${f:calculateAmount(row.balance)}">
    
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • @BalusC What if my jsp has (calculated) some value and I'd like to send that as a parameter?? – Sriram Nov 14 '12 at 15:00
  • 7
    @Sriram: First of all, are you sure that you aren't confusing JSP with HTML/JS? The way you put the question indicates that you seem to think that JSP runs in the webbrowser while this is completely untrue. JSP is a HTML/CSS/JS code producer. That's all. That should give you something to think about your question and approach. – BalusC Nov 14 '12 at 16:54
  • what i was looking for :) – aliopi Nov 22 '17 at 14:31
  • @PhilipRego: code in answer is just based on code in question. – BalusC Mar 21 '19 at 17:28
62

Another approach is to use Spring SpEL:

<%@taglib prefix="s" uri="http://www.springframework.org/tags" %>

<s:eval expression="T(org.company.Calculate).getAmount(row.balance)" var="rowBalance" />
Amount: ${rowBalance}

If you skip optional var="rowBalance" then <s:eval> will print the result of the expression to output.

dma_k
  • 10,431
  • 16
  • 76
  • 128
  • this is even better! for others you could provide a string in the static method by adding \"the_string_argument\" (instead of row.balance part). This is only if your method excepts strings. ;) Cheers! – despot May 07 '12 at 14:23
  • 3
    You can pass strings in single quotes e.g. `'the_string_argument'` − no need to dance with escaping. – dma_k May 08 '12 at 09:11
  • Cool, that worked for me in Spring... I was curious if it was possible to do 2 classes... just need to prefix the clas with a T() i assume... This worked for what I was doing: equivalent to: String text_stripped_html = Jsoup.clean(orig_text, Whitelist.none()); – armyofda12mnkeys Feb 22 '13 at 15:08
  • @msangel: Check other answers in this topic. – dma_k Sep 11 '13 at 11:11
6

If your Java class is:

package com.test.ejb.util;

public class CommonUtilFunc {

    public static String getStatusDesc(String status){

        if(status.equals("A")){
            return "Active";
        }else if(status.equals("I")){
            return "Inactive";
        }else{
            return "Unknown";
        }
    }
}

Then you can call static method 'getStatusDesc' as below in JSP page.

Use JSTL useBean to get class at top of the JSP page:

<jsp:useBean id="cmnUtilFunc" class="com.test.ejb.util.CommonUtilFunc"/>

Then call function where you required using Expression Language:

<table>
    <td>${cmnUtilFunc.getStatusDesc('A')}</td>
</table>
4

Bean like StaticInterface also can be used

<h:commandButton value="reset settings" action="#{staticinterface.resetSettings}"/>

and bean

package com.example.common;

import com.example.common.Settings;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean(name = "staticinterface")
@ViewScoped
public class StaticInterface {

    public StaticInterface() {
    }

    public void resetSettings() {
        Settings.reset();
    }
}
Lukas
  • 391
  • 4
  • 11
  • I cannot see any static keyword in the code except "Static" in the class name. – Uluk Biy Sep 04 '13 at 16:24
  • 2
    @UlukBiy, the `Settings.reset()` is a static method call. Lukas proposes creating a wrapper-like ManagedBean with a non-static method for each static method, that one wants to call from EL. It's a valid solution. – Vsevolod Golovanov Mar 20 '14 at 10:05
3

EL 2.2 has inbuild mechanism of calling methods. More here: oracle site. But it has no access to static methods. Though you can stil call it's via object reference. But i use another solution, described in this article: Calling a Static Method From EL

msangel
  • 9,895
  • 3
  • 50
  • 69
  • 1
    I would ague that EL 2.2 really adds a build-in support for calling a static method. The solutions is based on putting a bean into request contexts and (ugly) emulations a map + necessary parameters are passed during dereferencing. The additional burden of this approach is that one need to massage request context (e.g. in ``). – dma_k Sep 11 '13 at 14:09
2

If you're using struts2, you could use

<s:var name='myVar' value="%{@package.prefix.MyClass#myMethod('param')}"/>

and then reference 'myVar' in html or html tag attribute as ${myVar}

dhblah
  • 9,751
  • 12
  • 56
  • 92
2

Based on @Lukas answer you can use that bean and call method by reflection:

@ManagedBean (name = "staticCaller")
@ApplicationScoped
public class StaticCaller {
private static final Logger LOGGER = Logger.getLogger(StaticCaller.class);
/**
 * @param clazz
 * @param method
 * @return
 */
@SuppressWarnings("unchecked")
public <E> E call(String clazz, String method, Object... objs){
    final ClassLoader loader = Thread.currentThread().getContextClassLoader();
    final List<Class<?>> clasesparamList = new ArrayList<Class<?>>();
    final List<Object> objectParamList = new ArrayList<Object>();
    if (objs != null && objs.length > 0){
        for (final Object obj : objs){
            clasesparamList.add(obj.getClass());
            objectParamList.add(obj);
        }
    }
    try {           
        final Class<?> clase = loader.loadClass(clazz);
        final Method met = clase.getMethod(method, clasesparamList.toArray(new Class<?>[clasesparamList.size()]));
            return (E) met.invoke(null, objectParamList.toArray());
        } catch (ClassNotFoundException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (InvocationTargetException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (IllegalAccessException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (IllegalArgumentException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (NoSuchMethodException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (SecurityException e) {
            LOGGER.error(e.getMessage(), e);
        }
        return null;
    }
}

xhtml, into a commandbutton for example:

<p:commandButton action="#{staticCaller.call('org.company.Calculate', 'getAmount', row.balance)}" process="@this"/>
Juan
  • 544
  • 6
  • 20
  • It is not possible to use variable arguments in EL (2.2) method expressions. – Robert Kornmesser Oct 13 '16 at 12:15
  • Hi Robert, sorry what do you mean exactly, I have used that code for a long time, and I'm sure it work's. Where is my mistake? – Juan Oct 14 '16 at 11:39
  • I dont find the actuall spec, but as BalusC mentions here http://stackoverflow.com/questions/15560508/invoke-method-with-varargs-in-el-throws-java-lang-illegalargumentexception-wron this is the reason of `SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-localhost/127.0.0.1:8080-5) java.lang.IllegalArgumentException: wrong number of arguments`. – Robert Kornmesser Oct 24 '16 at 06:43
  • Yes you can not use variable arguments on EL. But you can use that method from EL. It can be used passing an array as last argument. In this case it is not necesary because there is just one object passed as last argument. – Juan Oct 24 '16 at 11:09
1
<c:forEach var="row" items="${rs.rows}">
        ID: ${row.id}<br/>
        Passwd: ${row.passwd}<br/>
<c:set var="balance" value="${row.balance}"/>
        Amount: <%=Calculate.getAmount(pageContext.getAttribute("balance").toString())%>
 </c:forEach>

In this solution, we're assigning value(Through core tag) to a variable and then we're fetching value of that variable in scriplet.

ash9
  • 149
  • 1
  • 3
0

In Struts2 or Webwork2, you can use this:

<s:set name="tourLanguage" value="@foo.bar.TourLanguage@getTour(#name)"/>

Then reference #tourLanguage in your jsp

sendon1982
  • 9,982
  • 61
  • 44