View Javadoc
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