com.sun.faces.el.ELUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jakarta.faces Show documentation
Show all versions of jakarta.faces Show documentation
EE4J Compatible Implementation for Jakarta Faces API
/*
* Copyright (c) 2023 Contributors to Eclipse Foundation.
* Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package com.sun.faces.el;
import static com.sun.faces.RIConstants.EMPTY_CLASS_ARGS;
import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.InterpretEmptyStringSubmittedValuesAsNull;
import static com.sun.faces.util.MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID;
import static com.sun.faces.util.MessageUtils.getExceptionMessageString;
import static com.sun.faces.util.ReflectionUtils.lookupMethod;
import static com.sun.faces.util.ReflectionUtils.newInstance;
import static com.sun.faces.util.Util.getCdiBeanManager;
import static java.lang.Boolean.FALSE;
import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.config.WebConfiguration;
import com.sun.faces.context.flash.FlashELResolver;
import com.sun.faces.util.Cache;
import com.sun.faces.util.LRUCache;
import jakarta.el.ArrayELResolver;
import jakarta.el.BeanELResolver;
import jakarta.el.CompositeELResolver;
import jakarta.el.ELContext;
import jakarta.el.ELResolver;
import jakarta.el.ExpressionFactory;
import jakarta.el.ListELResolver;
import jakarta.el.MapELResolver;
import jakarta.el.ResourceBundleELResolver;
import jakarta.el.ValueExpression;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import java.lang.reflect.Method;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Utility class for EL related methods.
*/
public class ELUtils {
/**
* The maximum size of the compositeComponentEvaluationCache
.
*/
private static final int compositeComponentEvaluationCacheMaxSize = 1000;
/**
* Helps to determine if a EL expression represents a composite component EL expression.
*/
private static final Pattern COMPOSITE_COMPONENT_EXPRESSION = Pattern.compile(".(?:[ ]+|[\\[{,(])cc[.].+[}]");
// do not use this Matcher, it's only for the Cache Factory
private static final Matcher COMPOSITE_COMPONENT_EXPRESSION_MATCHER = COMPOSITE_COMPONENT_EXPRESSION.matcher("");
/**
* Cache.Factory that initialize an element inside the LRUCache evaluating a Matcher against the input.
* We should be able to share a Matcher because the Factory it's executed atomically
* and this Matcher is used only here
*/
private static final Cache.Factory isCompositeExpressionInit = new Cache.Factory<>() {
// it would be safer to declare the shared Matcher here, but it requires Java 16+ ... Faces 5.0 ?
// private static final Matcher COMPOSITE_COMPONENT_EXPRESSION_MATCHER = COMPOSITE_COMPONENT_EXPRESSION.matcher("");
@Override
public Boolean newInstance(String expression) {
return expression == null ? FALSE : COMPOSITE_COMPONENT_EXPRESSION_MATCHER.reset(expression).find();
}
};
/**
* Private cache for storing evaluation results for composite components checks.
*/
private static final LRUCache compositeComponentEvaluationCache = new LRUCache<>(isCompositeExpressionInit, compositeComponentEvaluationCacheMaxSize);
/**
* Used to determine if EL method arguments are being passed to a composite component lookup expression.
*
* For example:
*
* #{cc.attrs.label('foo')}
*
* is illegal, while:
*
* #{cc.attrs.bean.label('foo')}
*
* is legal.
*/
private static final Pattern COMPOSITE_COMPONENT_LOOKUP_WITH_ARGS = Pattern.compile("(?:[ ]+|[\\[{,(])cc[.]attrs[.]\\w+[(].+[)]");
/**
* Use to determine if an expression being considered as a MethodExpression is a simple lookup (i.e.
* #{cc.attrs.myaction}).
*/
private static final Pattern METHOD_EXPRESSION_LOOKUP = Pattern.compile(".[{]cc[.]attrs[.]\\w+[}]");
public static final ArrayELResolver ARRAY_RESOLVER = new ArrayELResolver();
public static final BeanELResolver BEAN_RESOLVER = new BeanELResolver();
public static final FacesResourceBundleELResolver FACES_BUNDLE_RESOLVER = new FacesResourceBundleELResolver();
public static final FlashELResolver FLASH_RESOLVER = new FlashELResolver();
public static final ListELResolver LIST_RESOLVER = new ListELResolver();
public static final MapELResolver MAP_RESOLVER = new MapELResolver();
public static final ResourceBundleELResolver BUNDLE_RESOLVER = new ResourceBundleELResolver();
public static final ScopedAttributeELResolver SCOPED_RESOLVER = new ScopedAttributeELResolver();
public static final ResourceELResolver RESOURCE_RESOLVER = new ResourceELResolver();
public static final CompositeComponentAttributesELResolver COMPOSITE_COMPONENT_ATTRIBUTES_EL_RESOLVER = new CompositeComponentAttributesELResolver();
public static final EmptyStringToNullELResolver EMPTY_STRING_TO_NULL_RESOLVER = new EmptyStringToNullELResolver();
// ------------------------------------------------------------ Constructors
private ELUtils() {
throw new IllegalStateException();
}
// ---------------------------------------------------------- Public Methods
public static boolean isCompositeComponentExpr(String expression) {
return compositeComponentEvaluationCache.get(expression);
}
public static boolean isCompositeComponentMethodExprLookup(String expression) {
return METHOD_EXPRESSION_LOOKUP.matcher(expression).matches();
}
public static boolean isCompositeComponentLookupWithArgs(String expression) {
// TODO we should be trying to re-use the Matcher by calling
// pizzi80: not sure because it will require a synchronized block if this method
// is called by multiple threads
// m.reset(expression);
return COMPOSITE_COMPONENT_LOOKUP_WITH_ARGS.matcher(expression).find();
}
/**
*
* Create the ELResolver
chain for programmatic EL calls.
*
*
* @param composite a CompositeELResolver
* @param associate our ApplicationAssociate
*/
public static void buildFacesResolver(FacesCompositeELResolver composite, ApplicationAssociate associate) {
checkNotNull(composite, associate);
addCDIELResolver(composite);
composite.add(FLASH_RESOLVER);
composite.addPropertyELResolver(COMPOSITE_COMPONENT_ATTRIBUTES_EL_RESOLVER);
addELResolvers(composite, associate.getELResolversFromFacesConfig());
composite.add(associate.getApplicationELResolvers());
if (WebConfiguration.getInstance().isOptionEnabled(InterpretEmptyStringSubmittedValuesAsNull)) {
composite.addPropertyELResolver(EMPTY_STRING_TO_NULL_RESOLVER);
}
composite.addPropertyELResolver(RESOURCE_RESOLVER);
composite.addPropertyELResolver(BUNDLE_RESOLVER);
composite.addRootELResolver(FACES_BUNDLE_RESOLVER);
addEL3_0_Resolvers(composite, associate);
composite.addPropertyELResolver(MAP_RESOLVER);
composite.addPropertyELResolver(LIST_RESOLVER);
composite.addPropertyELResolver(ARRAY_RESOLVER);
composite.addPropertyELResolver(BEAN_RESOLVER);
composite.addRootELResolver(SCOPED_RESOLVER);
}
private static void checkNotNull(FacesCompositeELResolver composite, ApplicationAssociate associate) {
if (associate == null) {
throw new NullPointerException(getExceptionMessageString(NULL_PARAMETERS_ERROR_MESSAGE_ID, "associate"));
}
if (composite == null) {
throw new NullPointerException(getExceptionMessageString(NULL_PARAMETERS_ERROR_MESSAGE_ID, "composite"));
}
}
private static void addCDIELResolver(FacesCompositeELResolver composite) {
composite.add(getCdiBeanManager(FacesContext.getCurrentInstance()).getELResolver());
}
private static void addEL3_0_Resolvers(FacesCompositeELResolver composite, ApplicationAssociate associate) {
ExpressionFactory expressionFactory = associate.getExpressionFactory();
Method getStreamELResolverMethod = lookupMethod(ExpressionFactory.class, "getStreamELResolver", EMPTY_CLASS_ARGS);
if (getStreamELResolverMethod != null) {
try {
ELResolver streamELResolver = (ELResolver) getStreamELResolverMethod.invoke(expressionFactory, (Object[]) null);
if (streamELResolver != null) {
composite.addRootELResolver(streamELResolver);
// Assume that if we have getStreamELResolver, then we must have
// jakarta.el.staticFieldELResolver
composite.addRootELResolver((ELResolver) newInstance("jakarta.el.StaticFieldELResolver"));
}
} catch (IllegalArgumentException | ReflectiveOperationException | SecurityException t) {
// This is normal on containers that do not have these ELResolvers
}
}
}
public static Object evaluateValueExpression(ValueExpression expression, ELContext elContext) {
if (expression.isLiteralText()) {
return expression.getExpressionString();
}
return expression.getValue(elContext);
}
/**
* Create a ValueExpression
with the expected type of Object.class
*
* @param expression an EL expression
* @return a new ValueExpression
instance based off the provided valueRef
*/
public static ValueExpression createValueExpression(String expression) {
return createValueExpression(expression, Object.class);
}
public static ValueExpression createValueExpression(String expression, Class> expectedType) {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(), expression, expectedType);
}
public static Object coerce(Object value, Class> toType) {
return FacesContext.getCurrentInstance().getApplication().getExpressionFactory().coerceToType(value, toType);
}
// --------------------------------------------------------- Private Methods
/**
*
* Add the ELResolvers
from the provided list to the target CompositeELResolver
.
*
*
* @param target the CompositeELResolver
to which the ELResolver
s will be added.
* @param resolvers a List
of ELResolver
s
*/
private static void addELResolvers(CompositeELResolver target, List resolvers) {
if (resolvers != null && !resolvers.isEmpty()) {
for (ELResolver resolver : resolvers) {
target.add(resolver);
}
}
}
/*
* First look in the ApplicationAssociate. If that fails, return null;
*
*/
public static ExpressionFactory getDefaultExpressionFactory(FacesContext facesContext) {
if (facesContext == null) {
return null;
}
ExternalContext extContext = facesContext.getExternalContext();
if (extContext == null) {
return null;
}
return getDefaultExpressionFactory(ApplicationAssociate.getInstance(extContext), facesContext);
}
public static ExpressionFactory getDefaultExpressionFactory(ApplicationAssociate associate, FacesContext facesContext) {
if (associate == null) {
return null;
}
return associate.getExpressionFactory();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy