1 /*
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 2002 The Apache Software Foundation. All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
30 *
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
53 */
54
55 package net.sf.cglib.core;
56
57 import java.lang.reflect.Method;
58 import org.objectweb.asm.ClassVisitor;
59 import org.objectweb.asm.Label;
60 import org.objectweb.asm.Type;
61
62 /***
63 * Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
64 * Code for <code>equals</code> and <code>hashCode</code> methods follow the
65 * the rules laid out in <i>Effective Java</i> by Joshua Bloch.
66 * <p>
67 * To generate a <code>KeyFactory</code>, you need to supply an interface which
68 * describes the structure of the key. The interface should have a
69 * single method named <code>newInstance</code>, which returns an
70 * <code>Object</code>. The arguments array can be
71 * <i>anything</i>--Objects, primitive values, or single or
72 * multi-dimension arrays of either. For example:
73 * <p><pre>
74 * private interface IntStringKey {
75 * public Object newInstance(int i, String s);
76 * }
77 * </pre><p>
78 * Once you have made a <code>KeyFactory</code>, you generate a new key by calling
79 * the <code>newInstance</code> method defined by your interface.
80 * <p><pre>
81 * IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
82 * Object key1 = factory.newInstance(4, "Hello");
83 * Object key2 = factory.newInstance(4, "World");
84 * </pre><p>
85 * <b>Note:</b>
86 * <code>hashCode</code> equality between two keys <code>key1</code> and <code>key2</code> is only guaranteed if
87 * <code>key1.equals(key2)</code> <i>and</i> the keys were produced by the same factory.
88 *
89 * @version $Id: KeyFactory.java,v 1.18 2003/11/06 05:10:52 herbyderby Exp $
90 */
91 abstract public class KeyFactory {
92 private static final Signature GET_NAME =
93 TypeUtils.parseSignature("String getName()");
94 private static final Signature GET_CLASS =
95 TypeUtils.parseSignature("Class getClass()");
96 private static final Signature HASH_CODE =
97 TypeUtils.parseSignature("int hashCode()");
98 private static final Signature EQUALS =
99 TypeUtils.parseSignature("boolean equals(Object)");
100 private static final Signature TO_STRING =
101 TypeUtils.parseSignature("String toString()");
102 private static final Signature APPEND_STRING =
103 TypeUtils.parseSignature("StringBuffer append(String)");
104 private static final Type KEY_FACTORY =
105 TypeUtils.parseType("net.sf.cglib.core.KeyFactory");
106
107 //generated numbers:
108 private final static int PRIMES[] = {
109 11, 73, 179, 331,
110 521, 787, 1213, 1823,
111 2609, 3691, 5189, 7247,
112 10037, 13931, 19289, 26627,
113 36683, 50441, 69403, 95401,
114 131129, 180179, 247501, 340057,
115 467063, 641371, 880603, 1209107,
116 1660097, 2279161, 3129011, 4295723,
117 5897291, 8095873, 11114263, 15257791,
118 20946017, 28754629, 39474179, 54189869,
119 74391461, 102123817, 140194277, 192456917,
120 264202273, 362693231, 497900099, 683510293,
121 938313161, 1288102441, 1768288259 };
122
123
124 public static final Customizer CLASS_BY_NAME = new Customizer() {
125 public void customize(CodeEmitter e, Type type) {
126 if (type.equals(Constants.TYPE_CLASS)) {
127 e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
128 }
129 }
130 };
131
132 public static final Customizer OBJECT_BY_CLASS = new Customizer() {
133 public void customize(CodeEmitter e, Type type) {
134 e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS);
135 }
136 };
137
138 protected KeyFactory() {
139 }
140
141 public static KeyFactory create(Class keyInterface) {
142 return create(keyInterface, null);
143 }
144
145 public static KeyFactory create(Class keyInterface, Customizer customizer) {
146 Generator gen = new Generator();
147 gen.setInterface(keyInterface);
148 gen.setCustomizer(customizer);
149 return gen.create();
150 }
151
152 public static class Generator extends AbstractClassGenerator {
153 private static final Source SOURCE = new Source(KeyFactory.class.getName());
154 private Class keyInterface;
155 private Customizer customizer;
156 private int constant;
157 private int multiplier;
158
159 public Generator() {
160 super(SOURCE);
161 }
162
163 protected ClassLoader getDefaultClassLoader() {
164 return keyInterface.getClassLoader();
165 }
166
167 public void setCustomizer(Customizer customizer) {
168 this.customizer = customizer;
169 }
170
171 public void setInterface(Class keyInterface) {
172 this.keyInterface = keyInterface;
173 }
174
175 public KeyFactory create() {
176 setNamePrefix(keyInterface.getName());
177 return (KeyFactory)super.create(keyInterface.getName());
178 }
179
180 public void setHashConstant(int constant) {
181 this.constant = constant;
182 }
183
184 public void setHashMultiplier(int multiplier) {
185 this.multiplier = multiplier;
186 }
187
188 protected Object firstInstance(Class type) {
189 return ReflectUtils.newInstance(type);
190 }
191
192 protected Object nextInstance(Object instance) {
193 return instance;
194 }
195
196 public void generateClass(ClassVisitor v) {
197 ClassEmitter ce = new ClassEmitter(v);
198
199 Method newInstance = ReflectUtils.findNewInstance(keyInterface);
200 if (!newInstance.getReturnType().equals(Object.class)) {
201 throw new IllegalArgumentException("newInstance method must return Object");
202 }
203
204 Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
205 ce.begin_class(Constants.ACC_PUBLIC,
206 getClassName(),
207 KEY_FACTORY,
208 new Type[]{ Type.getType(keyInterface) },
209 Constants.SOURCE_FILE);
210 EmitUtils.null_constructor(ce);
211 EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
212
213 int seed = 0;
214 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
215 TypeUtils.parseConstructor(parameterTypes),
216 null,
217 null);
218 e.load_this();
219 e.super_invoke_constructor();
220 e.load_this();
221 for (int i = 0; i < parameterTypes.length; i++) {
222 seed += parameterTypes[i].hashCode();
223 ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
224 getFieldName(i),
225 parameterTypes[i],
226 null,
227 null);
228 e.dup();
229 e.load_arg(i);
230 e.putfield(getFieldName(i));
231 }
232 e.return_value();
233 e.end_method();
234
235 // hash code
236 e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null, null);
237 int hc = (constant != 0) ? constant : PRIMES[(int)(Math.abs(seed) % PRIMES.length)];
238 int hm = (multiplier != 0) ? multiplier : PRIMES[(int)(Math.abs(seed * 13) % PRIMES.length)];
239 e.push(hc);
240 for (int i = 0; i < parameterTypes.length; i++) {
241 e.load_this();
242 e.getfield(getFieldName(i));
243 EmitUtils.hash_code(e, parameterTypes[i], hm, customizer);
244 }
245 e.return_value();
246 e.end_method();
247
248 // equals
249 e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null, null);
250 Label fail = e.make_label();
251 e.load_arg(0);
252 e.instance_of_this();
253 e.if_jump(e.EQ, fail);
254 for (int i = 0; i < parameterTypes.length; i++) {
255 e.load_this();
256 e.getfield(getFieldName(i));
257 e.load_arg(0);
258 e.checkcast_this();
259 e.getfield(getFieldName(i));
260 EmitUtils.not_equals(e, parameterTypes[i], fail, customizer);
261 }
262 e.push(1);
263 e.return_value();
264 e.mark(fail);
265 e.push(0);
266 e.return_value();
267 e.end_method();
268
269 // toString
270 e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null, null);
271 e.new_instance(Constants.TYPE_STRING_BUFFER);
272 e.dup();
273 e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
274 for (int i = 0; i < parameterTypes.length; i++) {
275 if (i > 0) {
276 e.push(", ");
277 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
278 }
279 e.load_this();
280 e.getfield(getFieldName(i));
281 EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizer);
282 }
283 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
284 e.return_value();
285 e.end_method();
286
287 ce.end_class();
288 }
289
290 private String getFieldName(int arg) {
291 return "FIELD_" + arg;
292 }
293 }
294 }
This page was automatically generated by Maven