You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rd...@apache.org on 2005/07/14 00:29:40 UTC
svn commit: r216278 - in /jakarta/commons/proper/betwixt/trunk:
src/java/org/apache/commons/betwixt/digester/ src/resources/
src/test/org/apache/commons/betwixt/dotbetwixt/ xdocs/ xdocs/guide/
Author: rdonkin
Date: Wed Jul 13 15:29:37 2005
New Revision: 216278
URL: http://svn.apache.org/viewcvs?rev=216278&view=rev
Log:
New 'forceAccessible' attribute for element in dot betwixt. This allows non-public updaters to be discovered. Contributed by John M. Issue #35723.
Modified:
jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java
jakarta/commons/proper/betwixt/trunk/src/resources/dotbetwixt.dtd
jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.betwixt
jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.java
jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/TestXmlToBean.java
jakarta/commons/proper/betwixt/trunk/xdocs/guide/binding.xml
jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml
Modified: jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java?rev=216278&r1=216277&r2=216278&view=diff
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java (original)
+++ jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java Wed Jul 13 15:29:37 2005
@@ -16,6 +16,7 @@
*/
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.util.Map;
import org.apache.commons.betwixt.ElementDescriptor;
@@ -141,7 +142,8 @@
}
if ( propertyName != null && propertyName.length() > 0 ) {
- configureDescriptor(descriptor, attributes.getValue( "updater" ));
+ boolean forceAccessible = "true".equals(attributes.getValue("forceAccessible"));
+ configureDescriptor(descriptor, attributes.getValue("updater"), forceAccessible);
} else {
String value = attributes.getValue( "value" );
@@ -199,10 +201,32 @@
* @param elementDescriptor configure this <code>ElementDescriptor</code>
* @param updateMethodName custom update method. If null, then use standard
* @since 0.5
+ * @deprecated now calls <code>#configureDescriptor(ElementDescriptor, String, boolean)</code>
+ * which allow accessibility to be forced.
+ * The subclassing API was not really considered carefully when
+ * this class was created.
+ * If anyone subclasses this method please contact the mailing list
+ * and suitable hooks will be placed into the code.
*/
protected void configureDescriptor(
ElementDescriptor elementDescriptor,
String updateMethodName) {
+ configureDescriptor( elementDescriptor, null, false );
+ }
+
+ /**
+ * Sets the Expression and Updater from a bean property name
+ * Allows a custom updater to be passed in.
+ *
+ * @param elementDescriptor configure this <code>ElementDescriptor</code>
+ * @param updateMethodName custom update method. If null, then use standard
+ * @param forceAccessible if true and updateMethodName is not null,
+ * then non-public methods will be searched and made accessible (Method.setAccessible(true))
+ */
+ private void configureDescriptor(
+ ElementDescriptor elementDescriptor,
+ String updateMethodName,
+ boolean forceAccessible) {
Class beanClass = getBeanClass();
if ( beanClass != null ) {
String name = elementDescriptor.getPropertyName();
@@ -214,6 +238,7 @@
elementDescriptor,
descriptor,
updateMethodName,
+ forceAccessible,
beanClass );
getProcessedPropertyNameSet().add( name );
@@ -230,6 +255,7 @@
* @param propertyDescriptor configure from this <code>PropertyDescriptor</code>
* @param updateMethodName the name of the custom updater method to user.
* If null, then then
+ * @param forceAccessible if true and updateMethodName is not null, then non-public methods will be searched and made accessible (Method.setAccessible(true))
* @param beanClass the <code>Class</code> from which the update method should be found.
* This may be null only when <code>updateMethodName</code> is also null.
*/
@@ -237,6 +263,7 @@
ElementDescriptor elementDescriptor,
PropertyDescriptor propertyDescriptor,
String updateMethodName,
+ boolean forceAccessible,
Class beanClass ) {
Class type = propertyDescriptor.getPropertyType();
@@ -308,23 +335,11 @@
log.trace( " name:" + updateMethodName );
}
- Method updateMethod = null;
- Method[] methods = beanClass.getMethods();
- for ( int i = 0, size = methods.length; i < size; i++ ) {
- Method method = methods[i];
- if ( updateMethodName.equals( method.getName() ) ) {
- // we have a matching name
- // check paramters are correct
- if (methods[i].getParameterTypes().length == 1) {
- // we'll use first match
- updateMethod = methods[i];
- if ( log.isTraceEnabled() ) {
- log.trace("Matched method:" + updateMethod);
- }
- // done since we're using the first match
- break;
- }
- }
+ Method updateMethod;
+ if ( forceAccessible ) {
+ updateMethod = findAnyMethod( updateMethodName, beanClass );
+ } else {
+ updateMethod = findPublicMethod( updateMethodName, beanClass );
}
if (updateMethod == null) {
@@ -341,5 +356,55 @@
}
}
}
+ }
+
+ private Method findPublicMethod(String updateMethodName, Class beanType) {
+ Method[] methods = beanType.getMethods();
+ Method updateMethod = searchMethodsForMatch( updateMethodName, methods );
+ return updateMethod;
+ }
+
+ private Method searchMethodsForMatch(String updateMethodName, Method[] methods) {
+ Method updateMethod = null;
+ for ( int i = 0, size = methods.length; i < size; i++ ) {
+ Method method = methods[i];
+ if ( updateMethodName.equals( method.getName() ) ) {
+ // we have a matching name
+ // check paramters are correct
+ if (methods[i].getParameterTypes().length == 1) {
+ // we'll use first match
+ updateMethod = methods[i];
+ if ( log.isTraceEnabled() ) {
+ log.trace("Matched method:" + updateMethod);
+ }
+ // done since we're using the first match
+ break;
+ }
+ }
+ }
+ return updateMethod;
+ }
+
+ private Method findAnyMethod(String updateMethodName, Class beanType) {
+ // TODO: suspect that this algorithm may run into difficulties
+ // on older JVMs (particularly with package privilage interfaces).
+ // This seems like too esoteric a use case to worry to much about now
+ Method updateMethod = null;
+ Class classToTry = beanType;
+ do {
+ Method[] methods = classToTry.getDeclaredMethods();
+ updateMethod = searchMethodsForMatch(updateMethodName, methods);
+
+ //try next superclass - Object will return null and end loop if no method is found
+ classToTry = classToTry.getSuperclass();
+ } while ( updateMethod == null && classToTry != null );
+
+ if ( updateMethod != null ) {
+ boolean isPublic = Modifier.isPublic(updateMethod.getModifiers()) && Modifier.isPublic(beanType.getModifiers());
+ if ( !isPublic ) {
+ updateMethod.setAccessible(true);
+ }
+ }
+ return updateMethod;
}
}
Modified: jakarta/commons/proper/betwixt/trunk/src/resources/dotbetwixt.dtd
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/resources/dotbetwixt.dtd?rev=216278&r1=216277&r2=216278&view=diff
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/resources/dotbetwixt.dtd (original)
+++ jakarta/commons/proper/betwixt/trunk/src/resources/dotbetwixt.dtd Wed Jul 13 15:29:37 2005
@@ -49,6 +49,10 @@
Note that name is required except when the property is a collective
-->
<!ELEMENT element (attribute|addDefaults|element|text)*>
+<!--
+ forceAccessible is used to control whether Betwixt forces access (by reflection)
+ to methods which are not public but are accessible (by reflection).
+-->
<!ATTLIST element
name CDATA #IMPLIED
type CDATA #IMPLIED
@@ -58,6 +62,7 @@
updater CDATA #IMPLIED
class CDATA #IMPLIED
mappingDerivation (bind|introspection) #IMPLIED
+ forceAccessible (true|false) #IMPLIED
>
<!-- Use for mixed content text -->
Modified: jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.betwixt
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.betwixt?rev=216278&r1=216277&r2=216278&view=diff
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.betwixt (original)
+++ jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.betwixt Wed Jul 13 15:29:37 2005
@@ -24,6 +24,7 @@
<element name='bad-items'>
<element name='bad-item' property='badItems' updater='badItemAdder'/>
</element>
+ <element name='private-property' property='privateProperty' updater='setPrivateProperty' forceAccessible="true"/>
<addDefaults/>
</element>
</info>
Modified: jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.java?rev=216278&r1=216277&r2=216278&view=diff
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.java (original)
+++ jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/MixedUpdatersBean.java Wed Jul 13 15:29:37 2005
@@ -31,6 +31,7 @@
private String badName = "**UNSET**";
private List items = new ArrayList();
private List badItems = new ArrayList();
+ private String privateProperty;
//-------------------------- Constructors
@@ -39,7 +40,7 @@
public MixedUpdatersBean(String name) {
setName(name);
}
-
+
//--------------------------- Properties
public String getName() {
@@ -73,4 +74,15 @@
public void badItemAdder(String badItem) {
badItems.add(badItem);
}
+
+ public String getPrivateProperty() {
+ return privateProperty;
+ }
+
+ protected void setPrivateProperty(String privateProp) {
+ this.privateProperty = privateProp;
+ }
+ public void privatePropertyWorkaroundSetter(String privateProp) {
+ this.privateProperty = privateProp;
+ }
}
Modified: jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/TestXmlToBean.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/TestXmlToBean.java?rev=216278&r1=216277&r2=216278&view=diff
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/TestXmlToBean.java (original)
+++ jakarta/commons/proper/betwixt/trunk/src/test/org/apache/commons/betwixt/dotbetwixt/TestXmlToBean.java Wed Jul 13 15:29:37 2005
@@ -49,7 +49,7 @@
//---------------------------------- Tests
- public void _testCustomUpdaters() throws Exception {
+ public void testCustomUpdaters() throws Exception {
// might as well check writer whilst we're at it
MixedUpdatersBean bean = new MixedUpdatersBean("Lov");
bean.badNameSetter("Hate");
@@ -57,43 +57,25 @@
bean.badItemAdder("Black");
bean.addItem("Life");
bean.badItemAdder("Death");
-
-// SimpleLog log = new SimpleLog("[testCustomUpdaters:XMLIntrospector]");
-// log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
-
+ bean.privatePropertyWorkaroundSetter("Private");
+
StringWriter out = new StringWriter();
out.write("<?xml version='1.0'?>");
- BeanWriter writer = new BeanWriter(out);
-// writer.getXMLIntrospector().setLog(log);
-
-// log = new SimpleLog("[testCustomUpdaters:XMLIntrospectorHelper]");
-// log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
-// XMLIntrospectorHelper.setLog(log);
+ BeanWriter writer = new BeanWriter(out);;
writer.getBindingConfiguration().setMapIDs(false);
writer.write(bean);
String xml = "<?xml version='1.0'?><mixed><name>Lov</name><bad-name>Hate</bad-name>"
+ "<items><item>White</item><item>Life</item></items>"
- + "<bad-items><bad-item>Black</bad-item><bad-item>Death</bad-item></bad-items></mixed>";
+ + "<bad-items><bad-item>Black</bad-item><bad-item>Death</bad-item></bad-items>"
+ + "<private-property>Private</private-property></mixed>";
xmlAssertIsomorphicContent(
parseString(xml),
parseString(out.toString()),
true);
-// SimpleLog log = new SimpleLog("[testCustomUpdaters:XMLIntrospectorHelper]");
-// log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
-// XMLIntrospectorHelper.setLog(log);
-
-// log = new SimpleLog("[testCustomUpdaters:BeanRuleSet]");
-// log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
-// BeanRuleSet.setLog(log);
-
-// log = new SimpleLog("[testCustomUpdaters:ElementRule]");
-// log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
-// ElementRule.setLog(log);
-
// now we'll test reading via round tripping
BeanReader reader = new BeanReader();
reader.getBindingConfiguration().setMapIDs(false);
@@ -108,8 +90,10 @@
assertEquals("Item two wrong", "Life", items.get(1));
List badItems = bean.getBadItems();
assertEquals("Wrong number of bad items", 2, badItems.size());
- assertEquals("Bad item one wrong", "Black", badItems.get(0));
- assertEquals("Bad item two wrong", "Death", badItems.get(1));
+ // awaiting implementation
+ //assertEquals("Bad item one wrong", "Black", badItems.get(0));
+ //assertEquals("Bad item two wrong", "Death", badItems.get(1));
+ assertEquals("Private property incorrect", "Private", bean.getPrivateProperty());
}
@@ -120,15 +104,8 @@
StringReader xml = new StringReader(
"<?xml version='1.0' encoding='UTF-8'?><deep-thought alpha='Life' gamma='42'>"
+ "The Universe And Everything</deep-thought>");
-
- //SimpleLog log = new SimpleLog("[testMixedContent:BeanRuleSet]");
- //log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
- //BeanRuleSet.setLog(log);
- //log = new SimpleLog("[testMixedContent:BeanReader]");
- //log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
BeanReader reader = new BeanReader();
- //reader.setLog(log);
reader.registerBeanClass(MixedContentOne.class);
Object resultObject = reader.parse(xml);
assertEquals("Object is MixedContentOne", true, resultObject instanceof MixedContentOne);
@@ -141,11 +118,6 @@
/** Tests basic use of an implementation for an interface */
public void _testBasicInterfaceImpl() throws Exception {
- //SimpleLog log = new SimpleLog("[testBasicInterfaceImpl:BeanRuleSet]");
- //log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
- //BeanRuleSet.setLog(log);
- //log = new SimpleLog("[testBasicInterfaceImpl:BeanReader]");
- //log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
ExampleBean bean = new ExampleBean("Alice");
bean.addExample(new ExampleImpl(1, "Mad Hatter"));
@@ -161,7 +133,6 @@
BeanReader reader = new BeanReader();
- //reader.setLog(log);
reader.getXMLIntrospector().getConfiguration().setElementNameMapper(new HyphenatedNameMapper());
reader.getXMLIntrospector().getConfiguration().setWrapCollectionsInElement(false);
reader.registerBeanClass( ExampleBean.class );
Modified: jakarta/commons/proper/betwixt/trunk/xdocs/guide/binding.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/xdocs/guide/binding.xml?rev=216278&r1=216277&r2=216278&view=diff
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/xdocs/guide/binding.xml (original)
+++ jakarta/commons/proper/betwixt/trunk/xdocs/guide/binding.xml Wed Jul 13 15:29:37 2005
@@ -575,6 +575,48 @@
their type.
</p>
</subsection>
+ <subsection name='Writing To Inaccessible Setters'>
+ <p>
+Betwixt finds the getter from the bean property. When a custom updater is specified, though,
+Betwixt uses reflection to find a matching method name. By default, Betwixt will only search
+for a <code>public</code> method with the correct name. This behaviour can be controlled through
+the dot betwixt file. The <code>forceAccessible</code> attribute of the <code>element</code> element
+allows this behaviour to be configured.
+ </p>
+ <p>
+For example, consider a bean such as:
+ </p>
+<source><![CDATA[
+public class SomeBean {
+ ...
+ public SomeClass getSomeProperty() {
+ ...
+ }
+
+ void setSomeProperty(SomeClass value) {
+ ...
+ }
+ ...
+}
+]]></source>
+ <p>
+By default, the setter would not be found. To ensure that the method is found,
+the following dot betwixt fragment could be used:
+ </p>
+<source><![CDATA[
+...
+<element
+ name='SomeName'
+ property='someProperty'
+ updater='setSomeProperty'
+ forceAccessible="true"/>
+...
+]]></source>
+ <p>
+<strong>Note:</strong> when this attribute is set to true, Betwixt will conduct a search upwards through
+the superclasses if no matching methods are found in the implementation class.
+ </p>
+ </subsection>
</section>
<section name='Converting Objects And Primitives To Strings (And Back Again)'>
Modified: jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml?rev=216278&r1=216277&r2=216278&view=diff
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml (original)
+++ jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml Wed Jul 13 15:29:37 2005
@@ -188,6 +188,13 @@
</subsection>
</section>
<section name='Completed'>
+ <subsection name='Since 0.7'>
+ <ul>
+ <li>Added <code>forceAccessible</code> to <code>element</code> tag in dot betwixt file.
+ This allows updater methods to be found that are not public.
+ </li>
+ </ul>
+ </subsection>
<subsection name='0.7'>
<ul>
<li>Fixed bug in nested element diagnosing empty elements.
@@ -347,6 +354,15 @@
</subsection>
</section>
<section name='Deprecated'>
+ <subsection name='Since 0.7'>
+ <ul>
+ <li>ElementRule added forceAccessible attribute
+ <ul>
+ <li>configureDescriptor replaced by private method with extra parameter</li>
+ </ul>
+ </li>
+ </ul>
+ </subsection>
<subsection name='0.7'>
<ul>
<li>ObjectStringConverter direct flavour replaced with use of options
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org