Thanks Clinton; for an excellent mapper that's well designed and for
the pointers.

Here is what I came up with for an object wrapper factory. I don't
really like keeping it in static field on MetaObject, but I couldn't
come up with anything better. I'm not entirely certain the xml
configuration part is done correctly, but it adds
<ObjectWrapperFactory type="com.something.MyFactory" /> in the same
way as ObjectFactory.

I was hoping to be able to subclass BeanWrapper to accomplish my goal
of supporting scala objects, but it looks like it delegates to much to
Reflector and MetaClass. I will post my code for a scala object
wrapper and more generic base class when I complete it, if anyone is
interested.

Thanks, Chris



On Thu, Dec 31, 2009 at 11:00 AM, Clinton Begin <clinton.be...@gmail.com> wrote:
> For both cases, I believe all necessary changes would be in the wrappers.
> However, there are places where Map is treated like a special case.  But as
> long as you stick to making a peer to the bean wrapper, then you should be
> fine.
>
> While there's no factory class, the MetaObject framework uses a factory
> method w/ delegates rather than a constructor, and is aware of all known
> implementations.
>
>   private MetaObject(Object object, ObjectFactory objectFactory) {
>     this.originalObject = object;
>     this.objectFactory = objectFactory;
>     if (object instanceof ObjectWrapper) {
>       this.objectWrapper = (ObjectWrapper) object;
>     } else if (object instanceof Map) {
>       this.objectWrapper = new MapWrapper(this, (Map) object);
>     } else {
>       this.objectWrapper = new BeanWrapper(this, object);
>     }
>   }
>
>   public static MetaObject forObject(Object object, ObjectFactory
> objectFactory) {
>     if (object == null) {
>       return NULL_META_OBJECT;
>     } else {
>       return new MetaObject(object, objectFactory);
>     }
>   }
>
>
> So perhaps one implementation could be a 3rd party wrapper factory that can
> provide the new delegate.  It should be easy for you to code this, but the
> pain in the butt always comes down to where to configure such a thing.  I
> suppose just a new root config level element like <MetaClassWrapper
> type="com.something.ScalaObjectWrappperFactory"/>  The factory could have a
> method like:   isWrapperFor(Class type).
>
> Sounds perfectly possible.  Then we could add external support for things
> like dynabeans etc.
>
> Also, for Martin, I _think_ this might be all that is needed to create
> support for custom column translations like:  first_name => firstName etc.
>
> Clinton
>
>
>
> On Thu, Dec 31, 2009 at 5:11 AM, Martin Ellis <ellis....@gmail.com> wrote:
>>
>> 2009/12/31 Chris Reeves <ch...@ev-soft.net>:
>> > I would like to add support for scala objects to iBATIS 3 for a
>> > project I'm working on, and I have a few questions before I dive in
>> > too deep.
>>
>> Sounds interesting.
>> I assume you're referring to the need to call foo_= instead of setFoo.
>>
>> > This would allow the scala support to be added to the
>> > project in a contrib module so the main project would have no
>> > dependencies on the scala libraries, as I will probably use the
>> > ScalaObject marker interface to create the appropriate wrapper. Of
>> > course, if no one else is interested in native scala object support,
>> > this is moot.
>>
>> Not sure I follow.  Is there any benefit in casting to ScalaObject? I
>> wonder whether it's possible to reference the ScalaObject interface by
>> name only (hence, no need to link to it).
>>
>> Another option (if you do want to link to the scala libraries) might
>> be to make it an optional dependency.  Currently, iBATIS has build
>> dependencies on all sorts of logging frameworks, but they're all
>> optional at runtime.  Could do a similar thing with the scala libs (I
>> assume you're thinking about writing the integration in Java).
>>
>> > However, other getter/setter naming strategies that don't conform to
>> > the javabeans spec could also be plugged in if there was a
>> > configurable wrapper factory, which probably isn't very useful to most
>> > java developers, but may be useful for other jvm languages or some
>> > seriously strange legacy cruft.
>>
>> On the other hand, even for code with conventional getter/setter
>> naming, it might be useful for handling different column naming
>> conventions.
>>
>> In the iBATIS app I'm working on, all the database columns have
>> underscore_names, so I've ended up using column aliasing (SELECT
>> foo_bar fooBar, ...) for each column.
>>
>> I never figured out whether there was a better way to do this, but at
>> the time I was looking for a way to implement exactly the 'pluggable'
>> naming strategies you describe.
>>
>>
>> Martin
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-java-unsubscr...@ibatis.apache.org
>> For additional commands, e-mail: user-java-h...@ibatis.apache.org
>>
>
>
Index: ibatis-3-core/src/test/java/domain/misc/CustomBeanWrapper.java
===================================================================
--- ibatis-3-core/src/test/java/domain/misc/CustomBeanWrapper.java	(revision 0)
+++ ibatis-3-core/src/test/java/domain/misc/CustomBeanWrapper.java	(revision 0)
@@ -0,0 +1,10 @@
+package domain.misc;
+
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.wrapper.BeanWrapper;
+
+public class CustomBeanWrapper extends BeanWrapper {
+  public CustomBeanWrapper(MetaObject metaObject, Object object) {
+    super(metaObject, object);
+  }
+}
\ No newline at end of file
Index: ibatis-3-core/src/test/java/domain/misc/CustomBeanWrapperFactory.java
===================================================================
--- ibatis-3-core/src/test/java/domain/misc/CustomBeanWrapperFactory.java	(revision 0)
+++ ibatis-3-core/src/test/java/domain/misc/CustomBeanWrapperFactory.java	(revision 0)
@@ -0,0 +1,21 @@
+package domain.misc;
+
+import domain.jpetstore.Product;
+
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.wrapper.ObjectWrapper;
+import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
+
+public class CustomBeanWrapperFactory implements ObjectWrapperFactory {
+  public boolean hasWrapperFor(Object object) {
+    if (object instanceof Product) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+  
+  public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
+    return new CustomBeanWrapper(metaObject, object);
+  }
+}
\ No newline at end of file
Index: ibatis-3-core/src/test/java/org/apache/ibatis/reflection/MetaObjectTest.java
===================================================================
--- ibatis-3-core/src/test/java/org/apache/ibatis/reflection/MetaObjectTest.java	(revision 894875)
+++ ibatis-3-core/src/test/java/org/apache/ibatis/reflection/MetaObjectTest.java	(working copy)
@@ -2,6 +2,11 @@
 
 import domain.jpetstore.Product;
 import domain.misc.RichType;
