KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > cglib > core > KeyFactory


1 /*
2  * Copyright 2003,2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package net.sf.cglib.core;
18
19 import java.lang.reflect.Method JavaDoc;
20 import org.objectweb.asm.ClassVisitor;
21 import org.objectweb.asm.Label;
22 import org.objectweb.asm.Type;
23
24 /**
25  * Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
26  * Code for <code>equals</code> and <code>hashCode</code> methods follow the
27  * the rules laid out in <i>Effective Java</i> by Joshua Bloch.
28  * <p>
29  * To generate a <code>KeyFactory</code>, you need to supply an interface which
30  * describes the structure of the key. The interface should have a
31  * single method named <code>newInstance</code>, which returns an
32  * <code>Object</code>. The arguments array can be
33  * <i>anything</i>--Objects, primitive values, or single or
34  * multi-dimension arrays of either. For example:
35  * <p><pre>
36  * private interface IntStringKey {
37  * public Object newInstance(int i, String s);
38  * }
39  * </pre><p>
40  * Once you have made a <code>KeyFactory</code>, you generate a new key by calling
41  * the <code>newInstance</code> method defined by your interface.
42  * <p><pre>
43  * IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
44  * Object key1 = factory.newInstance(4, "Hello");
45  * Object key2 = factory.newInstance(4, "World");
46  * </pre><p>
47  * <b>Note:</b>
48  * <code>hashCode</code> equality between two keys <code>key1</code> and <code>key2</code> is only guaranteed if
49  * <code>key1.equals(key2)</code> <i>and</i> the keys were produced by the same factory.
50  *
51  * @version $Id: KeyFactory.java,v 1.26 2006/03/05 02:43:19 herbyderby Exp $
52  */

