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 2326a4e0 EMPIREDB-453 MyFaces: fix bug for value attribute expression
inside composite components.
2326a4e0 is described below
commit 2326a4e04d1a12d57616760c9d9159c7e9fda006
Author: Rainer Döbele <[email protected]>
AuthorDate: Tue Jan 7 21:08:00 2025 +0100
EMPIREDB-453
MyFaces: fix bug for value attribute expression inside composite components.
---
.../empire/jakarta/controls/InputControl.java | 3 +-
.../jakarta/controls/InputControlManager.java | 12 +++++++
.../empire/jakarta/impl/FacesImplementation.java | 11 +++++++
.../empire/jakarta/impl/MojarraImplementation.java | 25 ++++++++++-----
.../empire/jakarta/impl/MyFacesImplementation.java | 37 +++++++++++++++++-----
.../empire/jakarta/utils/TagEncodingHelper.java | 15 +++++++++
.../apache/empire/jsf2/controls/InputControl.java | 3 +-
.../empire/jsf2/controls/InputControlManager.java | 12 +++++++
.../empire/jsf2/impl/FacesImplementation.java | 11 +++++++
.../empire/jsf2/impl/MojarraImplementation.java | 9 ++++++
.../empire/jsf2/impl/MyFacesImplementation.java | 21 ++++++++++++
.../empire/jsf2/utils/TagEncodingHelper.java | 15 +++++++++
.../java/org/apache/empire/commons/ClassUtils.java | 20 ++++++++++++
13 files changed, 176 insertions(+), 18 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 3234861d..4120697f 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
@@ -508,7 +508,8 @@ public abstract class InputControl
/* -------------------------------------- */
// Assign value
- Object value = ii.getValue(false);
+ boolean evalExpression =
!InputControlManager.isInputValueExpressionEnabled();
+ Object value = ii.getValue(evalExpression);
if (value instanceof ValueExpression)
{
input.setValue(null);
diff --git
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControlManager.java
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControlManager.java
index 2fdfb663..51064e53 100644
---
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControlManager.java
+++
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControlManager.java
@@ -106,6 +106,18 @@ public final class InputControlManager
InputControlManager.attachedObjectsHandler = attachedObjectsHandler;
}
+ static boolean inputValueExpressionEnabled = true;
+
+ public static boolean isInputValueExpressionEnabled()
+ {
+ return inputValueExpressionEnabled;
+ }
+
+ public static void setInputValueExpressionEnabled(boolean
valueExpressionEnabled)
+ {
+ inputValueExpressionEnabled = valueExpressionEnabled;
+ }
+
private static Map<Class<? extends UIComponent>, String> componentTypeMap
= new HashMap<Class<? extends UIComponent>, String>();
@SuppressWarnings("unchecked")
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 107bcdf3..35216d3b 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,6 +18,8 @@
*/
package org.apache.empire.jakarta.impl;
+import java.lang.reflect.Method;
+
import jakarta.el.ELResolver;
import jakarta.el.ValueExpression;
import jakarta.faces.component.UIComponent;
@@ -106,6 +108,15 @@ public interface FacesImplementation
*/
ValueExpression unwrapValueExpression(ValueExpression ve);
+ /**
+ * Returns a read or write method for an attribute
+ * @param component the component
+ * @param attribute the attribute name
+ * @param writeMethod flag wheter to the read or write method
+ * @return the method or null
+ */
+ Method getAttributeMethod(final UIComponent component, String attribute,
boolean writeMethod);
+
/**
* BeanStorageProvider
* @author rainer
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 9b40b4db..0ae5b839 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,17 +18,10 @@
*/
package org.apache.empire.jakarta.impl;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
-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;
-
import org.apache.empire.exceptions.ItemExistsException;
import org.apache.empire.exceptions.NotSupportedException;
import org.apache.empire.jakarta.utils.ValueExpressionUnwrapper;
@@ -47,6 +40,14 @@ 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;
+
public class MojarraImplementation implements FacesImplementation
{
// Logger
@@ -155,6 +156,14 @@ public class MojarraImplementation implements
FacesImplementation
return ValueExpressionUnwrapper.getInstance().unwrap(ve);
}
+ @Override
+ public Method getAttributeMethod(final UIComponent component, String
attribute, boolean writeMethod)
+ {
+ // Not yet implemented.
+ // Is Implementation required?
+ return null;
+ }
+
private BeanStorageProvider beanStorage = null;
@Override
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 ed66c2f3..795d31bb 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,15 +18,9 @@
*/
package org.apache.empire.jakarta.impl;
+import java.lang.reflect.Method;
import java.util.List;
-
-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;
+import java.util.Map;
import org.apache.empire.commons.ClassUtils;
import org.apache.empire.exceptions.InternalException;
@@ -45,6 +39,14 @@ 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;
+
public class MyFacesImplementation implements FacesImplementation
{
// Logger
@@ -138,6 +140,25 @@ public class MyFacesImplementation implements
FacesImplementation
// now unwrap using the ValueExpressionUnwrapper
return ValueExpressionUnwrapper.getInstance().unwrap(ve);
}
+
+ @Override
+ public Method getAttributeMethod(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;
+ }
+ }
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 7c18f766..a1bfc6e1 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,6 +20,7 @@ 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;
@@ -30,6 +31,7 @@ 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;
@@ -68,6 +70,7 @@ 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;
@@ -826,7 +829,13 @@ public class TagEncodingHelper implements NamingContainer
if (value!=null && (component instanceof UIInput) &&
!((UIInput)component).isLocalValueSet())
value= null; /* should never come here! */
if (value==null)
+ { // Check readMethod
+ Method readMethod =
FacesUtils.getFacesImplementation().getAttributeMethod(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");
+ }
// Return the local value or the ValueExpression if any
return value;
}
@@ -936,6 +945,12 @@ public class TagEncodingHelper implements NamingContainer
// if value expression, don't check further
if (hasValueExpression())
{ // check readonly
+ FacesImplementation impl = FacesUtils.getFacesImplementation();
+ if (impl.getAttributeMethod(this.component, "value", false)!=null)
+ { // attribute is a javabean property!
+ return (impl.getAttributeMethod(this.component, "value",
true)==null);
+ }
+ // Check value expression
ValueExpression ve = findValueExpression("value");
return (ve!=null ?
ve.isReadOnly(FacesContext.getCurrentInstance().getELContext()) : null);
}
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 6ab5a116..68401e9c 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
@@ -508,7 +508,8 @@ public abstract class InputControl
/* -------------------------------------- */
// Assign value
- Object value = ii.getValue(false);
+ boolean evalExpression =
!InputControlManager.isInputValueExpressionEnabled();
+ Object value = ii.getValue(evalExpression);
if (value instanceof ValueExpression)
{
input.setValue(null);
diff --git
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControlManager.java
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControlManager.java
index 2fc55547..5a78ca48 100644
---
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControlManager.java
+++
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControlManager.java
@@ -106,6 +106,18 @@ public final class InputControlManager
InputControlManager.attachedObjectsHandler = attachedObjectsHandler;
}
+ static boolean inputValueExpressionEnabled = true;
+
+ public static boolean isInputValueExpressionEnabled()
+ {
+ return inputValueExpressionEnabled;
+ }
+
+ public static void setInputValueExpressionEnabled(boolean
valueExpressionEnabled)
+ {
+ inputValueExpressionEnabled = valueExpressionEnabled;
+ }
+
private static Map<Class<? extends UIComponent>, String> componentTypeMap
= new HashMap<Class<? extends UIComponent>, String>();
@SuppressWarnings("unchecked")
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 6c12fea9..a832965c 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,6 +18,8 @@
*/
package org.apache.empire.jsf2.impl;
+import java.lang.reflect.Method;
+
import javax.el.ELResolver;
import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
@@ -106,6 +108,15 @@ public interface FacesImplementation
*/
ValueExpression unwrapValueExpression(ValueExpression ve);
+ /**
+ * Returns a read or write method for an attribute
+ * @param component the component
+ * @param attribute the attribute name
+ * @param writeMethod flag wheter to the read or write method
+ * @return the method or null
+ */
+ Method getAttributeMethod(final UIComponent component, String attribute,
boolean writeMethod);
+
/**
* BeanStorageProvider
* @author rainer
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 d0148e86..dbc8fb7b 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,6 +18,7 @@
*/
package org.apache.empire.jsf2.impl;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@@ -155,6 +156,14 @@ public class MojarraImplementation implements
FacesImplementation
return ValueExpressionUnwrapper.getInstance().unwrap(ve);
}
+ @Override
+ public Method getAttributeMethod(final UIComponent component, String
attribute, boolean writeMethod)
+ {
+ // Not yet implemented.
+ // Is Implementation required?
+ return null;
+ }
+
private BeanStorageProvider beanStorage = null;
@Override
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 eee0750d..e792cf21 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,7 +18,9 @@
*/
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;
@@ -138,6 +140,25 @@ public class MyFacesImplementation implements
FacesImplementation
// now unwrap using the ValueExpressionUnwrapper
return ValueExpressionUnwrapper.getInstance().unwrap(ve);
}
+
+ @Override
+ public Method getAttributeMethod(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;
+ }
+ }
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 4e33739a..f6f311a5 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,6 +20,7 @@ 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;
@@ -44,6 +45,7 @@ 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;
@@ -82,6 +84,7 @@ 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;
@@ -826,7 +829,13 @@ public class TagEncodingHelper implements NamingContainer
if (value!=null && (component instanceof UIInput) &&
!((UIInput)component).isLocalValueSet())
value= null; /* should never come here! */
if (value==null)
+ { // Check readMethod
+ Method readMethod =
FacesUtils.getFacesImplementation().getAttributeMethod(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");
+ }
// Return the local value or the ValueExpression if any
return value;
}
@@ -936,6 +945,12 @@ public class TagEncodingHelper implements NamingContainer
// if value expression, don't check further
if (hasValueExpression())
{ // check readonly
+ FacesImplementation impl = FacesUtils.getFacesImplementation();
+ if (impl.getAttributeMethod(this.component, "value", false)!=null)
+ { // attribute is a javabean property!
+ return (impl.getAttributeMethod(this.component, "value",
true)==null);
+ }
+ // Check value expression
ValueExpression ve = findValueExpression("value");
return (ve!=null ?
ve.isReadOnly(FacesContext.getCurrentInstance().getELContext()) : null);
}
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 8887ba41..314d4eec 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
@@ -45,6 +45,8 @@ public final class ClassUtils
{
// Logger
private static final Logger log =
LoggerFactory.getLogger(ClassUtils.class);
+
+ public static final Object[] EMPTY_ARGS = new Object[0];
/*
* ClassUtils contains static methods only
@@ -670,6 +672,24 @@ public final class ClassUtils
return invokeSimpleMethod(object.getClass(), object, methodName, true);
}
+ /**
+ * Invoke a simple method (without 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 invokeSimpleMethod(Object object, Method method)
+ {
+ try
+ {
+ return method.invoke(object, EMPTY_ARGS);
+ }
+ catch (IllegalAccessException | IllegalArgumentException |
InvocationTargetException e)
+ {
+ throw new NotSupportedException(object, method.getName(), e);
+ }
+ }
+
/**
* Returns the JAR name that contains the implementation of a specific
class
* @param clazz the class