/* * � Copyright IBM Corp. 2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ /* * Author: Maire Kehoe (mkehoe@ie.ibm.com) * Date: 29-Nov-2005 */ package com.ibm.xsp.test.framework.registry; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; import javax.faces.component.StateHolder; import javax.faces.component.UIComponent; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.DateTimeConverter; import javax.faces.el.EvaluationException; import javax.faces.el.PropertyNotFoundException; import javax.faces.el.ValueBinding; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.FacesExceptionEx; import com.ibm.xsp.binding.ComponentBindingObject; import com.ibm.xsp.binding.MultiPartValueBinding; import com.ibm.xsp.binding.PropertyMap; import com.ibm.xsp.complex.ValueBindingObject; import com.ibm.xsp.model.DataContainer; import com.ibm.xsp.model.DataSource; import com.ibm.xsp.page.translator.ReflectUtil; import com.ibm.xsp.registry.*; import com.ibm.xsp.stylekit.StyleKitImpl; import com.ibm.xsp.test.framework.AbstractXspTest; import com.ibm.xsp.test.framework.TestProject; import com.ibm.xsp.test.framework.XspTestUtil; import com.ibm.xsp.test.framework.registry.annotate.PropertyTagsAnnotater; import com.ibm.xsp.test.framework.setup.SkipFileContent; import com.ibm.xsp.util.DataPublisher.ShadowedObject; /** * * * @author Maire Kehoe (mkehoe@ie.ibm.com) * 29-Nov-2005 * * Plugin: xsp.core.test */ public class PropertiesHaveSettersTest extends AbstractXspTest { private static final Class<?>[] OBJECT_PARAMETER = new Class[] { Object.class }; @Override public String getDescription() { return "that all "+XspTestUtil.getShortClass(FacesProperty.class) + "s where isAttribute is false have " + "a set method and correctly implemented get method"; } public void testPropertiesHaveSetters() throws Exception { try{ String failsStr = ""; FacesSharableRegistry reg = TestProject.createRegistryWithAnnotater(this, new PropertyTagsAnnotater()); List<Object[]> propSkips = getTotallySkippedProperties(reg); List<Object[]> propNotVB = getPropertyNotAllowValueBindings(reg); List<Object[]> defBindingSkips = getDefinitionNotAllowRuntimeBindings(reg); List<Object[]> cannotCreateInstanceSkips = getCannotCreateInstanceSkips(reg); MockValueBinding mvb = new MockValueBinding(); // for all definitions for (FacesDefinition def : TestProject.getComponentsAndComplexes(reg, this)) { Class<?> compClass = def.getJavaClass(); UIInput input = new UIInput(); // these are aggregated into defsWithAttrsDeclaredAsProps // for all non-inherited properties for (String name : def.getPropertyNames()) { FacesProperty prop = def.getProperty(name); if( prop instanceof FacesContainerProperty ){ FacesContainerProperty container = (FacesContainerProperty)prop; if( container.isCollection() && container.getCollectionAddMethod() != null ){ // skip those collections that specify an add method. // check collectionAddMethod corresponds to a method. Method addMethod = getMethod(compClass, container .getCollectionAddMethod(), new Class[] { container .getItemProperty().getJavaClass() }); if( null == addMethod ){ String msg = def.getFile().getFilePath()+" "+"The declared add method "; msg += compClass + "." + container.getCollectionAddMethod(); msg += "(" + prop.getJavaClass() + ")"; msg += " does not exist."; failsStr += msg + "\n"; } continue; } } int indexPropSkips = -1; if( isSkippedProperty(compClass, name) || -1 != (indexPropSkips = getSkipListIndex(propSkips, compClass, name)) ){ markSkipUsed(propSkips, indexPropSkips); continue; } if( prop.isAttribute() ){ // skip this attribute. // (only checking for attributes declared as properties) continue; } if( def instanceof FacesCompositeComponentDefinition && Arrays.binarySearch(StyleKitImpl._customControlBasePropertys, prop.getName()) < 0 ){ // control is a custom control and the property is a custom control definition // (as opposed to a property inherited from the custom control base) // These properties do not have getter/setters, as they are set through // UIIncludeComposite.getPropertyMap() continue; } Method[] methods = getSetMethods(compClass, name, prop.getJavaClass()); if( methods.length == 0 ){ if( def instanceof FacesComplexDefinition && "loaded".equals(prop.getName()) ){ // not fail, the complex-type loaded property is an exception, // because it is handled by the page loading, // instead of set onto the object. }else{ // UIPagerEx.setLang(String) not found: attribute incorrectly declared as a property failsStr += def.getFile().getFilePath()+" "+XspTestUtil.getAfterLastDot(compClass.getName())+".set" + Character.toUpperCase(name.charAt(0))+name.substring(1) + "(" + XspTestUtil.getAfterLastDot(prop.getJavaClass().getName()) + ") not found: attribute incorrectly declared as property" +'\n'; } } // also test that value binding properties are correctly implemented if (prop.getClass() == ValueBinding.class) { //if method is set<propName>(ValueBinding) String msg = def.getFile().getFilePath()+" "+compClass+"."+methods[0]+"(ValueBinding) "; msg += "set VB methods are not supported. "; msg += "Use set<propName>(String) methods that delegate to getValueBinding, "; msg += "or use set<propName>(MethodBinding) methods instead."; failsStr += msg + "\n"; } } // end for all non-inherited properties if( ! ReflectUtil.isClassInstantiable( def.getJavaClass() ) ){ // interface or abstract - won't be able to create an instance // Note, verifying that all tags can create instances // is checked in ComplexCheckTest and ComponentRendererTest. continue; } // ==== test invoke runtime value bindings ====================== if( !hasSetValueBindingMtd(def) ){ // the definition doesn't have an appropriate method for // setting a value binding. // Check it is in the known list. int index = getSkipListIndex(defBindingSkips, compClass); if( index >=0 ){ // skipped defBindingSkips.remove(index); }else{ // fail String msg = def.getFile().getFilePath()+" "+compClass.getName()+" not a "; msg += XspTestUtil.getShortClass(ValueBindingObject.class); msg += " so no method to set VBs "; msg += "(& not skipped in getDefinitionNotAllowRuntimeBindings)"; failsStr += msg + "\n"; } continue; } // test that delegation to a value binding works boolean isComponent = UIComponent.class.isAssignableFrom(compClass); if( ! isComponent && ! ValueBindingObject.class .isAssignableFrom(compClass) ){ continue; } // for all properties (including inherited) boolean attemptedCreateObject = false; for (String name : def.getPropertyNames()) { FacesProperty prop = def.getProperty(name); int indexPropNotVB = -1; if (prop.isAttribute() || isSkippedProperty(compClass, name) || -1 != getSkipListIndex(propSkips, compClass, name) || -1 != (indexPropNotVB = getSkipListIndex(propNotVB, compClass, name))) { markSkipUsed(propNotVB, indexPropNotVB); // have already marked the propSkips skip as used above continue; } if( def instanceof FacesCompositeComponentDefinition && Arrays.binarySearch(StyleKitImpl._customControlBasePropertys, prop.getName()) < 0 ){ // control is a custom control and the property is a custom control definition // (as opposed to a property inherited from the custom control base) // These properties do not have getter/setters, as they are set through // UIIncludeComposite.getPropertyMap() continue; } FacesProperty itemProp = prop; if( prop instanceof FacesContainerProperty ){ FacesContainerProperty container = (FacesContainerProperty)prop; if (container.isCollection() && container.getCollectionAddMethod() != null) { // if there's an addMethod don't check setValueBinding continue; } itemProp = container.getItemProperty(); } if( itemProp instanceof FacesMethodBindingProperty ){ // method bindings do not support setValueBinding continue; } boolean shouldAllowRuntimeBinding = true; boolean mustBeRuntimeBinding = false; if (itemProp instanceof FacesSimpleProperty) { FacesSimpleProperty simple = (FacesSimpleProperty) itemProp; shouldAllowRuntimeBinding = simple.isAllowRunTimeBinding(); mustBeRuntimeBinding = shouldAllowRuntimeBinding && !simple.isAllowNonBinding() && !simple.isAllowLoadTimeBinding(); } // find the get method Method getMethod = getGetMethod(compClass, prop); if( null == getMethod ){ // UIPagerEx.getLang() not found: no getter to test ValueBinding used String msg = def.getFile().getFilePath()+" "+XspTestUtil.getAfterLastDot(compClass.getName()); msg += "."+getterName(prop); msg += "() not found: no getter to test ValueBinding used"; failsStr += msg+"\n"; continue; // failed. } if( !prop.getJavaClass().equals(getMethod.getReturnType()) ){ Class<?> declareClass = getMethod.getDeclaringClass(); String msg = def.getFile().getFilePath()+" "+"Unexpected return type for "; msg += declareClass.getName()+ "." + getterName(prop) + "()"; if( !compClass.equals(declareClass) ){ msg += "[accessed from " + compClass.getName() + "]"; } msg += " expected "+prop.getJavaClass(); failsStr += msg+"\n"; } Class<?> declaringClass = getMethod.getDeclaringClass(); // set the VB onto the object if( attemptedCreateObject ){ // failed to create the object continue; } Object object = null; try{ object = compClass.newInstance(); }catch( Exception ex ){ if( isSkipCreateInstance(compClass, cannotCreateInstanceSkips) ){ continue; } if( ex instanceof InvocationTargetException ){ ex = (Exception) ((InvocationTargetException)ex).getCause(); } ex.printStackTrace(); failsStr += def.getFile().getFilePath()+" "+XspTestUtil.getAfterLastDot(compClass.getName())+ " instance create threw " +ex+'\n'; attemptedCreateObject = true; continue; } if(isComponent ){ try{ ((UIComponent)object).setValueBinding(name, mvb); }catch(IllegalArgumentException illegal){ illegal.printStackTrace(); failsStr += def.getFile().getFilePath()+" "+"Exception calling " + object.getClass().getName() + ".setValueBinding(\"" + name + "\", " + (mvb.getClass().getName()+"@??????") + ") on " + (object.getClass().getName()+"@??????")+"\n"; continue; } }else{ if (object instanceof ComponentBindingObject) { ((ComponentBindingObject)object).setComponent(input); } ((ValueBindingObject)object).setValueBinding(name, mvb); } // invoke the get method try{ getMethod.invoke(object, (Object[])null); }catch( Exception ex2 ){ // fail failsStr+= createFailInvokingVBGetter(compClass, getMethod, declaringClass, ex2)+ '\n'; mvb.clear(); continue; } // the value binding should have been invoked if( shouldAllowRuntimeBinding && !mvb.isWasInvoked() && ! ValueBinding.class.equals(prop.getJavaClass())){ //getMethod.invoke(object, (Object[])null); // for debugging if( PropertyTagsAnnotater.isTaggedAllowRuntimeBindingButNotInvoke(prop) ){ // extremely unlikely - there are very few use-cases where // the property should allow runtime-bindings but // they should not be invoked at runtime. // The only use-case encountered so far, is where the property // has been deprecated and setting any value does nothing. }else{ String calledOn = declaringClass != compClass ? "[Called on " + XspTestUtil.getShortClass(compClass) + "] " : " "; failsStr += def.getFile().getFilePath()+" "+XspTestUtil.getShortClass(declaringClass) + "." + getMethod.getName() + "()" + calledOn+ " getter did not invoke ValueBinding \n"; } }else if (! shouldAllowRuntimeBinding && mvb.isWasInvoked() ){ if( PropertyTagsAnnotater.isTaggedAllowRuntimeBindingButNotInvoke(prop) ){ // allow-runtime-binding-but-not-invoke failsStr += def.getFile().getFilePath()+" "+XspTestUtil.getShortClass(declaringClass) + "." + getMethod.getName() + "()" + " ValueBinding invoked, property inaccurately has <tags>allow-runtime-binding-but-not-invoke</ \n"; } // TODO (mkehoe) refine this skip // if it's a property defined on an Xsp* component, // ignore as it's generated code. boolean isDefined = def.isDefinedProperty(name); boolean skip = isDefined && XspTestUtil.getShortClass(def.getJavaClass()) .startsWith("Xsp"); FacesDefinition definer = null; if( !skip && !isDefined ){ definer = def.getParent(); while( null != definer && !definer.isDefinedProperty(name)){ definer = definer.getParent(); } if (definer != null && definer.getJavaClass().getName() .startsWith("javax.faces.component")) { // can't change the Sun controls skip = true; } } if( ! skip ){ // fail failsStr += def.getFile().getFilePath()+" "+XspTestUtil.getShortClass(def.getJavaClass()); if( null != definer ){ failsStr +=" "+XspTestUtil.getShortClass(definer.getJavaClass()); } failsStr += "." + getMethod.getName() + "() invoked VB but is declared as <allow-run-time-binding>false</ \n"; } } mvb.clear(); if( ! shouldAllowRuntimeBinding || mustBeRuntimeBinding ){ continue; } // invoke the set method Method[] methods = getSetMethods(compClass, name, prop.getJavaClass()); if( methods.length == 0 ){ // will have added a fail above continue; } Method setMethod = methods[0]; Object value; try{ value = getSomeValue(def, prop, prop.getJavaClass()); }catch(Exception e){ String msg = def.getFile().getFilePath()+" "+"Problem creating value to call " + XspTestUtil.getShortClass(def.getJavaClass()) + "." + setMethod.getName() + "(" + XspTestUtil.getShortClass(prop.getJavaClass()) + ") - " + e.toString(); failsStr += msg + "\n"; System.err.println(msg); e.printStackTrace(); continue; } try{ setMethod.invoke(object, value ); }catch(Exception e){ if( e instanceof InvocationTargetException ){ e = (Exception) e.getCause(); } String msg = def.getFile().getFilePath()+" "+"Problem calling set method " + XspTestUtil.getShortClass(compClass)+ "." + setMethod.getName()+ "(" + XspTestUtil .getShortClass(prop.getJavaClass()) + ") - " + e.toString(); failsStr += msg + "\n"; System.err.println(msg); e.printStackTrace(); continue; } // check that the value binding is ignored when the setter was called getMethod.invoke(object); if( mvb.isWasInvoked() ){ value = value instanceof String ? "\"" + value + "\"" : value; failsStr += def.getFile().getFilePath()+" "+XspTestUtil.getShortClass(def.getJavaClass())+" invoked VB in " + getMethod.getName() + "() after called " + setMethod.getName() + "(" + value + ") \n"; } mvb.clear(); }// end for all properties (including inherited) } // end for all definitions for (Object[] skip : propSkips) { if( ! isSkipMarkedAsUsed(skip) ){ failsStr += XspTestUtil.getShortClass((Class<?>) skip[1]) + "." + skip[0] + " Unused skip in getTotallySkippedProperties\n"; } } for (Object[] skip : propNotVB) { if( ! isSkipMarkedAsUsed(skip) ){ failsStr += XspTestUtil.getShortClass((Class<?>) skip[1]) + "." + skip[0] + " Unused skip for Property not allow ValueBinding\n"; } } for (Object[] skip : defBindingSkips) { failsStr += XspTestUtil.getShortClass((Class<?>) skip[0]) + " Unused skip in getDefinitionNotAllowRuntimeBindings, please update skip list.\n"; } for(Object[] skip: cannotCreateInstanceSkips ){ if( ! isSkipMarkedAsUsed(skip) ){ failsStr += XspTestUtil.getShortClass((Class<?>) skip[0]) + " " + " Unused skip for Cannot create Instance\n"; } } failsStr = XspTestUtil.removeMultilineFailSkips(failsStr, SkipFileContent.concatSkips(getSkips(), this, "testPropertiesHaveSetters")); if( failsStr.length() > 0 ){ fail(XspTestUtil.getMultilineFailMessage(failsStr)); } }catch(Exception ex){ // print the full stack trace ex.printStackTrace(); throw ex; } } protected String[] getSkips() { return StringUtil.EMPTY_STRING_ARRAY; } /** * @param compClass * @param cannotCreateInstanceSkips * @return */ private boolean isSkipCreateInstance(Class<?> compClass, List<Object[]> cannotCreateInstanceSkips) { int skipIndex = -1; int i = 0; for (Object[] skip : cannotCreateInstanceSkips) { if( compClass.equals(skip[0]) ){ skipIndex = i; break; } i++; } if( -1 == skipIndex ){ return false; } markSkipUsed(cannotCreateInstanceSkips, skipIndex); return true; } private boolean isSkipMarkedAsUsed(Object[] skip) { return skip.length >=4 && Boolean.TRUE.equals(skip[3]); } private void markSkipUsed(List<Object[]> propSkips, int indexPropSkips) { if( -1 != indexPropSkips ){ Object[] skip = propSkips.get(indexPropSkips); if( ! isSkipMarkedAsUsed(skip) ){ if( skip.length < 4 ){ skip = XspTestUtil.concat(skip, new Object[4 - skip.length]); propSkips.set(indexPropSkips, skip); } skip[3] = Boolean.TRUE; } } } /** * @param compClass * @param getMethod * @param declaringClass * @param ex2 * @return */ private String createFailInvokingVBGetter(Class<?> compClass, Method getMethod, Class<?> declaringClass, Exception exUnwrapped) { Throwable ex = exUnwrapped; if( ex instanceof InvocationTargetException ){ ex = ((InvocationTargetException)ex).getCause(); } // UISelectItemsEx.getValue() getter threw java.lang.NullPointerException String msg = XspTestUtil.getAfterLastDot(declaringClass.getName()); msg += "." + getMethod.getName() + "()"; if (declaringClass != compClass) { msg += "[Called on "; msg += XspTestUtil.getAfterLastDot(compClass.getName()); msg += "]"; } System.err.println(getClass().getName() + ".testPropertiesHaveSetters():" + " Exception calling " + msg); ex.printStackTrace(); msg += " getter for VB prop threw "+ ex; return msg; } /** * @param def * @param prop * @param javaClass * @return */ protected Object getSomeValue(FacesDefinition def, FacesProperty prop, Class<?> javaClass) throws Exception{ if (char.class.equals(javaClass)) { return Character.valueOf('z'); } if (byte.class.equals(javaClass)) { return Byte.valueOf((byte)5);// validate } if (short.class.equals(javaClass)) { return Short.valueOf((short)5);// validate } if (int.class.equals(javaClass)) { return Integer.valueOf(5);// validate } if (long.class.equals(javaClass)) { return Long.valueOf(5);// validate } if (float.class.equals(javaClass)) { return Float.valueOf(5.0F);// validate } if (double.class.equals(javaClass)) { return Double.valueOf(5.0);// validate } if (boolean.class.equals(javaClass)) { // Updated 2012-10-26, to default to FALSE // instead of TRUE, to catch the condition // where the setter is set to true, // but the getter is still invoking the // ValueBinding. return Boolean.FALSE; } if (String.class.equals(javaClass)) { return "hello"; } if( Converter.class.equals(javaClass) ){ return new DateTimeConverter(); } if( Locale.class.equals(javaClass) ){ return Locale.FRANCE; } if( TimeZone.class.equals(javaClass) ){ return TimeZone.getDefault(); } if( DataSource.class.equals(javaClass) ){ return new EmptyDataSource(); } if( ValueBinding.class.equals(javaClass) ){ return new MultiPartValueBinding(null/*getApplicationEx()*/, "hello"); } return javaClass.newInstance(); } private static class EmptyDataSource implements DataSource{ public DataContainer getDataContainer() throws FacesExceptionEx { return null; } public String getRequestParamPrefix() { return null; } public String getScope() { return null; } public String getBeanId() { return null; } public String getUniqueId() { return null; } public String getVar() { return "empty"; } public String[] getVars() { return new String[]{"empty"}; } public boolean isIgnoreRequestParams() { return true; } public boolean isReadonly() { return false; } public void popData(FacesContext context, UIComponent component, Map<String, Object> requestMap) throws FacesExceptionEx { } public void pushData(FacesContext context, UIComponent component, Map<String, Object> requestMap, List<ShadowedObject> shadowedData) throws FacesExceptionEx { } public void refresh() { } public boolean save(FacesContext context, boolean removeFromManager) throws FacesExceptionEx { return false; } public void setIgnoreRequestParams(boolean ignore) { } public void setRequestParamPrefix(String prefix) { } public void setScope(String scope) { } public void setVar(String var) { } // Note, before 8.5.2 DataSource extends StateHolder, ValueBindingObject // but that is no longer the case, so these methods are not needed. // public boolean isTransient() { // return false; // } // public void restoreState(FacesContext context, Object state) { // } // public Object saveState(FacesContext context) { // return null; // } // public void setTransient(boolean isTransient) { // } // public void beginRendering(FacesContext context) { // } // public ValueBinding getValueBinding(String property) { // return null; // } // public void setValueBinding(String property, ValueBinding binding) { // } } protected List<Object[]> getDefinitionNotAllowRuntimeBindings(FacesSharableRegistry reg){ List<Object[]> list = new ArrayList<Object[]>(); return list; } protected List<Object[]> getCannotCreateInstanceSkips(FacesSharableRegistry reg){ List<Object[]> list = new ArrayList<Object[]>(); return list; } /** * A List of arrays with 3 entries * <ul> * <li>[0] the propertyName,</li> * <li>[1] the (possibly null) Class where it's defined,</li> * <li>[2] if the Class is null, the string className where it's defined</li> * <li>([3] is added by the test, a Boolean indicating the skip has been used)</li> * </ul> * @param reg * @return */ protected List<Object[]> getPropertyNotAllowValueBindings(FacesSharableRegistry reg){ List<Object[]> list = new ArrayList<Object[]>(); return list; } private int getSkipListIndex(List<Object[]> skips, Class<?> objectClass, String propertyName) { int i = 0; for (Object[] skip : skips) { if( isSkipMatch(skip, objectClass, propertyName)){ return i; } i++; } return -1; } private boolean isSkipMatch(Object[] skip, Class<?> objectClass, String propertyName){ if( propertyName.equals(skip[0]) ){ Class<?> clazz = (Class<?>) skip[1]; if( null == clazz ){ try { clazz = Class.forName((String)skip[2]); skip[1] = clazz; } catch (ClassNotFoundException e) { // set it to a class with no subclass skip[1] = String.class; return false; } } if( clazz.isAssignableFrom(objectClass) ){ return true; } } return false; } private boolean isSkipMatch(Object[] skip, Class<?> objectClass ){ Class<?> skipClass = (Class<?>) skip[0]; if( null == skipClass ){ String skipName = (String)skip[1]; if( null == skipName){ // already tried to create the class // and it didn't work return false; } try { skipClass = Class.forName(skipName); skip[0] = skipClass; } catch (ClassNotFoundException e) { // set skipName to null skip[1] = null; return false; } } if( skipClass.equals(objectClass) ){ return true; } return false; } private int getSkipListIndex(List<Object[]> skipDefinitions, Class<?> objectClass) { int i = 0; for (Object[] skip : skipDefinitions) { if( isSkipMatch(skip, objectClass)){ return i; } i++; } return -1; } private Method getGetMethod(Class<?> objectClass, FacesProperty prop) { String methodName = getterName(prop); Method method = getMethod(objectClass, methodName, null); return method; } private String getterName(FacesProperty prop) { String propertyName = prop.getName(); Class<?> type = prop.getJavaClass(); String methodName = (boolean.class.equals(type) ? "is" : "get") + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); return methodName; } /** * @param totallySkippedProperties TODO * @param objectClass * @param propertyName * @return */ protected boolean isSkippedProperty(Class<?> objectClass, String propertyName) { if( "loaded".equals(propertyName) && ! UIComponent.class.isAssignableFrom(objectClass) && ! PropertyMap.class.isAssignableFrom(objectClass) && ! GroupPlaceholderClass.class.equals(objectClass) ){ // (not a component, composite-component, property-type or group) // skip the complex-type loaded property, // as there is no setLoaded method, since the property is handled // by the page loading. return true; } return false; } protected List<Object[]> getTotallySkippedProperties(FacesSharableRegistry reg) { List<Object[]> list = new ArrayList<Object[]>(); return list; } private boolean hasSetValueBindingMtd(FacesDefinition definition) { Class<?> defClass = definition.getJavaClass(); // has one of the setValueBinding methods handled // by the class that generates .java code boolean hasSetVB = UIComponent.class.isAssignableFrom(defClass) || ValueBindingObject.class.isAssignableFrom(defClass); // || PropertyMap.class.isAssignableFrom(defClass); // include composite is already a UIComponent. // ValueBindings set on it may be handled specially though //|| UIIncludeComposite.class.isAssignableFrom(defClass); return hasSetVB; } /** * Get the methods to use for property setting */ private static Method[] getSetMethods(Class<?> objectClass, String propertyName, Class<?> type) { // settings used for reflection Method method = null; Class<?>[] parameterTypes1 = new Class[] { type }; propertyName = propertyName.substring(0,1).toUpperCase() + propertyName.substring(1); // will try set and add as valid prefixes and using the value class or // plain Object class as parameter type ArrayList<Method> methods = new ArrayList<Method>(2); method = getMethod(objectClass, "set" + propertyName, parameterTypes1); //$NON-NLS-1$ if (method != null) methods.add(method); method = getMethod(objectClass, "set" + propertyName, OBJECT_PARAMETER); //$NON-NLS-1$ if (method != null) methods.add(method); return methods.toArray(new Method[methods.size()]); } private static Method getMethod(Class<?> objectClass, String methodName, Class<?>[] parameterTypes) { try { return objectClass.getMethod(methodName, parameterTypes); } catch (NoSuchMethodException nsme) { return null; } } private static class MockValueBinding extends ValueBinding implements StateHolder { private boolean _wasInvoked; public MockValueBinding(){} @Override public Object getValue(FacesContext arg0) throws EvaluationException, PropertyNotFoundException { _wasInvoked = true; return null; } public void clear(){ _wasInvoked = false; } public boolean isWasInvoked() { return _wasInvoked; } // ----------- do nothing --------------------- public void setTransient(boolean arg){} public Object saveState(FacesContext ctxt){ return null; } public void restoreState(FacesContext ctxt, Object obj){} public boolean isTransient(){ return true; } @Override public void setValue(FacesContext arg0, Object arg1) throws EvaluationException, PropertyNotFoundException {} @Override public boolean isReadOnly(FacesContext arg0) throws EvaluationException, PropertyNotFoundException { return false; } @SuppressWarnings("rawtypes") @Override public Class getType(FacesContext arg0) throws EvaluationException, PropertyNotFoundException { return null; } } // end class }