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 * https://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 017package org.springframework.cglib.core; 018 019import java.lang.reflect.Method; 020import java.security.ProtectionDomain; 021import java.util.Collections; 022import java.util.List; 023 024import org.springframework.asm.ClassVisitor; 025import org.springframework.asm.Label; 026import org.springframework.asm.Type; 027import org.springframework.cglib.core.internal.CustomizerRegistry; 028 029/** 030 * Generates classes to handle multi-valued keys, for use in things such as Maps and Sets. 031 * Code for <code>equals</code> and <code>hashCode</code> methods follow the 032 * the rules laid out in <i>Effective Java</i> by Joshua Bloch. 033 * <p> 034 * To generate a <code>KeyFactory</code>, you need to supply an interface which 035 * describes the structure of the key. The interface should have a 036 * single method named <code>newInstance</code>, which returns an 037 * <code>Object</code>. The arguments array can be 038 * <i>anything</i>--Objects, primitive values, or single or 039 * multi-dimension arrays of either. For example: 040 * <p><pre> 041 * private interface IntStringKey { 042 * public Object newInstance(int i, String s); 043 * } 044 * </pre><p> 045 * Once you have made a <code>KeyFactory</code>, you generate a new key by calling 046 * the <code>newInstance</code> method defined by your interface. 047 * <p><pre> 048 * IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class); 049 * Object key1 = factory.newInstance(4, "Hello"); 050 * Object key2 = factory.newInstance(4, "World"); 051 * </pre><p> 052 * <b>Note:</b> 053 * <code>hashCode</code> equality between two keys <code>key1</code> and <code>key2</code> is only guaranteed if 054 * <code>key1.equals(key2)</code> <i>and</i> the keys were produced by the same factory. 055 * @version $Id: KeyFactory.java,v 1.26 2006/03/05 02:43:19 herbyderby Exp $ 056 */ 057@SuppressWarnings({"rawtypes", "unchecked"}) 058abstract public class KeyFactory { 059 060 private static final Signature GET_NAME = 061 TypeUtils.parseSignature("String getName()"); 062 063 private static final Signature GET_CLASS = 064 TypeUtils.parseSignature("Class getClass()"); 065 066 private static final Signature HASH_CODE = 067 TypeUtils.parseSignature("int hashCode()"); 068 069 private static final Signature EQUALS = 070 TypeUtils.parseSignature("boolean equals(Object)"); 071 072 private static final Signature TO_STRING = 073 TypeUtils.parseSignature("String toString()"); 074 075 private static final Signature APPEND_STRING = 076 TypeUtils.parseSignature("StringBuffer append(String)"); 077 078 private static final Type KEY_FACTORY = 079 TypeUtils.parseType("org.springframework.cglib.core.KeyFactory"); 080 081 private static final Signature GET_SORT = 082 TypeUtils.parseSignature("int getSort()"); 083 084 //generated numbers: 085 private final static int PRIMES[] = { 086 11, 73, 179, 331, 087 521, 787, 1213, 1823, 088 2609, 3691, 5189, 7247, 089 10037, 13931, 19289, 26627, 090 36683, 50441, 69403, 95401, 091 131129, 180179, 247501, 340057, 092 467063, 641371, 880603, 1209107, 093 1660097, 2279161, 3129011, 4295723, 094 5897291, 8095873, 11114263, 15257791, 095 20946017, 28754629, 39474179, 54189869, 096 74391461, 102123817, 140194277, 192456917, 097 264202273, 362693231, 497900099, 683510293, 098 938313161, 1288102441, 1768288259}; 099 100 101 public static final Customizer CLASS_BY_NAME = new Customizer() { 102 public void customize(CodeEmitter e, Type type) { 103 if (type.equals(Constants.TYPE_CLASS)) { 104 e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME); 105 } 106 } 107 }; 108 109 public static final FieldTypeCustomizer STORE_CLASS_AS_STRING = new FieldTypeCustomizer() { 110 public void customize(CodeEmitter e, int index, Type type) { 111 if (type.equals(Constants.TYPE_CLASS)) { 112 e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME); 113 } 114 } 115 public Type getOutType(int index, Type type) { 116 if (type.equals(Constants.TYPE_CLASS)) { 117 return Constants.TYPE_STRING; 118 } 119 return type; 120 } 121 }; 122 123 /** 124 * {@link Type#hashCode()} is very expensive as it traverses full descriptor to calculate hash code. 125 * This customizer uses {@link Type#getSort()} as a hash code. 126 */ 127 public static final HashCodeCustomizer HASH_ASM_TYPE = new HashCodeCustomizer() { 128 public boolean customize(CodeEmitter e, Type type) { 129 if (Constants.TYPE_TYPE.equals(type)) { 130 e.invoke_virtual(type, GET_SORT); 131 return true; 132 } 133 return false; 134 } 135 }; 136 137 /** 138 * @deprecated this customizer might result in unexpected class leak since key object still holds a strong reference to the Object and class. 139 * It is recommended to have pre-processing method that would strip Objects and represent Classes as Strings 140 */ 141 @Deprecated 142 public static final Customizer OBJECT_BY_CLASS = new Customizer() { 143 public void customize(CodeEmitter e, Type type) { 144 e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS); 145 } 146 }; 147 148 protected KeyFactory() { 149 } 150 151 public static KeyFactory create(Class keyInterface) { 152 return create(keyInterface, null); 153 } 154 155 public static KeyFactory create(Class keyInterface, Customizer customizer) { 156 return create(keyInterface.getClassLoader(), keyInterface, customizer); 157 } 158 159 public static KeyFactory create(Class keyInterface, KeyFactoryCustomizer first, List<KeyFactoryCustomizer> next) { 160 return create(keyInterface.getClassLoader(), keyInterface, first, next); 161 } 162 163 public static KeyFactory create(ClassLoader loader, Class keyInterface, Customizer customizer) { 164 return create(loader, keyInterface, customizer, Collections.<KeyFactoryCustomizer>emptyList()); 165 } 166 167 public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer, 168 List<KeyFactoryCustomizer> next) { 169 Generator gen = new Generator(); 170 gen.setInterface(keyInterface); 171 // SPRING PATCH BEGIN 172 gen.setContextClass(keyInterface); 173 // SPRING PATCH END 174 175 if (customizer != null) { 176 gen.addCustomizer(customizer); 177 } 178 if (next != null && !next.isEmpty()) { 179 for (KeyFactoryCustomizer keyFactoryCustomizer : next) { 180 gen.addCustomizer(keyFactoryCustomizer); 181 } 182 } 183 gen.setClassLoader(loader); 184 return gen.create(); 185 } 186 187 188 public static class Generator extends AbstractClassGenerator { 189 190 private static final Source SOURCE = new Source(KeyFactory.class.getName()); 191 192 private static final Class[] KNOWN_CUSTOMIZER_TYPES = new Class[]{Customizer.class, FieldTypeCustomizer.class}; 193 194 private Class keyInterface; 195 196 // TODO: Make me final when deprecated methods are removed 197 private CustomizerRegistry customizers = new CustomizerRegistry(KNOWN_CUSTOMIZER_TYPES); 198 199 private int constant; 200 201 private int multiplier; 202 203 public Generator() { 204 super(SOURCE); 205 } 206 207 protected ClassLoader getDefaultClassLoader() { 208 return keyInterface.getClassLoader(); 209 } 210 211 protected ProtectionDomain getProtectionDomain() { 212 return ReflectUtils.getProtectionDomain(keyInterface); 213 } 214 215 /** 216 * @deprecated Use {@link #addCustomizer(KeyFactoryCustomizer)} instead. 217 */ 218 @Deprecated 219 public void setCustomizer(Customizer customizer) { 220 customizers = CustomizerRegistry.singleton(customizer); 221 } 222 223 public void addCustomizer(KeyFactoryCustomizer customizer) { 224 customizers.add(customizer); 225 } 226 227 public <T> List<T> getCustomizers(Class<T> klass) { 228 return customizers.get(klass); 229 } 230 231 public void setInterface(Class keyInterface) { 232 this.keyInterface = keyInterface; 233 } 234 235 public KeyFactory create() { 236 setNamePrefix(keyInterface.getName()); 237 return (KeyFactory) super.create(keyInterface.getName()); 238 } 239 240 public void setHashConstant(int constant) { 241 this.constant = constant; 242 } 243 244 public void setHashMultiplier(int multiplier) { 245 this.multiplier = multiplier; 246 } 247 248 protected Object firstInstance(Class type) { 249 return ReflectUtils.newInstance(type); 250 } 251 252 protected Object nextInstance(Object instance) { 253 return instance; 254 } 255 256 public void generateClass(ClassVisitor v) { 257 ClassEmitter ce = new ClassEmitter(v); 258 259 Method newInstance = ReflectUtils.findNewInstance(keyInterface); 260 if (!newInstance.getReturnType().equals(Object.class)) { 261 throw new IllegalArgumentException("newInstance method must return Object"); 262 } 263 264 Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes()); 265 ce.begin_class(Constants.V1_8, 266 Constants.ACC_PUBLIC, 267 getClassName(), 268 KEY_FACTORY, 269 new Type[]{Type.getType(keyInterface)}, 270 Constants.SOURCE_FILE); 271 EmitUtils.null_constructor(ce); 272 EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance)); 273 274 int seed = 0; 275 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, 276 TypeUtils.parseConstructor(parameterTypes), 277 null); 278 e.load_this(); 279 e.super_invoke_constructor(); 280 e.load_this(); 281 List<FieldTypeCustomizer> fieldTypeCustomizers = getCustomizers(FieldTypeCustomizer.class); 282 for (int i = 0; i < parameterTypes.length; i++) { 283 Type parameterType = parameterTypes[i]; 284 Type fieldType = parameterType; 285 for (FieldTypeCustomizer customizer : fieldTypeCustomizers) { 286 fieldType = customizer.getOutType(i, fieldType); 287 } 288 seed += fieldType.hashCode(); 289 ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL, 290 getFieldName(i), 291 fieldType, 292 null); 293 e.dup(); 294 e.load_arg(i); 295 for (FieldTypeCustomizer customizer : fieldTypeCustomizers) { 296 customizer.customize(e, i, parameterType); 297 } 298 e.putfield(getFieldName(i)); 299 } 300 e.return_value(); 301 e.end_method(); 302 303 // hash code 304 e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null); 305 int hc = (constant != 0) ? constant : PRIMES[(Math.abs(seed) % PRIMES.length)]; int hm = (multiplier != 0) ? multiplier : PRIMES[(Math.abs(seed * 13) % PRIMES.length)]; 307 e.push(hc); 308 for (int i = 0; i < parameterTypes.length; i++) { 309 e.load_this(); 310 e.getfield(getFieldName(i)); 311 EmitUtils.hash_code(e, parameterTypes[i], hm, customizers); 312 } 313 e.return_value(); 314 e.end_method(); 315 316 // equals 317 e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null); 318 Label fail = e.make_label(); 319 e.load_arg(0); 320 e.instance_of_this(); 321 e.if_jump(CodeEmitter.EQ, fail); 322 for (int i = 0; i < parameterTypes.length; i++) { 323 e.load_this(); 324 e.getfield(getFieldName(i)); 325 e.load_arg(0); 326 e.checkcast_this(); 327 e.getfield(getFieldName(i)); 328 EmitUtils.not_equals(e, parameterTypes[i], fail, customizers); 329 } 330 e.push(1); 331 e.return_value(); 332 e.mark(fail); 333 e.push(0); 334 e.return_value(); 335 e.end_method(); 336 337 // toString 338 e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null); 339 e.new_instance(Constants.TYPE_STRING_BUFFER); 340 e.dup(); 341 e.invoke_constructor(Constants.TYPE_STRING_BUFFER); 342 for (int i = 0; i < parameterTypes.length; i++) { 343 if (i > 0) { 344 e.push(", "); 345 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); 346 } 347 e.load_this(); 348 e.getfield(getFieldName(i)); 349 EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizers); 350 } 351 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING); 352 e.return_value(); 353 e.end_method(); 354 355 ce.end_class(); 356 } 357 358 private String getFieldName(int arg) { 359 return "FIELD_" + arg; 360 } 361 } 362 363}