+
+import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
+import domain.misc.CustomBeanWrapper;
+import domain.misc.CustomBeanWrapperFactory;
+
 import static org.junit.Assert.*;
 import org.junit.Test;
 
@@ -216,6 +221,26 @@
     assertEquals("Clinton", name.get("first"));
     assertEquals("1 Some Street", address.get("street"));
   }
+  
+  @Test
+  public void shouldNotUseObjectWrapperFactoryByDefault() {
+    MetaObject meta = MetaObject.forObject(new Product());
+    assertTrue(!meta.getObjectWrapper().getClass().equals(CustomBeanWrapper.class));
+  }
+  
+  @Test
+  public void shouldUseObjectWrapperFactoryWhenSet() {
+    ObjectWrapperFactory old = MetaObject.getObjectWrapperFactory();
+    MetaObject.setObjectWrapperFactory(new CustomBeanWrapperFactory());
+    
+    MetaObject meta = MetaObject.forObject(new Product());
+    
+    assertTrue(meta.getObjectWrapper().getClass().equals(CustomBeanWrapper.class));
+    
+    // Make sure the old default factory is in place and still works
+    MetaObject.setObjectWrapperFactory(old);
+    meta = MetaObject.forObject(new Product());
+    assertTrue(!meta.getObjectWrapper().getClass().equals(CustomBeanWrapper.class));
+  }
 
-
 }
Index: ibatis-3-core/src/main/java/org/apache/ibatis/session/Configuration.java
===================================================================
--- ibatis-3-core/src/main/java/org/apache/ibatis/session/Configuration.java	(revision 894875)
+++ ibatis-3-core/src/main/java/org/apache/ibatis/session/Configuration.java	(working copy)
@@ -24,6 +24,8 @@
 import org.apache.ibatis.plugin.InterceptorChain;
 import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
 import org.apache.ibatis.reflection.factory.ObjectFactory;
+import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
+import org.apache.ibatis.reflection.MetaObject;
 import org.apache.ibatis.transaction.Transaction;
 import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
 import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
@@ -173,7 +175,15 @@
   public void setObjectFactory(ObjectFactory objectFactory) {
     this.objectFactory = objectFactory;
   }
+  
+  public ObjectWrapperFactory getObjectWrapperFactory() {
+    return MetaObject.getObjectWrapperFactory();
+  }
 
+  public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
+    MetaObject.setObjectWrapperFactory(objectWrapperFactory);
+  }
+
   public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
     ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
     parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
