/* * Copyright 2006 - 2007 the original author or authors. * * 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 org.springmodules.xt.model.generator.factory; import java.lang.reflect.Proxy; import org.springmodules.xt.model.generator.DynamicGenerator; /** * <p> * Dynamically generate factory objects.<br> * For dynamically generating a factory object you simply have to provide * an interface with a number of setter methods, representing constructor arguments * and properties to use for constructing the <i>product object</i>, and a factory method * returning the class (or superclass) of that product object. * </p> * <p> * More specifically, the factory interface supports the following methods, that must obey the following rules: * <ul> * <li><b>Setter</b> methods must be annotated either with: * <ul> * <li>The {@link org.springmodules.xt.model.generator.annotation.ConstructorArg} annotation if they are constructor arguments * (plus the optional {@link org.springmodules.xt.model.generator.annotation.ConstructorArgType} annotation).</li> * <li>The {@link org.springmodules.xt.model.generator.annotation.Property} annotation if they are properties to be set.</li> * <li>The {@link org.springmodules.xt.model.generator.annotation.Value} annotation if they are just simple values to use later for other purposes.</li> * </ul> * </li> * <li>The <b>factory</b> method must be annotated with the {@link org.springmodules.xt.model.generator.annotation.FactoryMethod} * annotation.</li> * <li>Moreover, there can be <b>getter</b> methods corresponding to the setter methods above.</li> * </ul> * Any other method, if called, will throw an exception. * </p> * <p> * Once generated, the factory can be used by calling the setter methods, for initializing object constructor arguments and properties, * and finally the factory method. * </p> * <p> * Please <b>note</b> that this generator generates a new factory object for every call to its {@link #generate()} method, and the factory * generates a new product object for every call to its factory method. * </p> * <p> * <b>Restrictions</b>: The only restriction is that the getter methods of your factory cannot return primitive values; so, you * have to use wrapper objects instead when you need to return a primitive type. * </p> * <p>This class is <b>thread-safe</b>.</p> * * @param F The type of the dynamically generated factory object. * @param P The type of the product object created by the factory. * * @author Sergio Bossa */ public class DynamicFactoryGenerator<F, P> implements DynamicGenerator<F> { private Class<F> factoryClass; private Class<P> productClass; /** * Constructor. * @param factoryClass The class of the dynamically generated factory object: it must be an interface. * @param productClass The class of the object created by the factory: the type returned by the factory method in the * factory object must be the same, or a super-type, of this product class. */ public DynamicFactoryGenerator(Class<F> factoryClass, Class<P> productClass) { if (! factoryClass.isInterface()) { throw new IllegalArgumentException("The factory class must be an interface!"); } else { this.factoryClass = factoryClass; this.productClass = productClass; } } /** * Generate a new factory. */ public F generate() { FactoryGeneratorInterceptor interceptor = new FactoryGeneratorInterceptor(this.productClass); F factory = (F) Proxy.newProxyInstance(this.factoryClass.getClassLoader(), new Class[]{this.factoryClass}, interceptor); return factory; } }