Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSP,EL property not found

Tags:

java

jsp

jstl

el

I am creating a simple guest book in JSP in order to learn this technology. Currently I have two classes: guestbook/GuestBook.class and guestbook/Entry.class (I haven't finished the app yet, so I have only these classes) which are added into WEB-INF/libs/ and they're included properly. In my file index.jsp I am using guestbook.GuestBook class; its method returns Vector. When I iterate over entries and I'd like to print an author of the entry, I can see:

javax.el.PropertyNotFoundException: Property 'author' not found on type guestbook.Entry

I must add that Entry class is public and author attribute is declared in such way:

public String author;

So it is public, too. This is my code when I iterate over the entries:

<c:forEach items="${entries}" varStatus="i">
  <c:set var="entry" value="${entries[i.index]}" />
  <li><c:out value="${entry.author}" /></li>
</c:forEach>

and

entry.class.name

returns guestbook.Entry

The classes are in package guestbook (as you can guess), entries vector is passed to pageContext.

I do not know what is wrong with my way of doing it. Can anybody help me please with that? (Thanks in advance!)

like image 892
jackweb Avatar asked Nov 27 '11 12:11

jackweb


2 Answers

JSP EL will not recognise public fields in your classes, it only works with getter methods (which is good practice anyway - never expose your classes' state as public fields like this).

So use

private String author;

public String getAuthor() {
   return author;
}

instead of

public String author;

As a side note, your JSTL is overly complicated, it can be simplified to:

<c:forEach items="${entries}" var="entry">
  <li><c:out value="${entry.author}" /></li>
</c:forEach>

or even

<c:forEach items="${entries}" var="entry">
  <li>${entry.author}</li>
</c:forEach>

although the latter form will not XML-escape the author name, so isn't advised.

Lastly, the Vector class is obsolete, you should use ArrayList instead.

like image 96
skaffman Avatar answered Oct 18 '22 01:10

skaffman


You can also modify the EL-resolver to access public fields if a getter is not found. To do this, you first need to create your special ELResolver:

public class PublicFieldSupportingELResolver extends ELResolver {

    @Override
    public Class<?> getCommonPropertyType(ELContext context, Object base) {
        return null;
    }

    @Override
    public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
        return null;
    }

    @Override
    public Class<?> getType(ELContext context, Object base, Object property) {
        return null;
    }

    @Override
    public Object getValue(ELContext context, Object base, Object property) {
        try {
            return context.getELResolver().getValue(
                    context, base, property);
        } catch(RuntimeException ex) {
            if(property instanceof String && base != null) {
                try {
                    Field field = base.getClass().getDeclaredField((String) property);
                    Object value = field.get(base);
                    context.setPropertyResolved(true);
                    return value;
                } catch (Exception e) {
                    throw new PropertyNotFoundException(e);
                }
            } else {
                throw ex;
            }
        }
    }

    @Override
    public boolean isReadOnly(ELContext context, Object base, Object property) {
        return false;
    }

    @Override
    public void setValue(ELContext context, Object base, Object property, Object value) {
    }
}

Then you need a class to help you configure it:

public class PublicFieldSupportingELResolverConfigurer implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        JspFactory.getDefaultFactory()
                .getJspApplicationContext(event.getServletContext())
                .addELResolver(new PublicFieldSupportingELResolver());
    }

    public void contextDestroyed(ServletContextEvent event) {
    }
}

At last you need to run this configurer-class when the servlet starts up. Do this by adding this class as a servlet listener in your web.xml:

  <listener>
    <listener-class>your.package.PublicFieldSupportingELResolverConfigurer</listener-class>
  </listener>

Now you can refer to public fields in your JSPs.

like image 45
Aleksander Blomskøld Avatar answered Oct 18 '22 00:10

Aleksander Blomskøld