Index: ibatis-3-core/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java
===================================================================
--- ibatis-3-core/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java	(revision 894875)
+++ ibatis-3-core/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java	(working copy)
@@ -11,6 +11,7 @@
 import org.apache.ibatis.plugin.Interceptor;
 import org.apache.ibatis.reflection.MetaClass;
 import org.apache.ibatis.reflection.factory.ObjectFactory;
+import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
 import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.session.ExecutorType;
 import org.apache.ibatis.transaction.TransactionFactory;
@@ -59,6 +60,7 @@
       typeAliasesElement(root.evalNode("typeAliases"));
       pluginElement(root.evalNode("plugins"));
       objectFactoryElement(root.evalNode("objectFactory"));
+      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
       propertiesElement(root.evalNode("properties"));
       settingsElement(root.evalNode("settings"));
       environmentsElement(root.evalNode("environments"));
@@ -110,6 +112,14 @@
       configuration.setObjectFactory(factory);
     }
   }
+  
+  private void objectWrapperFactoryElement(XNode context) throws Exception {
+    if (context != null) {
+      String type = context.getStringAttribute("type");
+      ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
+      configuration.setObjectWrapperFactory(factory);
+    }
+  }
 
   private void propertiesElement(XNode context) throws Exception {
     if (context != null) {
Index: ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/ObjectWrapperFactory.java
===================================================================
--- ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/ObjectWrapperFactory.java	(revision 0)
+++ ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/ObjectWrapperFactory.java	(revision 0)
@@ -0,0 +1,11 @@
+package org.apache.ibatis.reflection.wrapper;
+
+import org.apache.ibatis.reflection.MetaObject;
+
+public interface ObjectWrapperFactory {
+
+  boolean hasWrapperFor(Object object);
+  
+  ObjectWrapper getWrapperFor(MetaObject metaObject, Object object);
+  
+}
\ No newline at end of file
Index: ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/DefaultObjectWrapperFactory.java
===================================================================
--- ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/DefaultObjectWrapperFactory.java	(revision 0)
+++ ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/DefaultObjectWrapperFactory.java	(revision 0)
@@ -0,0 +1,15 @@
+package org.apache.ibatis.reflection.wrapper;
+
+import org.apache.ibatis.reflection.MetaObject;
+
+public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {
+
+  public boolean hasWrapperFor(Object object) {
+    return false;
+  }
+  
+  public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
+    throw new RuntimeException("The DefaultObjectWrapperFactory should never be called to provide an ObjectWrapper.");
+  }
+  
+}
\ No newline at end of file
Index: ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaObject.java
===================================================================
--- ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaObject.java	(revision 894875)
+++ ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaObject.java	(working copy)
@@ -6,6 +6,8 @@
 import org.apache.ibatis.reflection.wrapper.BeanWrapper;
 import org.apache.ibatis.reflection.wrapper.MapWrapper;
 import org.apache.ibatis.reflection.wrapper.ObjectWrapper;
+import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
+import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
 
 import java.util.Map;
 
@@ -13,6 +15,8 @@
 
   private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
   public static final MetaObject NULL_META_OBJECT = new MetaObject(NullObject.class, DEFAULT_OBJECT_FACTORY);
+  
+  private static ObjectWrapperFactory objectWrapperFactory;
 
   private Object originalObject;
   private ObjectWrapper objectWrapper;
@@ -21,14 +25,33 @@
   private MetaObject(Object object, ObjectFactory objectFactory) {
     this.originalObject = object;
     this.objectFactory = objectFactory;
+    
+    ObjectWrapperFactory factory = getObjectWrapperFactory();
+    
     if (object instanceof ObjectWrapper) {
       this.objectWrapper = (ObjectWrapper) object;
+    } else if (factory != null && factory.hasWrapperFor(object)) {
+      this.objectWrapper = factory.getWrapperFor(this, object);
     } else if (object instanceof Map) {
       this.objectWrapper = new MapWrapper(this, (Map) object);
     } else {
       this.objectWrapper = new BeanWrapper(this, object);
     }
   }
+  
+  public static ObjectWrapperFactory getObjectWrapperFactory() {
+    if (objectWrapperFactory == null) {
+      objectWrapperFactory = new DefaultObjectWrapperFactory();
+    }
+    
+    return objectWrapperFactory;
+  }
+  
+  public static void setObjectWrapperFactory(ObjectWrapperFactory wrapperFactory) {
+    if (wrapperFactory != null) {
+      objectWrapperFactory = wrapperFactory;
+    }
+  }
 
   public static MetaObject forObject(Object object, ObjectFactory objectFactory) {
     if (object == null) {
---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscr...@ibatis.apache.org
For additional commands, e-mail: user-java-h...@ibatis.apache.org

Reply via email to