javajstleljstl-functions

JSTL - add parameters to call


I have the following code in JSTL that retrieve student picture in j2ee site

 <c:if test="${student.studentPictureId != null}">
        <a href="javascript:showImage('<c:out value="${student.studentId}"/>','<c:out value="${student.studentPictureId }"/>
</c:if>

I would like to make the code more generic
instead of calling

 student.studentPictureId 

I would like to call a generic function with an Enum :
function signature on the student class is like:

  Student class  
           String getPictureId(PictureTypeEnum picture type)

So final JSTL code will be like:

  <c:if test="${student.getPictureId(PictureTypeEnum.StudentCard) != null}">
        <a href="javascript:showImage('<c:out value="${student.studentId}"/>','<c:out value="${student.getPictureId(PictureTypeEnum.StudentCard)}"/>
</c:if>

I know that when calling

 <c:out value="${student.studentPictureId }"/>

Its basically calling a getter, student.getStudentPictureId() student.studentPictureId

But Is it possible to invoke student object method and pass parameters to it?


Solution

  • It's not possible to directly call a method from JSTL, so I use a kind of a hack: a QuickMap:

    public abstract class QuickMap<K,V> implements Map<K,V> {
        @Override
        public abstract V get(Object key);
    
        @Override
        public final int size() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final boolean isEmpty() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final boolean containsKey(Object key) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final boolean containsValue(Object value) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final V put(K key, V value) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final V remove(Object key) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final void putAll(Map<? extends K, ? extends V> m) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final void clear() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final Set<K> keySet() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final Collection<V> values() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public final Set<Entry<K, V>> entrySet() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }
    

    In your case, I would add the following method in your student class:

    public Map<Object,String> getStudentPictureIds() {
        return new QuickMap<Object,String>() {
            @Override
            public String get(Object k) {
                PictureTypeEnum type;
                if (k instanceof PictureTypeEnum) {
                    type = (PictureTypeEnum)k; 
                } else {
                    type = PictureTypeEnum.valueOf(k.toString());
                }
                return getStudentPictureId(type);
            }            
        };
    }
    

    Not that it's not easy to manipulate enums with JSTL, so the method also accepts Strings.

    You would use it as follows in your JSP:

    <c:out value="${student.pictureIds['StudentCard']}"/>