JSP,EL property not found
Asked Answered
M

3

10

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!)

Micahmicawber answered 27/11, 2011 at 12:5 Comment(0)
S
12

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.

Selfexpression answered 27/11, 2011 at 12:9 Comment(0)
S
4

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.

Seize answered 29/3, 2013 at 16:45 Comment(1)
Throws a StackOverflowException :) It appears that return context.getELResolver().getValue( context, base, property); calls the same getValue implementation.Inelastic
I
0

I had a problem in Build Path. javax.servlet.jsp.jstl-1.2.1.jar was deleted but not removed from Build Path. After removing it from Build Path Property 'xxx' not found issue disappeared.

Ist answered 1/3, 2015 at 22:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.