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

Reply via email to