| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /* Generated By:JJTree: Do not edit this line. AstValue.java */ |
| |
| package org.apache.el.parser; |
| |
| import java.lang.reflect.Array; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| |
| import javax.el.ELException; |
| import javax.el.ELResolver; |
| import javax.el.LambdaExpression; |
| import javax.el.MethodInfo; |
| import javax.el.PropertyNotFoundException; |
| import javax.el.ValueReference; |
| |
| import org.apache.el.lang.ELSupport; |
| import org.apache.el.lang.EvaluationContext; |
| import org.apache.el.stream.Optional; |
| import org.apache.el.util.MessageFactory; |
| import org.apache.el.util.ReflectionUtil; |
| |
| |
| /** |
| * @author Jacob Hookom [jacob@hookom.net] |
| */ |
| public final class AstValue extends SimpleNode { |
| |
| private static final Object[] EMPTY_ARRAY = new Object[0]; |
| |
| protected static class Target { |
| protected Object base; |
| |
| protected Object property; |
| } |
| |
| public AstValue(int id) { |
| super(id); |
| } |
| |
| @Override |
| public Class<?> getType(EvaluationContext ctx) throws ELException { |
| Target t = getTarget(ctx); |
| ctx.setPropertyResolved(false); |
| Class<?> result = ctx.getELResolver().getType(ctx, t.base, t.property); |
| if (!ctx.isPropertyResolved()) { |
| throw new PropertyNotFoundException(MessageFactory.get( |
| "error.resolver.unhandled", t.base, t.property)); |
| } |
| return result; |
| } |
| |
| private final Target getTarget(EvaluationContext ctx) throws ELException { |
| // evaluate expr-a to value-a |
| Object base = this.children[0].getValue(ctx); |
| |
| // if our base is null (we know there are more properties to evaluate) |
| if (base == null) { |
| throw new PropertyNotFoundException(MessageFactory.get( |
| "error.unreachable.base", this.children[0].getImage())); |
| } |
| |
| // set up our start/end |
| Object property = null; |
| int propCount = this.jjtGetNumChildren(); |
| |
| int i = 1; |
| // Evaluate any properties or methods before our target |
| ELResolver resolver = ctx.getELResolver(); |
| while (i < propCount) { |
| if (i + 2 < propCount && |
| this.children[i + 1] instanceof AstMethodParameters) { |
| // Method call not at end of expression |
| base = resolver.invoke(ctx, base, |
| this.children[i].getValue(ctx), null, |
| ((AstMethodParameters) |
| this.children[i + 1]).getParameters(ctx)); |
| i += 2; |
| } else if (i + 2 == propCount && |
| this.children[i + 1] instanceof AstMethodParameters) { |
| // Method call at end of expression |
| ctx.setPropertyResolved(false); |
| property = this.children[i].getValue(ctx); |
| i += 2; |
| |
| if (property == null) { |
| throw new PropertyNotFoundException(MessageFactory.get( |
| "error.unreachable.property", property)); |
| } |
| } else if (i + 1 < propCount) { |
| // Object with property not at end of expression |
| property = this.children[i].getValue(ctx); |
| ctx.setPropertyResolved(false); |
| base = resolver.getValue(ctx, base, property); |
| i++; |
| |
| } else { |
| // Object with property at end of expression |
| ctx.setPropertyResolved(false); |
| property = this.children[i].getValue(ctx); |
| i++; |
| |
| if (property == null) { |
| throw new PropertyNotFoundException(MessageFactory.get( |
| "error.unreachable.property", property)); |
| } |
| } |
| if (base == null) { |
| throw new PropertyNotFoundException(MessageFactory.get( |
| "error.unreachable.property", property)); |
| } |
| } |
| |
| Target t = new Target(); |
| t.base = base; |
| t.property = property; |
| return t; |
| } |
| |
| @Override |
| public Object getValue(EvaluationContext ctx) throws ELException { |
| Object base = this.children[0].getValue(ctx); |
| int propCount = this.jjtGetNumChildren(); |
| int i = 1; |
| Object suffix = null; |
| ELResolver resolver = ctx.getELResolver(); |
| while (base != null && i < propCount) { |
| suffix = this.children[i].getValue(ctx); |
| if (i + 1 < propCount && |
| (this.children[i+1] instanceof AstMethodParameters)) { |
| AstMethodParameters mps = |
| (AstMethodParameters) this.children[i+1]; |
| if (base instanceof Optional && "orElseGet".equals(suffix) && |
| mps.jjtGetNumChildren() == 1) { |
| Node paramFoOptional = mps.jjtGetChild(0); |
| if (!(paramFoOptional instanceof AstLambdaExpression || |
| paramFoOptional instanceof LambdaExpression)) { |
| throw new ELException(MessageFactory.get( |
| "stream.optional.paramNotLambda", suffix)); |
| } |
| } |
| // This is a method |
| Object[] paramValues = mps.getParameters(ctx); |
| base = resolver.invoke(ctx, base, suffix, |
| getTypesFromValues(paramValues), paramValues); |
| i+=2; |
| } else { |
| // This is a property |
| if (suffix == null) { |
| return null; |
| } |
| |
| ctx.setPropertyResolved(false); |
| base = resolver.getValue(ctx, base, suffix); |
| i++; |
| } |
| } |
| if (!ctx.isPropertyResolved()) { |
| throw new PropertyNotFoundException(MessageFactory.get( |
| "error.resolver.unhandled", base, suffix)); |
| } |
| return base; |
| } |
| |
| @Override |
| public boolean isReadOnly(EvaluationContext ctx) throws ELException { |
| Target t = getTarget(ctx); |
| ctx.setPropertyResolved(false); |
| boolean result = |
| ctx.getELResolver().isReadOnly(ctx, t.base, t.property); |
| if (!ctx.isPropertyResolved()) { |
| throw new PropertyNotFoundException(MessageFactory.get( |
| "error.resolver.unhandled", t.base, t.property)); |
| } |
| return result; |
| } |
| |
| @Override |
| public void setValue(EvaluationContext ctx, Object value) |
| throws ELException { |
| Target t = getTarget(ctx); |
| ctx.setPropertyResolved(false); |
| ELResolver resolver = ctx.getELResolver(); |
| |
| // coerce to the expected type |
| Class<?> targetClass = resolver.getType(ctx, t.base, t.property); |
| resolver.setValue(ctx, t.base, t.property, |
| ELSupport.coerceToType(ctx, value, targetClass)); |
| if (!ctx.isPropertyResolved()) { |
| throw new PropertyNotFoundException(MessageFactory.get( |
| "error.resolver.unhandled", t.base, t.property)); |
| } |
| } |
| |
| @Override |
| // Interface el.parser.Node uses raw types (and is auto-generated) |
| public MethodInfo getMethodInfo(EvaluationContext ctx, |
| @SuppressWarnings("rawtypes") Class[] paramTypes) |
| throws ELException { |
| Target t = getTarget(ctx); |
| Method m = ReflectionUtil.getMethod( |
| ctx, t.base, t.property, paramTypes, null); |
| return new MethodInfo(m.getName(), m.getReturnType(), m |
| .getParameterTypes()); |
| } |
| |
| @Override |
| // Interface el.parser.Node uses a raw type (and is auto-generated) |
| public Object invoke(EvaluationContext ctx, |
| @SuppressWarnings("rawtypes") Class[] paramTypes, |
| Object[] paramValues) throws ELException { |
| |
| Target t = getTarget(ctx); |
| Method m = null; |
| Object[] values = null; |
| Class<?>[] types = null; |
| if (isParametersProvided()) { |
| values = ((AstMethodParameters) this.jjtGetChild( |
| this.jjtGetNumChildren() - 1)).getParameters(ctx); |
| types = getTypesFromValues(values); |
| } else { |
| values = paramValues; |
| types = paramTypes; |
| } |
| m = ReflectionUtil.getMethod(ctx, t.base, t.property, types, values); |
| |
| // Handle varArgs and any coercion required |
| values = convertArgs(ctx, values, m); |
| |
| Object result = null; |
| try { |
| result = m.invoke(t.base, values); |
| } catch (IllegalAccessException iae) { |
| throw new ELException(iae); |
| } catch (IllegalArgumentException iae) { |
| throw new ELException(iae); |
| } catch (InvocationTargetException ite) { |
| Throwable cause = ite.getCause(); |
| if (cause instanceof ThreadDeath) { |
| throw (ThreadDeath) cause; |
| } |
| if (cause instanceof VirtualMachineError) { |
| throw (VirtualMachineError) cause; |
| } |
| throw new ELException(cause); |
| } |
| return result; |
| } |
| |
| private Object[] convertArgs(EvaluationContext ctx, Object[] src, Method m) { |
| Class<?>[] types = m.getParameterTypes(); |
| if (types.length == 0) { |
| // Treated as if parameters have been provided so src is ignored |
| return EMPTY_ARRAY; |
| } |
| |
| int paramCount = types.length; |
| |
| if (m.isVarArgs() && paramCount > 1 && (src == null || paramCount > src.length) || |
| !m.isVarArgs() && (paramCount > 0 && src == null || |
| src != null && src.length != paramCount)) { |
| String srcCount = null; |
| if (src != null) { |
| srcCount = Integer.toString(src.length); |
| } |
| String msg; |
| if (m.isVarArgs()) { |
| msg = MessageFactory.get("error.invoke.tooFewParams", |
| m.getName(), srcCount, Integer.toString(paramCount)); |
| } else { |
| msg = MessageFactory.get("error.invoke.wrongParams", |
| m.getName(), srcCount, Integer.toString(paramCount)); |
| } |
| throw new IllegalArgumentException(msg); |
| } |
| |
| if (src == null) { |
| // Must be a varargs method with a single parameter. |
| // Use a new array every time since the called code could modify the |
| // contents of the array |
| return new Object[1]; |
| } |
| |
| Object[] dest = new Object[paramCount]; |
| |
| for (int i = 0; i < paramCount - 1; i++) { |
| dest[i] = ELSupport.coerceToType(ctx, src[i], types[i]); |
| } |
| |
| if (m.isVarArgs()) { |
| Object[] varArgs = (Object[]) Array.newInstance( |
| m.getParameterTypes()[paramCount - 1].getComponentType(), |
| src.length - (paramCount - 1)); |
| for (int i = 0; i < src.length - (paramCount - 1); i ++) { |
| varArgs[i] = ELSupport.coerceToType(ctx, src[paramCount - 1 + i], |
| types[paramCount - 1].getComponentType()); |
| } |
| dest[paramCount - 1] = varArgs; |
| } else { |
| dest[paramCount - 1] = ELSupport.coerceToType( |
| ctx, src[paramCount - 1], types[paramCount - 1]); |
| } |
| |
| return dest; |
| } |
| |
| private Class<?>[] getTypesFromValues(Object[] values) { |
| if (values == null) { |
| return null; |
| } |
| |
| Class<?> result[] = new Class<?>[values.length]; |
| for (int i = 0; i < values.length; i++) { |
| if (values[i] == null) { |
| result[i] = null; |
| } else { |
| result[i] = values[i].getClass(); |
| } |
| } |
| return result; |
| } |
| |
| |
| /** |
| * @since EL 2.2 |
| */ |
| @Override |
| public ValueReference getValueReference(EvaluationContext ctx) { |
| // Check this is a reference to a base and a property |
| if (this.children.length > 2 && |
| this.jjtGetChild(2) instanceof AstMethodParameters) { |
| // This is a method call |
| return null; |
| } |
| Target t = getTarget(ctx); |
| return new ValueReference(t.base, t.property); |
| } |
| |
| |
| /** |
| * @since EL 2.2 |
| */ |
| @Override |
| public boolean isParametersProvided() { |
| // Assumption is that method parameters, if present, will be the last |
| // child |
| int len = children.length; |
| if (len > 2) { |
| if (this.jjtGetChild(len - 1) instanceof AstMethodParameters) { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |