jakartaee / expression-language

Jakarta Expression Language
https://eclipse.org/ee4j/el
Other
60 stars 49 forks source link

MapELResolver#getType why returns Object.class? #162

Closed jbescos closed 2 years ago

jbescos commented 2 years ago

Hello, I have a question because of some problems with apache trinidad impl (find more context about this at the end). https://github.com/apache/myfaces-trinidad/blob/master/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/DateTimeConverter.java

That class is not working properly in the line 139 because Object is always assignable to a subclass.

Currently MapELResolver#getType returns Object.class. The MapELResolver#getValue return the value of the Map for the specified property.

Wouldn't make more sense to change the next in MapELResolver#getType to be more consistent with MapELResolver#getValue?.

Originally there is:

        if (base != null && base instanceof Map) {
            context.setPropertyResolved(true);
            return Object.class;
        }

My suggestion:

        if (base != null && base instanceof Map) {
            context.setPropertyResolved(true);
            Map map = (Map) base;
            Object value = map.get(property); 
            if (value != null) {
                return value.getClass();
            } else {
                return Object.class;
            }
        }

More context about the issue:

In older JSF versions AstChoice#getType actually returns the class from the value:

/*    */   public Class getType(EvaluationContext ctx) throws ELException {
/* 54 */     Object val = getValue(ctx);
/* 55 */     return (val != null) ? val.getClass() : null;
/*    */   }

But in new JSF versions, it relies in the getType:

/*    */   public Class getType(EvaluationContext ctx) throws ELException {
/* 34 */     Object obj0 = this.children[0].getValue(ctx);
/* 35 */     Boolean b0 = coerceToBoolean(obj0);
/* 36 */     return this.children[b0.booleanValue() ? 1 : 2].getType(ctx);
/*    */   }

Then, in older JSF versions the method MapELResolver#getValue is invoked and it obtains the class from that instance. Meanwhile in newer JSF versions it invokes MapELResolver#getType, and this returns always Object.class.

markt-asf commented 2 years ago

As per the Javadoc:

If the base object is a map, returns the most general acceptable type for a value in this map. ... Assuming the base is a Map, this method will always return Object.class. This is because

  • Maps accept any object as the value for a given key.