53 abstract public class KeyFactory {
54     private static final Signature GET_NAME =
55       TypeUtils.parseSignature("String getName()");
56     private static final Signature GET_CLASS =
57       TypeUtils.parseSignature("Class getClass()");
58     private static final Signature HASH_CODE =
59       TypeUtils.parseSignature("int hashCode()");
60     private static final Signature EQUALS =
61       TypeUtils.parseSignature("boolean equals(Object)");
62     private static final Signature TO_STRING =
63       TypeUtils.parseSignature("String toString()");
64     private static final Signature APPEND_STRING =
65       TypeUtils.parseSignature("StringBuffer append(String)");
66     private static final Type KEY_FACTORY =
67       TypeUtils.parseType("net.sf.cglib.core.KeyFactory");
68     
69     //generated numbers:
70
private final static int PRIMES[] = {
71                11, 73, 179, 331,
72               521, 787, 1213, 1823,
73              2609, 3691, 5189, 7247,
74             10037, 13931, 19289, 26627,
75             36683, 50441, 69403, 95401,
76            131129, 180179, 247501, 340057,
77            467063, 641371, 880603, 1209107,
78           1660097, 2279161, 3129011, 4295723,
79           5897291, 8095873, 11114263, 15257791,
80          20946017, 28754629, 39474179, 54189869,
81          74391461, 102123817, 140194277, 192456917,
82         264202273, 362693231, 497900099, 683510293,
83         938313161, 1288102441, 1768288259 };
84     
85
86     public static final Customizer CLASS_BY_NAME = new Customizer() {
87         public void customize(CodeEmitter e, Type type) {
88             if (type.equals(Constants.TYPE_CLASS)) {
89                 e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
90             }
91         }
92     };
93
94     public static final Customizer OBJECT_BY_CLASS = new Customizer() {
95         public void customize(CodeEmitter e, Type type) {
96             e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS);
97         }
98     };
99
100     protected KeyFactory() {
101     }
102
103     public static KeyFactory create(Class JavaDoc keyInterface) {
104         return create(keyInterface, null);
105     }
106
107     public static KeyFactory create(Class JavaDoc keyInterface, Customizer customizer) {
108         return create(keyInterface.getClassLoader(), keyInterface, customizer);
109     }
110
111     public static KeyFactory create(ClassLoader JavaDoc loader, Class JavaDoc keyInterface, Customizer customizer) {
112         Generator gen = new Generator();
113         gen.setInterface(keyInterface);
114         gen.setCustomizer(customizer);
115         gen.setClassLoader(loader);
116         return gen.create();
117     }
118
119     public static class Generator extends AbstractClassGenerator {
120         private static final Source SOURCE = new Source(KeyFactory.class.getName());
121         private Class JavaDoc keyInterface;
122         private Customizer customizer;
123         private int constant;
124         private int multiplier;
125
126         public Generator() {
127             super(SOURCE);
128         }
129
130         protected ClassLoader JavaDoc getDefaultClassLoader() {
131             return keyInterface.getClassLoader();
132         }
133
134         public void setCustomizer(Customizer customizer) {
135             this.customizer = customizer;
136         }
137
138         public void setInterface(Class JavaDoc keyInterface) {
139             this.keyInterface = keyInterface;
140         }
141
142         public KeyFactory create() {
143             setNamePrefix(keyInterface.getName());
144             return (KeyFactory)super.create(keyInterface.getName());
145         }
146
147         public void setHashConstant(int constant) {
148             this.constant = constant;
149         }
150
151         public void setHashMultiplier(int multiplier) {
152             this.multiplier = multiplier;
153         }
154
155         protected Object JavaDoc firstInstance(Class JavaDoc type) {
156             return ReflectUtils.newInstance(type);
157         }
158
159         protected Object JavaDoc nextInstance(Object JavaDoc instance) {
160             return instance;
161         }
162
163         public void generateClass(ClassVisitor v) {
164             ClassEmitter ce = new ClassEmitter(v);
165             
166             Method JavaDoc newInstance = ReflectUtils.findNewInstance(keyInterface);
167             if (!newInstance.getReturnType().equals(Object JavaDoc.class)) {
168                 throw new IllegalArgumentException JavaDoc("newInstance method must return Object");
169             }
170
171             Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
172             ce.begin_class(Constants.V1_2,
173                            Constants.ACC_PUBLIC,
174                            getClassName(),
175                            KEY_FACTORY,
176                            new Type[]{ Type.getType(keyInterface) },
177                            Constants.SOURCE_FILE);
178             EmitUtils.null_constructor(ce);
179             EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
180
181             int seed = 0;
182             CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
183                                             TypeUtils.parseConstructor(parameterTypes),
184                                             null);
185             e.load_this();
186             e.super_invoke_constructor();
187             e.load_this();
188             for (int i = 0; i < parameterTypes.length; i++) {
189                 seed += parameterTypes[i].hashCode();
190                 ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
191                                  getFieldName(i),
192                                  parameterTypes[i],
193                                  null);
194                 e.dup();
195                 e.load_arg(i);
196                 e.putfield(getFieldName(i));
197             }
198             e.return_value();
199             e.end_method();
200             
201             // hash code
202
e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null);
203             int hc = (constant != 0) ? constant : PRIMES[(int)(Math.abs(seed) % PRIMES.length)];
204             int hm = (multiplier != 0) ? multiplier : PRIMES[(int)(Math.abs(seed * 13) % PRIMES.length)];
205             e.push(hc);
206             for (int i = 0; i < parameterTypes.length; i++) {
207                 e.load_this();
208                 e.getfield(getFieldName(i));
209                 EmitUtils.hash_code(e, parameterTypes[i], hm, 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, customizer);
227             }
228             e.push(1);
229             e.return_value();
230             e.mark(fail);
231             e.push(0);
232             e.return_value();
233             e.end_method();
234
235             // toString
236
e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null);
237             e.new_instance(Constants.TYPE_STRING_BUFFER);
238             e.dup();
239             e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
240             for (int i = 0; i < parameterTypes.length; i++) {
241                 if (i > 0) {
242                     e.push(", ");
243                     e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
244                 }
245                 e.load_this();
246                 e.getfield(getFieldName(i));
247                 EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizer);
248             }
249             e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
250             e.return_value();
251             e.end_method();
252
253             ce.end_class();
254         }
255
256         private String JavaDoc getFieldName(int arg) {
257             return "FIELD_" + arg;
258         }
259     }
260 }
261
Popular Tags