001: /*
002: * Copyright 2003,2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package net.sf.cglib.core;
018:
019: import java.lang.reflect.Method;
020: import org.objectweb.asm.ClassVisitor;
021: import org.objectweb.asm.Label;
022: import org.objectweb.asm.Type;
023:
024: /**
025: * Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
026: * Code for <code>equals</code> and <code>hashCode</code> methods follow the
027: * the rules laid out in <i>Effective Java</i> by Joshua Bloch.
028: * <p>
029: * To generate a <code>KeyFactory</code>, you need to supply an interface which
030: * describes the structure of the key. The interface should have a
031: * single method named <code>newInstance</code>, which returns an
032: * <code>Object</code>. The arguments array can be
033: * <i>anything</i>--Objects, primitive values, or single or
034: * multi-dimension arrays of either. For example:
035: * <p><pre>
036: * private interface IntStringKey {
037: * public Object newInstance(int i, String s);
038: * }
039: * </pre><p>
040: * Once you have made a <code>KeyFactory</code>, you generate a new key by calling
041: * the <code>newInstance</code> method defined by your interface.
042: * <p><pre>
043: * IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
044: * Object key1 = factory.newInstance(4, "Hello");
045: * Object key2 = factory.newInstance(4, "World");
046: * </pre><p>
047: * <b>Note:</b>
048: * <code>hashCode</code> equality between two keys <code>key1</code> and <code>key2</code> is only guaranteed if
049: * <code>key1.equals(key2)</code> <i>and</i> the keys were produced by the same factory.
050: *
051: * @version $Id: KeyFactory.java,v 1.26 2006/03/05 02:43:19 herbyderby Exp $
052: */
053: abstract public class KeyFactory {
054: private static final Signature GET_NAME = TypeUtils
055: .parseSignature("String getName()");
056: private static final Signature GET_CLASS = TypeUtils
057: .parseSignature("Class getClass()");
058: private static final Signature HASH_CODE = TypeUtils
059: .parseSignature("int hashCode()");
060: private static final Signature EQUALS = TypeUtils
061: .parseSignature("boolean equals(Object)");
062: private static final Signature TO_STRING = TypeUtils
063: .parseSignature("String toString()");
064: private static final Signature APPEND_STRING = TypeUtils
065: .parseSignature("StringBuffer append(String)");
066: private static final Type KEY_FACTORY = TypeUtils
067: .parseType("net.sf.cglib.core.KeyFactory");
068:
069: //generated numbers:
070: private final static int PRIMES[] = { 11, 73, 179, 331, 521, 787,
071: 1213, 1823, 2609, 3691, 5189, 7247, 10037, 13931, 19289,
072: 26627, 36683, 50441, 69403, 95401, 131129, 180179, 247501,
073: 340057, 467063, 641371, 880603, 1209107, 1660097, 2279161,
074: 3129011, 4295723, 5897291, 8095873, 11114263, 15257791,
075: 20946017, 28754629, 39474179, 54189869, 74391461,
076: 102123817, 140194277, 192456917, 264202273, 362693231,
077: 497900099, 683510293, 938313161, 1288102441, 1768288259 };
078:
079: public static final Customizer CLASS_BY_NAME = new Customizer() {
080: public void customize(CodeEmitter e, Type type) {
081: if (type.equals(Constants.TYPE_CLASS)) {
082: e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
083: }
084: }
085: };
086:
087: public static final Customizer OBJECT_BY_CLASS = new Customizer() {
088: public void customize(CodeEmitter e, Type type) {
089: e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS);
090: }
091: };
092:
093: protected KeyFactory() {
094: }
095:
096: public static KeyFactory create(Class keyInterface) {
097: return create(keyInterface, null);
098: }
099:
100: public static KeyFactory create(Class keyInterface,
101: Customizer customizer) {
102: return create(keyInterface.getClassLoader(), keyInterface,
103: customizer);
104: }
105:
106: public static KeyFactory create(ClassLoader loader,
107: Class keyInterface, Customizer customizer) {
108: Generator gen = new Generator();
109: gen.setInterface(keyInterface);
110: gen.setCustomizer(customizer);
111: gen.setClassLoader(loader);
112: return gen.create();
113: }
114:
115: public static class Generator extends AbstractClassGenerator {
116: private static final Source SOURCE = new Source(
117: KeyFactory.class.getName());
118: private Class keyInterface;
119: private Customizer customizer;
120: private int constant;
121: private int multiplier;
122:
123: public Generator() {
124: super (SOURCE);
125: }
126:
127: protected ClassLoader getDefaultClassLoader() {
128: return keyInterface.getClassLoader();
129: }
130:
131: public void setCustomizer(Customizer customizer) {
132: this .customizer = customizer;
133: }
134:
135: public void setInterface(Class keyInterface) {
136: this .keyInterface = keyInterface;
137: }
138:
139: public KeyFactory create() {
140: setNamePrefix(keyInterface.getName());
141: return (KeyFactory) super .create(keyInterface.getName());
142: }
143:
144: public void setHashConstant(int constant) {
145: this .constant = constant;
146: }
147:
148: public void setHashMultiplier(int multiplier) {
149: this .multiplier = multiplier;
150: }
151:
152: protected Object firstInstance(Class type) {
153: return ReflectUtils.newInstance(type);
154: }
155:
156: protected Object nextInstance(Object instance) {
157: return instance;
158: }
159:
160: public void generateClass(ClassVisitor v) {
161: ClassEmitter ce = new ClassEmitter(v);
162:
163: Method newInstance = ReflectUtils
164: .findNewInstance(keyInterface);
165: if (!newInstance.getReturnType().equals(Object.class)) {
166: throw new IllegalArgumentException(
167: "newInstance method must return Object");
168: }
169:
170: Type[] parameterTypes = TypeUtils.getTypes(newInstance
171: .getParameterTypes());
172: ce.begin_class(Constants.V1_2, Constants.ACC_PUBLIC,
173: getClassName(), KEY_FACTORY, new Type[] { Type
174: .getType(keyInterface) },
175: Constants.SOURCE_FILE);
176: EmitUtils.null_constructor(ce);
177: EmitUtils.factory_method(ce, ReflectUtils
178: .getSignature(newInstance));
179:
180: int seed = 0;
181: CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
182: TypeUtils.parseConstructor(parameterTypes), null);
183: e.load_this ();
184: e.super _invoke_constructor();
185: e.load_this ();
186: for (int i = 0; i < parameterTypes.length; i++) {
187: seed += parameterTypes[i].hashCode();
188: ce.declare_field(Constants.ACC_PRIVATE
189: | Constants.ACC_FINAL, getFieldName(i),
190: parameterTypes[i], null);
191: e.dup();
192: e.load_arg(i);
193: e.putfield(getFieldName(i));
194: }
195: e.return_value();
196: e.end_method();
197:
198: // hash code
199: e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null);
200: int hc = (constant != 0) ? constant : PRIMES[(int) (Math
201: .abs(seed) % PRIMES.length)];
202: int hm = (multiplier != 0) ? multiplier
203: : PRIMES[(int) (Math.abs(seed * 13) % PRIMES.length)];
204: e.push(hc);
205: for (int i = 0; i < parameterTypes.length; i++) {
206: e.load_this ();
207: e.getfield(getFieldName(i));
208: EmitUtils.hash_code(e, parameterTypes[i], hm,
209: customizer);
210: }
211: e.return_value();
212: e.end_method();
213:
214: // equals
215: e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null);
216: Label fail = e.make_label();
217: e.load_arg(0);
218: e.instance_of_this ();
219: e.if_jump(e.EQ, fail);
220: for (int i = 0; i < parameterTypes.length; i++) {
221: e.load_this ();
222: e.getfield(getFieldName(i));
223: e.load_arg(0);
224: e.checkcast_this ();
225: e.getfield(getFieldName(i));
226: EmitUtils.not_equals(e, parameterTypes[i], fail,
227: customizer);
228: }
229: e.push(1);
230: e.return_value();
231: e.mark(fail);
232: e.push(0);
233: e.return_value();
234: e.end_method();
235:
236: // toString
237: e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null);
238: e.new_instance(Constants.TYPE_STRING_BUFFER);
239: e.dup();
240: e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
241: for (int i = 0; i < parameterTypes.length; i++) {
242: if (i > 0) {
243: e.push(", ");
244: e.invoke_virtual(Constants.TYPE_STRING_BUFFER,
245: APPEND_STRING);
246: }
247: e.load_this ();
248: e.getfield(getFieldName(i));
249: EmitUtils.append_string(e, parameterTypes[i],
250: EmitUtils.DEFAULT_DELIMITERS, customizer);
251: }
252: e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
253: e.return_value();
254: e.end_method();
255:
256: ce.end_class();
257: }
258:
259: private String getFieldName(int arg) {
260: return "FIELD_" + arg;
261: }
262: }
263: }
|