r2367 - in trunk: nuiton-utils/src/main/java/org/nuiton/util/beans nuiton-utils/src/main/java/org/nuiton/util/converter nuiton-utils/src/test/java/org/nuiton/util/beans nuiton-utils/src/test/resources/zip nuiton-validator/src/main/java/org/nuiton/validator/xwork2
Author: tchemit Date: 2012-07-10 14:31:55 +0200 (Tue, 10 Jul 2012) New Revision: 2367 Url: http://nuiton.org/repositories/revision/nuiton-utils/2367 Log: fixes #2178: Can use nested properties in validator field add svn properties + license headers Added: trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BeanC.java Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/beans/BeanUtil.java trunk/nuiton-utils/src/main/java/org/nuiton/util/converter/KeyStrokeConverter.java trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BeanUtilTest.java trunk/nuiton-utils/src/test/resources/zip/not-a-zip.zip trunk/nuiton-utils/src/test/resources/zip/this-is-a-zip.zap trunk/nuiton-validator/src/main/java/org/nuiton/validator/xwork2/XWork2ValidatorUtil.java Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/beans/BeanUtil.java =================================================================== --- trunk/nuiton-utils/src/main/java/org/nuiton/util/beans/BeanUtil.java 2012-07-07 19:44:37 UTC (rev 2366) +++ trunk/nuiton-utils/src/main/java/org/nuiton/util/beans/BeanUtil.java 2012-07-10 12:31:55 UTC (rev 2367) @@ -170,6 +170,81 @@ return result; } + /** + * Obtains all readable properties from a given type. + * + * @param beanType the type to seek + * @return the set of all readable properties for the given type + * @since 2.0 + */ + public static boolean isNestedReadableProperty(Class<?> beanType, String propertyName) { + boolean result = propertyName.contains("."); + if (result) { + int dotIndex = propertyName.indexOf("."); + String firstLevelProperty = propertyName.substring(0, dotIndex); + + Class<?> nestedType = getReadableType(beanType, firstLevelProperty); + if (nestedType == null) { + + result = false; + } else { + + String rest = propertyName.substring(dotIndex+1); + result = isNestedReadableProperty(nestedType, rest); + } + + } else { + + // not a nested property check it directly + Class<?> nestedType = getReadableType(beanType, propertyName); + result = nestedType != null; + } + + return result; + } + + public static Class<?> getReadableType(Class<?> beanType, String propertyName) { + PropertyDescriptor[] descriptors = + PropertyUtils.getPropertyDescriptors(beanType); + + Class<?> result = null; + for (PropertyDescriptor descriptor : descriptors) { + String name = descriptor.getName(); + if (descriptor.getReadMethod() != null && + propertyName.equals(name)) { + result = descriptor.getReadMethod().getReturnType(); + break; + } + } + + if (result == null) { + + // try with super-class + if (beanType.getSuperclass() != null) { + + // get properties fro super-class + result = getReadableType(beanType.getSuperclass(), propertyName); + } + } + + if (result == null) { + + // try it with interfaces + Class<?>[] interfaces = beanType.getInterfaces(); + for (Class<?> anInterface : interfaces) { + + result = getReadableType(anInterface, propertyName); + + if (result != null) { + + // found it + break; + } + } + } + return result; + } + protected static void getReadableProperties(Class<?> beanType, Set<String> result, Set<Class<?>> exploredTypes) { Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/converter/KeyStrokeConverter.java =================================================================== --- trunk/nuiton-utils/src/main/java/org/nuiton/util/converter/KeyStrokeConverter.java 2012-07-07 19:44:37 UTC (rev 2366) +++ trunk/nuiton-utils/src/main/java/org/nuiton/util/converter/KeyStrokeConverter.java 2012-07-10 12:31:55 UTC (rev 2367) @@ -1,8 +1,8 @@ /* * #%L * Nuiton Utils :: Nuiton Utils - * $Id:$ - * $HeadURL:$ + * $Id$ + * $HeadURL$ * %% * Copyright (C) 2004 - 2012 CodeLutin * %% Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/converter/KeyStrokeConverter.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Added: trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BeanC.java =================================================================== --- trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BeanC.java (rev 0) +++ trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BeanC.java 2012-07-10 12:31:55 UTC (rev 2367) @@ -0,0 +1,108 @@ +package org.nuiton.util.beans; +/* + * #%L + * Nuiton Utils :: Nuiton Utils + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2012 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +/** + * To test http://nuiton.org/issues/2178. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.1 + */ +public class BeanC { + + public static final String PROPERTY_A = "a"; + + public static final String PROPERTY_AA = "aa"; + + public static final String PROPERTY_B = "b"; + + protected BeanA a; + + protected BeanAA aa; + + protected BeanB b; + + protected PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + + public BeanA getA() { + return a; + } + + public void setA(BeanA a) { + Object oldValue = this.a; + this.a = a; + firePropertyChange(PROPERTY_A, oldValue, a); + } + + public BeanAA getAa() { + return aa; + } + + public void setAa(BeanAA aa) { + Object oldValue = this.aa; + this.aa = aa; + firePropertyChange(PROPERTY_AA, oldValue, aa); + } + + public BeanB getB() { + return b; + } + + public void setB(BeanB b) { + Object oldValue = this.b; + this.b = b; + firePropertyChange(PROPERTY_B, oldValue, b); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, + PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + protected void firePropertyChange(String propertyName, Object oldValue, + Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + protected PropertyChangeListener[] getPropertyChangeListeners() { + return pcs.getPropertyChangeListeners(); + } +} Property changes on: trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BeanC.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BeanUtilTest.java =================================================================== --- trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BeanUtilTest.java 2012-07-07 19:44:37 UTC (rev 2366) +++ trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BeanUtilTest.java 2012-07-10 12:31:55 UTC (rev 2367) @@ -116,6 +116,56 @@ } @Test + public void getNestedReadeableProperty() { + + assertFoundNestedReadableProperties(BeanA.class, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F); + + assertFoundNestedReadableProperties(BeanB.class, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F, + BeanB.PROPERTY_BB, + BeanB.PROPERTY_A2, + BeanB.PROPERTY_B2, + BeanB.PROPERTY_C2, + BeanB.PROPERTY_D2, + BeanB.PROPERTY_E2, + BeanB.PROPERTY_F2 + ); + + assertFoundNestedReadableProperties(BeanC.class, + BeanC.PROPERTY_A, + BeanC.PROPERTY_AA, + BeanC.PROPERTY_B, + BeanC.PROPERTY_A + "." + BeanA.PROPERTY_A, + BeanC.PROPERTY_A + "." + BeanA.PROPERTY_A, + BeanC.PROPERTY_A + "." + BeanA.PROPERTY_B, + BeanC.PROPERTY_A + "." + BeanA.PROPERTY_C, + BeanC.PROPERTY_A + "." + BeanA.PROPERTY_D, + BeanC.PROPERTY_A + "." + BeanA.PROPERTY_E, + BeanC.PROPERTY_A + "." + BeanA.PROPERTY_F, + BeanC.PROPERTY_B + "." + BeanB.PROPERTY_BB, + BeanC.PROPERTY_B + "." + BeanB.PROPERTY_A2, + BeanC.PROPERTY_B + "." + BeanB.PROPERTY_B2, + BeanC.PROPERTY_B + "." + BeanB.PROPERTY_C2, + BeanC.PROPERTY_B + "." + BeanB.PROPERTY_D2, + BeanC.PROPERTY_B + "." + BeanB.PROPERTY_E2, + BeanC.PROPERTY_B + "." + BeanB.PROPERTY_F2, + BeanC.PROPERTY_B + "." + BeanB.PROPERTY_A2 + ".class" + + ); + } + + @Test public void addPropertyChangeListener() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { PropertyChangeListener l = new BeanContextSupport(); @@ -176,4 +226,11 @@ Assert.assertTrue(readableProperties.contains(expectedproperty)); } } + + protected void assertFoundNestedReadableProperties(Class<?> type, String... expectedproperties) { + for (String expectedproperty : expectedproperties) { + boolean actual = BeanUtil.isNestedReadableProperty(type, expectedproperty); + Assert.assertTrue("Did not found nested property " + expectedproperty, actual); + } + } } Property changes on: trunk/nuiton-utils/src/test/resources/zip/not-a-zip.zip ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Property changes on: trunk/nuiton-utils/src/test/resources/zip/this-is-a-zip.zap ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Modified: trunk/nuiton-validator/src/main/java/org/nuiton/validator/xwork2/XWork2ValidatorUtil.java =================================================================== --- trunk/nuiton-validator/src/main/java/org/nuiton/validator/xwork2/XWork2ValidatorUtil.java 2012-07-07 19:44:37 UTC (rev 2366) +++ trunk/nuiton-validator/src/main/java/org/nuiton/validator/xwork2/XWork2ValidatorUtil.java 2012-07-10 12:31:55 UTC (rev 2367) @@ -77,40 +77,25 @@ ConfigurationManager confManager = new ConfigurationManager(); Configuration conf = confManager.getConfiguration(); Container container = conf.getContainer(); - ValueStackFactory stackFactory = - container.getInstance(ValueStackFactory.class); + ValueStackFactory stackFactory = container.getInstance(ValueStackFactory.class); ValueStack vs = stackFactory.createValueStack(); return vs; } - public static <O> XWork2ScopeValidator<O> newXWorkScopeValidator(Class<O> beanClass, - String contextName, - Set<String> fields - ) { - return newXWorkScopeValidator(beanClass, - contextName, - fields, - getSharedValueStack() - ); + public static <O> XWork2ScopeValidator<O> newXWorkScopeValidator(Class<O> beanClass, String contextName, + Set<String> fields) { + return newXWorkScopeValidator(beanClass, contextName, fields, getSharedValueStack()); } - public static <O> XWork2ScopeValidator<O> newXWorkScopeValidator(Class<O> beanClass, - String contextName, - Set<String> fields, - ValueStack vs) { + public static <O> XWork2ScopeValidator<O> newXWorkScopeValidator(Class<O> beanClass, String contextName, + Set<String> fields, ValueStack vs) { - return new XWork2ScopeValidator<O>(beanClass, - contextName, - fields, - vs - ); + return new XWork2ScopeValidator<O>(beanClass, contextName, fields, vs); } - public static String getContextForScope(String context, - NuitonValidatorScope scope) { - return (context == null ? "" : context + "-") + - scope.name().toLowerCase(); + public static String getContextForScope(String context, NuitonValidatorScope scope) { + return (context == null ? "" : context + "-") + scope.name().toLowerCase(); } protected static ActionValidatorManager newValidationManager(ValueStack vs) { @@ -138,17 +123,14 @@ // init validator Container container = context.getContainer(); ActionValidatorManager validatorManager = - container.getInstance(ActionValidatorManager.class, - "no-annotations"); + container.getInstance(ActionValidatorManager.class, "no-annotations"); return validatorManager; } - public static <O> Map<NuitonValidatorScope, String[]> detectFields(Class<O> type, - String context, + public static <O> Map<NuitonValidatorScope, String[]> detectFields(Class<O> type, String context, NuitonValidatorScope[] scopeUniverse) { - Set<String> availableFields = BeanUtil.getReadableProperties(type); ActionValidatorManager validatorManager = newValidationManager(null); @@ -157,13 +139,8 @@ for (NuitonValidatorScope scope : scopeUniverse) { - Set<String> fieldNames = detectFieldsForScope(validatorManager, - type, - scope, - context, - availableFields, - false - ); + Set<String> fieldNames = + detectFieldsForScope(validatorManager, type, scope, context, availableFields, false); if (log.isDebugEnabled()) { log.debug("detected validator fields for scope " + scope + @@ -174,9 +151,7 @@ // fields detected in this validator, keep it - fields.put(scope, - fieldNames.toArray(new String[fieldNames.size()]) - ); + fields.put(scope, fieldNames.toArray(new String[fieldNames.size()])); } } @@ -193,7 +168,6 @@ String scopeContext = getContextForScope(context, scope); - Set<String> fields = new HashSet<String>(); int skip = 0; @@ -227,12 +201,20 @@ fields.add(fName); } else { - // not a readable property, can not add it - String message = "Field " + fName + " in scope [" + scopeContext + "] is not a readable property of " + type.getName(); - if (log.isErrorEnabled()) { - log.error(message); + if (BeanUtil.isNestedReadableProperty(type, fName)) { + + fields.add(fName); + + } else { + // not a readable property, can not add it + String message = + "Field " + fName + " in scope [" + scopeContext + "] is not a readable property of " + + type.getName(); + if (log.isErrorEnabled()) { + log.error(message); + } + throw new IllegalStateException(message); } - throw new IllegalStateException(message); } } }
participants (1)
-
tchemit@users.nuiton.org