This is an automated email from the ASF dual-hosted git repository.
doebele pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/empire-db.git
The following commit(s) were added to refs/heads/master by this push:
new 91aff76b EMPIREDB-453 TagEncodingHelper: new implemetation for
findTopValueExpression()
91aff76b is described below
commit 91aff76b1fc2be0f947a5cd602cecb999cd1910a
Author: Rainer Döbele <[email protected]>
AuthorDate: Wed Jan 8 18:29:14 2025 +0100
EMPIREDB-453
TagEncodingHelper: new implemetation for findTopValueExpression()
---
.../empire/jakarta/controls/InputControl.java | 27 ++--
.../empire/jakarta/impl/FacesImplementation.java | 42 ++-----
.../empire/jakarta/impl/MojarraImplementation.java | 34 ++---
.../empire/jakarta/impl/MyFacesImplementation.java | 37 +-----
.../empire/jakarta/utils/TagEncodingHelper.java | 138 +++++++++++++++------
.../jakarta/utils/ValueExpressionUnwrapper.java | 21 ++--
.../apache/empire/jsf2/controls/InputControl.java | 7 +-
.../empire/jsf2/impl/FacesImplementation.java | 42 ++-----
.../empire/jsf2/impl/MojarraImplementation.java | 34 ++---
.../empire/jsf2/impl/MyFacesImplementation.java | 37 +-----
.../empire/jsf2/utils/TagEncodingHelper.java | 138 +++++++++++++++------
.../jsf2/utils/ValueExpressionUnwrapper.java | 15 ++-
.../java/org/apache/empire/commons/ClassUtils.java | 28 ++++-
13 files changed, 334 insertions(+), 266 deletions(-)
diff --git
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControl.java
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControl.java
index 4120697f..3d06e286 100644
---
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControl.java
+++
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControl.java
@@ -23,16 +23,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
-import jakarta.el.ValueExpression;
-import jakarta.faces.component.UIComponent;
-import jakarta.faces.component.UIComponentBase;
-import jakarta.faces.component.UIData;
-import jakarta.faces.component.UIInput;
-import jakarta.faces.component.behavior.ClientBehaviorHolder;
-import jakarta.faces.context.FacesContext;
-import jakarta.faces.context.ResponseWriter;
-import jakarta.faces.event.PhaseId;
-
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.OptionEntry;
import org.apache.empire.commons.Options;
@@ -48,6 +38,16 @@ import org.apache.empire.jakarta.utils.TagStyleClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import jakarta.el.ValueExpression;
+import jakarta.faces.component.UIComponent;
+import jakarta.faces.component.UIComponentBase;
+import jakarta.faces.component.UIData;
+import jakarta.faces.component.UIInput;
+import jakarta.faces.component.behavior.ClientBehaviorHolder;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.context.ResponseWriter;
+import jakarta.faces.event.PhaseId;
+
public abstract class InputControl
{
@@ -483,6 +483,11 @@ public abstract class InputControl
throw new ItemNotFoundException("UIInput");
}
+ protected boolean isInputValueExpressionEnabled()
+ {
+ return InputControlManager.isInputValueExpressionEnabled();
+ }
+
protected void setInputValue(UIInput input, InputInfo ii)
{
// Restore submitted value
@@ -508,7 +513,7 @@ public abstract class InputControl
/* -------------------------------------- */
// Assign value
- boolean evalExpression =
!InputControlManager.isInputValueExpressionEnabled();
+ boolean evalExpression = !isInputValueExpressionEnabled();
Object value = ii.getValue(evalExpression);
if (value instanceof ValueExpression)
{
diff --git
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/FacesImplementation.java
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/FacesImplementation.java
index 7d290519..385e7572 100644
---
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/FacesImplementation.java
+++
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/FacesImplementation.java
@@ -18,11 +18,7 @@
*/
package org.apache.empire.jakarta.impl;
-import java.lang.reflect.Method;
-
import jakarta.el.ELResolver;
-import jakarta.el.ValueExpression;
-import jakarta.faces.component.UIComponent;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
@@ -81,41 +77,27 @@ public interface FacesImplementation
*/
public Object getManagedBean(final String beanName, final FacesContext
fc);
- /**
+ /*
* Return the parentComponent for a given ValueExpression.
+ *
+ * Obsolete since 2025-01-08 with EMPIREDB-453
*
- * Implementation for Mojarra:
- * ---------------------------
- * if (ve instanceof ContextualCompositeValueExpression)
- * {
- * FacesContext ctx = FacesContext.getCurrentInstance();
- * ContextualCompositeValueExpression ccve =
(ContextualCompositeValueExpression)ve;
- * CompositeComponentStackManager manager =
CompositeComponentStackManager.getManager(ctx);
- * UIComponent cc = manager.findCompositeComponentUsingLocation(ctx,
ccve.getLocation());
- * // set Parent
- * return cc;
- * }
- *
* @param ve the value expression
* @return the component
- */
+ *
UIComponent getValueParentComponent(final ValueExpression ve);
+ */
- /**
- * Returns the inner value expression
+ /*
+ * Returns the inner value expression of a taglib attribute
+ *
+ * Obsolete since 2025-01-08 with EMPIREDB-453
+ *
* @param ve the original ValueExpression
* @return the unwrapped ValueExpression (may be null)
- */
+ *
ValueExpression unwrapValueExpression(ValueExpression ve);
-
- /**
- * Returns a read or write method for an JavaBean property
- * @param component the UIComponent
- * @param attribute the attribute name
- * @param writeMethod flag whether to the read or write method
- * @return the method or null
- */
- Method getPropertyMethod(final UIComponent component, String attribute,
boolean writeMethod);
+ */
/**
* BeanStorageProvider
diff --git
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/MojarraImplementation.java
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/MojarraImplementation.java
index 55f45860..c3cd9cbc 100644
---
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/MojarraImplementation.java
+++
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/MojarraImplementation.java
@@ -18,32 +18,25 @@
*/
package org.apache.empire.jakarta.impl;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.apache.empire.exceptions.ItemExistsException;
import org.apache.empire.exceptions.NotSupportedException;
-import org.apache.empire.jakarta.utils.ValueExpressionUnwrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.application.ApplicationInstanceFactoryMetadataMap;
-import com.sun.faces.component.CompositeComponentStackManager;
import com.sun.faces.config.ConfigManager;
import com.sun.faces.config.processor.ApplicationConfigProcessor;
-import com.sun.faces.facelets.el.ContextualCompositeValueExpression;
-import com.sun.faces.facelets.el.TagValueExpression;
import com.sun.faces.mgbean.BeanManager;
import com.sun.faces.mgbean.ManagedBeanInfo;
import com.sun.faces.spi.InjectionProvider;
import com.sun.faces.spi.InjectionProviderException;
import jakarta.el.ELResolver;
-import jakarta.el.ValueExpression;
import jakarta.faces.FacesException;
-import jakarta.faces.component.UIComponent;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.servlet.ServletContext;
@@ -129,9 +122,17 @@ public class MojarraImplementation implements
FacesImplementation
return mbean;
}
+ /*
+ * Obsolete since 2025-01-08 with EMPIREDB-453
+ *
@Override
- public UIComponent getValueParentComponent(final ValueExpression ve)
+ @SuppressWarnings("unchecked")
+ public UIComponent getValueParentComponent(ValueExpression ve)
{
+ // Unwrap
+ if (ve instanceof FacesWrapper<?>)
+ ve = ((FacesWrapper<ValueExpression>)ve).getWrapped();
+ // ContextualCompositeValueExpression
if (ve instanceof ContextualCompositeValueExpression)
{
FacesContext ctx = FacesContext.getCurrentInstance();
@@ -147,22 +148,9 @@ public class MojarraImplementation implements
FacesImplementation
@Override
public ValueExpression unwrapValueExpression(ValueExpression ve)
{
- // unwrap from com.sun.faces.facelets.el.TagValueExpression
- if (ve instanceof TagValueExpression)
- { // cast and getWrapped
- ve = ((TagValueExpression)ve).getWrapped();
- }
- // now unwrap using the ValueExpressionUnwrapper
- return ValueExpressionUnwrapper.getInstance().unwrap(ve);
- }
-
- @Override
- public Method getPropertyMethod(final UIComponent component, String
attribute, boolean writeMethod)
- {
- // Not yet implemented.
- // Is Implementation required?
- return null;
+ return ValueExpressionUnwrapper.getInstance().unwrap(ve, "${");
}
+ */
private BeanStorageProvider beanStorage = null;
diff --git
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/MyFacesImplementation.java
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/MyFacesImplementation.java
index 85493c4e..daf0e584 100644
---
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/MyFacesImplementation.java
+++
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/MyFacesImplementation.java
@@ -18,16 +18,13 @@
*/
package org.apache.empire.jakarta.impl;
-import java.lang.reflect.Method;
import java.util.List;
-import java.util.Map;
import org.apache.empire.commons.ClassUtils;
import org.apache.empire.exceptions.InternalException;
import org.apache.empire.exceptions.ItemExistsException;
import org.apache.empire.exceptions.ItemNotFoundException;
import org.apache.empire.exceptions.NotSupportedException;
-import org.apache.empire.jakarta.utils.ValueExpressionUnwrapper;
import org.apache.myfaces.application.ApplicationImpl;
import org.apache.myfaces.cdi.util.BeanEntry;
import org.apache.myfaces.config.RuntimeConfig;
@@ -35,15 +32,12 @@ import
org.apache.myfaces.config.impl.digester.elements.ManagedBeanImpl;
import org.apache.myfaces.spi.InjectionProvider;
import org.apache.myfaces.spi.InjectionProviderException;
import org.apache.myfaces.spi.InjectionProviderFactory;
-import org.apache.myfaces.view.facelets.el.ContextAwareTagValueExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.el.ELContext;
import jakarta.el.ELResolver;
-import jakarta.el.ValueExpression;
import jakarta.faces.application.Application;
-import jakarta.faces.component.UIComponent;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
@@ -123,6 +117,9 @@ public class MyFacesImplementation implements
FacesImplementation
return application.getELResolver().getValue(elcontext, null, beanName);
}
+ /*
+ * Obsolete since 2025-01-08 with EMPIREDB-453
+ *
@Override
public UIComponent getValueParentComponent(final ValueExpression ve)
{
@@ -132,33 +129,9 @@ public class MyFacesImplementation implements
FacesImplementation
@Override
public ValueExpression unwrapValueExpression(ValueExpression ve)
{
- // unwrap from
org.apache.myfaces.view.facelets.el.ContextAwareTagValueExpression
- if (ve instanceof ContextAwareTagValueExpression)
- { // cast and getWrapped
- ve = ((ContextAwareTagValueExpression)ve).getWrapped();
- }
- // now unwrap using the ValueExpressionUnwrapper
- return ValueExpressionUnwrapper.getInstance().unwrap(ve);
- }
-
- @Override
- public Method getPropertyMethod(final UIComponent component, String
attribute, boolean writeMethod)
- {
- try {
- // get the map
- Map<String, Object> attrMap = component.getAttributes();
- Object propDescHolder =
ClassUtils.invokeMethod(attrMap.getClass(), attrMap, "getPropertyDescriptor",
new Class<?>[] { String.class }, new Object[] { "value" }, true);
- if (propDescHolder == null)
- return null;
- // Get the method
- Method method =
(Method)ClassUtils.invokeSimplePrivateMethod(propDescHolder, (writeMethod ?
"getWriteMethod" : "getReadMethod"));
- return method;
- } catch(Exception e) {
- // Not valid
- log.warn("FacesImplementation.getAttributeMethod() for {} failed
with exception: {}", attribute, e);
- return null;
- }
+ return ValueExpressionUnwrapper.getInstance().unwrap(ve, "${");
}
+ */
private BeanStorageProvider beanStorage = null;
diff --git
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/TagEncodingHelper.java
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/TagEncodingHelper.java
index eca41eb1..64d3167c 100644
---
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/TagEncodingHelper.java
+++
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/TagEncodingHelper.java
@@ -20,7 +20,6 @@ package org.apache.empire.jakarta.utils;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
@@ -31,7 +30,6 @@ import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.empire.commons.Attributes;
-import org.apache.empire.commons.ClassUtils;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.Options;
import org.apache.empire.commons.StringUtils;
@@ -70,12 +68,10 @@ import
org.apache.empire.jakarta.controls.InputControl.ValueInfo;
import org.apache.empire.jakarta.controls.InputControlManager;
import org.apache.empire.jakarta.controls.SelectInputControl;
import org.apache.empire.jakarta.controls.TextInputControl;
-import org.apache.empire.jakarta.impl.FacesImplementation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.el.ValueExpression;
-import jakarta.faces.FacesWrapper;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.component.NamingContainer;
import jakarta.faces.component.UIComponent;
@@ -815,27 +811,17 @@ public class TagEncodingHelper implements NamingContainer
else
{ // Get from tag
if (evalExpression)
- {
+ { // evaluate the value
Object value = component.getValue();
- /* Do we need to convert the value?
- if (value!=null && (valueInfo instanceof InputInfo))
- value = getInputControl().getConvertedValue(component,
(InputInfo)valueInfo, value);
- */
return value;
}
else
- { // Check LocalValue and ValueExpression
+ { // Return the local value or the ValueExpression if any
Object value = component.getLocalValue();
if (value!=null && (component instanceof UIInput) &&
!((UIInput)component).isLocalValueSet())
value= null; /* should never come here! */
if (value==null)
- { // Check readMethod
- Method readMethod =
FacesUtils.getFacesImplementation().getPropertyMethod(this.component, "value",
false);
- if (readMethod!=null)
- return ClassUtils.invokeSimpleMethod(this.component,
readMethod); // attribute is a javabean property!
- // use a value expression
- value = findValueExpression("value");
- }
+ value = getValueExpression();
// Return the local value or the ValueExpression if any
return value;
}
@@ -903,12 +889,11 @@ public class TagEncodingHelper implements NamingContainer
}
}
else
- { // Get from tag
- // tag.setValue(value);
- ValueExpression ve = component.getValueExpression("value");
+ { // Set Value attribute
+ ValueExpression ve = getValueExpression();
if (ve == null)
throw new PropertyReadOnlyException("value");
-
+ // set value
FacesContext ctx = FacesContext.getCurrentInstance();
ve.setValue(ctx.getELContext(), value);
}
@@ -945,13 +930,7 @@ public class TagEncodingHelper implements NamingContainer
// if value expression, don't check further
if (hasValueExpression())
{ // check readonly
- FacesImplementation impl = FacesUtils.getFacesImplementation();
- if (impl.getPropertyMethod(this.component, "value", false)!=null)
- { // attribute is a javabean property!
- return (impl.getPropertyMethod(this.component, "value",
true)==null);
- }
- // Check value expression
- ValueExpression ve = findValueExpression("value");
+ ValueExpression ve = getValueExpression();
return (ve!=null ?
ve.isReadOnly(FacesContext.getCurrentInstance().getELContext()) : null);
}
// check record component
@@ -1256,6 +1235,10 @@ public class TagEncodingHelper implements NamingContainer
return rec;
}
+ /*
+ * Old code
+ * Replaced 2025-01-08 with EMPIREDB-453
+ *
protected boolean hasValueExpression()
{
// Find expression
@@ -1302,8 +1285,8 @@ public class TagEncodingHelper implements NamingContainer
// find parent
UIComponent valueParent =
FacesUtils.getFacesImplementation().getValueParentComponent(ve);
if (valueParent!=null)
- { // use the value parent
- parent = valueParent;
+ { // use the value parent
+ parent = valueParent;
}
else
{ // find parent
@@ -1319,11 +1302,7 @@ public class TagEncodingHelper implements NamingContainer
// find attribute
ValueExpression next = parent.getValueExpression(attrib);
if (next == null)
- { /* allow literal (obsolte 2024-10-12)
- if (allowLiteral && (parent.getAttributes().get(attrib)!=null))
- return ve;
- */
- // not found
+ { // not found
return null;
}
// get new expression String
@@ -1333,6 +1312,95 @@ public class TagEncodingHelper implements NamingContainer
// found
return ve;
}
+ */
+
+ protected ValueExpression getValueExpression()
+ {
+ return component.getValueExpression("value");
+ }
+
+ protected boolean hasValueExpression()
+ {
+ // Find expression
+ if (this.hasValueExpr<0)
+ { // Find top expression
+ ValueExpression ve = findTopValueExpression("value");
+ /*
+ * Alternatively, check ValueReference
+ *
+ ValueExpression ve = this.component.getValueExpression("value");
+ while (ve!=null)
+ { // check ValueReference
+ ValueReference vr =
ve.getValueReference(FacesContext.getCurrentInstance().getELContext());
+ if (vr==null)
+ { // No value reference
+ ve = null;
+ }
+ else if
(vr.getBase().getClass().getName().endsWith("CompositeComponentAttributesMapWrapper"))
+ { // CompositeComponentELResolver
+ ve =
(ValueExpression)ClassUtils.invokeMethod(vr.getBase().getClass(), vr.getBase(),
"getExpression", new Class<?>[] { String.class }, new Object[] {
vr.getProperty() }, true);
+ }
+ else
+ { // found
+ if (log.isDebugEnabled())
+ log.debug("ValueReference of of type {}",
vr.getBase().getClass().getName());
+ break;
+ }
+ }
+ */
+ // store result to avoid multiple detection
+ hasValueExpr = ((ve!=null) ? (byte)1 : (byte)0);
+ }
+ return (hasValueExpr>0);
+ }
+
+ // composite component expression
+ protected static final String CC_ATTR_EXPR = "#{cc.attrs.";
+ protected static String TAGLIB_ATTR_PREFIX = "${";
+
+ protected ValueExpression findTopValueExpression(String attribute)
+ {
+ // Check for expression
+ ValueExpression ve = this.component.getValueExpression(attribute);
+ UIComponent parent = this.component;
+ while (ve!=null)
+ {
+ String expr = ve.getExpressionString();
+ if (expr.startsWith(CC_ATTR_EXPR))
+ { // Unwrap composite component attribute
+ parent = UIComponent.getCompositeComponentParent(parent);
+ if (parent == null)
+ { log.error("No CompositeComponentParent for {} expression
was {}", getColumnName(), expr);
+ return null; // parent not found
+ }
+ // check expression
+ int end = expr.indexOf('}');
+ String attrib = expr.substring(CC_ATTR_EXPR.length(), end);
+ if (attrib.indexOf('.')>0)
+ break; // do not investigate any further
+ // next expression
+ ve = parent.getValueExpression(attrib);
+ }
+ else
+ { // Unwrap for Facelet-Tags to work
+ ValueExpression next =
ValueExpressionUnwrapper.getInstance().unwrap(ve, TAGLIB_ATTR_PREFIX);
+ if (ve==next)
+ break; // do not investigate any further
+ // log result
+ ve = next;
+ // debug
+ if (log.isDebugEnabled())
+ { // log result
+ if (ve!=null && !expr.equals(ve.getExpressionString()))
+ log.debug("ValueExpression \"{}\" has been resolved to
\"{}\" from class {}", expr, ve.getExpressionString(), ve.getClass().getName());
+ else if (ve==null)
+ log.debug("ValueExpression \"{}\" has been resolved to
NULL", expr);
+ }
+ }
+ }
+ // top expression or null
+ return ve;
+ }
protected Object getBeanPropertyValue(Object bean, String property)
{
diff --git
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/ValueExpressionUnwrapper.java
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/ValueExpressionUnwrapper.java
index 78ed7a93..82604b59 100644
---
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/ValueExpressionUnwrapper.java
+++
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/ValueExpressionUnwrapper.java
@@ -18,14 +18,15 @@
*/
package org.apache.empire.jakarta.utils;
-import jakarta.el.ValueExpression;
-import jakarta.el.VariableMapper;
-
import org.apache.empire.commons.ClassUtils;
import org.apache.empire.commons.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import jakarta.el.ValueExpression;
+import jakarta.el.VariableMapper;
+import jakarta.faces.FacesWrapper;
+
/**
* ValueExpressionUnwrapper
* @author doebele
@@ -75,16 +76,20 @@ public class ValueExpressionUnwrapper
log.debug("Instance of {} created", this.getClass().getName());
}
- public ValueExpression unwrap(ValueExpression ve)
+ @SuppressWarnings("unchecked")
+ public ValueExpression unwrap(ValueExpression ve, String exprPrefix)
{ // now unwrap ValueExpressionImpl
if (ve!=null && !ve.isLiteralText())
{ // immediate evaluation?
String expression = ve.getExpressionString();
- if (expression.startsWith("${"))
+ if (expression.startsWith(exprPrefix))
{ // expected: ve = org.apache.el.ValueExpressionImpl
- if
(ve.getClass().getName().equals("org.apache.el.ValueExpressionImpl"))
+ ValueExpression veImpl = ve;
+ if (veImpl instanceof FacesWrapper<?>)
+ veImpl =
((FacesWrapper<ValueExpression>)veImpl).getWrapped();
+ if
(veImpl.getClass().getName().equals("org.apache.el.ValueExpressionImpl"))
{ // get the Node
- Object node = ClassUtils.invokeSimplePrivateMethod(ve,
"getNode");
+ Object node = ClassUtils.invokeSimplePrivateMethod(veImpl,
"getNode");
if (node!=null)
{ // We have a Node
// Now get the Image
@@ -92,7 +97,7 @@ public class ValueExpressionUnwrapper
if (StringUtils.isNotEmpty(image))
{ // We have an image
// Now find the varMapper
- VariableMapper varMapper =
(VariableMapper)ClassUtils.getPrivateFieldValue(ve, "varMapper");
+ VariableMapper varMapper =
(VariableMapper)ClassUtils.getPrivateFieldValue(veImpl, "varMapper");
if (varMapper!=null)
{ // Resolve variable using mapper
ve = varMapper.resolveVariable(image);
diff --git
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
index 68401e9c..5cd50d1b 100644
---
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
+++
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
@@ -483,6 +483,11 @@ public abstract class InputControl
throw new ItemNotFoundException("UIInput");
}
+ protected boolean isInputValueExpressionEnabled()
+ {
+ return InputControlManager.isInputValueExpressionEnabled();
+ }
+
protected void setInputValue(UIInput input, InputInfo ii)
{
// Restore submitted value
@@ -508,7 +513,7 @@ public abstract class InputControl
/* -------------------------------------- */
// Assign value
- boolean evalExpression =
!InputControlManager.isInputValueExpressionEnabled();
+ boolean evalExpression = !isInputValueExpressionEnabled();
Object value = ii.getValue(evalExpression);
if (value instanceof ValueExpression)
{
diff --git
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/FacesImplementation.java
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/FacesImplementation.java
index 55faeb83..d4e3b6bf 100644
---
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/FacesImplementation.java
+++
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/FacesImplementation.java
@@ -18,11 +18,7 @@
*/
package org.apache.empire.jsf2.impl;
-import java.lang.reflect.Method;
-
import javax.el.ELResolver;
-import javax.el.ValueExpression;
-import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
@@ -81,41 +77,27 @@ public interface FacesImplementation
*/
public Object getManagedBean(final String beanName, final FacesContext
fc);
- /**
+ /*
* Return the parentComponent for a given ValueExpression.
+ *
+ * Obsolete since 2025-01-08 with EMPIREDB-453
*
- * Implementation for Mojarra:
- * ---------------------------
- * if (ve instanceof ContextualCompositeValueExpression)
- * {
- * FacesContext ctx = FacesContext.getCurrentInstance();
- * ContextualCompositeValueExpression ccve =
(ContextualCompositeValueExpression)ve;
- * CompositeComponentStackManager manager =
CompositeComponentStackManager.getManager(ctx);
- * UIComponent cc = manager.findCompositeComponentUsingLocation(ctx,
ccve.getLocation());
- * // set Parent
- * return cc;
- * }
- *
* @param ve the value expression
* @return the component
- */
+ *
UIComponent getValueParentComponent(final ValueExpression ve);
+ */
- /**
- * Returns the inner value expression
+ /*
+ * Returns the inner value expression of a taglib attribute
+ *
+ * Obsolete since 2025-01-08 with EMPIREDB-453
+ *
* @param ve the original ValueExpression
* @return the unwrapped ValueExpression (may be null)
- */
+ *
ValueExpression unwrapValueExpression(ValueExpression ve);
-
- /**
- * Returns a read or write method for an JavaBean property
- * @param component the component
- * @param attribute the attribute name
- * @param writeMethod flag whether to the read or write method
- * @return the method or null
- */
- Method getPropertyMethod(final UIComponent component, String attribute,
boolean writeMethod);
+ */
/**
* BeanStorageProvider
diff --git
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/MojarraImplementation.java
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/MojarraImplementation.java
index 13416f8a..8518e231 100644
---
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/MojarraImplementation.java
+++
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/MojarraImplementation.java
@@ -18,31 +18,24 @@
*/
package org.apache.empire.jsf2.impl;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.el.ELResolver;
-import javax.el.ValueExpression;
import javax.faces.FacesException;
-import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import org.apache.empire.exceptions.ItemExistsException;
import org.apache.empire.exceptions.NotSupportedException;
-import org.apache.empire.jsf2.utils.ValueExpressionUnwrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.application.ApplicationInstanceFactoryMetadataMap;
-import com.sun.faces.component.CompositeComponentStackManager;
import com.sun.faces.config.ConfigManager;
import com.sun.faces.config.processor.ApplicationConfigProcessor;
-import com.sun.faces.facelets.el.ContextualCompositeValueExpression;
-import com.sun.faces.facelets.el.TagValueExpression;
import com.sun.faces.mgbean.BeanManager;
import com.sun.faces.mgbean.ManagedBeanInfo;
import com.sun.faces.spi.InjectionProvider;
@@ -129,9 +122,17 @@ public class MojarraImplementation implements
FacesImplementation
return mbean;
}
+ /*
+ * Obsolete since 2025-01-08 with EMPIREDB-453
+ *
@Override
- public UIComponent getValueParentComponent(final ValueExpression ve)
+ @SuppressWarnings("unchecked")
+ public UIComponent getValueParentComponent(ValueExpression ve)
{
+ // Unwrap
+ if (ve instanceof FacesWrapper<?>)
+ ve = ((FacesWrapper<ValueExpression>)ve).getWrapped();
+ // ContextualCompositeValueExpression
if (ve instanceof ContextualCompositeValueExpression)
{
FacesContext ctx = FacesContext.getCurrentInstance();
@@ -147,22 +148,9 @@ public class MojarraImplementation implements
FacesImplementation
@Override
public ValueExpression unwrapValueExpression(ValueExpression ve)
{
- // unwrap from com.sun.faces.facelets.el.TagValueExpression
- if (ve instanceof TagValueExpression)
- { // cast and getWrapped
- ve = ((TagValueExpression)ve).getWrapped();
- }
- // now unwrap using the ValueExpressionUnwrapper
- return ValueExpressionUnwrapper.getInstance().unwrap(ve);
- }
-
- @Override
- public Method getPropertyMethod(final UIComponent component, String
attribute, boolean writeMethod)
- {
- // Not yet implemented.
- // Is Implementation required?
- return null;
+ return ValueExpressionUnwrapper.getInstance().unwrap(ve, "${");
}
+ */
private BeanStorageProvider beanStorage = null;
diff --git
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/MyFacesImplementation.java
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/MyFacesImplementation.java
index c806bf8c..87c7b54c 100644
---
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/MyFacesImplementation.java
+++
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/MyFacesImplementation.java
@@ -18,15 +18,11 @@
*/
package org.apache.empire.jsf2.impl;
-import java.lang.reflect.Method;
import java.util.List;
-import java.util.Map;
import javax.el.ELContext;
import javax.el.ELResolver;
-import javax.el.ValueExpression;
import javax.faces.application.Application;
-import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
@@ -35,7 +31,6 @@ import org.apache.empire.exceptions.InternalException;
import org.apache.empire.exceptions.ItemExistsException;
import org.apache.empire.exceptions.ItemNotFoundException;
import org.apache.empire.exceptions.NotSupportedException;
-import org.apache.empire.jsf2.utils.ValueExpressionUnwrapper;
import org.apache.myfaces.application.ApplicationImpl;
import org.apache.myfaces.cdi.util.BeanEntry;
import org.apache.myfaces.config.RuntimeConfig;
@@ -43,7 +38,6 @@ import
org.apache.myfaces.config.impl.digester.elements.ManagedBeanImpl;
import org.apache.myfaces.spi.InjectionProvider;
import org.apache.myfaces.spi.InjectionProviderException;
import org.apache.myfaces.spi.InjectionProviderFactory;
-import org.apache.myfaces.view.facelets.el.ContextAwareTagValueExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -123,6 +117,9 @@ public class MyFacesImplementation implements
FacesImplementation
return application.getELResolver().getValue(elcontext, null, beanName);
}
+ /*
+ * Obsolete since 2025-01-08 with EMPIREDB-453
+ *
@Override
public UIComponent getValueParentComponent(final ValueExpression ve)
{
@@ -132,33 +129,9 @@ public class MyFacesImplementation implements
FacesImplementation
@Override
public ValueExpression unwrapValueExpression(ValueExpression ve)
{
- // unwrap from
org.apache.myfaces.view.facelets.el.ContextAwareTagValueExpression
- if (ve instanceof ContextAwareTagValueExpression)
- { // cast and getWrapped
- ve = ((ContextAwareTagValueExpression)ve).getWrapped();
- }
- // now unwrap using the ValueExpressionUnwrapper
- return ValueExpressionUnwrapper.getInstance().unwrap(ve);
- }
-
- @Override
- public Method getPropertyMethod(final UIComponent component, String
attribute, boolean writeMethod)
- {
- try {
- // get the map
- Map<String, Object> attrMap = component.getAttributes();
- Object propDescHolder =
ClassUtils.invokeMethod(attrMap.getClass(), attrMap, "getPropertyDescriptor",
new Class<?>[] { String.class }, new Object[] { "value" }, true);
- if (propDescHolder == null)
- return null;
- // Get the method
- Method method =
(Method)ClassUtils.invokeSimplePrivateMethod(propDescHolder, (writeMethod ?
"getWriteMethod" : "getReadMethod"));
- return method;
- } catch(Exception e) {
- // Not valid
- log.warn("FacesImplementation.getAttributeMethod() for {} failed
with exception: {}", attribute, e);
- return null;
- }
+ return ValueExpressionUnwrapper.getInstance().unwrap(ve, "${");
}
+ */
private BeanStorageProvider beanStorage = null;
diff --git
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
index ef7b969f..504a08f3 100644
---
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
+++
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
@@ -20,14 +20,12 @@ package org.apache.empire.jsf2.utils;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import javax.el.ValueExpression;
-import javax.faces.FacesWrapper;
import javax.faces.application.FacesMessage;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
@@ -45,7 +43,6 @@ import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.empire.commons.Attributes;
-import org.apache.empire.commons.ClassUtils;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.Options;
import org.apache.empire.commons.StringUtils;
@@ -84,7 +81,6 @@ import org.apache.empire.jsf2.controls.InputControl.ValueInfo;
import org.apache.empire.jsf2.controls.InputControlManager;
import org.apache.empire.jsf2.controls.SelectInputControl;
import org.apache.empire.jsf2.controls.TextInputControl;
-import org.apache.empire.jsf2.impl.FacesImplementation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -815,27 +811,17 @@ public class TagEncodingHelper implements NamingContainer
else
{ // Get from tag
if (evalExpression)
- {
+ { // evaluate the value
Object value = component.getValue();
- /* Do we need to convert the value?
- if (value!=null && (valueInfo instanceof InputInfo))
- value = getInputControl().getConvertedValue(component,
(InputInfo)valueInfo, value);
- */
return value;
}
else
- { // Check LocalValue and ValueExpression
+ { // Return the local value or the ValueExpression if any
Object value = component.getLocalValue();
if (value!=null && (component instanceof UIInput) &&
!((UIInput)component).isLocalValueSet())
value= null; /* should never come here! */
if (value==null)
- { // Check readMethod
- Method readMethod =
FacesUtils.getFacesImplementation().getPropertyMethod(this.component, "value",
false);
- if (readMethod!=null)
- return ClassUtils.invokeSimpleMethod(this.component,
readMethod); // attribute is a javabean property!
- // use a value expression
- value = findValueExpression("value");
- }
+ value = getValueExpression();
// Return the local value or the ValueExpression if any
return value;
}
@@ -903,12 +889,11 @@ public class TagEncodingHelper implements NamingContainer
}
}
else
- { // Get from tag
- // tag.setValue(value);
- ValueExpression ve = component.getValueExpression("value");
+ { // Set Value attribute
+ ValueExpression ve = getValueExpression();
if (ve == null)
throw new PropertyReadOnlyException("value");
-
+ // set value
FacesContext ctx = FacesContext.getCurrentInstance();
ve.setValue(ctx.getELContext(), value);
}
@@ -945,13 +930,7 @@ public class TagEncodingHelper implements NamingContainer
// if value expression, don't check further
if (hasValueExpression())
{ // check readonly
- FacesImplementation impl = FacesUtils.getFacesImplementation();
- if (impl.getPropertyMethod(this.component, "value", false)!=null)
- { // attribute is a javabean property!
- return (impl.getPropertyMethod(this.component, "value",
true)==null);
- }
- // Check value expression
- ValueExpression ve = findValueExpression("value");
+ ValueExpression ve = getValueExpression();
return (ve!=null ?
ve.isReadOnly(FacesContext.getCurrentInstance().getELContext()) : null);
}
// check record component
@@ -1256,6 +1235,10 @@ public class TagEncodingHelper implements NamingContainer
return rec;
}
+ /*
+ * Old code
+ * Replaced 2025-01-08 with EMPIREDB-453
+ *
protected boolean hasValueExpression()
{
// Find expression
@@ -1302,8 +1285,8 @@ public class TagEncodingHelper implements NamingContainer
// find parent
UIComponent valueParent =
FacesUtils.getFacesImplementation().getValueParentComponent(ve);
if (valueParent!=null)
- { // use the value parent
- parent = valueParent;
+ { // use the value parent
+ parent = valueParent;
}
else
{ // find parent
@@ -1319,11 +1302,7 @@ public class TagEncodingHelper implements NamingContainer
// find attribute
ValueExpression next = parent.getValueExpression(attrib);
if (next == null)
- { /* allow literal (obsolte 2024-10-12)
- if (allowLiteral && (parent.getAttributes().get(attrib)!=null))
- return ve;
- */
- // not found
+ { // not found
return null;
}
// get new expression String
@@ -1333,6 +1312,95 @@ public class TagEncodingHelper implements NamingContainer
// found
return ve;
}
+ */
+
+ protected ValueExpression getValueExpression()
+ {
+ return component.getValueExpression("value");
+ }
+
+ protected boolean hasValueExpression()
+ {
+ // Find expression
+ if (this.hasValueExpr<0)
+ { // Find top expression
+ ValueExpression ve = findTopValueExpression("value");
+ /*
+ * Alternatively, check ValueReference
+ *
+ ValueExpression ve = this.component.getValueExpression("value");
+ while (ve!=null)
+ { // check ValueReference
+ ValueReference vr =
ve.getValueReference(FacesContext.getCurrentInstance().getELContext());
+ if (vr==null)
+ { // No value reference
+ ve = null;
+ }
+ else if
(vr.getBase().getClass().getName().endsWith("CompositeComponentAttributesMapWrapper"))
+ { // CompositeComponentELResolver
+ ve =
(ValueExpression)ClassUtils.invokeMethod(vr.getBase().getClass(), vr.getBase(),
"getExpression", new Class<?>[] { String.class }, new Object[] {
vr.getProperty() }, true);
+ }
+ else
+ { // found
+ if (log.isDebugEnabled())
+ log.debug("ValueReference of of type {}",
vr.getBase().getClass().getName());
+ break;
+ }
+ }
+ */
+ // store result to avoid multiple detection
+ hasValueExpr = ((ve!=null) ? (byte)1 : (byte)0);
+ }
+ return (hasValueExpr>0);
+ }
+
+ // composite component expression
+ protected static final String CC_ATTR_EXPR = "#{cc.attrs.";
+ protected static String TAGLIB_ATTR_PREFIX = "${";
+
+ protected ValueExpression findTopValueExpression(String attribute)
+ {
+ // Check for expression
+ ValueExpression ve = this.component.getValueExpression(attribute);
+ UIComponent parent = this.component;
+ while (ve!=null)
+ {
+ String expr = ve.getExpressionString();
+ if (expr.startsWith(CC_ATTR_EXPR))
+ { // Unwrap composite component attribute
+ parent = UIComponent.getCompositeComponentParent(parent);
+ if (parent == null)
+ { log.error("No CompositeComponentParent for {} expression
was {}", getColumnName(), expr);
+ return null; // parent not found
+ }
+ // check expression
+ int end = expr.indexOf('}');
+ String attrib = expr.substring(CC_ATTR_EXPR.length(), end);
+ if (attrib.indexOf('.')>0)
+ break; // do not investigate any further
+ // next expression
+ ve = parent.getValueExpression(attrib);
+ }
+ else
+ { // Unwrap for Facelet-Tags to work
+ ValueExpression next =
ValueExpressionUnwrapper.getInstance().unwrap(ve, TAGLIB_ATTR_PREFIX);
+ if (ve==next)
+ break; // do not investigate any further
+ // log result
+ ve = next;
+ // debug
+ if (log.isDebugEnabled())
+ { // log result
+ if (ve!=null && !expr.equals(ve.getExpressionString()))
+ log.debug("ValueExpression \"{}\" has been resolved to
\"{}\" from class {}", expr, ve.getExpressionString(), ve.getClass().getName());
+ else if (ve==null)
+ log.debug("ValueExpression \"{}\" has been resolved to
NULL", expr);
+ }
+ }
+ }
+ // top expression or null
+ return ve;
+ }
protected Object getBeanPropertyValue(Object bean, String property)
{
diff --git
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/ValueExpressionUnwrapper.java
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/ValueExpressionUnwrapper.java
index 1a6c60af..8d2e27a0 100644
---
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/ValueExpressionUnwrapper.java
+++
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/ValueExpressionUnwrapper.java
@@ -20,6 +20,7 @@ package org.apache.empire.jsf2.utils;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
+import javax.faces.FacesWrapper;
import org.apache.empire.commons.ClassUtils;
import org.apache.empire.commons.StringUtils;
@@ -75,16 +76,20 @@ public class ValueExpressionUnwrapper
log.debug("Instance of {} created", this.getClass().getName());
}
- public ValueExpression unwrap(ValueExpression ve)
+ @SuppressWarnings("unchecked")
+ public ValueExpression unwrap(ValueExpression ve, String exprPrefix)
{ // now unwrap ValueExpressionImpl
if (ve!=null && !ve.isLiteralText())
{ // immediate evaluation?
String expression = ve.getExpressionString();
- if (expression.startsWith("${"))
+ if (expression.startsWith(exprPrefix))
{ // expected: ve = org.apache.el.ValueExpressionImpl
- if
(ve.getClass().getName().equals("org.apache.el.ValueExpressionImpl"))
+ ValueExpression veImpl = ve;
+ if (veImpl instanceof FacesWrapper<?>)
+ veImpl =
((FacesWrapper<ValueExpression>)veImpl).getWrapped();
+ if
(veImpl.getClass().getName().equals("org.apache.el.ValueExpressionImpl"))
{ // get the Node
- Object node = ClassUtils.invokeSimplePrivateMethod(ve,
"getNode");
+ Object node = ClassUtils.invokeSimplePrivateMethod(veImpl,
"getNode");
if (node!=null)
{ // We have a Node
// Now get the Image
@@ -92,7 +97,7 @@ public class ValueExpressionUnwrapper
if (StringUtils.isNotEmpty(image))
{ // We have an image
// Now find the varMapper
- VariableMapper varMapper =
(VariableMapper)ClassUtils.getPrivateFieldValue(ve, "varMapper");
+ VariableMapper varMapper =
(VariableMapper)ClassUtils.getPrivateFieldValue(veImpl, "varMapper");
if (varMapper!=null)
{ // Resolve variable using mapper
ve = varMapper.resolveVariable(image);
diff --git a/empire-db/src/main/java/org/apache/empire/commons/ClassUtils.java
b/empire-db/src/main/java/org/apache/empire/commons/ClassUtils.java
index 314d4eec..921e4a0b 100644
--- a/empire-db/src/main/java/org/apache/empire/commons/ClassUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/commons/ClassUtils.java
@@ -681,7 +681,10 @@ public final class ClassUtils
public static Object invokeSimpleMethod(Object object, Method method)
{
try
- {
+ { // check params
+ if (object==null || method==null)
+ throw new InvalidArgumentException("object|method", null);
+ // invoke
return method.invoke(object, EMPTY_ARGS);
}
catch (IllegalAccessException | IllegalArgumentException |
InvocationTargetException e)
@@ -689,6 +692,29 @@ public final class ClassUtils
throw new NotSupportedException(object, method.getName(), e);
}
}
+
+ /**
+ * Invoke a method with parameters on an object
+ * @param object the object on which to invoke the method
+ * @param method the method
+ * @return the return value
+ */
+ public static Object invokeMethod(Object object, Method method, Object...
params)
+ {
+ try
+ { // check params
+ if (object==null || method==null)
+ throw new InvalidArgumentException("object|method", null);
+ if (method.getParameterCount()!=params.length)
+ throw new InvalidArgumentException("params.length",
params.length);
+ // invoke
+ return method.invoke(object, params);
+ }
+ catch (IllegalAccessException | IllegalArgumentException |
InvocationTargetException e)
+ {
+ throw new NotSupportedException(object, method.getName(), e);
+ }
+ }
/**
* Returns the JAR name that contains the implementation of a specific
class