/* * Copyright 2007 The Apache Software Foundation. * * 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. */ package net.sf.beanlib.spi; import net.sf.beanlib.PropertyInfo; /** * Custom Bean Transformer SPI. * <p> * Used to provide custom transformation that takes precedence over the default transformation. * <h2>Quick Start</h2> For example, by default when BeanReplicator is replicating the content of a JavaBean, it would * try to instantiate the target class via the no-arg constructor. If the no-arg constructor is not defined (such as in * the Point class below), it would cause a NoSuchMethodException to be thrown: * * <pre> * <blockquote>public class Point { * private final int x, y; * * // missing no-arg constructor * public Point(int x, int y) { * this.x = x; * this.y = y; * } * public int getX() { return x; } * public int getY() { return y; } * } * * public class Bean { * private Point point; * public Point getPoint() { return point; } * public void setPoint(Point point) { this.point = point; } * } * * ... * // Initialize a bean * Bean from = new Bean(); * from.setPoint(new Point(1,2)); * * // Tries to replicate the bean using the default implementation * BeanReplicator replicator = new BeanReplicator(); * // Will cause NoSuchMethodException, as Point does not have a no-arg constructor * Bean to = replicator.replicateBean(from); * </blockquote> * </pre> * * One way to get around this problem is to define a custom transformer and the respective factory: * * <pre> * <blockquote>public class MyBeanTransformer implements CustomBeanTransformerSpi { * public boolean isTransformable(Object from, Class toClass, PropertyInfo propertyInfo) { * return toClass == Point.class; * } * * public <T> T transform(Object in, Class<T> toClass, PropertyInfo propertyInfo) { * Point from = (Point)in; * // Note the framework takes care of the issue of object identity, * // so we don't need to here. * return (T)new Point(from.getX(), from.getY()); * } * } * * public class MyBeanTransformerFactory implements CustomBeanTransformerSpi.Factory { * public CustomBeanTransformerSpi newCustomBeanTransformer(BeanTransformerSpi beanTransformer) { * return new MyBeanTransformer(); * } * } * * ... * // Initialize a bean * Bean from = new Bean(); * from.setPoint(new Point(1,2)); * * // Partially overrides the default transformer behavior * BeanTransformerSpi transformer = new BeanTransformer(new MyBeanTransformerFactory()); * BeanReplicator replicator = new BeanReplicator(transformer); * * // Replicates the bean * Bean to = replicator.replicateBean(from); // now works! * </blockquote> * </pre> * * <h2>Customizing HibernateBeanReplicator</h2> Customizing the behavior of HibernateBeanReplicator is basically * identical to that of BeanReplicator as decribed above. For example, assuming the same MyBeanTransformerFactory * defined above is used, * * <pre> * <blockquote>// Partially overrides the default Hibernate bean transformer's behavior * HibernateBeanReplicator replicator = new Hibernate3BeanReplicator(); * replicator.initCustomTransformerFactory(new MyBeanTransformerFactory()); * replicator.copy(...); * </blockquote> * </pre> * * @see BeanTransformerSpi * @author Joe D. Velopar */ public interface CustomBeanTransformerSpi extends Transformable { /** * Custom Bean Transformer Factory SPI. * * @author Joe D. Velopar */ public static interface Factory { /** * Returns a custom transformer. * * @param contextBeanTransformer the context bean transformer currently used to provide the default * transformation behavior. */ public CustomBeanTransformerSpi newCustomBeanTransformer(BeanTransformerSpi contextBeanTransformer); } /** * Returns true if the given object is to be transformed by this transformer; false otherwise. * * @param from source object * @param propertyInfo If null, it means the in object is a root level object. Otherwise, propertyInfo contains * information about the input object as a java bean property value to be transformed. * @param toClass target class */ public boolean isTransformable(Object from, Class<?> toClass, PropertyInfo propertyInfo); }