简体   繁体   中英

How does the JSF EL Field Referencing From Getter Setter work?

I want to replicate this for my own project but not for xhtml or other xml structured files. I want to replicate this kind of feature in java files. Is it possible?

#{Object.field}

example class

class Object
{
   public String getField()
   {
      return "field";
   }

   public void setField()
   {
   }
}

It somehow converts the suffix of the getter and setter to work like an actual field reference. But I want the developers to ONLY be able to put the actual field. So it shows error on compile when they don't put an actual field's name (which is the suffix of the getter and setter function).

I don't literally want to use EL expression. "#{Object.field}". I just want to replicate the system to ease the developers from having to use looping, getter and setter to make a table. If it's possible, I want them to be able to code it like this

createTable(new Field[]{Object.field1, Object.field4, Object.field6}, new Object[]{object1, object2, object3});
//new Field[]{Object.field1, Object.field4} <-- selected fields
//new Object[]{object1, object2, object3} <-- objects that is going to be shown in the table

I found that it is possible to do that by using java reflection. But there is to much hassle to get a particular "Field". If I could make it as easy as "Object.fieldName" to get the "Field" it'd be great.

I think what you need is EL Resolver. You need to implement ELResolver from javax & whenever you have any EL string , just resolve it using your own EL Resolver.

Below is sample code. It won't work as it is, so try deleting unnecessary stuff like function mapper, variable mapper etc & then run it.

Maven dependancies

    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>el-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>jasper-el</artifactId>
        <version>6.0.18</version>
    </dependency>

Custom EL Resolver

package ravi.tutorial.el;

import java.beans.FeatureDescriptor;
import java.util.Iterator;
import java.util.Map;

import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.MapELResolver;


public class DemoELResolver extends ELResolver {

    private ELResolver delegate = new MapELResolver();
    private Map<Object, Object> userMap;

    public DemoELResolver(Map<Object, Object> userMap) {
        this.userMap = userMap;
    }

    @Override
    public Object getValue(ELContext context, Object base, Object property) {
        if (base == null) {
            base = userMap;
        }
        return delegate.getValue(context, base, property);
    }

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

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

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

    @Override
    public boolean isReadOnly(ELContext context, Object base, Object property) {
        if (base == null) {
            base = userMap;
        }
        return delegate.isReadOnly(context, base, property);
    }

    @Override
    public void setValue(ELContext context, Object base, Object property,
            Object value) {
        if (base == null) {
            base = userMap;
        }
        delegate.setValue(context, base, property, value);
    }

}

Using ELResolver

    ExpressionFactory expressionFactory;

    if (args == null || args.length == 0) {
        System.out
                .println("Enter command line argument  1=Apache Jasper   2=Sourceforge JUEL.");
        return;
    }

    if (args[0].equals("1")) {
        expressionFactory = new org.apache.el.ExpressionFactoryImpl();
        System.out.println("Choosing org.apache.el.ExpressionFactoryImpl");
    } else if (args[0].equals("2")) {
        expressionFactory = new de.odysseus.el.ExpressionFactoryImpl();
        System.out.println("Choosing de.odysseus.el.ExpressionFactoryImpl");
    } else {
        System.out.println("Wrong argument");
        return;
    }

    // create a map with some variables in it
    Map<Object, Object> userMap = new HashMap<Object, Object>();
    userMap.put("x", new Integer(123));
    userMap.put("y", new Integer(456));

    // get the method for ${myprefix:hello(string)}
    Method sayHello = DemoEL.class.getMethod("sayHello",
            new Class[] { String.class });

    // create the context
    ELResolver demoELResolver = new DemoELResolver(userMap);
    final VariableMapper variableMapper = new DemoVariableMapper();
    final DemoFunctionMapper functionMapper = new DemoFunctionMapper();
    functionMapper.addFunction("myprefix", "hello", sayHello);
    final CompositeELResolver compositeELResolver = new CompositeELResolver();
    compositeELResolver.add(demoELResolver);
    compositeELResolver.add(new ArrayELResolver());
    compositeELResolver.add(new ListELResolver());
    compositeELResolver.add(new BeanELResolver());
    compositeELResolver.add(new MapELResolver());
    ELContext context = new ELContext() {
        @Override
        public ELResolver getELResolver() {
            return compositeELResolver;
        }

        @Override
        public FunctionMapper getFunctionMapper() {
            return functionMapper;
        }

        @Override
        public VariableMapper getVariableMapper() {
            return variableMapper;
        }
    };

    // create and resolve a value expression
    String sumExpr = "${x+y}";
    ValueExpression ve = expressionFactory.createValueExpression(context,
            sumExpr, Object.class);
    Object result = ve.getValue(context);
    System.out.println("Result=" + result);

    // call a function
    String fnExpr = "#{myprefix:hello('Dave')}";
    ValueExpression fn = expressionFactory.createValueExpression(context,
            fnExpr, Object.class);
    fn.getValue(context);

Reference: http://weblogs.java.net/blog/felipeal/archive/2008/10/adding_el_suppo.html

Those expressions are strings, which can be evaluated at runtime only. The field name is prefixed with get/set to form the method name which is then invoked on the object using the Reflection API.

If it were possible to enforce something like that at compile then they would certainly have done that, I think.

Object.field1 that's not valid, unless you actually have a public field like that in that class. It has to be a string "Object.field1" . And you can't really check the content of that string at compile time.

So, it's not possible to enforce that at compile-time. The best you can do is throw a runtime-exception.

I think you don't need to build a system as complicated as the EL-API. Just learn the Reflection API .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM