refactored MethodHandles
diff --git a/api/src/main/java/javax/faces/component/_ComponentAttributesMap.java b/api/src/main/java/javax/faces/component/_ComponentAttributesMap.java
index 5b6bf64..50a35f3 100755
--- a/api/src/main/java/javax/faces/component/_ComponentAttributesMap.java
+++ b/api/src/main/java/javax/faces/component/_ComponentAttributesMap.java
@@ -19,8 +19,6 @@
package javax.faces.component;
import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Method;
@@ -28,13 +26,14 @@
import java.util.Collections;
import java.util.Map;
import java.util.Set;
-import java.util.WeakHashMap;
-import java.util.concurrent.ConcurrentHashMap;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.Resource;
import javax.faces.context.FacesContext;
+import org.apache.myfaces.core.api.shared.lang.LambdaPropertyDescriptor;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorUtils;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorWrapper;
/**
* <p>
@@ -86,12 +85,8 @@
// the javabean properties of the associated component. This is built by
// introspection on the associated UIComponent. Don't serialize this as
// it can always be recreated when needed.
- private transient Map<String, _PropertyDescriptorHolder> _propertyDescriptorMap = null;
+ private transient Map<String, ? extends PropertyDescriptorWrapper> _propertyDescriptorMap = null;
- // Cache for component property descriptors
- private static Map<Class<?>, Map<String, _PropertyDescriptorHolder>> propertyDescriptorCache =
- new WeakHashMap<Class<?>, Map<String, _PropertyDescriptorHolder>>();
-
private boolean _isCompositeComponent;
private boolean _isCompositeComponentSet;
@@ -175,7 +170,7 @@
if (MARK_CREATED.length() == keyLength &&
MARK_CREATED.equals(key))
{
- return ((UIComponentBase)_component).getOamVfMarkCreated() != null;
+ return ((UIComponentBase) _component).getOamVfMarkCreated() != null;
}
else if (FACET_NAME_KEY.length() == keyLength &&
FACET_NAME_KEY.equals(key))
@@ -211,7 +206,11 @@
return _isCompositeComponent;
}
}
- return getPropertyDescriptor((String) key) == null ? getUnderlyingMap().containsKey(key) : false;
+
+ PropertyDescriptorWrapper pd = getPropertyDescriptor((String) key);
+ return pd == null || pd.getReadMethod() == null
+ ? getUnderlyingMap().containsKey(key)
+ : false;
}
/**
@@ -309,8 +308,8 @@
}
// is there a javabean property to read?
- _PropertyDescriptorHolder propertyDescriptor = getPropertyDescriptor((String) key);
- if (propertyDescriptor != null)
+ PropertyDescriptorWrapper propertyDescriptor = getPropertyDescriptor((String) key);
+ if (propertyDescriptor != null && propertyDescriptor.getReadMethod() != null)
{
value = getComponentProperty(propertyDescriptor);
}
@@ -493,8 +492,8 @@
}
}
- _PropertyDescriptorHolder propertyDescriptor = getPropertyDescriptor((String) key);
- if (propertyDescriptor != null)
+ PropertyDescriptorWrapper propertyDescriptor = getPropertyDescriptor((String) key);
+ if (propertyDescriptor != null && propertyDescriptor.getReadMethod() != null)
{
throw new IllegalArgumentException("Cannot remove component property attribute");
}
@@ -569,8 +568,8 @@
}
}
- _PropertyDescriptorHolder propertyDescriptor = getPropertyDescriptor(key);
- if (propertyDescriptor == null)
+ PropertyDescriptorWrapper propertyDescriptor = getPropertyDescriptor(key);
+ if (propertyDescriptor == null || propertyDescriptor.getReadMethod() == null)
{
if (value == null)
{
@@ -614,51 +613,13 @@
* that class.
* <p/>
*/
- private _PropertyDescriptorHolder getPropertyDescriptor(String key)
+ private PropertyDescriptorWrapper getPropertyDescriptor(String key)
{
if (_propertyDescriptorMap == null)
{
- // Try to get descriptor map from cache
- _propertyDescriptorMap = propertyDescriptorCache.get(_component.getClass());
-
- // Cache miss: create descriptor map and put it in cache
- if (_propertyDescriptorMap == null)
- {
- // Create descriptor map...
- BeanInfo beanInfo;
- try
- {
- beanInfo = Introspector.getBeanInfo(_component.getClass());
- }
- catch (IntrospectionException e)
- {
- throw new FacesException(e);
- }
-
- PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
- _propertyDescriptorMap = new ConcurrentHashMap<>();
- for (int i = 0; i < propertyDescriptors.length; i++)
- {
- PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
- Method readMethod = propertyDescriptor.getReadMethod();
- if (readMethod != null)
- {
- _propertyDescriptorMap.put(propertyDescriptor.getName(),
- new _PropertyDescriptorHolder(propertyDescriptor, readMethod));
- }
- }
-
- // ... and put it in cache
- synchronized (propertyDescriptorCache)
- {
- // Use a synchronized block to ensure proper operation on concurrent use cases.
- // This is a racy single check, because initialization over the same class could happen
- // multiple times, but the same result is always calculated. The synchronized block
- // just ensure thread-safety, because only one thread will modify the cache map
- // at the same time.
- propertyDescriptorCache.put(_component.getClass(), _propertyDescriptorMap);
- }
- }
+ _propertyDescriptorMap = PropertyDescriptorUtils.getCachedPropertyDescriptors(
+ _component.getFacesContext().getExternalContext(),
+ _component.getClass());
}
return _propertyDescriptorMap.get(key);
}
@@ -674,7 +635,7 @@
* @throws FacesException if any other problem occurs while invoking
* the getter method.
*/
- private Object getComponentProperty(_PropertyDescriptorHolder propertyDescriptor)
+ private Object getComponentProperty(PropertyDescriptorWrapper propertyDescriptor)
{
Method readMethod = propertyDescriptor.getReadMethod();
if (readMethod == null)
@@ -685,6 +646,11 @@
try
{
+ if (propertyDescriptor instanceof LambdaPropertyDescriptor)
+ {
+ return ((LambdaPropertyDescriptor) propertyDescriptor).getReadFunction().apply(_component);
+ }
+
return readMethod.invoke(_component, EMPTY_ARGS);
}
catch (Exception e)
@@ -704,7 +670,7 @@
* @throws FacesException if any other problem occurs while invoking
* the getter method.
*/
- private void setComponentProperty(_PropertyDescriptorHolder propertyDescriptor, Object value)
+ private void setComponentProperty(PropertyDescriptorWrapper propertyDescriptor, Object value)
{
Method writeMethod = propertyDescriptor.getWriteMethod();
if (writeMethod == null)
@@ -715,7 +681,14 @@
try
{
- writeMethod.invoke(_component, new Object[]{value});
+ if (propertyDescriptor instanceof LambdaPropertyDescriptor)
+ {
+ ((LambdaPropertyDescriptor) propertyDescriptor).getWriteFunction().accept(_component, value);
+ }
+ else
+ {
+ writeMethod.invoke(_component, new Object[]{value});
+ }
}
catch (Exception e)
{
diff --git a/api/src/main/java/javax/faces/component/_PropertyDescriptorHolder.java b/api/src/main/java/javax/faces/component/_PropertyDescriptorHolder.java
deleted file mode 100644
index 46b5f86..0000000
--- a/api/src/main/java/javax/faces/component/_PropertyDescriptorHolder.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.
- */
-package javax.faces.component;
-
-import java.beans.PropertyDescriptor;
-import java.lang.ref.Reference;
-import java.lang.ref.SoftReference;
-import java.lang.reflect.Method;
-
-class _PropertyDescriptorHolder
-{
- private final PropertyDescriptor _descriptor;
- private Reference<Method> _readMethodRef;
- private Reference<Method> _writeMethodRef;
-
- public _PropertyDescriptorHolder(PropertyDescriptor descriptor)
- {
- _descriptor = descriptor;
- _readMethodRef = new SoftReference<Method>(_descriptor.getReadMethod());
- }
-
- public _PropertyDescriptorHolder(PropertyDescriptor descriptor, Method readMethod)
- {
- _descriptor = descriptor;
- _readMethodRef = new SoftReference<Method>(readMethod);
- }
-
- public String getName()
- {
- return _descriptor.getName();
- }
-
- public Method getReadMethod()
- {
- Method readMethod = _readMethodRef.get();
- if (readMethod == null)
- {
- readMethod = _descriptor.getReadMethod();
- _readMethodRef = new SoftReference<Method>(readMethod);
- }
- return readMethod;
- }
-
- public Method getWriteMethod()
- {
- if (_writeMethodRef == null || _writeMethodRef.get() == null)
- {
- // In facelets, the Method instance used to write the variable is stored
- // in a variable (see org.apache.myfaces.view.facelets.tag.BeanPropertyTagRule),
- // so the impact of this synchronized call at the end is minimal compared with
- // getReadMethod. That's the reason why cache it here in a lazy way is enough
- // instead retrieve it as soon as this holder is created.
- Method writeMethod = _descriptor.getWriteMethod();
- _writeMethodRef = new SoftReference<Method>(writeMethod);
- }
- return _writeMethodRef.get();
- }
-
- public PropertyDescriptor getPropertyDescriptor()
- {
- return _descriptor;
- }
-}
diff --git a/api/src/main/java/org/apache/myfaces/core/api/shared/lang/LambdaPropertyDescriptor.java b/api/src/main/java/org/apache/myfaces/core/api/shared/lang/LambdaPropertyDescriptor.java
new file mode 100644
index 0000000..284f641
--- /dev/null
+++ b/api/src/main/java/org/apache/myfaces/core/api/shared/lang/LambdaPropertyDescriptor.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+package org.apache.myfaces.core.api.shared.lang;
+
+import java.beans.PropertyDescriptor;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+public class LambdaPropertyDescriptor extends PropertyDescriptorWrapper
+{
+ Function<Object, Object> readFunction;
+ BiConsumer<Object, Object> writeFunction;
+
+ public LambdaPropertyDescriptor(Class<?> beanClass, PropertyDescriptor wrapped)
+ {
+ super(beanClass, wrapped);
+ }
+
+ public Function<Object, Object> getReadFunction()
+ {
+ return readFunction;
+ }
+
+ public BiConsumer<Object, Object> getWriteFunction()
+ {
+ return writeFunction;
+ }
+}
diff --git a/impl/src/main/java/org/apache/myfaces/util/lang/MethodHandleUtils.java b/api/src/main/java/org/apache/myfaces/core/api/shared/lang/PropertyDescriptorUtils.java
similarity index 73%
rename from impl/src/main/java/org/apache/myfaces/util/lang/MethodHandleUtils.java
rename to api/src/main/java/org/apache/myfaces/core/api/shared/lang/PropertyDescriptorUtils.java
index f6f31dc..97339a1 100644
--- a/impl/src/main/java/org/apache/myfaces/util/lang/MethodHandleUtils.java
+++ b/api/src/main/java/org/apache/myfaces/core/api/shared/lang/PropertyDescriptorUtils.java
@@ -16,8 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.myfaces.util.lang;
+package org.apache.myfaces.core.api.shared.lang;
+import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.invoke.CallSite;
@@ -28,17 +29,27 @@
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.Collections;
-import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.ObjDoubleConsumer;
import java.util.function.ObjIntConsumer;
import java.util.function.ObjLongConsumer;
import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
-public final class MethodHandleUtils
+public class PropertyDescriptorUtils
{
+ /**
+ * Defines if MethodHandles and LambdaMetafactory instead of Reflection should be used for getter/setter.
+ */
+ @JSFWebConfigParam(since="2.3-next", defaultValue="true", expectedValues="true,false", tags="performance")
+ public static final String USE_METHOD_HANDLES = "org.apache.myfaces.USE_METHOD_HANDLES";
+
+ private static final String CACHE_KEY = PropertyDescriptorUtils.class.getName() + ".CACHE";
+
private static Method privateLookupIn;
static
@@ -52,46 +63,76 @@
{
}
}
-
- public static class LambdaPropertyDescriptor
+
+ private static Map<String, Map<String, ? extends PropertyDescriptorWrapper>> getCache(ExternalContext ec)
{
- private PropertyDescriptor wrapped;
- private Method readMethod;
- private Function<Object, Object> readFunction;
- private Method writeMethod;
- private BiConsumer<Object, Object> writeFunction;
-
- public PropertyDescriptor getWrapped()
+ Map<String, Map<String, ? extends PropertyDescriptorWrapper>> cache =
+ (Map<String, Map<String, ? extends PropertyDescriptorWrapper>>)
+ ec.getApplicationMap().get(CACHE_KEY);
+ if (cache == null)
{
- return wrapped;
+ cache = new ConcurrentHashMap<>(1000);
}
- public Class<?> getPropertyType()
+ return cache;
+ }
+
+ public static Map<String, ? extends PropertyDescriptorWrapper> getCachedPropertyDescriptors(ExternalContext ec,
+ Class<?> target)
+ {
+ return getCache(ec).computeIfAbsent(target.getName(), k ->
{
- return wrapped.getPropertyType();
- }
-
- public Method getReadMethod()
+ return getPropertyDescriptors(ec, target, false);
+ });
+ }
+
+ public static boolean isMethodHandlesSupported(ExternalContext ec)
+ {
+ if (privateLookupIn == null)
{
- return readMethod;
+ return false;
}
- public Function<Object, Object> getReadFunction()
- {
- return readFunction;
- }
-
- public Method getWriteMethod()
- {
- return writeMethod;
- }
-
- public BiConsumer<Object, Object> getWriteFunction()
- {
- return writeFunction;
- }
+ String useMethodHandles = ec.getInitParameter(USE_METHOD_HANDLES);
+ return useMethodHandles != null && useMethodHandles.contains("true");
}
+ public static Map<String, ? extends PropertyDescriptorWrapper> getPropertyDescriptors(ExternalContext ec,
+ Class<?> target,
+ boolean skipPropertyWithoutReadMethod)
+ {
+ if (isMethodHandlesSupported(ec))
+ {
+ return getLambdaPropertyDescriptors(target);
+ }
+
+ try
+ {
+ PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(target).getPropertyDescriptors();
+
+ Map<String, PropertyDescriptorWrapper> map = new ConcurrentHashMap<>(propertyDescriptors.length);
+
+ for (int i = 0; i < propertyDescriptors.length; i++)
+ {
+ PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
+ Method readMethod = propertyDescriptor.getReadMethod();
+ if (readMethod == null && skipPropertyWithoutReadMethod)
+ {
+ continue;
+ }
+
+ map.put(propertyDescriptor.getName(),
+ new PropertyDescriptorWrapper(target, propertyDescriptor, readMethod));
+ }
+
+ return map;
+ }
+ catch (IntrospectionException e)
+ {
+ throw new FacesException(e);
+ }
+ }
+
public static LambdaPropertyDescriptor getLambdaPropertyDescriptor(Class<?> target, String name)
{
try
@@ -108,7 +149,7 @@
{
MethodHandles.Lookup lookup = (MethodHandles.Lookup) privateLookupIn.invoke(null, target,
MethodHandles.lookup());
- return createLambdaPropertyDescriptor(pd, lookup);
+ return createLambdaPropertyDescriptor(target, pd, lookup);
}
}
@@ -120,17 +161,15 @@
}
}
- public static LambdaPropertyDescriptor createLambdaPropertyDescriptor(PropertyDescriptor pd,
+
+ public static LambdaPropertyDescriptor createLambdaPropertyDescriptor(Class<?> target, PropertyDescriptor pd,
MethodHandles.Lookup lookup) throws Throwable
{
- LambdaPropertyDescriptor lpd = new LambdaPropertyDescriptor();
- lpd.wrapped = pd;
+ LambdaPropertyDescriptor lpd = new LambdaPropertyDescriptor(target, pd);
Method readMethod = pd.getReadMethod();
if (readMethod != null)
{
- lpd.readMethod = readMethod;
-
MethodHandle handle = lookup.unreflect(readMethod);
CallSite callSite = LambdaMetafactory.metafactory(lookup,
"apply",
@@ -144,8 +183,6 @@
Method writeMethod = pd.getWriteMethod();
if (writeMethod != null)
{
- lpd.writeMethod = writeMethod;
-
MethodHandle handle = lookup.unreflect(writeMethod);
lpd.writeFunction = createSetter(lookup, lpd, handle);
}
@@ -163,14 +200,13 @@
return Collections.emptyMap();
}
- HashMap<String, LambdaPropertyDescriptor> properties = new HashMap<>(propertyDescriptors.length);
+ Map<String, LambdaPropertyDescriptor> properties = new ConcurrentHashMap<>(propertyDescriptors.length);
- MethodHandles.Lookup lookup = (MethodHandles.Lookup) privateLookupIn.invoke(null, target,
- MethodHandles.lookup());
-
+ MethodHandles.Lookup lookup = (MethodHandles.Lookup)
+ privateLookupIn.invoke(null, target, MethodHandles.lookup());
for (PropertyDescriptor pd : Introspector.getBeanInfo(target).getPropertyDescriptors())
{
- LambdaPropertyDescriptor lpd = createLambdaPropertyDescriptor(pd, lookup);
+ LambdaPropertyDescriptor lpd = createLambdaPropertyDescriptor(target, pd, lookup);
properties.put(pd.getName(), lpd);
}
diff --git a/api/src/main/java/org/apache/myfaces/core/api/shared/lang/PropertyDescriptorWrapper.java b/api/src/main/java/org/apache/myfaces/core/api/shared/lang/PropertyDescriptorWrapper.java
new file mode 100644
index 0000000..27c9271
--- /dev/null
+++ b/api/src/main/java/org/apache/myfaces/core/api/shared/lang/PropertyDescriptorWrapper.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+package org.apache.myfaces.core.api.shared.lang;
+
+import java.beans.PropertyDescriptor;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Method;
+import javax.faces.FacesWrapper;
+
+public class PropertyDescriptorWrapper implements FacesWrapper<PropertyDescriptor>
+{
+ private final PropertyDescriptor wrapped;
+ private Reference<Method> readMethodRef;
+ private Reference<Method> writeMethodRef;
+
+ public PropertyDescriptorWrapper(Class<?> beanClass, PropertyDescriptor wrapped)
+ {
+ this.wrapped = wrapped;
+ this.readMethodRef = new SoftReference<>(wrapped.getReadMethod());
+ }
+
+ public PropertyDescriptorWrapper(Class<?> beanClass, PropertyDescriptor wrapped, Method readMethod)
+ {
+ this.wrapped = wrapped;
+ this.readMethodRef = new SoftReference<>(readMethod);
+ }
+
+ public Class<?> getPropertyType()
+ {
+ return wrapped.getPropertyType();
+ }
+
+ public String getName()
+ {
+ return wrapped.getName();
+ }
+
+ @Override
+ public PropertyDescriptor getWrapped()
+ {
+ return wrapped;
+ }
+
+ public Method getReadMethod()
+ {
+ Method readMethod = readMethodRef.get();
+ if (readMethod == null)
+ {
+ readMethod = wrapped.getReadMethod();
+ readMethodRef = new SoftReference<>(readMethod);
+ }
+ return readMethod;
+ }
+
+ public Method getWriteMethod()
+ {
+ if (writeMethodRef == null || writeMethodRef.get() == null)
+ {
+ // In facelets, the Method instance used to write the variable is stored
+ // in a variable (see org.apache.myfaces.view.facelets.tag.BeanPropertyTagRule),
+ // so the impact of this synchronized call at the end is minimal compared with
+ // getReadMethod. That's the reason why cache it here in a lazy way is enough
+ // instead retrieve it as soon as this holder is created.
+ Method writeMethod = wrapped.getWriteMethod();
+ writeMethodRef = new SoftReference<>(writeMethod);
+ }
+ return writeMethodRef.get();
+ }
+}
diff --git a/extensions/quarkus/deployment/src/main/java/org/apache/myfaces/core/extensions/quarkus/deployment/MyFacesProcessor.java b/extensions/quarkus/deployment/src/main/java/org/apache/myfaces/core/extensions/quarkus/deployment/MyFacesProcessor.java
index 1e9cee2..0fe37c6 100644
--- a/extensions/quarkus/deployment/src/main/java/org/apache/myfaces/core/extensions/quarkus/deployment/MyFacesProcessor.java
+++ b/extensions/quarkus/deployment/src/main/java/org/apache/myfaces/core/extensions/quarkus/deployment/MyFacesProcessor.java
@@ -30,7 +30,6 @@
import javax.faces.flow.FlowScoped;
import javax.faces.flow.builder.FlowDefinition;
import javax.faces.model.FacesDataModel;
-import javax.faces.push.PushContext;
import javax.faces.render.FacesBehaviorRenderer;
import javax.faces.render.FacesRenderer;
import javax.faces.validator.FacesValidator;
@@ -50,7 +49,7 @@
import org.apache.myfaces.config.annotation.CdiAnnotationProviderExtension;
import org.apache.myfaces.config.element.NamedEvent;
import org.apache.myfaces.core.extensions.quarkus.runtime.exception.QuarkusExceptionHandlerFactory;
-import org.apache.myfaces.el.resolver.MethodHandleBeanELResolver;
+import org.apache.myfaces.el.resolver.LambdaBeanELResolver;
import org.apache.myfaces.flow.cdi.FlowBuilderFactoryBean;
import org.apache.myfaces.flow.cdi.FlowScopeBeanHolder;
import org.apache.myfaces.push.cdi.PushContextFactoryBean;
@@ -58,8 +57,7 @@
import org.apache.myfaces.push.cdi.WebsocketChannelTokenBuilderBean;
import org.apache.myfaces.push.cdi.WebsocketSessionBean;
import org.apache.myfaces.push.cdi.WebsocketViewBean;
-import org.apache.myfaces.util.lang.MethodHandleUtils;
-import org.apache.myfaces.view.facelets.tag.MethodHandleMetadataTargetImpl;
+import org.apache.myfaces.view.facelets.tag.LambdaMetadataTargetImpl;
import org.apache.myfaces.webapp.StartupServletContextListener;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
@@ -124,6 +122,7 @@
import org.apache.myfaces.application.viewstate.StateUtils;
import org.apache.myfaces.cdi.util.BeanEntry;
import org.apache.myfaces.config.FacesConfigurator;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorUtils;
import org.apache.myfaces.core.extensions.quarkus.runtime.spi.QuarkusFactoryFinderProvider;
import org.apache.myfaces.el.ELResolverBuilderForFaces;
import org.apache.myfaces.renderkit.ErrorPageWriter;
@@ -277,15 +276,6 @@
Optional<String> projectStage = resolveProjectStage(config);
initParam.produce(new ServletInitParamBuildItem(ProjectStage.PROJECT_STAGE_PARAM_NAME, projectStage.get()));
- Optional<String> enableWebsocketsEndpoint = config.getOptionalValue(
- PushContext.ENABLE_WEBSOCKET_ENDPOINT_PARAM_NAME,
- String.class);
- if (enableWebsocketsEndpoint.isPresent())
- {
- initParam.produce(new ServletInitParamBuildItem(PushContext.ENABLE_WEBSOCKET_ENDPOINT_PARAM_NAME,
- enableWebsocketsEndpoint.get()));
- }
-
// common
initParam.produce(new ServletInitParamBuildItem(
MyfacesConfig.LOG_WEB_CONTEXT_PARAMS, "false"));
@@ -802,11 +792,11 @@
void registerRuntimeInitialization(BuildProducer<RuntimeInitializedClassBuildItem> runtimeInitClassBuildItem)
{
runtimeInitClassBuildItem.produce(
- new RuntimeInitializedClassBuildItem(MethodHandleBeanELResolver.class.getCanonicalName()));
+ new RuntimeInitializedClassBuildItem(LambdaBeanELResolver.class.getCanonicalName()));
runtimeInitClassBuildItem.produce(
- new RuntimeInitializedClassBuildItem(MethodHandleMetadataTargetImpl.class.getCanonicalName()));
+ new RuntimeInitializedClassBuildItem(LambdaMetadataTargetImpl.class.getCanonicalName()));
runtimeInitClassBuildItem.produce(
- new RuntimeInitializedClassBuildItem(MethodHandleUtils.class.getCanonicalName()));
+ new RuntimeInitializedClassBuildItem(PropertyDescriptorUtils.class.getCanonicalName()));
}
diff --git a/extensions/quarkus/showcase/src/main/resources/META-INF/web.xml b/extensions/quarkus/showcase/src/main/resources/META-INF/web.xml
index 9cc3e3a..35816fa 100644
--- a/extensions/quarkus/showcase/src/main/resources/META-INF/web.xml
+++ b/extensions/quarkus/showcase/src/main/resources/META-INF/web.xml
@@ -20,7 +20,12 @@
<web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
-
+
+ <context-param>
+ <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
<context-param>
<param-name>primefaces.THEME</param-name>
diff --git a/extensions/quarkus/showcase/src/main/resources/application.properties b/extensions/quarkus/showcase/src/main/resources/application.properties
index cf94889..c5e2196 100644
--- a/extensions/quarkus/showcase/src/main/resources/application.properties
+++ b/extensions/quarkus/showcase/src/main/resources/application.properties
@@ -14,6 +14,5 @@
quarkus.log.console.format=%s%n
javax.faces.PROJECT_STAGE=Development
-javax.faces.ENABLE_WEBSOCKET_ENDPOINT=true
quarkus.log.console.level=INFO
quarkus.log.file.path=/tmp/debug.log
\ No newline at end of file
diff --git a/impl/src/main/java/org/apache/myfaces/config/MyfacesConfig.java b/impl/src/main/java/org/apache/myfaces/config/MyfacesConfig.java
index 8e0bec6..6e554b4 100755
--- a/impl/src/main/java/org/apache/myfaces/config/MyfacesConfig.java
+++ b/impl/src/main/java/org/apache/myfaces/config/MyfacesConfig.java
@@ -18,7 +18,6 @@
*/
package org.apache.myfaces.config;
-import java.lang.invoke.MethodHandles;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -812,14 +811,6 @@
protected final static boolean ALWAYS_FORCE_SESSION_CREATION_DEFAULT = false;
/**
- * Defines if MethodHandles and LambdaMetafactory instead of Reflection should be used for getter/setter.
- */
- @JSFWebConfigParam(since="2.3-next", defaultValue="true", expectedValues="true,false", tags="performance")
- public static final String USE_METHOD_HANDLES =
- "org.apache.myfaces.USE_METHOD_HANDLES";
- protected final static boolean USE_METHOD_HANDLES_DEFAULT = true;
-
- /**
* Defines the {@link java.util.ResourceBundle.Control} to use for all
* {@link java.util.ResourceBundle#getBundle(java.lang.String)} calls.
*/
@@ -906,7 +897,6 @@
private int websocketMaxConnections = WEBSOCKET_MAX_CONNECTIONS_DEFAULT;
private boolean renderClientBehaviorScriptsAsString = RENDER_CLIENTBEHAVIOR_SCRIPTS_AS_STRING_DEFAULT;
private boolean alwaysForceSessionCreation = ALWAYS_FORCE_SESSION_CREATION_DEFAULT;
- private boolean useMethodHandles = USE_METHOD_HANDLES_DEFAULT;
private ResourceBundle.Control resourceBundleControl;
private boolean automaticExtensionlessMapping = AUTOMATIC_EXTENSIONLESS_MAPPING_DEFAULT;
@@ -960,17 +950,6 @@
{
numberOfFlashTokensInSession = (NUMBER_OF_VIEWS_IN_SESSION_DEFAULT
/ NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_DEFAULT) + 1;
-
- try
- {
- MethodHandles.class.getMethod("privateLookupIn", Class.class,
- MethodHandles.Lookup.class);
- useMethodHandles = true;
- }
- catch (NoSuchMethodException e)
- {
- useMethodHandles = false;
- }
}
private static MyfacesConfig createAndInitializeMyFacesConfig(ExternalContext extCtx)
@@ -1338,21 +1317,6 @@
cfg.alwaysForceSessionCreation = getBoolean(extCtx, ALWAYS_FORCE_SESSION_CREATION,
ALWAYS_FORCE_SESSION_CREATION_DEFAULT);
-
- cfg.useMethodHandles = getBoolean(extCtx, USE_METHOD_HANDLES,
- USE_METHOD_HANDLES_DEFAULT);
- if (cfg.useMethodHandles)
- {
- try
- {
- MethodHandles.class.getMethod("privateLookupIn", Class.class,
- MethodHandles.Lookup.class);
- }
- catch (NoSuchMethodException e)
- {
- cfg.useMethodHandles = false;
- }
- }
String resourceBundleControl = getString(extCtx, RESOURCE_BUNDLE_CONTROL, null);
if (StringUtils.isNotBlank(resourceBundleControl))
@@ -1823,11 +1787,6 @@
return alwaysForceSessionCreation;
}
- public boolean isUseMethodHandles()
- {
- return useMethodHandles;
- }
-
public ProjectStage getProjectStage()
{
return projectStage;
diff --git a/impl/src/main/java/org/apache/myfaces/el/ELResolverBuilderForFaces.java b/impl/src/main/java/org/apache/myfaces/el/ELResolverBuilderForFaces.java
index 5bb2804..9587d37 100644
--- a/impl/src/main/java/org/apache/myfaces/el/ELResolverBuilderForFaces.java
+++ b/impl/src/main/java/org/apache/myfaces/el/ELResolverBuilderForFaces.java
@@ -46,7 +46,8 @@
import org.apache.myfaces.el.resolver.ScopedAttributeResolver;
import org.apache.myfaces.el.resolver.implicitobject.ImplicitObjectResolver;
import org.apache.myfaces.config.MyfacesConfig;
-import org.apache.myfaces.el.resolver.MethodHandleBeanELResolver;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorUtils;
+import org.apache.myfaces.el.resolver.LambdaBeanELResolver;
import org.apache.myfaces.util.lang.ClassUtils;
/**
@@ -140,9 +141,9 @@
list.add(new MapELResolver());
list.add(new ListELResolver());
list.add(new ArrayELResolver());
- if (myfacesConfig.isUseMethodHandles())
+ if (PropertyDescriptorUtils.isMethodHandlesSupported(facesContext.getExternalContext()))
{
- list.add(new MethodHandleBeanELResolver());
+ list.add(new LambdaBeanELResolver(facesContext.getExternalContext()));
}
else
{
diff --git a/impl/src/main/java/org/apache/myfaces/el/resolver/MethodHandleBeanELResolver.java b/impl/src/main/java/org/apache/myfaces/el/resolver/LambdaBeanELResolver.java
similarity index 75%
rename from impl/src/main/java/org/apache/myfaces/el/resolver/MethodHandleBeanELResolver.java
rename to impl/src/main/java/org/apache/myfaces/el/resolver/LambdaBeanELResolver.java
index b69959f..4cb9f51 100644
--- a/impl/src/main/java/org/apache/myfaces/el/resolver/MethodHandleBeanELResolver.java
+++ b/impl/src/main/java/org/apache/myfaces/el/resolver/LambdaBeanELResolver.java
@@ -26,15 +26,20 @@
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.PropertyNotWritableException;
-import org.apache.myfaces.util.lang.MethodHandleUtils;
+import javax.faces.context.ExternalContext;
+import org.apache.myfaces.core.api.shared.lang.LambdaPropertyDescriptor;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorUtils;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorWrapper;
-public class MethodHandleBeanELResolver extends BeanELResolver
+public class LambdaBeanELResolver extends BeanELResolver
{
- private final ConcurrentHashMap<String, Map<String, MethodHandleUtils.LambdaPropertyDescriptor>> cache;
+ private final ExternalContext externalContext;
+ private final ConcurrentHashMap<String, Map<String, ? extends PropertyDescriptorWrapper>> cache;
- public MethodHandleBeanELResolver()
+ public LambdaBeanELResolver(ExternalContext externalContext)
{
- cache = new ConcurrentHashMap<>(1000);
+ this.externalContext = externalContext;
+ this.cache = new ConcurrentHashMap<>(1000);
}
@Override
@@ -85,7 +90,7 @@
context.setPropertyResolved(base, property);
- MethodHandleUtils.LambdaPropertyDescriptor propertyDescriptor = getPropertyDescriptor(base, property);
+ LambdaPropertyDescriptor propertyDescriptor = getPropertyDescriptor(base, property);
if (propertyDescriptor.getWriteFunction() == null)
{
throw new PropertyNotWritableException("Property \"" + (String) property
@@ -127,14 +132,12 @@
return null;
}
- protected MethodHandleUtils.LambdaPropertyDescriptor getPropertyDescriptor(Object base, Object property)
+ protected LambdaPropertyDescriptor getPropertyDescriptor(Object base, Object property)
{
- Map<String, MethodHandleUtils.LambdaPropertyDescriptor> beanCache = cache.computeIfAbsent(
+ Map<String, ? extends PropertyDescriptorWrapper> beanCache = cache.computeIfAbsent(
base.getClass().getName(),
- k -> new ConcurrentHashMap<>());
+ k -> PropertyDescriptorUtils.getCachedPropertyDescriptors(externalContext, base.getClass()));
- return beanCache.computeIfAbsent(
- (String) property,
- k -> MethodHandleUtils.getLambdaPropertyDescriptor(base.getClass(), k));
+ return (LambdaPropertyDescriptor) beanCache.get((String) property);
}
}
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/BeanPropertyTagRule.java b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/BeanPropertyTagRule.java
index 0216cd7..55615b5 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/BeanPropertyTagRule.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/BeanPropertyTagRule.java
@@ -41,9 +41,9 @@
@Override
public Metadata applyRule(String name, TagAttribute attribute, MetadataTarget meta)
{
- if (meta instanceof MethodHandleMetadataTargetImpl)
+ if (meta instanceof LambdaMetadataTargetImpl)
{
- BiConsumer<Object, Object> f = ((MethodHandleMetadataTargetImpl) meta).getWriteFunction(name);
+ BiConsumer<Object, Object> f = ((LambdaMetadataTargetImpl) meta).getWriteFunction(name);
// if the property is writable
if (f != null)
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MethodHandleMetadataTargetImpl.java b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/LambdaMetadataTargetImpl.java
similarity index 68%
rename from impl/src/main/java/org/apache/myfaces/view/facelets/tag/MethodHandleMetadataTargetImpl.java
rename to impl/src/main/java/org/apache/myfaces/view/facelets/tag/LambdaMetadataTargetImpl.java
index 05b3833..ab298e0 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MethodHandleMetadataTargetImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/LambdaMetadataTargetImpl.java
@@ -24,24 +24,29 @@
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
+import javax.faces.context.FacesContext;
import javax.faces.view.facelets.MetadataTarget;
-import org.apache.myfaces.util.lang.MethodHandleUtils;
+import org.apache.myfaces.core.api.shared.lang.LambdaPropertyDescriptor;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorUtils;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorWrapper;
-public class MethodHandleMetadataTargetImpl extends MetadataTarget
+public class LambdaMetadataTargetImpl extends MetadataTarget
{
- private final Map<String, MethodHandleUtils.LambdaPropertyDescriptor> propertyDescriptors;
+ private final Map<String, ? extends PropertyDescriptorWrapper> propertyDescriptors;
private final Class<?> type;
- public MethodHandleMetadataTargetImpl(Class<?> type) throws IntrospectionException
+ public LambdaMetadataTargetImpl(Class<?> type) throws IntrospectionException
{
this.type = type;
- this.propertyDescriptors = MethodHandleUtils.getLambdaPropertyDescriptors(type);
+ this.propertyDescriptors = PropertyDescriptorUtils.getCachedPropertyDescriptors(
+ FacesContext.getCurrentInstance().getExternalContext(),
+ type);
}
@Override
public PropertyDescriptor getProperty(String name)
{
- MethodHandleUtils.LambdaPropertyDescriptor lpd = getLambdaProperty(name);
+ LambdaPropertyDescriptor lpd = getLambdaProperty(name);
if (lpd == null)
{
return null;
@@ -53,7 +58,7 @@
@Override
public Class<?> getPropertyType(String name)
{
- MethodHandleUtils.LambdaPropertyDescriptor lpd = getLambdaProperty(name);
+ LambdaPropertyDescriptor lpd = getLambdaProperty(name);
if (lpd == null)
{
return null;
@@ -65,7 +70,7 @@
@Override
public Method getReadMethod(String name)
{
- MethodHandleUtils.LambdaPropertyDescriptor lpd = getLambdaProperty(name);
+ LambdaPropertyDescriptor lpd = getLambdaProperty(name);
if (lpd == null)
{
return null;
@@ -83,7 +88,7 @@
@Override
public Method getWriteMethod(String name)
{
- MethodHandleUtils.LambdaPropertyDescriptor lpd = getLambdaProperty(name);
+ LambdaPropertyDescriptor lpd = getLambdaProperty(name);
if (lpd == null)
{
return null;
@@ -98,14 +103,14 @@
return type.isAssignableFrom(type);
}
- public MethodHandleUtils.LambdaPropertyDescriptor getLambdaProperty(String name)
+ public LambdaPropertyDescriptor getLambdaProperty(String name)
{
- return propertyDescriptors.get(name);
+ return (LambdaPropertyDescriptor) propertyDescriptors.get(name);
}
public Function<Object, Object> getReadFunction(String name)
{
- MethodHandleUtils.LambdaPropertyDescriptor lpd = getLambdaProperty(name);
+ LambdaPropertyDescriptor lpd = getLambdaProperty(name);
if (lpd == null)
{
return null;
@@ -116,7 +121,7 @@
public BiConsumer<Object, Object> getWriteFunction(String name)
{
- MethodHandleUtils.LambdaPropertyDescriptor lpd = getLambdaProperty(name);
+ LambdaPropertyDescriptor lpd = getLambdaProperty(name);
if (lpd == null)
{
return null;
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MetaRulesetImpl.java b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MetaRulesetImpl.java
index e5f7988..aedd5d1 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MetaRulesetImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MetaRulesetImpl.java
@@ -34,7 +34,8 @@
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.apache.myfaces.config.MyfacesConfig;
+import javax.faces.context.FacesContext;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorUtils;
import org.apache.myfaces.util.lang.Assert;
import org.apache.myfaces.view.facelets.PassthroughRule;
import org.apache.myfaces.view.facelets.tag.jsf.PassThroughLibrary;
@@ -325,9 +326,10 @@
{
try
{
- if (MyfacesConfig.getCurrentInstance().isUseMethodHandles())
+ if (PropertyDescriptorUtils.isMethodHandlesSupported(
+ FacesContext.getCurrentInstance().getExternalContext()))
{
- meta = new MethodHandleMetadataTargetImpl(_type);
+ meta = new LambdaMetadataTargetImpl(_type);
}
else
{
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeMetaRulesetImpl.java b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeMetaRulesetImpl.java
index 5d4d3ed..e708320 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeMetaRulesetImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeMetaRulesetImpl.java
@@ -38,17 +38,16 @@
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.apache.myfaces.config.MyfacesConfig;
+import org.apache.myfaces.core.api.shared.lang.PropertyDescriptorUtils;
import org.apache.myfaces.util.lang.Assert;
-import org.apache.myfaces.view.facelets.tag.MethodHandleMetadataTargetImpl;
+import org.apache.myfaces.view.facelets.tag.LambdaMetadataTargetImpl;
import org.apache.myfaces.view.facelets.tag.NullMetadata;
public class CompositeMetaRulesetImpl extends MetaRuleset
{
private final static Logger log = Logger.getLogger(CompositeMetadataTargetImpl.class.getName());
- private static final String METADATA_KEY
- = "org.apache.myfaces.view.facelets.tag.composite.CompositeMetaRulesetImpl.METADATA";
+ private static final String METADATA_KEY = CompositeMetaRulesetImpl.class.getName() + ".METADATA";
private static Map<String, MetadataTarget> getMetaData()
{
@@ -215,9 +214,10 @@
{
try
{
- if (MyfacesConfig.getCurrentInstance().isUseMethodHandles())
+ if (PropertyDescriptorUtils.isMethodHandlesSupported(
+ FacesContext.getCurrentInstance().getExternalContext()))
{
- meta = new MethodHandleMetadataTargetImpl(_type);
+ meta = new LambdaMetadataTargetImpl(_type);
}
else
{