001: // ============================================================================
002: // $Id: ConstructUnary.java,v 1.16 2006/05/08 02:23:26 davidahall Exp $
003: // Copyright (c) 2003-2005 David A. Hall
004: // ============================================================================
005: // The contents of this file are subject to the Common Development and
006: // Distribution License (CDDL), Version 1.0 (the License); you may not use this
007: // file except in compliance with the License. You should have received a copy
008: // of the the License along with this file: if not, a copy of the License is
009: // available from Sun Microsystems, Inc.
010: //
011: // http://www.sun.com/cddl/cddl.html
012: //
013: // From time to time, the license steward (initially Sun Microsystems, Inc.) may
014: // publish revised and/or new versions of the License. You may not use,
015: // distribute, or otherwise make this file available under subsequent versions
016: // of the License.
017: //
018: // Alternatively, the contents of this file may be used under the terms of the
019: // GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
020: // case the provisions of the LGPL are applicable instead of those above. If you
021: // wish to allow use of your version of this file only under the terms of the
022: // LGPL, and not to allow others to use your version of this file under the
023: // terms of the CDDL, indicate your decision by deleting the provisions above
024: // and replace them with the notice and other provisions required by the LGPL.
025: // If you do not delete the provisions above, a recipient may use your version
026: // of this file under the terms of either the CDDL or the LGPL.
027: //
028: // This library is distributed in the hope that it will be useful,
029: // but WITHOUT ANY WARRANTY; without even the implied warranty of
030: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
031: // ============================================================================
032:
033: package net.sf.jga.fn.property;
034:
035: import java.lang.reflect.Constructor;
036: import java.lang.reflect.InvocationTargetException;
037: import java.text.MessageFormat;
038: import net.sf.jga.fn.EvaluationException;
039: import net.sf.jga.fn.UnaryFunctor;
040:
041: /**
042: * Unary Functor that constructs an object of the given class via a
043: * one-argument constructor.
044: * <p>
045: * Copyright © 2003-2005 David A. Hall
046: *
047: * @author <a href="mailto:davidahall@users.sourceforge.net">David A. Hall</a>
048: **/
049:
050: public class ConstructUnary<T, R> extends UnaryFunctor<T, R> {
051:
052: static final long serialVersionUID = -6046849006655934333L;
053:
054: // the type of the object built by the constructor
055: private Class<R> _objclass;
056:
057: // the argument type for the constructor
058: private Class<T> _argclass;
059:
060: // the constructor being invoked
061: private transient Constructor<R> _ctor;
062:
063: /**
064: * Builds a functor that will build an object of class
065: * <code>ctorclass</code>, given an argument of class <code>argclass</code>.
066: * The classes passed to the constructor must be assignable to the generic
067: * arguments (when generics are in use):
068: * <code>
069: * ConstructUnary<String,Integer> ctor =
070: * new ConstructUnary<String,Integer>(String.class,Integer.class);
071: * </code>
072: * @throws IllegalArgumentException if either argument is omitted, or if the
073: * constructor cannot be found.
074: */
075:
076: public ConstructUnary(Class<T> argclass, Class<R> ctorclass) {
077: if (argclass == null) {
078: String msg = "Argument Class must be specified";
079: throw new IllegalArgumentException(msg);
080: }
081:
082: if (ctorclass == null) {
083: String msg = "Class to be constructed must be specified";
084: throw new IllegalArgumentException(msg);
085: }
086:
087: try {
088: _argclass = argclass;
089: _objclass = ctorclass;
090: _ctor = getConstructor();
091: } catch (NoSuchMethodException x) {
092: String msg = "No constructor found for class {0} that takes an argument of class {1}";
093: Object args[] = new Object[] { ctorclass, argclass };
094:
095: IllegalArgumentException x1 = new IllegalArgumentException(
096: MessageFormat.format(msg, args));
097: x1.initCause(x);
098: throw x1;
099: }
100: }
101:
102: /**
103: * Lazily loads the constructor
104: */
105: public synchronized Constructor<R> getConstructor()
106: throws NoSuchMethodException {
107: if (_ctor == null)
108: _ctor = _objclass.getConstructor(new Class[] { _argclass });
109:
110: return _ctor;
111: }
112:
113: // UnaryFunctor interface
114:
115: /**
116: * Builds an object via a one-arg constructor, passing the given value.
117: * <p>
118: * @return the object built by the constructor
119: */
120: public R fn(T arg) {
121:
122: try {
123: R val = (R) getConstructor().newInstance(
124: new Object[] { arg });
125: return val;
126: } catch (NoSuchMethodException x) {
127: String msg = "No constructor for class {0} that takes an argument of type {1}";
128: Object[] args = new Object[] { _objclass.getName(),
129: _argclass.getName() };
130: throw new EvaluationException(MessageFormat.format(msg,
131: args), x);
132: } catch (InstantiationException x) {
133: String msg = "class {0} is abstract: cannot be constructed";
134: Object[] args = new Object[] { _objclass.getName() };
135: throw new EvaluationException(MessageFormat.format(msg,
136: args), x);
137: } catch (IllegalArgumentException x) {
138: String msg = "class {0} ctor({1}) cannot be called with {2}";
139: Object[] args = new Object[] { _objclass.getName(),
140: _argclass.getName(), arg };
141: throw new EvaluationException(MessageFormat.format(msg,
142: args), x);
143: } catch (IllegalAccessException x) {
144: String msg = "class {0} ctor({1}) is not accessible";
145: Object[] args = new Object[] { _objclass.getName(),
146: _argclass.getName() };
147: throw new EvaluationException(MessageFormat.format(msg,
148: args), x);
149: } catch (InvocationTargetException x) {
150: String msg = "class {0} ctor({1}) failed: "
151: + x.getMessage();
152: Object[] args = new Object[] { _objclass.getName(),
153: _argclass.getName() };
154: throw new EvaluationException(MessageFormat.format(msg,
155: args), x);
156: }
157: }
158:
159: /**
160: * Calls the Visitor's <code>visit(ConstructUnary)</code> method, if it
161: * implements the nested Visitor interface.
162: */
163: public void accept(net.sf.jga.fn.Visitor v) {
164: if (v instanceof ConstructUnary.Visitor)
165: ((ConstructUnary.Visitor) v).visit(this );
166: else
167: v.visit(this );
168: }
169:
170: // Object overrides
171:
172: public String toString() {
173: return "new " + _objclass.getName() + "(["
174: + _argclass.getName() + "])";
175: }
176:
177: // Acyclic Visitor
178:
179: /**
180: * Interface for classes that may interpret a <b>ConstructUnary</b>
181: * predicate.
182: */
183: public interface Visitor extends net.sf.jga.fn.Visitor {
184: public void visit(ConstructUnary host);
185: }
186: }
|